Создадим файл BtImage.asm. Я не буду подробно
описывать каждую использованную функцию,
интересующиеся программированием под DOS 🙂
могут посмотреть про них в соответствующих
доках и хелпах. Уж простите меня за то, как
это написано, так хотелось сделать прогу
поменьше 🙂 

org 100h
use16
lea bx,[Buffer] ;куда читаем
mov cx,01h ;откуда читаем 
xor dx,dx
mov ax,0201h ;
ah=02h - подфункция
чтения с диска, al=01h - сколько секторов
читать

int 13h

xor cx,cx 
lea dx, [FileName] 
mov ah, 3ch ;
подфункция DOS
создать файл

int 21h
xchg bx, ax
lea dx,[Buffer] ;
адрес, что писать
mov cx, 200h ;
сколько байт писать
mov ah, 40h ;
подфункция DOS писать
байты

int 21h 
mov ah, 3eh ;
закрыть файл
int 21h

ret

FileName db 'floppy.img',0
Buffer db 0

После ассемблирования получилась прога
размером 53 байт. Любители изврата могут
посмотреть файл btimage2.asm, там я попытался
уменьшить эту программу вообще насколько
это возможно (у меня 42 байт), так, ради
прикола (имя файла уменьшать нельзя).

Запускаем прогу и в файле floppy.img получаем
образ бутсектора дискеты. Нам надо изменить
его BPB согласно нашей программе (надо
изменить число секторов перед первой FAT).
Это можно сделать с помощью абсолютно
любого hex-редактора. Я использую для
подобных целей HIEW, он наиболее удобен, так
как умеет дизассемблировать программы, что
может оказаться чрезвычайно полезным. Пока
размер нашего загрузчика бутсекторов
составляет всего около 3 Кб, я думаю, если мы
зарезервируем 12 секторов (0Ch в
шестнадцатиричной системе), итого 512*10=5120
байт, то этого вполне хватит. Запускаем
hex-editor и меняем два байт со смещением 0Eh (см.
структуру загрузочного сектора DOS) на 000Ch (точнее
в HEX-редакторе 0C 00). Поменяем на 000Ch и ResSecs в
нашей BPB:

ResSecs dw 000Ch

Вернёмся к написанию процедуры загрузки с
CD-ROM'а. Теперь в нашем распоряжении есть
бутсектор, который мы присоединим как
данные к нашей программе (в файле main.asm):

DOSBootSector file 'floppy.img'

И теперь просто перепишем его по адресу 7C00h,
и передадим туда управление:

BootFromCD:
cli
lea si,[DOSBootSector]
mov di,7C00h
mov cx,128 ;
так как пересылаются
двойные слова, то пересылку надо сделать
512/4=128 раз

rep movsd
sti

jmp 7C00h
ret

На время пересылки лучше запретить
прерывания на случай всяких аппаратных
прерываний вроде уже знакомого прерывания
таймера. Даже если вдруг это прерывание
выполнится, но во время пересылки, после
возврата из прерывания повторяемая
операция возобновляется с точки прерывания,
но возобновляется корректно не всегда.

И не забудем подключить boot.inc

include 'boot.inc'.

Ну что же, в общем программа написана,
осталось привести её в нормальный вид. Во
первых, предлагаю код поместить в начале, а
данные - в конце образа. Для этого
достаточно написать все includ'ы, кроме самого
main.asm, и данные в файле main.asm, причём то, где
подключаются данные, поместить в конец:

include 'graphic.inc'
include 'keyb.inc'
include 'boot.inc'

include 'text.inc'

InterfaceData file 'IntData.bin'
DOSBootSector file 'floppy.img'

Теперь так приятно полюбоваться на неё в
hex-view'ере 😉 Раздражает пустота в начале.
Можно вставить туда код, отключающий курсор,
чтобы глаза не мозолил:

mov ah,01h ;подфункция BIOS, задающая
форму курсора
mov cx,2019h
int 10h

Приятно будет, если по нажатии на escape комп
будет грузится с винта, например, HDA1, а при
нажатии на пробел - с сидюка, к тому-же это
ничего не стоит. Добавим в цикл ввода данных
с клавиатуры обработчики:

cmp al, 1bh ;escape
jz BootFromHDA1

cmp al, ' ' ;пробел
jz BootFromCD

Можно, даже нужно очистить экран перед
запуском бутсектора, а лучше вообще
сохранить всё содержимое экрана, а потом
восстановить его. Есть два способа:
прочитать экран через функции прерывания int
10h BIOS или сохранить содержимое видеопамяти.
Оба просто реализуются, но второй работает
побыстрее, поэтому воспользуемся им:

cli
push si
push di
push es
push ds
push 0B800h ;
адрес видеопамяти
0B800:0000h

pop ds
push 01000h ;
приёмник es:di 1000:0000h
pop es
xor si,si
xor di,di
mov cx,1000 ;
размер страницы
видеопамяти 80*25*2=4000 байт, мы пересылаем
двойные слова (4 байт)

rep movsd
pop ds
pop es
pop di
pop si
sti

Мы просто скопировали часть памяти. Вставим
этот код в bootsect.asm (в принципе неважно куда,
главное до jmp Main_Program). Процедура, копирующая
информацию обратно:

OldScreen:
cli
push si
push di
push es
push ds
push 0B800h ;
адрес видеопамяти
0B800:0000h

pop ds
push 01000h ;
источник ds:si 1000:0000h
pop es
xor si,si
xor di,di
mov cx,1000 
rep movsd
pop ds
pop es
pop di
pop si
sti
ret

Её можно поместить в graphic.asm. Впишем её вызов 

call OldScreen

перед обоими jmp'ами в 7C00h.

Также можно сохранить содержимое всех
регистров ( на всякий случай 32 битных), чтобы
загруженный бутсектор ощущал себя так, как
будто его загрузил BIOS 🙂

pushad
push ebp
push ds
push es
push fs
push gs

и перед самым jmp 7C00h восстановим их:

pop gs
pop fs
pop es
pop ds
pop ebp
popad

Вроде всё хорошо, но чего-то не хватает.
Давайте раскрасим наш образ экрана.
Программно это делается легко, но неудобно
для последующей модификации. Это конечно
нехорошо следовать примеру Microsoft в
отношении размера программ (я как-то от
скуки дизассемблировал ntldr и долго не мог
придти в себя, а про io.sys вообще молчу), но всё-таки
увеличить нашу программу на 2000 байт я думаю
можно. Ведь увеличивается она за счёт
данных, а не за счёт кода. А код у нас как
никак походит на нормальный. Кому не лень
почти бессмысленно тратить кучу времени и
сил, чтобы нарисовать весь экран программно,
может заняться этим. А то можно как-нибудь
извратится и даже надписи сделать
программно 🙂

Мы создадим образ массива атрибутов для
каждого символа. Как это сделать? Всего
цветов 16: 

00H черный 04H красный 08H темно-серый 0cH светло-красный
01H синий 05H розовый 09H ярко-синий 0dH светло-розовый
02H зеленый 06H коричневый 0aH светло-зеленый 0eH желтый
03H голубой 07H серый 0bH светло-голубой 0fH белый

Атрибут можно вычислить по формуле (фон*16)+передний
план, add 128 для мерцания. Если нужен чистый
цвет, то это просто номер цвета (см. выше).
Итак, я предлагаю запустить hex-редактори
вперёд! Для удобства можно скопировать
IncData.bin в Color.bin и прямо в нём всё исправить.
Конечно медленно и туповато, а другие
предложения есть? Да, сделать то же в уже
знакомом ASCII Art Studio.

Теперь надо смешать эти два файла так, чтобы
сначала шёл символ, а потом его цвет, чтобы
получить образ страницы видеопамяти.
Программу для этого можно взять здесь mixe.exe
и mixe.dpr. 
Работает эта программа аналогично
предыдущей:

mixe intdata.bin color.bin screen.img

Естественно теперь, если мы захотим
подкорректировать цвет, нам не надо будет
менять color.bin, это гораздо удобнее сделать
прямо в screen.img. Может потребоваться наоборот,
разделить образ видеопамяти на два файла.
Для этого можно использовать эту программу
demixe.exe и demixe.dpr. Теперь надо модифицировать
процедуру вывода образа на экран.
Достаточно просто скопировать этот образ в
видеопамять (0B800:0000):

DrawInterface:
cli
push si 
push di
push es
lea si,[Screen]
push 0B800h ;поместим в es сегмент видеопамяти
pop es
xor di,di
mov cx,1000 ;скопируем 1000 двойных слов
rep movsd
pop es
pop di
pop si
sti
ret

А в main.asm конечно объявим переменную Screen:

Screen file 'Screen.img'

Чтобы было совсем круто, давайте добавим
функцию вывода бутсектора на экран по
нажатии F3. Иногда это может оказать
определённую помощь (особенно извращенцам
:)). В бесконечный цикл, точнее туда, где
поверяются расширенные сканкоды (extended_scancode)
добавим:

cmp ah,61 ;F3
jz ViewBootSector

И обработчик:

ViewBootSector:
cmp [MenuItemSelected],0
jz @keypress

cmp [MenuItemSelected],4
jz @keypress

mov dl,01h ; определим, какой
диск смотреть

cmp [MenuItemSelected],1
jz @ViewBSector

mov dl,80h
cmp [MenuItemSelected],2
jz @ViewBSector

mov dl,81h

@ViewBSector:

call Erase

mov bx,0A000h ; это будет буфер,
там нашей программы нет

mov cx,01h ;
откуда читаем 
xor dh,dh
mov ax,0201h ;
ah=02h - подфункция
чтения с диска, al=01h - сколько секторов
читать

int 13h
jc @read_error ;
проверим, не было
ли ошибки

call PrintEx
jmp @keypress

Процедура PrintEx будет выводить на экран
бутсектор так, чтобы он не стёр рамку:

PrintEx:
pusha
mov dx,0C01h ;
в dx - начальные
координаты: dh=12, dl=1

mov si,bx
mov cx,512 ;
на экран - 512 байт
mov bl,2 ;
цвет - зелёный
@4:
cmp dl,79
jz @5
lodsb
call PrintSymbol
inc dl
loop @4
jmp @6

@5:
mov dl,1
inc dh
jmp @4
@6:
popa
ret

Процедура Erase сотрёт старый бутсектор на
случай, если новый не прочитается:

Erase:
pusha
mov dx,0C01h ;
в dx - начальные
координаты: dh=12, dl=1

mov cx,512 ;
на экран - 512 байт
mov al,' ' ;
символ - пробел
@7:
cmp dl,79
jz @8
call PrintSymbol
inc dl
loop @7
jmp @9

@8:
mov dl,1
inc dh
jmp @7
@9:
popa
ret

Ну вот и всё! Осталось сделать кое-какой
косметический ремонт, вроде в main.asm
расположить сначала код, потом данные.
Можно добавить

times (6144-($-7C00h)) db 0

в самый конец main.asm, чтобы размер нашего
образа точно равнялся 12 секторам, а ещё там
можно написать какую-нибудь ерунду, вроде
"Здесь был Я" 🙂

Итак, сама программа написана, осталось
записать её на дискету с помощью, например,
RawwriteWin перезагрузить комп и наслаждаться
результатом ;).

Теперь на эту дискету можно записать io.sys,
command.com, msdos.sys и т.д. Будет грузится DOS, когда
выбирается загрузка с CD-ROM (почему так, см.
выше, ведь программа предназначена для CD). 

В этой программе отсутствует возможность
загрузки с CD-ROM'а (не с того, для которого эта
прога предназначается) и с Secondary Master/Slave. При
желании последнее вы добавите без труда, а
вот с загрузкой с другого CD-ROM'а есть
определённые проблемы. Ведь она происходит
не так, как с дискеты или жёсткого диска (вернее,
возможно сделать, чтобы было так, но это
является исключением, см. выше). 

На этом мы пока и закончим. 

В следующей статье подробно рассмотрим:

- основные недостатки существующих
загрузочных дисков
- создание меню загрузки
- основы загрузки драйверов в DOS
- как уменьшить место, занимаемое
драйверами
- как сделать, чтобы когда вынимаешь CD, комп
работал
- NTFS под DOS
- полезные программы

... и некоторые другие интересные вещи.

Check Also

Спаси и сохрани! Сравниваем популярные программы для резервного копирования

«Полетел диск» — это всегда событие. Если оно происходит в небе при большом стечении народ…

Оставить мнение