Recover from page fault

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
codyd51
Member
Member
Posts: 77
Joined: Fri May 20, 2016 2:29 pm
Location: London, UK
GitHub: https://github.com/codyd51
Contact:

Recover from page fault

Post by codyd51 »

Hello!

My paging implementation is largely from JamesM's series. Currently, when we encounter a page fault, we print out some debug info and halt execution, however this clearly isn't optimal. I'm trying to recover from a page fault and continue execution as if nothing happened. My current page fault handler is below. As you can see, if the page exists, then we allocate the page and simply return. When I run this (specifically, the iret), I get a general protection fault, indicating that my attempt at recovery doesn't work.

Code: Select all

void alloc_frame(page_t* page, int is_kernel, int is_writeable);
page_t* get_page(uint32_t address, int make, page_directory_t* dir);

void page_fault(registers_t* regs) {
   switch_to_text();

   //page fault has occured
   //faulting address is stored in CR2 register
   uint32_t faulting_address;
   asm volatile("mov %%cr2, %0" : "=r" (faulting_address));

   //error code tells us what happened
   int present = !(regs->err_code & 0x1); //page not present
   int rw = regs->err_code & 0x2; //write operation?
   int us = regs->err_code & 0x4; //were we in user mode?
   int reserved = regs->err_code & 0x8; //overwritten CPU-reserved bits of page entry?
   int id = regs->err_code & 0x10; //caused by instruction fetch?

   printf_err("Encountered page fault at %x. Info follows", faulting_address);

   if (present) printf_err("Page was present");
   else printf_err("Page was not present");
   
   if (rw) printf_err("Operation was a write");
   else printf_err("Operation was a read");

   if (us) printf_err("User mode");
   else printf_err("Supervisor mode");

   if (reserved) printf_err("Overwrote CPU-resereved bits of page entry");

   if (id) printf_err("Faulted during instruction fetch");

   if (regs->eip != faulting_address) {
      printf_err("Page fault caused by executing unpaged memory");
   } 
   else {
      printf_err("Page fault caused by reading unpaged memory");
   }

   //if this page was present, attempt to recover by allocating the page
   if (present) {
      alloc_frame(get_page(faulting_address, !present, current_directory), !us, rw);
      asm volatile("iret");
      return;
   }

   common_halt(&regs);
}
Does anyone have any idea as to what I could try? I'd be more than happy to post more of the implementation if necessary.

Thanks!
alexfru
Member
Member
Posts: 1112
Joined: Tue Mar 04, 2014 5:27 am

Re: Recover from page fault

Post by alexfru »

Your iret(d) in the middle of the C code completely disregards how the compiler generates the function prologue/epilogue code and the stack state. You should use proper exception handler wrappers written in assembly.
codyd51
Member
Member
Posts: 77
Joined: Fri May 20, 2016 2:29 pm
Location: London, UK
GitHub: https://github.com/codyd51
Contact:

Re: Recover from page fault

Post by codyd51 »

alexfru wrote:Your iret(d) in the middle of the C code completely disregards how the compiler generates the function prologue/epilogue code and the stack state. You should use proper exception handler wrappers written in assembly.
Thanks! Fixed, the calling routine now saves and restores the stack properly. I keep generating another page fault each time I try to handle one (resulting in an infinite loop of page faults), so it seems I'm not allocating the page correctly.
alexfru
Member
Member
Posts: 1112
Joined: Tue Mar 04, 2014 5:27 am

Re: Recover from page fault

Post by alexfru »

Do you remove the error code from the stack before iretd?
codyd51
Member
Member
Posts: 77
Joined: Fri May 20, 2016 2:29 pm
Location: London, UK
GitHub: https://github.com/codyd51
Contact:

Re: Recover from page fault

Post by codyd51 »

alexfru wrote:Do you remove the error code from the stack before iretd?
Yeah. Here's the IRQ routine:

Code: Select all

irq_common_stub:
	pusha		; pushes edi, esi, ebp, esp, ebx, edx, ecx, eax

	mov ax, ds	; lower 16 bits of eax = ds
	push eax 	; save data segment descriptor

	mov ax, 0x10	; load kernel data segment descriptor
	mov ds, ax
	mov es, ax
	mov fs, ax
	mov gs, ax

	call irq_handler

	pop ebx 	; reload original data segment descriptor
	mov ds, bx
	mov es, bx
	mov fs, bx
	mov gs, bx

	popa		; pops edi, esi, ebp, etc
	add esp, 8	; cleans up pushed error code and pushed ISR number
	iret		; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP
alexfru
Member
Member
Posts: 1112
Joined: Tue Mar 04, 2014 5:27 am

Re: Recover from page fault

Post by alexfru »

pushad
popad
iretd
?
codyd51
Member
Member
Posts: 77
Joined: Fri May 20, 2016 2:29 pm
Location: London, UK
GitHub: https://github.com/codyd51
Contact:

Re: Recover from page fault

Post by codyd51 »

Changed the pusha, popa, and iret to pushad, popad, and iretd, same issue. I noticed that the faulting address is 0x41013ffc, however the page address returned by get_page is 0x4008204c.
Rew
Member
Member
Posts: 28
Joined: Mon Oct 29, 2012 2:26 pm

Re: Recover from page fault

Post by Rew »

There is a known issue with how JamesM tutorial handles passing registers during irq handling. Without seeing your irq_handler it is impossible to say for sure that it is your problem. However, you are at the stage that many people run into it.

Some questions that would give helpful background:
Does your paging code work generally for preallocation without page faults? Can you map (not identity map) different areas and successfully access memory? Can you alloc additional memory after paging is enabled and successfully read/write to it?
Does interrupt handling work as a whole? Have you been able to successfully handle other interrupts without faulting?
You have a switch_to_text function. How is this implemented? Do you have any evidence that you can call switch_to_text and continue running code without faulting?
Do the addresses and flags that are reported in your page fault handler make sense? Are you faulting at the address that you expect?
Post Reply