11:58
Написание простого boot-сектора — Лисья нора
§ Устройство MBR
Начнем с того, что бутсектор должен располагаться в 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 ; Чтобы реагировал на CTRL+ALT+DEL
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 ; 0Eh печать символа в терминале
lodsb ; Загрузка символа из DS:SI
and al, al ; Проверка AL на 0
je $ ; Если 0, остановить процессор
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
; Задача boot-сектора это загрузить и запустить программу
; Конечно же, лучше чтобы программа была в FAT, но пока что так
mov [7C00h], dl ; Сохранить DL (Drive Letter ;)
mov ah, 41h ; Проверка на поддержку режима DAP
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 ; 0 | размер DAP = 16
dw 0040h ; 2 | читать 64 секторов (32 кб)
dw 0000h ; 4 | смещение (=0)
dw 0800h ; 6 | сегмент (=800h) * 10h = 0000:8000
dq 1 ; 8 | номер сектора от 0 до N-1 (1 = второй сектор)§ Загрузка с Floppy
macro brk { xchg bx, bx }
org 7c00h
jmp short start
db 00h
; ----------------------------------------------------------------------
; BPB: Bios Parameter Block
; ----------------------------------------------------------------------
db "FLOPPY12" ; 03 Signature
dw 200h ; 0B Bytes in sector
db 1 ; 0D Sectors by cluster
dw 65 ; 0E Count reserver sectors (32K+Boot)
db 2 ; 10 Count of FAT
dw 00E0h ; 11 Count of Root Entries (224)
dw 0B40h ; 13 Total count of sectors
db 0F0h ; 15 Media
dw 9 ; 16 Sectors in FAT
dw 12h ; 18 Sectors on track
dw 2 ; 1A Count of heads
dd 0 ; 1C Hidden Sectors (large)
dd 0 ; 20 Total Sectors
db 0 ; 24 Number of Phys.
db 1 ; 25 Flags
db 29h ; 26 Ext Sig
dd 07E00000h ; 27 Serial Numbers ES:BX
db 'CORE BIN' ; 2B Label / Exec File
db 'FAT12 ' ; 36 Type of FS
; ----------------------------------------------------------------------
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
; ----------------------------------------------------------------------
; AX - number of sector, ES:BX pointer to data place
; ----------------------------------------------------------------------
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 ; es:bx, cx/dx
pop cx ax
ret
; ----------------------------------------------------------------------
; ESTIMATED FILL ZERO
; ----------------------------------------------------------------------
times 7c00h + (512 - 2) - $ db 0x00
dw 0xAA55