Адресация в защищенном режиме
Я пробую учебники по разработке загрузчиков. Я могу читать загрузчик stage2, используя соглашения FAT12. Сейчас я пытаюсь загрузить ядро в реальном режиме, а затем скопировать его по адресу 0x0100000.
Я получаю тройную ошибку при копировании + переход на 0x0100000. В основном я не могу понять, как получить доступ или перейти к 0x0100000.
Мой код работает, когда я использую
IMAGE_PMODE_BASE equ 0x1000
IMAGE_RMODE_BASE equ 0x1000
krnl32.bin: boot/kernel_entry.o ${OBJ}
i386-elf-ld -o $@ -Ttext 0x01000 $^ --oformat binary
Что мне не хватает? Я читал о дескрипторе: смещение адресации в защищенном режиме, там написано: DESC: OFFSET(16 бит). Также смещение умножается на 4 КБ, используя настройку гранулярности в GDT.
Я настроил GDT, как это:
gdt_start:
dd 0 ; null descriptor
dd 0
; gdt code: ; code descriptor
dw 0FFFFh ; limit low
dw 0 ; base low
db 0 ; base middle
db 10011010b ; access
db 11001111b ; granularity
db 0 ; base high
; gdt data: ; data descriptor
dw 0FFFFh ; limit low (Same as code)10:56 AM 7/8/2007
dw 0 ; base low
db 0 ; base middle
db 10010010b ; access
db 11001111b ; granularity
db 0 ; base high
end_of_gdt:
toc:
dw end_of_gdt - gdt_start - 1 ; limit (Size of GDT)
dd gdt_start ; base of GDT
; give the descriptor offsets names
NULL_DESC equ 0
CODE_DESC equ 0x8
DATA_DESC equ 0x10
Я связываю ядро, как показано ниже:
krnl32.bin: boot/kernel_entry.o ${OBJ}
i386-elf-ld -o $@ -Ttext 0x0100000 $^ --oformat binary
Стадия 2 загрузчик
[bits 16]
[org 0x500]
jmp main
%include "boot/stage2/print16.s"
%include "boot/stage2/print32.s"
%include "boot/stage2/floppy16_driver.s"
%include "boot/stage2/fat12.s"
%include "boot/stage2/gdt.s"
%include "boot/stage2/a20.s"
;*******************************************************
; Data Section
;*******************************************************
msgFailure db 0x0D, 0x0A, "Failed", 0x00
welcomeMessage db 0x0D, 0x0A, "Landed in STAGE TWO...", 0x00
enableA20Msg db 0x0D, 0x0A, "Enabled A20. Installed GDT", 0x00
ImageName db "KRNL32 BIN"
ImageSize db 0
IMAGE_PMODE_BASE equ 0xffff
IMAGE_RMODE_BASE equ 0x1000
main:
;-------------------------------;
; Setup segments and stack ;
;-------------------------------;
cli ; clear interrupts
xor ax, ax ; null segments
mov ds, ax
mov es, ax
mov ax, 0x0000 ; stack begins at 0x9000-0xffff
mov ss, ax
mov sp, 0xFFFF
sti ; enable interrupts
mov si, welcomeMessage
call Print16
call _EnableA20
call InstallGDT
sti
mov si, enableA20Msg
call Print16
call LoadRoot
mov ebx, 0
mov ebp, IMAGE_RMODE_BASE
mov esi, ImageName
call LoadFile ; load our file
mov dword [ImageSize], ecx
cmp ax, 0
je EnterStage3
mov si, msgFailure
call Print16
mov ah, 0
int 0x16 ; await keypress
int 0x19 ; warm boot computer
jmp $;
EnterStage3:
cli
mov eax, cr0
or eax, 1
mov cr0, eax
jmp CODE_DESC:Stage3
[bits 32]
Stage3:
mov ax, DATA_DESC ; set data segments to data selector (0x10)
mov ds, ax
mov ss, ax
mov es, ax
mov esp, 90000h ; stack begins from 90000h
CopyImage:
mov eax, dword [ImageSize]
movzx ebx, word [bpbBytesPerSector]
mul ebx
mov ebx, 4
div ebx
cld
mov esi, IMAGE_RMODE_BASE
mov edi, IMAGE_PMODE_BASE
mov ecx, eax
rep movsd ; copy image to its protected mode address
jmp IMAGE_PMODE_BASE
jmp $;
1 ответ
Вы устанавливаете GDT, который имеет 32-битный дескриптор для кода и 32-битный дескриптор для данных. В защищенном режиме регистры CS/DS/ES/SS/FS/GS больше не являются сегментными регистрами в том смысле, в каком они были видны в реальном режиме. В защищенном режиме они содержат селектор, который указывает на запись в GDT (или LDT). Этот код загружает регистры данных:
mov ax, DATA_DESC ; set data segments to data selector (0x10)
mov ds, ax
mov ss, ax
mov es, ax
Вы не можете установить регистр CS таким образом. FAR jmp может установить желаемый селектор кода и установить смещение в одной инструкции. Вот что делает эта инструкция:
jmp CODE_DESC:Stage3
Ваш GDT настроен с помощью дескрипторов кода и данных, которые представляют собой модель с 4 ГБ плоской памяти, где базовое значение равно 0x00000000, а ограничение равно 0xffffffff. Это означает, что один раз в защищенном режиме, и вы используете селекторы, которые указывают на эти дескрипторы, вы можете получить доступ ко всей памяти напрямую от 0x00000000 до 0xffffffff. Это означает, что все, что вам нужно сделать, это jmp 0x100000
перейти к адресу памяти 0x100000. В вашем коде вы захотите использовать 0x100000 как не только место для перехода, но и место памяти, которое ваша копия памяти использует в качестве своей базы.
Имея это в виду, простое решение состоит в том, чтобы изменить:
IMAGE_PMODE_BASE equ 0x1000
чтобы:
IMAGE_PMODE_BASE equ 0x100000