Дисклеймер?
Хай Хабр! Это серия статей по написанию моей ОС с нуля. Я лютый фанат ретропрограммирования, поэтому я мгновенно забуду про существование EDК. Просьба не писать комменты по типу "BIOS давно устарела где UEFI?". Пишу это просто чтобы было, что почитать вечером и порелаксить. Спасибо.
Давайте договоримся
Если вы не владеете языком ассемблера, то можете испытать сложности в понимании происходящего. Пользуюсь я ассемблером FASM
Включение ПК
При включении ПК, процессор загружает в ОЗУ БИОС, она (БИОС) в свою очередь считывает носители на наличие загрузочной сигнатуры - слова 0х55АА по смещению 0x1FE. Если она (сигнатура) присутствует, то первые 512 байт с носителя загружается в ОЗУ по адресу 0х7С00 и БИОС передает управление этому коду.
К делу
Напишем загрузчик, который очистит экран и напечатает "Привет, мир!":
format binary as "sec"
use16
org 0x7C00
jmp boot
nop
db 'HEXOS ' ; db 8
dw 512 ; bytes per sector
db 1 ; sectors per cluster
dw 1 ; number of reserver sectors
db 2 ; count of FAT data structures
dw 224 ; count of 32-byte dir. entries (224*32 = 14 sectors)
dw 2880 ; count of sectors on the volume (2880 for 1.44 mbytes disk)
db 0f0h ; f0 - used for removable media
dw 9 ; count of sectors by one copy of FAT
dw 18 ; sectors per track
dw 2 ; number of heads
dd 0 ; count of hidden sectors
dd 0 ; count of sectors on the volume (if > 65535)
db 0 ; int 13h drive number
db 0 ; reserved
db 29h ; Extended boot signature
db 0 ; Volume serial number
db 'HEXOS ' ; Volume label (db 11)
db 'HAT16 ' ; file system type (db 8)
msg db "Hello, World!!", 0x0D, 0x0A, 0x00
printsz:
mov ah, 0x0E
.cycle:
lodsb
test al, al
jz .end
int 0x10
jmp .cycle
.end:
ret
;
;
boot:
mov ax, 0x0003
int 0x10
mov si, msg
call printsz
;
cli
hlt
;
times 512-$+$$-2 db 0x00
db 0x55, 0xAA
Итак, запускаем это чудо в qemu и видим:
Ура! Всё работает. Но я называю это "Загрузчик", несмотря на то, что он ничего не загружает. Нехорошо. Нам нужно также избавится от ограничения в 512 байт. в такой маленький обьем мало-ли что уместится.
Подходим к делу серьезно
Итак, нам нужно избавиться от ограничения в 512 байт. для этого, как вариант, можно написать весь интересующий нас код отдельно, а потом просто подгрузить его. Да, для этого и существуют загрузчики.
К делу 2
Напишем загрузчик, который будет загружать остальной код с диска в ОЗУ по адресу 0х7Е00(или же 0х7С00+512):
boot.asm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) HexOS author 2019-2022. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
format binary as "sec"
use16
org 7C00h
jmp boot_entry
nop
include "bpb.inc"
msg db "HexOS bootloader v2.1.3 by Ivan Chetchasov", 0Dh, 0Ah, 0x00
log db "Loading second stage...", 0Dh, 0Ah, 0x00
include "boot.inc"
boot_entry:
cls
printsz msg
printsz log
mov ah, 02h
mov al, 10h
mov cx, 0002h
mov bx, 7E00h
movs es, 0000h
int 13h
mov sp, 7E0h
movs ds, 7E00h
jmp 0000:7E00h
cli
hlt
jmp $-2
times 200h-2h-$+$$ db 00h
dw 0AA55h
boot.inc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) HexOS author 2019-2022. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
__print_stringz__:
mov ah, 0x0E
__print_stringz__.__print_loop__:
lodsb
test al, al
jz __print_stringz__.__print_ending__
int 10h
jmp __print_stringz__.__print_loop__
__print_stringz__.__print_ending__:
ret
macro printsz charptr {
push ax si
mov si, charptr
call __print_stringz__
pop si ax
}
macro cls {
push ax
mov ax, 0003h
int 10h
pop ax
}
macro movs reg, src {
push ax
mov ax, src
mov es, ax
pop ax
}
second.asm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) HexOS author 2019-2022. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
format binary as "sec"
org 7E00h
start:
use16
; header zone
jmp second_entry
nop
; import zone
include "second.inc"
; executable zone
second_entry:
cls
;printsz msg0
mov ah, 02h
mov al, 08h
mov cx, 0012h; 0012h is correct
; dl was not modified
mov bx, 8100h
movs es, 0000h
int 13h
jc err0
mov sp, 810h
movs ds, 8100h
jmp 0000:8100h
err0:
; construct BSOD stylish
cls
MOV AH, 06h
XOR AL, AL
XOR CX, CX
MOV DX, 184Fh
MOV BH, 17h
INT 10h
; print data
printsz bsod0
jmp endall
endall:
cli
hlt
jmp $-2
; data zone
msg0 db "HexOS Second-stage Bootloader v2.2.1 by Ivan Chetchasov", newline
db "LOG: Loading HAT16 filetable", newline, 00h
bsod0:
db newline
db newline
db " ((((((", newline
db " ((::::::( ERROR OCCURRED", newline
db " ((:::::::( At position: 00007E32h", newline
db " (:::::::((", newline
db " (::::::( Reason: cannot load kernel", newline
db " :::::: (:::::( Maybe your disk is corrupted", newline
db " :::::: (:::::( So try to re-install system", newline
db " :::::: (:::::( Or append file 'System/kernel.hex'", newline
db " (:::::( To your disk with other PC", newline
db " (:::::( (be careful, maybe virus killed", newline
db " (:::::( your PC, don`t infect other one!)", newline
db " :::::: (::::::( ", newline
db " :::::: (:::::::(( ", newline
db " :::::: ((:::::::( ", newline
db " ((::::::(", newline
db " ((((((", newline
db newline
db "Errcode: 0000000Dh Errname: ERROR_CANNOT_LOAD_KERNEL", newline, 00h
; filler
times 200h*16-1+start-$ db 00h
; magic
db EOF
second.inc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) HexOS author 2019-2022. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
__print_stringz__:
mov ah, 0x0E
__print_stringz__.__print_loop__:
lodsb
test al, al
jz __print_stringz__.__print_ending__
int 10h
jmp __print_stringz__.__print_loop__
__print_stringz__.__print_ending__:
ret
macro printsz charptr {
push ax si
mov si, charptr
call __print_stringz__
pop si ax
}
macro cls {
push ax
mov ax, 0003h
int 10h
pop ax
}
macro movs reg, src {
push ax
mov ax, src
mov es, ax
pop ax
}
newline equ 0Dh, 0Ah
EOF equ 128
kernel.asm
format binary as "hex"
org 8100h
mov ah, 0x0E
mov al, "X"
int 0x10
cli
hlt
times 0E0h*200h+$$-$ db 0x00
image.asm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) HexOS author 2019-2022. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
file "boot\boot.sec"
file "boot\second.sec"
file "kernel\kernel.hex"
при запуске в qemu, мы видим во-такую букву "Х":
Думаю, на этом пока все. Спасибо за внимание!
П.Ы.: Принимаю любые предложения по развитию проекта в лс Хабра
Ссылки: