Page 1 of 4
[Solved] Paging problem + GPFs
Posted: Wed Apr 30, 2008 6:09 am
by White-spirit
Hello all,
I've read the Osdev wiki article about paging, so I've written a little code to activate it, but after activating it ( by or-ing CR0 with 0x80000000 ), Bochs says ">> (invalid) : FFFF" ...
Here's the code( I'm not sure the page tables initialization is correct... ) :
Code: Select all
#include "paging.h"
u32int page_dir[1024];
u32int page_table[1048576];
void init_pagedir(){
int i = 0;
for( i = 0; i <= 1024; i++ ){
page_dir[i] ^= page_dir[i];
page_dir[i] = page_table + 1024 * i;
page_dir[i] = page_dir[i] >> 12;
page_dir[i] = page_dir[i] << 12;
page_dir[i] = page_dir[i] | 3;
}
}
void init_pagetable(){
int i = 0;
for( i = 0; i < 1048576; i++ ){
page_table[i] ^= page_table[i];
page_table[i] = i*4096;
page_table[i] = page_table[i] | 3;
}
}
void load_pagedir(){
asm volatile ("\
movl %0, %%eax; \
movl %%eax, %%cr3; \
" :: "r" (page_dir));
}
void activate_paging(){
asm volatile ("\
movl %cr0, %eax; \
or $0x80000000, %eax; \
movl %eax, %cr0 \
");
}
void init_paging(){
printf("[DEBUG] activate_paging is located at 0x8:%h ( %d )\n", &activate_paging, &activate_paging);
init_pagedir();
init_pagetable();
printf("\n *Loading page directory...");
load_pagedir();
printf("[DONE]");
printf("\n *Activating paging...");
activate_paging();
printf("[DONE]");
printf("\n *Paging is...");
}
I've debugged with Bochs but it doesn't help me much ( it's probably because I'm not familiar with Bochs
) but I've seen that it reboots after "movl %eax, %cr0" .
I wrote this code with the feet?
I personally don't understand all the paging articles I've read on JamesM's kernel development tutorials, Brokenthorn tutorials, the Osdev wiki, and SOS's tutorial... SOS uses complicated macros so it doesn't help me much, it's because I'm dumb or maybe not ready for this subject ...
Thanks
Posted: Wed Apr 30, 2008 2:32 pm
by Ready4Dis
First off, why are you ^=, then =... why set it to zero if you're just going to set it in the next line anyways?
Second, please try to avoid arithmetric functions on pointers.. I would change:
Code: Select all
page_dir[i] = page_table + 1024 * i;
to
Code: Select all
page_dir[i] = &page_table[i*1024];
An easier way would be something like this however:
Code: Select all
u32int page_dir[1024];
u32int page_table[1024][1024]; //1024*1024 is more obvious to me
void InitTables(void)
{
u32int Ctr,Ct2, Addr=0;
for (Ctr=0;Ctr!=1024;++Ctr) //Page directory
{
for (Ct2=0;Ct2!=1024;++Ctr) //Each page table
{
page_table[Ctr][Ct2] = Addr; //Set to next address
Addr += 4096;
}
page_dir[Ctr] = &page_table[Ctr][0] | 3; //Set this
}
}
Also, make suer your page_dir and page_table are page aligned (4096 bytes), if they're not, and you are doing >>12, <<12 you may be writing over memory that you don't want to be. Also, never do <= 1024... that means it will go from 0 > 1024 (including 1024!), which will over-run your page_dir, since element 1024 would be invalid memory.
Posted: Wed Apr 30, 2008 3:21 pm
by White-spirit
Thanks for your help, and yes, it's < not <= .
I've used your code but it still doesn't work :/
Also, I've changed it a little but it's also the same :s :
Code: Select all
#define log2ph(x) (((void*)(x))+0x40000000)
#define ph2log(x) (((void*)(x))-0x40000000)
u32int page_dir[1024];
u32int page_table[1024][1024];
void init_tables(){
int i,j;
int ph_address = 0;
ph_address = log2ph(ph_address);
for( i = 0; i < 1024; i++ ){
for( j = 0; j < 1024; j++){
page_table[i][j] = ph_address;
page_table[i][j] = page_table[i][j] | 3;
ph_address += 4096;
}
page_dir[i] = &page_table[i][0];
page_dir[i] |= 3;
}
}
Posted: Wed Apr 30, 2008 4:51 pm
by Ready4Dis
Make sure page_dir and page_table are both page aligned. Also, a print out of the bochs output may be helpful, as well as displaying the value of page_dir and page_table to see where the problem may lie. Juts out of curiousity, why are you doing log2ph and ph2log? Where are you linking your kernel? Take out the log2ph, you want to set the physical address = 0 at the start, to map the entire memory range. Unless you're trying to make your kernel look like it's at 0x00000000, there is no reason for this. And it will mess it up if you don't location the part of the kernel after paging is enabled to be 0x00000000. So the return from your set CR3 call will crash because it is trying to read the stack and from the wrong place (since everything is shifted by 1gb). Try it without that function (macro) and let us know, also post other information I asked and I'll continue helping.
Posted: Thu May 01, 2008 1:59 am
by White-spirit
Thanks.
But what means "page aligned" ? Sorry but I'm not a native english speaker ^^"
Here's the Bochs log :
Code: Select all
00000003572i[BIOS ] $Revision: 1.193 $ $Date: 2007/12/20 18:12:11 $
00000080000e[VGA ] character height = 1, skipping text update
00000160000e[VGA ] character height = 1, skipping text update
00000240000e[VGA ] character height = 1, skipping text update
00000317073i[KBD ] reset-disable command received
00000320000e[VGA ] character height = 1, skipping text update
00000351651i[BIOS ] Starting rombios32
00000352363i[BIOS ] ram_size=0x02000000
00000372784i[BIOS ] Found 1 cpu(s)
00000400000e[VGA ] character height = 1, skipping text update
00000480000e[VGA ] character height = 1, skipping text update
00000560000e[VGA ] character height = 1, skipping text update
00000640000e[VGA ] character height = 1, skipping text update
00000662092i[VBIOS] VGABios $Id: vgabios.c,v 1.66 2006/07/10 07:47:51 vruppert Exp $
00000662163i[VGA ] VBE known Display Interface b0c0
00000662195i[VGA ] VBE known Display Interface b0c4
00000665120i[VBIOS] VBE Bios $Id: vbe.c,v 1.58 2006/08/19 09:39:43 vruppert Exp $
00000800000i[XGUI ] charmap update. Font Height is 16
00001109360i[BIOS ] Booting from 0000:7c00
00006486695i[BIOS ] int13_harddisk: function 41, unmapped device for ELDL=80
00006491498i[BIOS ] int13_harddisk: function 08, unmapped device for ELDL=80
00006496157i[BIOS ] *** int 15h function AX=00c0, BX=0000 not yet supported!
00071430371i[CPU0 ] CPU is in protected mode (active)
00071430371i[CPU0 ] CS.d_b = 32 bit
00071430371i[CPU0 ] SS.d_b = 32 bit
00071430371i[CPU0 ] EFER = 0x00000000
00071430371i[CPU0 ] | RAX=00000000ffffffff RBX=000000000002d000
00071430371i[CPU0 ] | RCX=00000000000003ff RDX=000000000000002e
00071430371i[CPU0 ] | RSP=0000000000106e08 RBP=00000000001072b0
00071430371i[CPU0 ] | RSI=0000000000053c8e RDI=0000000000053c8f
00071430371i[CPU0 ] | R8=0000000000000000 R9=0000000000000000
00071430371i[CPU0 ] | R10=0000000000000000 R11=0000000000000000
00071430371i[CPU0 ] | R12=0000000000000000 R13=0000000000000000
00071430371i[CPU0 ] | R14=0000000000000000 R15=0000000000000000
00071430371i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af pf cf
00071430371i[CPU0 ] | SEG selector base limit G D
00071430371i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00071430371i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 000fffff 1 1
00071430371i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00071430371i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00071430371i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 000fffff 1 1
00071430371i[CPU0 ] | FS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00071430371i[CPU0 ] | GS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00071430371i[CPU0 ] | MSR_FS_BASE:0000000000000000
00071430371i[CPU0 ] | MSR_GS_BASE:0000000000000000
00071430371i[CPU0 ] | RIP=00000000c7538168 (00000000c7538168)
00071430371i[CPU0 ] | CR0=0x80000011 CR1=0x0 CR2=0x0000000000000000
00071430371i[CPU0 ] | CR3=0x00508c80 CR4=0x00000000
00071430371i[CPU0 ] >> (invalid) : FFFF
00071430371e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
00071430371i[SYS ] bx_pc_system_c::Reset(SOFTWARE) called
00071430371i[CPU0 ] cpu software reset
00071430371i[APIC0] local apic in CPU 0 initializing
Next at t=71430371
(0) [0xfffffff0] f000:fff0 (unk. ctxt): jmp far f000:e05b ; ea5be000f0
But when I use this ( because CR3 needs the physical address ) :
Code: Select all
void load_pagedir(){
asm volatile ("\
movl %0, %%eax; \
movl %%eax, %%cr3; \
" :: "r" (log2ph(page_dir)));
}
instead of this :
Code: Select all
void load_pagedir(){
asm volatile ("\
movl %0, %%eax; \
movl %%eax, %%cr3; \
" :: "r" (page_dir));
}
I get another error message :
Code: Select all
00071406647i[CPU0 ] CPU is in protected mode (active)
00071406647i[CPU0 ] CS.d_b = 32 bit
00071406647i[CPU0 ] SS.d_b = 32 bit
00071406647i[CPU0 ] EFER = 0x00000000
00071406647i[CPU0 ] | RAX=0000000080000011 RBX=000000000002d000
00071406647i[CPU0 ] | RCX=00000000000003ff RDX=000000000000002e
00071406647i[CPU0 ] | RSP=00000000001072b0 RBP=00000000001072b0
00071406647i[CPU0 ] | RSI=0000000000053c8e RDI=0000000000053c8f
00071406647i[CPU0 ] | R8=0000000000000000 R9=0000000000000000
00071406647i[CPU0 ] | R10=0000000000000000 R11=0000000000000000
00071406647i[CPU0 ] | R12=0000000000000000 R13=0000000000000000
00071406647i[CPU0 ] | R14=0000000000000000 R15=0000000000000000
00071406647i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf SF zf af PF cf
00071406647i[CPU0 ] | SEG selector base limit G D
00071406647i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00071406647i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 000fffff 1 1
00071406647i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00071406647i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00071406647i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 000fffff 1 1
00071406647i[CPU0 ] | FS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00071406647i[CPU0 ] | GS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00071406647i[CPU0 ] | MSR_FS_BASE:0000000000000000
00071406647i[CPU0 ] | MSR_GS_BASE:0000000000000000
00071406647i[CPU0 ] | RIP=000000000010146f (000000000010146f)
00071406647i[CPU0 ] | CR0=0x80000011 CR1=0x0 CR2=0x0000000000000040
00071406647i[CPU0 ] | CR3=0x40508c80 CR4=0x00000000
00071406647i[CPU0 ] >> or byte ptr ds:[eax], cl : 0808
00071406647e[CPU0 ] exception(): 3rd (14) exception with no resolution, shutdown status is 00h, resetting
I'ill continue debugging ...
Thanks
Posted: Thu May 01, 2008 2:49 am
by jnc100
White-spirit wrote:Thanks.
But what means "page aligned"
He means that all paging structures must be aligned on a page-boundary, i.e. for protected mode this means that they must be located on a multiple of 4kiB. Given the value of cr3 in your dump, your's obviously aren't...
Regards,
John.
Posted: Thu May 01, 2008 3:30 am
by pcmattman
Page alignment isn't too hard:
Code: Select all
#define PAGE_ALIGNED( p ) (p & ~0xFFF)
Posted: Thu May 01, 2008 5:40 am
by White-spirit
Thanks but it still doesn't work ...
I've aligned the addresses to the previous page boundary, and now I'm getting this from Bochs :
Code: Select all
00078761354i[CPU0 ] CPU is in protected mode (active)
00078761354i[CPU0 ] CS.d_b = 32 bit
00078761354i[CPU0 ] SS.d_b = 32 bit
00078761354i[CPU0 ] EFER = 0x00000000
00078761354i[CPU0 ] | RAX=0000000080000011 RBX=000000000002d000
00078761354i[CPU0 ] | RCX=0000000000109c7c RDX=000000000000002e
00078761354i[CPU0 ] | RSP=00000000001072b0 RBP=00000000001072b0
00078761354i[CPU0 ] | RSI=0000000000053c8e RDI=0000000000053c8f
00078761354i[CPU0 ] | R8=0000000000000000 R9=0000000000000000
00078761354i[CPU0 ] | R10=0000000000000000 R11=0000000000000000
00078761354i[CPU0 ] | R12=0000000000000000 R13=0000000000000000
00078761354i[CPU0 ] | R14=0000000000000000 R15=0000000000000000
00078761354i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf SF zf af PF cf
00078761354i[CPU0 ] | SEG selector base limit G D
00078761354i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00078761354i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 000fffff 1 1
00078761354i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00078761354i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00078761354i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 000fffff 1 1
00078761354i[CPU0 ] | FS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00078761354i[CPU0 ] | GS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00078761354i[CPU0 ] | MSR_FS_BASE:0000000000000000
00078761354i[CPU0 ] | MSR_GS_BASE:0000000000000000
00078761354i[CPU0 ] | RIP=00000000001014bc (00000000001014bc)
00078761354i[CPU0 ] | CR0=0x80000011 CR1=0x0 CR2=0x0000000000000040
00078761354i[CPU0 ] | CR3=0x40108c80 CR4=0x00000000
00078761354i[CPU0 ] >> add byte ptr ds:[eax], al : 0000
00078761354e[CPU0 ] exception(): 3rd (14) exception with no resolution, shutdown status is 00h, resetting
Here's the modified code :
Code: Select all
#define log2ph(x) (((void*)(x))+0x40000000)
#define ph2log(x) (((void*)(x))-0x40000000)
#define p_align(x) (((u32int)(x)) & (u32int)~0xFFF)
u32int page_dir[1024];
u32int page_table[1024][1024];
u32int* aligned_page_dir;
u32int* aligned_page_table;
void align_tables(){
aligned_page_dir = (u32int*)(p_align(page_dir));
aligned_page_table = (u32int*)(p_align(page_table));
}
void init_tables(){
int i,j;
int ph_address = 0;
for( i = 0; i < 1024; i++ ){
for( j = 0; j < 1024; j++){
aligned_page_table[1024 * i + j] = ph_address;
aligned_page_table[1024 * i + j] = aligned_page_table[1024 * i + j] | 3;
ph_address += 4096;
}
aligned_page_dir[i] = &aligned_page_table[i];
aligned_page_dir[i] |= 3;
}
}
void load_pagedir(){
asm volatile ("\
movl %0, %%eax; \
movl %%eax, %%cr3; \
" :: "r" (log2ph(aligned_page_dir)));
}
void activate_paging(){
asm volatile ("\
movl %cr0, %eax; \
or $0x80000000, %eax; \
movl %eax, %cr0 \
");
}
void init_paging(){
printf("[DEBUG] activate_paging is located at virtual address 0x8:%h, and physical address %h", &activate_paging, log2ph(&activate_paging));
align_tables();
init_tables();
printf("\n *Loading page directory...");
load_pagedir();
printf("[DONE]");
printf("\n *Activating paging...");
activate_paging();
printf("[DONE]");
printf("\n *Paging is...");
}
Any idea ?
Thanks
Posted: Thu May 01, 2008 5:43 am
by zerosum
00078761354i[CPU0 ] | CR3=0x40108c80 CR4=0x00000000
You need to page-align your structures, as suggested above. The value in CR3 shows that your top-level structure at least is not page-aligned. Either that or you're loading the wrong address into CR3.
Posted: Thu May 01, 2008 5:50 am
by White-spirit
zerosum wrote:00078761354i[CPU0 ] | CR3=0x40108c80 CR4=0x00000000
You need to page-align your structures, as suggested above. The value in CR3 shows that your top-level structure at least is not page-aligned. Either that or you're loading the wrong address into CR3.
I agree with you that the value of CR3 is not page aligned, but the structures are already aligned, what am I doing wrong ?
Thanks
Posted: Thu May 01, 2008 5:56 am
by zerosum
I've not really gone through your code to be honest, but I can see a problem on the first couple of lines...
You've declared your paging structures as simple arrays inside your kernel. Do you know where the compiler is putting these? I'd suggest their position is not page-aligned
What I've done is put my kernel paging structures at the first page boundary after the kernel ends. It doesn't matter where they are as long as they're page-aligned.
Simply taking the address of the arrays you've created and masking out bits doesn't make them page-aligned... it just gives the wrong address when you try to load it into CR3, compounding the problem.
So there looks to me to be two problems (possibly more, I stopped at this point):
1) The paging structures are still not page-aligned
2) You're loading the wrong value into CR3
Cheers,
Lee
Posted: Thu May 01, 2008 6:12 am
by White-spirit
Yeaaaaaah, it works fine just after deleting log2ph .
An explanation please? I thought CR3 needs the physical address
EDIT : It fails if I call the "sti" instruction :
Code: Select all
00078788024i[CPU0 ] CPU is in protected mode (active)
00078788024i[CPU0 ] CS.d_b = 32 bit
00078788024i[CPU0 ] SS.d_b = 32 bit
00078788024i[CPU0 ] EFER = 0x00000000
00078788024i[CPU0 ] | RAX=0000000000000000 RBX=0000000000108c60
00078788024i[CPU0 ] | RCX=0000000000109c7c RDX=0000000000000020
00078788024i[CPU0 ] | RSP=00000000001072d8 RBP=00000000001072f0
00078788024i[CPU0 ] | RSI=0000000000053c8e RDI=0000000000053c8f
00078788024i[CPU0 ] | R8=0000000000000000 R9=0000000000000000
00078788024i[CPU0 ] | R10=0000000000000000 R11=0000000000000000
00078788024i[CPU0 ] | R12=0000000000000000 R13=0000000000000000
00078788024i[CPU0 ] | R14=0000000000000000 R15=0000000000000000
00078788024i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df IF tf sf ZF af PF cf
00078788024i[CPU0 ] | SEG selector base limit G D
00078788024i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D
00078788024i[CPU0 ] | CS:0008( 0001| 0| 0) 00000000 000fffff 1 1
00078788024i[CPU0 ] | DS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00078788024i[CPU0 ] | SS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00078788024i[CPU0 ] | ES:0010( 0002| 0| 0) 00000000 000fffff 1 1
00078788024i[CPU0 ] | FS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00078788024i[CPU0 ] | GS:0010( 0002| 0| 0) 00000000 000fffff 1 1
00078788024i[CPU0 ] | MSR_FS_BASE:0000000000000000
00078788024i[CPU0 ] | MSR_GS_BASE:0000000000000000
00078788024i[CPU0 ] | RIP=0000000000100c13 (0000000000100c13)
00078788024i[CPU0 ] | CR0=0x80000011 CR1=0x0 CR2=0x0000000000000000
00078788024i[CPU0 ] | CR3=0x00508000 CR4=0x00000000
00078788024i[CPU0 ] >> call .+0x00000477 (0x0010108f) : E877040000
00078788024e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
Posted: Thu May 01, 2008 6:16 am
by zerosum
It does.
And how the hell that is working, I have no idea
Cheers,
Lee
Posted: Thu May 01, 2008 9:28 am
by White-spirit
The interrupts don't work, it's normal ?
I'm setting the IDT before activating paging .
Posted: Thu May 01, 2008 3:43 pm
by pcmattman
An explanation please? I thought CR3 needs the physical address
Exactly! Why were you adding 0x40000000 to get a "physical" address? Do you even understand what you're talking about here?