Comments 37
система, которая есть на любом компьютере — BIOS
Вынужден огорчить, но BIOS встречается уже далеко не везде: например, отсутствует на компьютерах Apple Mac.
Сейчас операционные системы переходят на UEFI.
Во-во. Про Биос и 512 байт уже все кто лень писали. Я было понадеялся, что ну может наконец кто-нибудь через UEFI будет грузиться. Ан нет. Все как в статьях 20 летней (а может и больше) давности
Цикл статей про OS на Rust под Raspbery Pi. Это одна статья, но я помню, что было еще. И еще статья на хабре.
UEFI (я могу ошибаться, потому что только hello world писал) в общих чертах не сложно. Вам потребуется EDK2 (девелопмент тулкит для TianoCore — Open Source имплементации интерфейса UEFI) и документация на API (возможно, я ошибся и не ту ссылку кинул). EFI-приложение с точки зрения кода — обычная программа на C, только API свое. Потом все собираете согласно манам, полученный .efi-файл кладете куда-нибудь в /EFI/BOOT
на диске, загружаетесь в EFI Shell и запускаете. Для x86-64, если я не ошибаюсь, если он называется bootx64.efi
, то будет запущен автоматом, если загружаться с того диска, где он лежит.
Никакой магии, ассемблера, 512 байт и int 21
. А про сам UEFI интерфейс было и на хабре.
7C00h
мы говорим, что код нужно загружать в ОЗУ по адресу 0x7C00.Я правильно понимаю, что, следовательно, если написать
org 666h
, то код загрузится в ОЗУ по адресу 0x666? (Спойлер: нет).Опять??!
Зачем??
cli ;Запрещаем прерывания (чтобы ничего не отвлекало)
sti ;Запрещаем прерывания
Не ошиблись в комментарии?
Их было много… Большинство начинает за здравие, кончает за упокой… Но это не значит, что не надо продолжать работу в этом направлении. Нормальной, а главное, законченной серии статей про написание ОС на хабре лично я не видел.
use16
org 0h
; ---------------------------------------------------------------------------------------
; Boot
;
; DL - Boot drive number
; ---------------------------------------------------------------------------------------
; Start
mov ax, 07C0h
mov ds, ax
; Initialize stack
mov ax, 9000h
cli
mov ss, ax
mov sp, 0FFF0h
sti
; Set destination segment to load kernel to
mov ax, 50h
mov es, ax
mov si, msg_boot_loading
call print_string
; Reset floppy drive
mov ah, 0
int 13h
jc .boot_error
; Load kernel into memory
mov ax, 0
mov bx, sectors_per_track
mov cx, heads_per_cylinder
call calc_chs
xor bx, bx ; es:bx -> buffer
mov al, 18 ; sectors count; read 18 sectors of loader
mov ah, 2
int 13h
jc .boot_error
; Set data segment
push es
pop ds
; Pass control to kernel
push ds
push word kernel_entry
retf
; Show error
.boot_error:
mov si, msg_fail
call print_string
.boot_finish:
hlt
jmp .boot_finish
;
; Print String
;
; DS:SI must point to zero-terminated string
;------------------
print_string:
pushf
push ax
push bx
push si
cld
mov ah, 0Eh
mov bh, 0
print_string.repeat:
lodsb
cmp al, 0
je print_string.finish
int 10h
jmp print_string.repeat
print_string.finish:
pop si
pop bx
pop ax
popf
ret
;
; Calculate CHS address by logical sector address
;
; AX - Logical sector number
; BX - Sectors per track
; CX - Heads per cylinder
; Returns (ready for Int13h:02h call):
; CL - Sector number
; CH - Track number
; DH - Head number
; -----------------
calc_chs:
pushf
push ax
push bx
xor dx, dx ; prepare dx:ax for operation
div bx ; divide by sectors per track
inc dl ; add 1 (obsolute sector formula)
mov bl, dl
xor dx, dx ; prepare dx:ax for operation
div cx ; mod by number of heads (Absolue head formula)
mov dh, dl ; everything else was already done from the first formula
mov ch, al ; not much else to
mov cl, bl
pop bx
pop ax
popf
ret
; Data
msg_boot_loading db 'Loading kernel... ', 0
msg_ok db 'Ok.', 0Dh, 0Ah, 0
msg_fail db 'Failed!', 0Dh, 0Ah, 0
sectors_per_track dw 18
heads_per_cylinder dw 2
times 510 - ($ - $$) db 0
dw 0xAA55
; ---------------------------------------------------------------------------------------
; Kernel (real mode)
; ---------------------------------------------------------------------------------------
; CS, DS, and ES now set to 0050h, SS to 9000h
kernel_entry:
mov si, msg_ok
call print_string
mov eax, 0FAFAFDFDh
shr eax, 16
cmp ax, 0FAFAh
jne .fail
mov si, msg_ok
call print_string
; push 0B800h
; pop es
; xor di, di
; mov word [es:di], 0730h
nop
nop
nop
nop
mov ax, an_address
.finish:
hlt
jmp .finish
.fail:
mov si, msg_fail
call print_string
jmp .finish
; ---------------------------------------------------------------------------------------
; Kernel (protected mode)
; ---------------------------------------------------------------------------------------
; Data
gdt:
; null descriptor
dd 0
dd 0
; code descriptor
gdt_code_limit_low dw 0FFFFh
gdt_code_base_low dw 0
gdt_code_base_middle db 0
gdt_code_access db 10011010b
gdt_code_granularity db 11001111b
gdt_code_base_high db 0
; data descriptor
gdt_data_limit_low dw 0FFFFh
gdt_data_base_low dw 0
gdt_data_base_middle db 0
gdt_data_access db 10010010b
gdt_data_granularity db 11001111b
gdt_data_base_high db 0
;
; Print Byte
;
; AL - byte to print
;------------------
print_byte:
pushf
push ax
push dx
mov dl, al
shr al, 4
add al, 48
cmp al, 58
jl print_byte.print
add al, 7
print_byte.print:
call print_char
mov al, dl
and al, 0Fh
add al, 48
cmp al, 58
jl print_byte.print2
add al, 7
print_byte.print2:
call print_char
pop dx
pop ax
popf
ret
;
; Print Char
;
; AL - char to print
;------------------
print_char:
pushf
push ax
push bx
xor bx, bx
mov ah, 0Eh
int 10h
pop bx
pop ax
popf
ret
;
; Print New Line Chars
;
;------------------
print_nl:
pushf
push ax
mov al, 0Dh
call print_char
mov al, 0Ah
call print_char
pop ax
popf
ret
;
; Print Word
;
; AX - word to print
;------------------
print_word:
push ax
mov al, ah
call print_byte
pop ax
call print_byte
ret
;
; Print Bytes
;
; DS:SI - pointer to data to print
; CX - number of bytes to print
;------------------
print_bytes:
pushf
push ax
push cx
push si
print_bytes.repeat:
mov al, [si]
call print_byte
dec cx ; !!
inc si
jcxz print_bytes.finish ; replace to loop???
mov al, 20h
call print_char
jmp print_bytes.repeat
print_bytes.finish:
pop si
pop cx
pop ax
popf
ret
;
; Print Number
;
; AX - number to print
; BL - number base (2, 8 or 10)
;------------------
print_num:
pushf
push ax
push bx
push cx
push dx
xor cx, cx
mov bh, 0
print_num.repeat:
xor dx, dx
div bx
push dx
inc cx
cmp ax, 0
jne print_num.repeat
print_num.output:
pop ax
add al, 48
call print_char
loop print_num.output
pop dx
pop cx
pop bx
pop ax
popf
ret
;
; Print Decimal Number
;
; AX - number to print
; -----------------
print_decimal:
push bx
mov bl, 10
call print_num
pop bx
ret
an_address:
;
;
;
;
; -----------------
Вообще скорее просто ассемблер хотел вспомнить от нечего делать.
Собственно, вот:
https://wiki.osdev.org/Entering_Long_Mode_Directly
P.S. Ну вот выше как раз ссылку на ту статью дали.
Эхх сколько таких циклов было лет 15 назад
90%стопорилось на загрузчике 9% доходили до интерпретатора командной строки и поддержки fat, 0,(9)%доходили до vesa графики
Дошедших до прикладных программ единицы
Если поможет — вот мои потуги 2013 года в этом направлении.
Ностальгия. Вспомнил, как 15 лет назад на WASM писал загрузчик, ядро с переходом в защищённый режим, простенький менеджер процессов. Забросил на этапе реализации виртуальной памяти.
спасибо! жду продолжения! здорово что всё с пояснениями и без сторонних библиотек, хочется понять как всё работает с самого начала
Пишем операционную систему. Часть 1. Загрузчик