Дисклеймер?
Хай Хабр! Это серия статей по написанию моей ОС с нуля. Я лютый фанат ретропрограммирования, поэтому я мгновенно забуду про существование EDК. Просьба не писать комменты по типу «BIOS давно устарела где UEFI?». Пишу это просто чтобы было, что почитать вечером и порелаксить. Спасибо.
Давайте договоримся
Если вы не владеете языком ассемблера, то можете испытать сложности в понимании происходящего. Пользуюсь я ассемблером <a href=»https://flatassembler.net»>FASM</a>
Включение ПК
При включении ПК, процессор загружает в ОЗУ БИОС, она (БИОС) в свою очередь считывает носители на наличие загрузочной сигнатуры — слова 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, мы видим во-такую букву «Х»:
Думаю, на этом пока все. Спасибо за внимание!
ссылка на оригинал статьи https://habr.com/ru/post/670030/
Добавить комментарий