GDT (and perhaps unreal mode) issues
Posted: Wed Feb 25, 2009 4:24 pm
Greetings,
I've been working on the 2nd stage of my bootloader for a while and I've encountered some problems. I'm guessing my GDT is properly set up wrongly, but to be honest, I've no idea how the GDT exactly works although I've read the Intel manuals and some tutorials (e.g.: James Molloy's tutorial, osdev wiki, etc.) on it though. As I've two issues, I will (try to) separate them throughout this topic for clearness.
The first issue is when I'm trying to get to protected mode.
The 2nd stage enables the A20, enters unreal mode and loads the kernel sector by sector to 2000:0000 and then moves it to 0x100000. After that it checks the ELF header and sets up the ELF segments "properly". So far as I've tested and checked it (mainly via hexadecimal values being printed on the screen) that functions normally, at least, it looks like it functions normally. But then I try to disable the interrupts, load my temporary GDT, enter protected mode (again) and set up the segment registers. The main issue I seem to have is that I can't set the code segment directly (logical) or indirectly (by doing a jump).
The GDT for protected mode (don't even ask why I've two GDTs, tabs have a size of eight characters instead of four on the IDEs I use):
Getting into protected mode and setting up the GDT for protected mode:
The other issue seems to be happening when trying to move (read "copy") each sector from the kernel to higher memory. When I tried doing this with one of my test beds and with Bochs, the bootloader just "failed". It doesn't triple fault though, it just "hangs" for some miraculous reason.
Entering unreal mode:
The unreal mode GDT:
The memcpy subroutine (normally I'd do this with rep movsb as suggested by the Rolling your own bootloader article, but I wasn't sure about what rep movsb would do with edi and esi):
Moving the kernel to higher memory:
I hope I provided enough information to make my problems clear.
Regards,
Stephan van Schaik.
I've been working on the 2nd stage of my bootloader for a while and I've encountered some problems. I'm guessing my GDT is properly set up wrongly, but to be honest, I've no idea how the GDT exactly works although I've read the Intel manuals and some tutorials (e.g.: James Molloy's tutorial, osdev wiki, etc.) on it though. As I've two issues, I will (try to) separate them throughout this topic for clearness.
The first issue is when I'm trying to get to protected mode.
The 2nd stage enables the A20, enters unreal mode and loads the kernel sector by sector to 2000:0000 and then moves it to 0x100000. After that it checks the ELF header and sets up the ELF segments "properly". So far as I've tested and checked it (mainly via hexadecimal values being printed on the screen) that functions normally, at least, it looks like it functions normally. But then I try to disable the interrupts, load my temporary GDT, enter protected mode (again) and set up the segment registers. The main issue I seem to have is that I can't set the code segment directly (logical) or indirectly (by doing a jump).
The GDT for protected mode (don't even ask why I've two GDTs, tabs have a size of eight characters instead of four on the IDEs I use):
Code: Select all
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Protected Mode GDT ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
gdtr:
.size dw gdt_end - gdt -1
.address dd gdt
gdt:
.desc_null dw 0x0000, 0x0000, 0x0000, 0x0000 ; 0x00: null descriptor.
.desc_code dw 0xFFFF, 0x0000, 0x9A00, 0x00CF ; 0x08: code descriptor.
.desc_data dw 0xFFFF, 0x0000, 0x9200, 0x00CF ; 0x10: data descriptor.
gdt_end:
Code: Select all
cli ; Disable interrupts.
lgdt [gdtr]
mov eax, cr0 ; Set eax to cr0.
or eax, 1 ; Set the PMode bit.
mov cr0, eax ; Set cr0 to eax (enter PMode).
jmp 0x08:flush
flush:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
The other issue seems to be happening when trying to move (read "copy") each sector from the kernel to higher memory. When I tried doing this with one of my test beds and with Bochs, the bootloader just "failed". It doesn't triple fault though, it just "hangs" for some miraculous reason.
Entering unreal mode:
Code: Select all
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Enter unreal mode ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
cli ; Disable interrupts as we get into protected mode.
push ds ; Store our data segment.
lgdt [ugdtr] ; Load our GDT table.
mov eax, cr0 ; Set eax to cr0.
or eax, 1 ; Set the PMode bit.
mov cr0, eax ; Set cr0 to eax (enter PMode).
mov bx, 0x08
mov ds, bx
mov eax, cr0 ; Set eax to cr0.
and eax, 0xFFFFFFFE ; Unset the PMode bit.
mov cr0, eax ; Set cr0 to eax (leave PMode).
pop ds ; Restore our data segment.
sti ; Enable interrupts again as we're now in unreal mode.
push ds
push ax
; Impossible to do in real mode, possible to do in unreal mode.
xor ax, ax
mov ds, ax
mov bx, 0x0F01 ; Smiley character.
mov eax, 0x0B8000 ; 32-bit offset.
mov word [ds:eax], bx ; Write the character to VRAM.
pop ax
pop ds
; Impossible to do in protected mode, possible to do in unreal mode.
mov si, UnrealMode ; Load UnrealMode into SI.
call print ; Print it.
; We really are in unreal mode :o. Time to do voodoo (mode) stuff.
Code: Select all
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Unreal Mode GDT ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ugdtr:
.size dw ugdt_end - ugdt -1
.address dd ugdt
ugdt:
.desc_null dw 0x0000, 0x0000, 0x0000, 0x0000 ; 0x00: null descriptor.
.desc_flat dw 0xFFFF, 0x0000, 0x9200, 0x004F ; 0x08: flat descriptor.
ugdt_end:
Code: Select all
memcpy:
pusha
push es
.cpy:
xor eax, eax
mov es, ax
mov al, byte [es:esi]
mov byte [es:edi], al
inc edi
inc esi
loop .cpy
pop es
popa
ret
Code: Select all
pusha
mov esi, 0x20000
mov edi, dword [kernelbuffer]
mov ax, cx
mul word [bpbBytesPerSector]
mov cx, dx
shr ecx, 8
mov cx, ax
call memcpy
add edi, ecx
mov dword [kernelbuffer], edi
popa
I hope I provided enough information to make my problems clear.
Regards,
Stephan van Schaik.