§ Устройство 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