§ Описание

Зачастую возникает желание создать свою ОС, но никак не знаешь, с чего начать? Так вот ответ простой — бутсектор! Если напишешь бутсектор, считай, половина ОС в твоем кармане. Ахаха! Поверил? А вот и нет. Это 0.01% от операционной системы.

§ Исходный код

Код написан с использованием fasm.
        macro   brk { xchg bx, bx }
        org     7c00h

        jmp     short start
        db      00h

; ----------------------------------------------------------------------
; BPB: Bios Parameter Block
; ----------------------------------------------------------------------
        db      "FLOPPY12"          ; 03 Signature
        dw      200h                ; 0B Байт в секторе
        db      1                   ; 0D Секторов на кластер
        dw      1                   ; 0E Количество зарезервированных секторов
        db      2                   ; 10 Количество FAT
        dw      00E0h               ; 11 Количество Root Entries (224)
        dw      0B40h               ; 13 Всего секторов
        db      0F0h                ; 15 Параметр media
        dw      9                   ; 16 Секторов в FAT
        dw      12h                 ; 18 Секторов на дорожке (18)
        dw      2                   ; 1A Количество дорожек
        dd      0                   ; 1C Скрытых секторов (large mode)
        dd      0                   ; 20 Всего секторов (large mode)
        db      0                   ; 24 Номер физического девайса
        db      1                   ; 25 Флаги
        db      29h                 ; 26 Расширенная сигнатура
        dd      07E00000h           ; 27 Серийный номер, но используется для ES:BX
        db      'DEMO    BIN'       ; 2B Лейбл, используется для файла загрузки
        db      'FAT12    '         ; 36 Тип файловой системы
; ----------------------------------------------------------------------

start:
        cli                         ; IF=0
        cld                         ; DF=0
        xor     ax, ax              ; Очистка DS: ES: SS: сегментов
        mov     ds, ax
        mov     es, ax
        mov     ss, ax
        mov     sp, 7c00h           ; Установка стека
        mov     ax, 19              ; Сектор 19-й содержит первый сектор
dir:    les     bx, [7c27h]         ; root-каталога и он читается в $7E00
        call    ReadSector          ; с диска, сектор задается через LBA (AX)
        mov     di, bx              ; ES:DI - Начало записей в ROOT
        mov     bp, 16              ; 16 файлов в секторе из 512 байт
item:   mov     si, 7c2bh           ; DS:SI - Проверка имени формата 8.3
        mov     cx, 12              ; 11 + 1 - Сравниваем 11 символов (+1)
        push    di
        repe    cmpsb               ; Сравнение строк
        pop     di
        jcxz    file_found          ; Файл был найден, перейти к загрузке
        add     di, 32              ; Иначе искать следующую строку
        dec     bp
        jne     item                ; Если просмотр в секторе закончился
        inc     ax                  ; Перейти к следующему сектору
        sub     word [7c11h], 16    ; Кол-во оставшихся записей
        jne     dir                 ; Сектора еще не закончились в ROOT?
        int     18h                 ; Нет запускного файла

; ----------------------------------------------------------------------
; Загрузка файла по адресу 8000h
; ----------------------------------------------------------------------

file_found:

        mov     ax, [es: di + 1Ah]  ; Номер кластера
        mov     [7c22h], word 800h  ; Адрес, где начинатся программа

next:   push    ax                  ; В AX содержится номер читаемого кластера
        add     ax, 31              ; 33-сектор находится DATA-секция
        les     bx, [7c20h]         ; Область памяти, куда будет читать
        call    ReadSector
        add     [7c22h], word 20h   ; +20h сегментов (32*16=512 байт)
        pop     ax                  ; Искать следующий кластер по текущему
        mov     bx, 3               ; Умножить на 3 полубайта (по 4 бита)
        mul     bx                  ; Поскольку FAT12 -- 12-битная
        push    ax
        shr     ax, 1 + 9           ; Найти номер сектора FAT
        inc     ax                  ; Пропуск +1 BPB
        mov     si, ax              ; Сохранить номер этого сектора на потом
        les     bx, [7c27h]         ; Скачать сюда ES:BX=07e0:0000
        call    ReadSector
        pop     ax                  ; Восстановить номер кластера
        mov     bp, ax              ; Теперь он в BP
        mov     di, ax
        shr     di, 1               ; Найти кластер в загруженном секторе FAT
        and     di, 0x1FF           ; Срезать лишние биты
        mov     ax, [es: di]        ; Загрузка в AX указателя на следующий кластер
        cmp     di, 0x1FF           ; Если не хватает данных (конец сектора FAT)
        jne     @f
        push    ax                  ; Сохраняем AX
        xchg    ax, si
        inc     ax                  ; Следующий сектор FAT
        call    ReadSector          ; Читается в 7E00:0000
        pop     ax
        mov     ah, [es: bx]        ; И дополняем AH (которого не хватало)
@@:     test    bp, 1               ; Если младший бит кластера равен 0
        jz      @f                  ; То ничего не делать
        shr     ax, 4               ; Иначе, нечетные кластеры сдвинуть вправо на 4 бита
@@:     and     ax, 0x0FFF          ; Ограничить от 0 до 4095
        cmp     ax, 0x0FF0          ; Если следующий кластер < 4080
        jb      next                ; Продолжить чтение, если так
        jmp     0 : $8000           ; Иначе запускает программу

; ----------------------------------------------------------------------
; AX - номер сектора от 0 до n, ES:BX указывает на данные
; ----------------------------------------------------------------------

ReadSector:

        push    ax bx           ; Сохранить AX, BX
        mov     cx, 12h         ; 18 секторов на дорожку
        cwd                     ; DX=0
        div     cx              ; Разделить LBA на 18
        xchg    ax, cx          ; Результат в CX
        mov     dh, cl          ; Сохранить CL в DH
        and     dh, 1           ; В DH будет номер головки (0 или 1)
        shr     cx, 1           ; В CX будет номер цилиндра
        xchg    ch, cl          ; В CL будет старший цилиндр, в CH младший
        shr     cl, 6           ; В старших 2-х битах старшие 2 бита цилиндра
        inc     dx              ; Номер головки 1 или 2
        or      cl, dl          ; Объединить биты [5:0] сектора и старшего цилиндра
        mov     dl, 0           ; Номер диска 00 - Floppy
        mov     ax, 0201h       ; Чтение данных
        int     13h             ; ES:BX, параметры CHS в CX/DX
        pop     bx ax           ; Восстановить AX, BX
        ret

; ----------------------------------------------------------------------
; Оставшееся пространство заполнить нулями
; ----------------------------------------------------------------------

        times   7c00h + (512 - 2) - $ db 0x00
        dw      0xAA55