Paging / Switch to long mode problem

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
kdx7214
Member
Member
Posts: 25
Joined: Tue Jun 07, 2011 5:34 pm

Paging / Switch to long mode problem

Post by kdx7214 »

I'm not sure what is going wrong with this code, but would appreciate some guidance on it. I'm attempting to boot from grub2 (finally got that working) and then switch to LM and jump to a C code section (not included). Everything works fine until the point where the "halt" is placed. The lines after that attempt to enable paging and it all goes south from there (i.e. tries to address memory at 0x0000FFFE for some reason).

It's supposed to work as follows (or so I think):

1. grub2 puts us in pmode and starts
2. sanity checks and remap pic
3. setup paging
4. set EFER and LM
5. enable LM - should be in compatibility mode so still need to load a GDT

The code is my poor attempt to identity map the first 4mb of ram and then enable paging. If you see what's wrong please let me know :)

Thanks!
Mike



Code: Select all

start:
	mov	esp, _sys_stack
	mov	[grub2_meminfo], ebx			; Store the grub2 memory pointer (if valid)

	cmp	eax, 0x36D76289				; GRUB2 magic value
	jne	error

	call	check_cpuid				; Make sure CPUID is supported
	cmp	eax, dword 1
	jne	error

	mov	eax, 0x80000000				; Check for extended CPUID functions
	CPUID
	cmp	eax, 0x80000001				; if < this, no extended fns to check for LM
	jb	error

	mov	eax, 0x80000001				; Extended functions of CPUID
	CPUID
	bt	edx, 29					; Check for long mode
	jnc	error

	cli						; Disable interrupts
	call	remap_pic				; Remap IRQ0 to IRQ15 -> INT 0x20 - INT 0x2F

	mov	eax, cr0				; Get contents of cr0
	bt	eax, 31					; Check bit 31
	jc	error					; Set means paging is already enabled

	mov	edi, PML4				; Clear out the PML4 table
	xor	eax, eax
	mov	ecx, 1024
	rep stosd

	mov	edi, 0x200000				; Start of first PDPT
	xor	eax, eax
	mov	ecx, 0x1000				; Clear some memory for page tables
	rep stosd

	mov	eax, 0x200003				; PML4 -> PDPT	
	mov	[PML4], eax				; Thank you little endian machine

	mov	eax, 0x201003
	mov	edi, 0x200000
	mov	[edi], eax				; PDPT -> PDT

	add	edi, 0x1000
	mov	eax, 0x202003
	mov	[edi], eax				; PDT -> PT (first)
	add	edi, 8
	mov	eax, 0x203003
	mov	[edi], eax				; PDT -> PT (second)

	mov	edi, 0x00202000				; Start of first PT to fill
	mov	ebx, 0x00000003				; Map from address 0 (with present, r/w set)
	mov	ecx, 1024				; Do BOTH PT's (first and second)
.SetEntry:
	mov	DWORD [edi], ebx
	add	ebx, 0x1000
	add	edi, 8
	loop	.SetEntry

	mov	eax, PML4
	mov	cr3, eax				; Set the top level page table address

	mov	eax, cr4
	or	eax, 1 << 5				; Enable PAE
	mov	cr4, eax

 	mov	ecx, 0xC0000080				; Enable LM in the EFER register
	rdmsr
	or	eax, 1 << 8
	wrmsr

	mov	[0xb8000], byte 'Y'                       ; Display a char and halt
	hlt

	mov	eax, cr0
	or	eax, 1 << 31
	mov	cr0, eax				; Should now be in 64-bit compatiblity mode


	mov	eax, 0x03200320
	mov	ecx, 0x0500
	mov	edi, 0xb8000
.here:	mov	[edi], eax
	dec	ecx
	add	edi, 4
	jnz	.here


error:	mov	edi, 0xb8000
	mov	[edi], eax
	jmp	$

User avatar
xenos
Member
Member
Posts: 1121
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: Paging / Switch to long mode problem

Post by xenos »

It seems that you cleared the PML4T and the PDPT before using them (and writing to the lower dword of their page entries), but you did not clear the PDT and the PT as well. Instead, you only write to the lower dword of each entry of these tables, and leave the higher dword untouched. Since this higher dword may contain garbage before you use it, chances are good that your page tables still contain this garbage.

Are you using real hardware or some PC simulator such as Bochs? In the latter case, I would recommend you have a look at the debug output whenever your kernel crashes, or to run the built-in debugger and check the paging structures with "info page".
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
kdx7214
Member
Member
Posts: 25
Joined: Tue Jun 07, 2011 5:34 pm

Re: Paging / Switch to long mode problem

Post by kdx7214 »

So I tried extending the amount of memory being cleared to 0x5000 dwords (starting at the 3mb mark). The instant I set cr0 to enable paging I get a spurious jump to f000:fffe and an invalid memory access. I tried using bochs debugger but I can't use "info tab" to view paging tables because paging never got enabled.

Any other suggestions to try?

Thanks!
Mike
User avatar
Owen
Member
Member
Posts: 1700
Joined: Fri Jun 13, 2008 3:21 pm
Location: Cambridge, United Kingdom
Contact:

Re: Paging / Switch to long mode problem

Post by Owen »

f000:fffe is the entry point of Bochs BIOS. Your machine triple faulted.

Your sequence looks good, though I'm not personally certain about your paging structures. If it were me doing this, I would have a pre-built PML4, PDPT and PD laid out in the binary
User avatar
xenos
Member
Member
Posts: 1121
Joined: Thu Aug 11, 2005 11:00 pm
Libera.chat IRC: xenos1984
Location: Tartu, Estonia
Contact:

Re: Paging / Switch to long mode problem

Post by xenos »

Could you post the output of your bochs log file (the part containing the crash)? The triple fault means that you probably messed up your paging structures somehow, or the control registers are not set properly. I don't see what's wrong with your code, though... It looks fine to me.

Another thing you could try is to manually dump the contents of your paging structures using the "x" command in bochs debugger.

One more thing... Which address does PML4T point to? Is it page aligned?
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS
kdx7214
Member
Member
Posts: 25
Joined: Tue Jun 07, 2011 5:34 pm

Re: Paging / Switch to long mode problem

Post by kdx7214 »

That was it! I forgot to page align the PML4 table. Go figure! *doh!*

Thanks!
Mike
Post Reply