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

в 8:39, , рубрики: asm, bootload

Дисклеймер?

Хай Хабр! Это серия статей по написанию моей ОС с нуля. Я лютый фанат ретропрограммирования, поэтому я мгновенно забуду про существование 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 "bootboot.sec"
file "bootsecond.sec"
file "kernelkernel.hex"

при запуске в qemu, мы видим во-такую букву "Х":

X
X

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

П.Ы.: Принимаю любые предложения по развитию проекта в лс Хабра

Ссылки:

  1. HexOS-GitHub

  2. Следующая часть

Автор: Четчасов Иван

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js