I am trying out boot loader development tutorials. I am able to read stage2 boot loader using FAT12 conventions. Now I am trying to load kernel in real mode and later copy it to 0x0100000 address.
I am getting triple fault while copying + jumping to 0x0100000. Basically I am not able figure out how to access or jump to 0x0100000.
My code works when I use
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
What is it I am missing ? I read about descriptor: offset addressing in protected mode, it says DESC: OFFSET(16 bit). Also offset is multiplied with 4KB using granularity setting in GDT.
I have set up gdt like this:
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
I am linking kernel as below:
krnl32.bin: boot/kernel_entry.o ${OBJ}
i386-elf-ld -o $@ -Ttext 0x0100000 $^ --oformat binary
Stage 2 boot loader
[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 $;
You set up a GDT that has a 32-bit Descriptor for code and 32-bit descriptor for data. In protected mode the registers CS/DS/ES/SS/FS/GS are no longer segment registers in the sense they were seen in real mode. In protected mode they contain a selector that points to an entry in the GDT (or an LDT). This code loads the data registers:
mov ax, DATA_DESC ; set data segments to data selector (0x10)
mov ds, ax
mov ss, ax
mov es, ax
You can't set the CS register like this. A FAR jmp can set both the code segment selector you want and sets the offset in one instruction. That is what this instruction does:
jmp CODE_DESC:Stage3
Your GDT is set up with code and data descriptors that are a 4gb flat memory model where the base is 0x00000000 and limit is 0xffffffff. This means once in protected mode and you are using selectors that point at these descriptors you can access all memory directly from 0x00000000 to 0xffffffff. This means that all you need to do is jmp 0x100000 to jump to memory address 0x100000. In your code you'll want to use 0x100000 as not only the place to jump to but also the memory location your memory copy uses as its base.
With that in mind, the simple fix is to change:
IMAGE_PMODE_BASE equ 0x1000
to:
IMAGE_PMODE_BASE equ 0x100000
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With