Оглавление
§ Устройство MBR
Зачастую возникает желание создать свою ОС, но никак не знаешь, с чего начать? Так вот ответ простой – бутсектор! Если напишешь бутсектор, считай, половина ОС в твоем кармане. Ахаха! Поверил? А вот и нет. Это 0.01% от операционной системы.
Начнем с того, что бутсектор должен располагаться в MBR. Дело в том, что после разметки диска, начиная с 446-го байта и заканчивая 512-м, на диске уже есть разметка 4 primary разделов. По этой причине, код бутсектора для диска (hd) а не флоппи (fd), должен быть не более 446 байт. Это очень важно. Сам же код сектора загружается биосом по адресу 0000h:7C00h (CS=0000h, IP=7C00h) в реальном режиме работы процессора. Это так всегда происходит. Наша задача что-то сделать с этим.
000 Программный код бут загрузчика
1BE Дескриптор 1-го раздела диска (16 байт)
1CE Дескриптор 2-го раздела диска (16 байт)
1DE Дескриптор 3-го раздела диска (16 байт)
1EE Дескриптор 4-го раздела диска (16 байт)
1FE Сигнатура 0xAA55 (или 55h AAh)
Сама же структура раздела такая
00 1 Признак активности раздела
01 1 Начало раздела — головка
02 1 Начало раздела — сектор (биты 0—5), цилиндр (биты 6, 7)
03 1 Начало раздела — цилиндр (старшие биты 8, 9 хранятся в байте номера сектора)
04 1 Код типа раздела
05 1 Конец раздела — головка
06 1 Конец раздела — сектор (биты 0—5), цилиндр (биты 6, 7)
07 1 Конец раздела — цилиндр (старшие биты 8, 9 хранятся в байте номера сектора)
08 4 Смещение первого сектора
0C 4 Количество секторов раздела
В современных дисках головка, сектор и цилиндр вообще ни к чему. К тому же, даже смещение или первого сектора количество секторов на диске, описанных через 4 байта, может быть не таким большим. Ну сколько он может быть? Допустим, сектор занимает 512 байт, а максимально адресуемый размер диска получится 2^32*2^9 = 2^41 байт. Так как 1 гигабайт = 2^30 байт, то тогда 2^41/2^30 = 2^11 гигабайт (2048 Гб), что равно 2 терабайта. Сейчас диски есть на 4 Тб, какой там 2 Тб. И вот как с этим справляется наш герой? Все на просмотр картины второй! (Шутка) На самом деле для больших дисков используется GPT-механизм, который только в UEFI есть, а в старом BIOS этого нет. Никто не знал, что 4Тб диски вообще будут в природе. Но поскольку мои диски более 512 Гб не особо превышают, то мне норм.
§ Обновление сектора
Я думаю, что нужно написать простой makefile для обновления сектора
all:
rm -f *.lock
fasm boot.asm
dd conv=notrunc if=boot.bin of=disk.img bs=446 count=1
bochs -f c.bxrc -q > /dev/null 2>&1
Сначала удаляются лок-файлы, если они были, потом ассемблируется файл boot.asm, далее с помощью утилиты dd заменяются первые 446 байта на диске и запускается bochs.
Сам же код boot.asm максимально прост:
org 7C00h
cld
sti
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 7C00h
jmp $
В этом коде просто устанавливаются сегментные регистры в 0 и стек ставится под кодом бут-сектора.
Напишу Hello World, используя функцию BIOS INT 10h
mov si, ab
@@: mov ah, 0Eh
lodsb
and al, al
je $
int 10h
jmp @b
ab: db "Hello World",0
Чтобы выгрузить данный бут-сектор на реальную флешку, можно воспользоваться такой командой
sudo dd conv=notrunc if=boot.bin of=/dev/sdX bs=446 count=1
Где /sdX – это устройство флешки, например, sdd или sde, это надо узнать через команду df -h, там будет выведен список подключенных устройств.
Я вот проверил свой код, все работает хорошо.
§ Вариант с загрузкой 32Кб
org 7c00h
macro brk { xchg bx, bx }
cli
cld
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 7C00h
mov [7C00h], dl
mov ah, 41h
mov bx, 55AAh
int 13h
jc error
mov ah, 42h
mov si, DAP
mov dl, [7C00h]
int 13h
jc error
jmp 0 : 8000h
error: jmp $
DAP: dw 0010h
dw 0040h
dw 0000h
dw 0800h
dq 1
§ Вариант I: Простой
Качается 64 сектора (32Кб) с диска в память и запуск.
macro brk { xchg bx, bx }
org 7c00h
jmp short start
db 00h
db "FLOPPY12"
dw 200h
db 1
dw 65
db 2
dw 00E0h
dw 0B40h
db 0F0h
dw 9
dw 12h
dw 2
dd 0
dd 0
db 0
db 1
db 29h
dd 07E00000h
db 'CORE BIN'
db 'FAT12 '
start: cli
cld
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov esp, 7c00h
mov ax, 1
mov bx, $8000
mov cx, 64
@@: call ReadSector
add bx, 512
inc ax
loop @b
jmp 0 : $8000
ret
ReadSector:
push ax cx
mov cx, 12h
cwd
div cx
xchg ax, cx
mov dh, cl
and dh, 1
shr cx, 1
xchg ch, cl
shr cl, 6
inc dx
or cl, dl
mov dl, 0
mov ax, 0201h
int 13h
pop cx ax
ret
times 7c00h + (512 - 2) - $ db 0x00
dw 0xAA55
§ Вариант II: Поиск загрузочного файла
Расширенный код, загрузка из FAT12 файла. Код написан с использованием fasm.
macro brk { xchg bx, bx }
org 7c00h
jmp short start
db 00h
db "FLOPPY12"
dw 200h
db 1
dw 1
db 2
dw 00E0h
dw 0B40h
db 0F0h
dw 9
dw 12h
dw 2
dd 0
dd 0
db 0
db 1
db 29h
dd 07E00000h
db 'DEMO BIN'
db 'FAT12 '
start:
cli
cld
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 7c00h
mov ax, 19
dir: les bx, [7c27h]
call ReadSector
mov di, bx
mov bp, 16
item: mov si, 7c2bh
mov cx, 12
push di
repe cmpsb
pop di
jcxz file_found
add di, 32
dec bp
jne item
inc ax
sub word [7c11h], 16
jne dir
int 18h
file_found:
mov ax, [es: di + 1Ah]
mov [7c22h], word 800h
next: push ax
add ax, 31
les bx, [7c20h]
call ReadSector
add [7c22h], word 20h
pop ax
mov bx, 3
mul bx
push ax
shr ax, 1 + 9
inc ax
mov si, ax
les bx, [7c27h]
call ReadSector
pop ax
mov bp, ax
mov di, ax
shr di, 1
and di, 0x1FF
mov ax, [es: di]
cmp di, 0x1FF
jne @f
push ax
xchg ax, si
inc ax
call ReadSector
pop ax
mov ah, [es: bx]
@@: test bp, 1
jz @f
shr ax, 4
@@: and ax, 0x0FFF
cmp ax, 0x0FF0
jb next
jmp 0 : $8000
ReadSector:
push ax bx
mov cx, 12h
cwd
div cx
xchg ax, cx
mov dh, cl
and dh, 1
shr cx, 1
xchg ch, cl
shr cl, 6
inc dx
or cl, dl
mov dl, 0
mov ax, 0201h
int 13h
pop bx ax
ret
times 7c00h + (512 - 2) - $ db 0x00
dw 0xAA55