Page 1 of 1
Page fault and what does the fault address 0x80000400 mean?
Posted: Thu May 29, 2008 11:00 am
by negcit.K
I've wrote some code to implement the virtual memory, but it comes lots of faults.
In the setup_page() function, I have initialize all the memory like that:
Code: Select all
void setup_page(void)
{
/* PG_DIR is defined as 0x800000, and PG_TABLE is defined as (PG_DIR + PG_SIZE)*/
unsigned long address = 0;
unsigned long table = PG_TABLE;
int i;
for (i=0; i<PG_PAGES; i++) {
pg_table[i] = address | 7;
address += PG_SIZE; /*PG_SIZE is 4K*/
}
for (i=0; i<8; i++) {
pg_dir[i] = table | 7;
table += PG_SIZE;
}
for (; i<1024;i++)
pg_dir[i] = 6;
__asm__("movl $0x800000,%%eax\n"
"movl %%eax, %%cr3\n"
"movl %%cr0, %%eax\n"
"orl $0x80000000, %%eax\n"
"movl %%eax, %%cr0\n"
::"a"(PG_DIR));
}
As i set all the Present bit of all the memory i have(32 M), i except nothing wrong would happened. But i almost get the same message:
The wrong address is 0x80000400. (I just handle the wrong address and halt).
And i don't understand what does the address 0x80000400 mean. With i enabled the paging system, it would handle some address more understandable like 0x00410000 but not 0x80000400 (And i don't think it's a **LINE** address...)
Thanks a lot.
Posted: Thu May 29, 2008 11:08 am
by Combuster
Obviously, something is accessing a location it should not.
Your page fault handler gets a lot more information than just the faulting address, try printing the error code and return address as well. That should tell you what is causing the error, and may give you an idea as to the "why".
Posted: Thu May 29, 2008 12:27 pm
by AJ
Just a guess, but it looks like you have taken something like the contents of CR0 (in other words a flag-type register) and are trying to access it as a memory location. The value 0x80000400 would just have flags at bits 31 and 10 set.
Cheers,
Adam
Posted: Thu May 29, 2008 5:39 pm
by iammisc
Why don't you look at the eip in your fault handler and determine exactly where your kernel is faulting?
Posted: Fri May 30, 2008 2:03 am
by negcit.K
iammisc wrote:Why don't you look at the eip in your fault handler and determine exactly where your kernel is faulting?
I can find the eip in the bochs log file, but how can i find the wrong address in which function or in the function itself though i knew the eip, say 0x000038da.
Posted: Fri May 30, 2008 2:08 am
by AJ
Hi,
Two options here:
1) Use Bochs Debugger
2) EIP is pushed when the first PFE happens. Your PFE handler should be able to read this value and print it.
Cheers,
Adam
Posted: Fri May 30, 2008 3:49 am
by negcit.K
found it.
boring happens here:
Code: Select all
return (*v & (1<<(7-(i%8)))) != 0; /*In function testb()*/
and when i shrink the range, i found some sentence like *v,that is to say read value of somewhere, It would invoke the page fault handler and print out the wrong address : 0x80000400.
but when i test the sentence like in mem_debug() (a function in mm.c) , it would not happen.
I debug it a long time but nothing can work, so i really need your help.
Thanks!
Posted: Fri May 30, 2008 4:24 am
by AJ
Code: Select all
return (*v & (1<<(7-(i%8)))) != 0;
That statement does not deserve to work. Have you got all compiler warnings turned on (not just -Wall - see the more comprehensive list in Solar's
Makefile tutorial ) including -Werror?
Could you just clarify what that's supposed to do? I think the only thing that could cause a page fault there is the dereferencing of v. What value does v contain? I bet it is 0x80000400. When you dereference it, you try to read from that address.
Cheers,
Adam
Posted: Fri May 30, 2008 5:39 am
by negcit.K
Thank you AJ.
AJ wrote:Code: Select all
return (*v & (1<<(7-(i%8)))) != 0;
What value does v contain?
In the first call of testb(), it's value is 0x401000.
I tried again and found something amazing:
here is my main part of my init():
Code: Select all
mem_init();
trap_init();
con_init();
keyboard_init();
timer_init(100);
time_init();
rd_init(0x400000);
And in the ram disk initial rd_init() function(start means the start address of ram disk and in there it's 0x400000)
Code: Select all
void rd_init(unsigned long start)
{
struct super_block *sb;
printk("ram disk initing ...");
sb = (struct super_block *) (start + 512);
super_init(sb);
memset((start+ 2<<9), 0x0, (sb->s_nblocks - 2) << 9); /*THIS statement */
printk("\nrd_init: Complete!\n");
}
the memset sentence also invoke the page fault handler ,and the wrong address is also 0x80000400.
but when i change this sentence to this:
Code: Select all
memset(0x401000, 0x0, (sb->s_nblocks-2)<<9); /* 0x401000 = start + 2<<9 */
Amazing nothing wrong happened.
Posted: Fri May 30, 2008 5:55 am
by AJ
Check your C
operator precedence!
Code: Select all
memset((start+ 2<<9), 0x0, (sb->s_nblocks - 2) << 9); /*THIS statement */
'+' has higher precedence than '<<'. This means that you add 2 to 'start', getting the value 0x400002, and then shift the whole answer by 9 bits, giving a result of guess what value?*
The code you actually need is:
Code: Select all
memset((start+ (2<<9)), 0x0, (sb->s_nblocks - 2) << 9); /*THIS statement */
Cheers,
Adam
*Ans: 0x80000400
Posted: Fri May 30, 2008 7:36 am
by negcit.K
I don't know why i get these informations:
Code: Select all
THE FAULT ADDRESS: 80000400
EIP: 00000008:0000258C
ESP: 00000000:00000000
EFLAGS: 00010286
ERROR_CODE:80000400
ds: 00000010
es: 00000010
fs: 00000010
the fault address and the error code are the same.
here is my code:
Code: Select all
.globl page_fault
page_fault:
xchgl %eax,(%esp)
pushl %ecx
pushl %edx
push %ds
push %es
push %fs
movl $0x10,%edx
mov %dx,%ds
mov %dx,%es
mov %dx,%fs
movl %cr2,%edx
pushl %edx
testl $1,%eax
jne 1f
call do_no_page
jmp 2f
1: call do_wp_page
2: addl $4,%esp
pop %fs
pop %es
pop %ds
popl %edx
popl %ecx
popl %eax
iret
Code: Select all
void do_no_page(unsigned long address, long fs, long es, long ds, unsigned long edx, unsigned long ecx, unsigned long error_code, unsigned long eip, unsigned long cs, unsigned long eflags, unsigned long esp, unsigned long ss)
{
printk("\nTHE PAGE FAULT INFORMATION\n\n");
printk("THE FAULT ADDRESS:\t%p\n",address);
printk("EIP:\t%p:%p\n",cs,eip);
printk("ESP:\t%p:%p\n",ss,esp);
printk("EFLAGS:\t%p\n",eflags);
printk("ERROR_CODE:%p\n",error_code);
printk("ds:\t%p\nes:\t%p\nfs:\t%p\n",ds,es,fs);
while(1)
;
}
Posted: Fri May 30, 2008 8:03 am
by AJ
Hi,
Have you changed your code as per my previous post and you are still getting the same PFE, or did that work and you just want help with this different question now?
Cheers,
Adam
Posted: Fri May 30, 2008 8:14 am
by negcit.K
Thank you AJ.
I changed the code, then rewrite the page fault handler program, and the out message just like the previous saying.
I think the wrong part is my page fault handler, so i paste it here.And AJ, Can you give me some advise on how to fix it up.
Posted: Fri May 30, 2008 8:55 am
by AJ
I'm afraid I'm not too happy with AT&T syntax and do my exception handling quite differently, but for a start you should be saving all registers with a pushad, which I can't see. Maybe someone else can help you more with this.
Can I also suggest that once you have pushed all the registers, you save the value of esp on to the stack (save it in eax first). This means that you will just pass one parameter to your C code, which is a pointer to all the other registers you need. Have a look at
James Molloy's Tutorials - specifically the one on IRQ's. This will give you a better idea about interrupt wrapping.
If you continue with interrupt handlers like the one you have there, I think the kernel is going to get messy very quickly.
Cheers,
Adam
Posted: Fri May 30, 2008 9:14 am
by negcit.K
Thanks!
I will try it and do debug again.