Написание ОС с нуля: Часть 1 — Загрузчик

Дисклеймер?

Хай Хабр! Это серия статей по написанию моей ОС с нуля. Я лютый фанат ретропрограммирования, поэтому я мгновенно забуду про существование 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, мы видим во-такую букву «Х»:

X
X

Думаю, на этом пока все. Спасибо за внимание!


ссылка на оригинал статьи https://habr.com/ru/post/670030/

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *