GDT (and perhaps unreal mode) issues

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
StephanvanSchaik
Member
Member
Posts: 127
Joined: Sat Sep 29, 2007 5:43 pm
Location: Amsterdam, The Netherlands

GDT (and perhaps unreal mode) issues

Post by StephanvanSchaik »

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):

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:
Getting into protected mode and setting up the GDT for protected mode:

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.
The unreal mode GDT:

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:
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):

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
Moving the kernel to higher memory:

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.
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Re: GDT (and perhaps unreal mode) issues

Post by bewing »

Um, I don't think you quite understand Unreal mode, and the process of switching between modes.

I admit that Intel is not very clear on "the right way" to do it, and many methods that do not follow the rules still seem to work (such as the method that Microsoft uses).

But you are never doing any far jump to set CS to being a Pmode segment -- so I do not think you are ever really entering Pmode .... And you are certainly not leaving Pmode properly ....

And the whole point of Unreal mode is that you set the segment registers with 16bit Pmode GDT entries -- and then you NEVER reset them. As long as you don't reset them, you can still use them as Pmode segment registers, even when you are back in Real mode. In your case, you set DS to a Pmode GDT entry, but the very first thing you do when you supposedly get back to unreal mode is to reset DS (POP DS). So you are back to normal Real mode, and not in Unreal mode at all.
StephanvanSchaik
Member
Member
Posts: 127
Joined: Sat Sep 29, 2007 5:43 pm
Location: Amsterdam, The Netherlands

Re: GDT (and perhaps unreal mode) issues

Post by StephanvanSchaik »

bewing wrote:Um, I don't think you quite understand Unreal mode, and the process of switching between modes.
That's true :lol:. The main thing I understand is how to enable and disable protected mode. Simply by setting and unsetting the pmode-flag in the CR0 register. But when something like GDT comes into play, I get confused about how it works (I'm going to read the GDT article on the OSDev wiki more carefully).
bewing wrote:I admit that Intel is not very clear on "the right way" to do it, and many methods that do not follow the rules still seem to work (such as the method that Microsoft uses).
In case of the GDT I may have looked wrong though as it seemed more as an introduction part then a in-depth part [Section 2.1.1(.1)]. Now if I look at it again I should've read chapter three more thoroughly, so that's probably my fault. Not that I was accusing Intel about that anyway. For the other sections I can't really speak as I haven't read much of the Intel volumes yet :oops:.
bewing wrote:And the whole point of Unreal mode is that you set the segment registers with 16bit Pmode GDT entries -- and then you NEVER reset them. As long as you don't reset them, you can still use them as Pmode segment registers, even when you are back in Real mode. In your case, you set DS to a Pmode GDT entry, but the very first thing you do when you supposedly get back to unreal mode is to reset DS (POP DS). So you are back to normal Real mode, and not in Unreal mode at all.
I get what you mean, by restoring the DS-register I don't use the GDT at all.

So if I am right, I should do a far jump for setting the CS-register and I shouldn't recover the DS-register. Please correct me, if I'm wrong.


Regards,
Stephan van Schaik.
User avatar
JAAman
Member
Member
Posts: 879
Joined: Wed Oct 27, 2004 11:00 pm
Location: WA

Re: GDT (and perhaps unreal mode) issues

Post by JAAman »

In case of the GDT I may have looked wrong though as it seemed more as an introduction part then a in-depth part [Section 2.1.1(.1)]. Now if I look at it again I should've read chapter three more thoroughly, so that's probably my fault. Not that I was accusing Intel about that anyway. For the other sections I can't really speak as I haven't read much of the Intel volumes yet :oops:.
GDT is actually quite simple, i generally recommend reading chapters 3 & 4 at least 2 times through before starting, and only asking questions after reading those 2 chapters 2 times...

3A:3.2-3A:3.5 are the sections that talks about segmentation, (and through that, the GDT) -- specifically, check out:

3A:3.2.1 -- this is basically the form used by most modern OSs, as it is very simple to implement, and doesnt require much to maintain
3A:3.4 -- important section on segmentation -- i suggest reading all of it, but specifically:

3A:3.4.2/3 -- these sections describe the use of segment registers in PMode
3A:3.4.5 -- this section describes the entries in the GDT and how they are used -- compare this to section 3.4.3
Post Reply