На днях баловался с загрузчиком для ОС. Требованиями были минимум выполняемых действий (остальное должно выполняться уже в ядре) и удобный и готовый к страничной адресации формат загружаемого ядра.
После некоторых размышлений пришел к такому варианту:
1. в первичном загрузчике считываем в память вторичный загрузчик и ядро. Прыгаем во вторичный загрузчик;
2. по адресу 2k (0x800) размещаем GDT;
3. переходим в защищенный режим (куда уж без него то :) );
4. загружаем PE ядро. Прыгаем в него.
Довольно удачный компромис, на мой взгляд. И загрузчик получился довольно простой и ядро я теперь могу писать в любимой Visual Studio, как почти обычное 32бит приложение.
Недостатки компилятора от Майкрософт для такого рода занятий это уже вопрос второй ;)
Основной код:
include 'struct.inc'
include 'pe.inc'
include 'boot.inc'
PAGE_SIZE = 0x1000
GDT_OFFSET = 0x800
; Global Descriptor Table
GDT:
dd 0,0
db 0FFh, 0FFh, 00h, 00h, 00h, 10011010b, 11001111b, 00 ; code
db 0FFh, 0FFh, 00h, 00h, 00h, 10010010b, 11001111b, 00 ; data
GDT_size equ $-GDT
GDTR dw GDT_size-1
dd GDT_OFFSET
loader_entry:
; open address line A20
in al, 92h
or al, 2
out 92h, al
; copy GDT to the 2nd kb RAM
; это удобно, поскольку в первых 2к расположим IDT
mov cx, GDT_size
mov di, GDT_OFFSET
mov si, GDT
rep movsb
lgdt fword [GDTR]
; disable all ints
; в том числе и немаскируемые
cli
in al, 70h
or al, 80h
out 70h, al
; jump to PM
mov eax, cr0
or al, 1
mov cr0, eax
; load new selector to the CS
jmp 00001000b:.protected_entry
use32
.protected_entry:
; init selectors
mov ax,00010000b
mov ds, ax
mov es, ax
mov ss, ax
;
; simple PE loader for loading PE kernel.
;
mov ebx, kernel_image
cmp word [ebx + IMAGE_DOS_HEADER.e_magic], IMAGE_DOS_SIGNATURE
jne .image_error
add ebx, [ebx + IMAGE_DOS_HEADER.e_lfanew]
cmp dword [ebx + IMAGE_NT_HEADERS.Signature], IMAGE_NT_SIGNATURE
jne .image_error
mov dx, [ebx + IMAGE_NT_HEADERS.FileHeader.NumberOfSections]
mov eax, ebx ; PE header
add ebx, sizeof.IMAGE_NT_HEADERS
cld
@@:
mov ecx, [ebx + IMAGE_SECTION_HEADER.SizeOfRawData]
mov esi, [ebx + IMAGE_SECTION_HEADER.PointerToRawData]
add esi, kernel_image
mov edi, [ebx + IMAGE_SECTION_HEADER.VirtualAddress]
add edi, [eax + IMAGE_NT_HEADERS.OptionalHeader.ImageBase] ; ImageBase
rep movsb
add ebx, sizeof.IMAGE_SECTION_HEADER
dec dx
jnz @b
mov ebx, [eax + IMAGE_NT_HEADERS.OptionalHeader.ImageBase]
add ebx, [eax + IMAGE_NT_HEADERS.OptionalHeader.AddressOfEntryPoint]
jmp ebx ; Jump to kernel entry point
.image_error:
jmp $
kernel_image:
; вот это собственно наше ядро
file 'kernel.exe'
Хороший пример кода fasm для перевода в PM и обработки прерываний сделал и описал Great на wasm.ru.
Пример похожего решения, но для gcc и nasm можно найти на классном сайте lowlevel.ru
пятница, 15 февраля 2008 г.
Подписаться на:
Сообщения (Atom)