4MB page size 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
User avatar
muisei
Member
Member
Posts: 79
Joined: Sat Sep 23, 2006 2:10 pm
Location: Bulgaria
Contact:

4MB page size problem

Post by muisei »

I decided to use 4MB pages for my kernel and wrote a simple test kernel before I break the original.
The problem is that it doesn't work.When I run the code in QEMU it exits with the following error "qemu: fatal: Trying to execute code outside RAM or ROM at 0x0010066c".When I tested it on a real PC it rebooted.The code is relocated at the first MB.
I've read the Intel's manuals and searched the web a coulpe of times but couldn't found anything related to this problem.Any clues what I'm missing?

Here are the functions I use to initialise the page dir:

Code: Select all

volatile struct pg_dir_t *kpg_dir=NULL;
for(i=0;i<PG_DIR_ENT_NUM;i++)
        {
                // Set page not present.
                kpg_dir[i].p=0;
                /* If the page is within the real memory then set it present.'i' shifted 22 bits left then divided by 1024 is equal to only 12 shifts left.
                  */
                if( mb_info->mem_upper>=(i<<12) )  kpg_dir[i].p=1;
                kpg_dir[i].r_w=1;
                kpg_dir[i].u_s=0;
                kpg_dir[i].pwt=1;
                kpg_dir[i].pcd=0;
                kpg_dir[i].a=0;
                kpg_dir[i].d=0;
                kpg_dir[i].ps=1;
                kpg_dir[i].g=0;
                kpg_dir[i].avl=0;
                kpg_dir[i].res_low=0;
                kpg_dir[i].res_high=0;
                // 'i' is the physical page address.
                kpg_dir[i].base_addr=i;
        };
Here is the code I use to start paging:

Code: Select all

  
u_int cr0=GET_CR0(),cr4=GET_CR4();
cr4|=CR4_PSE;
SET_CR4(cr4);
SET_CR3(kpg_dir);
cr0|=CR0_PG;
SET_CR0(cr0);
for(;;);
Here are the structures and macros used:

Code: Select all

struct pg_dir_t
{
	u_int	p:1;
	u_int	r_w:1;
	u_int	u_s:1;
	u_int	pwt:1;
	u_int	pcd:1;
	u_int	a:1;
	u_int	d:1;
	u_int	ps:1;
	u_int	g:1;
	u_int	avl:3;
	u_int	res_low:4;
	u_int	res_high:6;
	u_int	base_addr:10;
}__attribute__((__packed__));

#define PG_DIR_ENT_NUM 0x400

/**
 * Get and return CR0 register
 */
#define GET_CR0()\
({\
	u_int cr0;\
	__asm__ __volatile__("mov %0,%%cr0":"=r"(cr0):);\
	cr0;\
})

/**
 * Set CR0 register
 */
#define SET_CR0(cr0)\
({\
	__asm__ __volatile__("mov %%cr0,%0"::"r"((u_int)cr0));\
})

/**
 * Set CR3 register
 */
#define SET_CR3(cr3)\
({\
	__asm__ __volatile__("mov %%cr3,%0"::"r"((u_int)cr3));\
})

/**
 * Get and return CR4 register
 */
#define GET_CR4()\
({\
	u_int cr4;\
	__asm__ __volatile__("mov %0,%%cr4":"=r"(cr4):);\
	cr4;\
})

/**
 * Set CR4 register
 */
#define SET_CR4(cr4)\
({\
	__asm__ __volatile__("mov %%cr4,%0"::"r"((u_int)cr4));\
})

Last edited by muisei on Thu Apr 19, 2007 7:43 am, edited 1 time in total.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

several remarks:

Code: Select all

#define PG_DIR_ENT_NUM 0x100000
in 386 paging every table has 1024 entries (0x400)

Code: Select all

   u_int   res_low:4;
   u_int   res_high:6;
   u_int   base_addr:10;
this is just confusing use of reserved fields. the middle 10 bits (res_low, res_high) are needed when you are not using 4M pages, which you no doubt will need sometime. Also, with PSE36 part of the reserved area has gotten meaning.
using base_addr:20; would be better (if you want more of bitfields, you could try using an union)

The CR0/CR3/CR4 macro's are ugly as well. static inline functions would be better.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
muisei
Member
Member
Posts: 79
Joined: Sat Sep 23, 2006 2:10 pm
Location: Bulgaria
Contact:

Post by muisei »

Combuster wrote:in 386 paging every table has 1024 entries (0x400)
I changed this but it still refuses to run.

Thanks for the remarks Combuster.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

"surface scan complete, starting mental emulation"

ehm i think your logic is flawed:

Code: Select all

                // Set page not present.
                kpg_dir[i].p=0;
                /* If the page is within the real memory then set it present.'i' shifted 22 bits left then divided by 1024 is equal to only 12 shifts left.
                  */
                if( mb_info->mem_upper>=(i<<12) )  kpg_dir[i].p=1; 
i << 12 equals i * 4kb. you are enabling pages as 4MB, causing you to map 4096 times too much memory...

also (considering you fixed i<<12 to i<<22), if you have 4MB of memory, then i=0 and i=1 would pass the test (4M >=0M, 4M >= 4M), so you end up mapping one page too much.

Also, you are dereferencing a null pointer. Is that done on purpose?

and then we come to the most likely cause:
mov %%cr3, %0
in AT&T syntax, the destination is located at the right, so instead of loading cr3, you are loading your page directory pointer with the undefined contents of cr3.
same way, set_cr0 actually does get_cr0 and the same goes for cr4.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
muisei
Member
Member
Posts: 79
Joined: Sat Sep 23, 2006 2:10 pm
Location: Bulgaria
Contact:

Post by muisei »

I forgot to mention that I'm using "-masm=intel" optin of the GCC which enables the Intel's syntax.Sorry for misleading you.I've tested the macros with bochs'es debugger and they work correctly.

EDIT:"The pointer I'm dereferencing is pointing to the end of the kernel.There is a code which find the end of the kernel and set 'kpg_dir' to point to that location.I've put the declaration here for your convenience."

I set the present bit on all pages and I think It should work as long as I don't touch above the real mem.

Here is a picture of bochs with some useful debugging output.
Attachments
snapshot1.png
snapshot1.png (20.96 KiB) Viewed 1651 times
Last edited by muisei on Thu Apr 19, 2007 9:15 am, edited 1 time in total.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

Page directory initialised at 0x00107109
Eeeh, that thing must be page-aligned :shock:
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
muisei
Member
Member
Posts: 79
Joined: Sat Sep 23, 2006 2:10 pm
Location: Bulgaria
Contact:

Post by muisei »

Now it works :P .Thank you very much Combuster.
Post Reply