OSDev.org
https://forum.osdev.org/

Enabling Paging - GPF
https://forum.osdev.org/viewtopic.php?f=1&t=23167
Page 1 of 1

Author:  mmurfin87 [ Sat Feb 19, 2011 2:42 am ]
Post subject:  Enabling Paging - GPF

Hello,

I've been creeping on these forums since last summer. I've been reading all the tutorials I could find, mainly Bran's and JamesM's. I've gotten to the point where I'm looking to enable paging. I completely understand the very high level theory, but I'm not 100% on the nitty gritty implementation details. I'm a little hung up on some of the locations JamesM, out of the blue, decides to use for storing certain things with no explanation. I've read that his code on his personal website isn't maintained and might be buggy, so I've also been following the code he has on code.google.com. I've spent the past few days reading every thread that even mentions the word "paging" on this forum. I've been pouring over the wiki to no avail.

Now to the problem.

I successfully set up a GDT (with 3 values, null, a code, and a data segment; 0- 4GB limit, 4KB granularity), and IDT with working interrupt service routines and IRQs, the timer is set up.
I'm reading the multiboot memory map, but I'm not using it yet. I've been printing out all the addresses floating around and you may find them of use.

My kernel ends at address 0x00106CC8, so I allocate the first page directory at 0x00108000. The first page table follows at 0x00109000. The read/write and present flags are correctly set on those pages.

This is the paging enable code:
Code:
int i;
unsigned int cr0;

install_interrupt_handler(14, &page_fault);

// Allocate a new frame for the page directory to sit in
unsigned int *pd = (unsigned int*)AllocateFrame();  // AllocateFrame() returns the next page aligned address that is free

// Clear it
memset_dw(pd, 0, 0x1000);

// Create the first page table entry to go in the new page directory
unsigned int *pt = (unsigned int*)AllocateFrame();

// Assign it to the page directory and set its flags
pd[0] = (unsigned int)pt | PAGE_PRESENT | PAGE_WRITE;

// Identity map the first 4MB of physical memory to it
for (i = 0; i < 1024; i++)
   pt[i] = (i*0x1000) | PAGE_PRESENT | PAGE_WRITE;

SwitchPageDirectory(pd);  // simply does - asm volatile("mov %0, %%cr3" : : "r" (pd));

// Enable paging
asm volatile ("mov %%cr0, %0" : "=r" (cr0));
cr0 |= 0x80000000;
asm volatile ("mov %0, %%cr0" : : "r" (cr0));

pagingActive = 1;


All pretty straightforward. Now, though, if I try to force a page fault with
Code:
// quick test of page fault handler
unsigned int *ptr = (unsigned int*)0xC0000000;
*ptr = 500;


It throws a General Protection fault.

Shouldn't it be throwing a page fault?

Furthermore even if I do this
Code:
// quick test of page fault handler
unsigned int *ptr = (unsigned int*)0xC0000000;
unsigned int doPageFault = *ptr;
doPageFault++;


where I would expect a page fault, I get nothing and execution continues...

I am out of my league on this problem so far. I could imagine that maybe the page_fault handler is somehow not paged in, so when it tries to execute that code it throws the GPF, but my IDT is identity mapped in, and also if I simply change the int from 14 to 13 in the install_interrupt_handler routine, it runs my page_fault handler just fine for the GPF.

Please, someone just tell me I'm doing something obviously retarded so I can facepalm and keep going.

Thanks.

Author:  thepowersgang [ Sat Feb 19, 2011 5:27 am ]
Post subject:  Re: Enabling Paging - GPF

I'm either thinking an error in the INT14 IDT entry, or there's an off-by-one error in your interrupt register code.

@berkus - That would cause an overrun, no real issue here (but still a bug)

Author:  Chandra [ Sat Feb 19, 2011 5:37 am ]
Post subject:  Re: Enabling Paging - GPF

I would recommend Bochs in this case. First off, uninstall the 'Page Fault' handler and see if your code still fires the 'General Protection Fault'. If it does, you may throw out all the exception handlers from your code and run your code under Bochs. Examine the Bochs debug window to see what fault it reports. If it is again the same GPF, then, you may want to examine the contents of CR0 and CR3 register to figure out if paging is actually enabled and if page directory is where you want it to be. If it reports page fault, then there might be some problem with your interrupt handlers. Check them.

Regards,
Chandra

Edit: Can we have the code for interrupt handlers?

Author:  Tosi [ Sat Feb 19, 2011 6:19 am ]
Post subject:  Re: Enabling Paging - GPF

Also, for a good description of every kind of paging structure imaginable and all the other assorted features, I would recommend the Intel manuals. Check with those and make sure you are setting the structures up correctly.

Author:  mmurfin87 [ Sat Feb 19, 2011 11:37 am ]
Post subject:  Re: Enabling Paging - GPF

berkus wrote:
Does memset_dw take number of dwords to clear?

Yes it does. I was coding late last night and this morning when I woke up I realized the problem you point out. Then I just now realized that I'm retarded and apparently I forgot how pointers work for about an hour last night. Thank you, and I fixed that. No longer using dwords.

Chandra wrote:
I would recommend Bochs in this case. First off, uninstall the 'Page Fault' handler and see if your code still fires the 'General Protection Fault'.

It does.
Chandra wrote:
If it is again the same GPF, then, you may want to examine the contents of CR0 and CR3 register to figure out if paging is actually enabled and if page directory is where you want it to be.

CR0=0xe0000011
CR3=0x00108000
The paging bit is enabled and the page directory is where I told it to be.

Chandra wrote:
Edit: Can we have the code for interrupt handlers?

Ask and ye shall recieve.

I will admit I'm lost in all the Intel assembly code. I learned assembly for MIPS once, so I know *basically* whats happening, but I'm don't know very much about the specifics of the x86 processor. I really just want to get into portable C code since I intend on running this on ARM someday (I like RISC).

My interrupt handlers are pretty basic.
Code:
isr13:
  cli
  ; this exception already pushes an error code
  push byte 13
  jmp isr_common_stub

and
Code:
isr_common_stub:
  pusha

  mov ax, ds
  push eax

  mov ax, 0x10   ; Load the Kernel Data Segment Descriptor
  mov ds, ax
  mov es, ax
  mov fs, ax
  mov gs, ax

  push esp
  call fault_handler
  add esp, 4

  pop ebx
  mov ds, bx
  mov es, bx
  mov fs, bx
  mov gs, bx

  popa
  add esp, 8   ; Cleans up the pushed error code and pushed ISR number
  iret      ; Pop 5 things at once: CS, EIP, EFLAGS, SS, and ESP

and then finally
Code:
void fault_handler(struct regs *r)
{
  void (*handler)(struct regs *r);

  handler = isrs[r->int_no];

  if (handler)
    handler(r);

  /* Is this a fault whose number is from 0 to 31? */
  if (r->int_no < 32)
  {
    /* Display the description for the exception that occurred */
    /* For now, deal with the exception by entering an infinite loop */
    puts (exception_messages[r->int_no]);
    puts (" System Halted!\n");
    for (;;);
  }
}


Thank you for responding!

I've noticed that when I try to write to the ptr to force a page fault, bochs says "write_virtual_dword_32() segment limit violation".
I set the limit in my GDT to 0xFFFFFFFF which is 4 GB and way higher than 0xC0000000...
Code:
void gdt_set_gate(int num, unsigned long base, unsigned long limit, unsigned char access, unsigned char gran);

Code:
// The null descriptor
gdt_set_gate(0, 0, 0, 0, 0);
 
// The second entry is the Code Segment.  The base address is 0, the limit is 4 GB, it uses 4 KB granularity, uses 32 bit opcodes
gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF);
 
// The third entry is the Data Segment.  Its the same as the Code Segment, but the descriptor type is that of a Data Segment
gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF);

and yes, the GDT is properly installed.

Confusing...

Author:  mmurfin87 [ Sat Feb 19, 2011 4:50 pm ]
Post subject:  Re: Enabling Paging - GPF

Well I appear to have fixed it.

The problem was in my GDT. It was twofold, I think. For starters in the set_gate function I had left out
Code:
gdt[num].granularity = (limit >> 16) & 0x0F;


The other problem could have been that my limit was set at 0xFFFFFFFF instead of 0xFFFFF. I don't think this would have been a problem since it would have just set the limit to a value higher than could be addressed anyway, but its fixed now.

Thanks for the help.

Author:  mmurfin87 [ Tue Feb 21, 2012 5:13 pm ]
Post subject:  Re: Enabling Paging - GPF

Well, I solved this problem, and quickly ran into another one that I never solved.

I backed up my project just before I fixed this error apparently, and just recently wiped my hard drive thinking I had a backup of my most recent work.

Nope, I'm now back to a version of my code just before I fixed this problem. Except the fix I posted above doesn't seem to work. Damnit, what else did I do?!

Just though I'd share my stupid experience.

Page 1 of 1 All times are UTC - 6 hours
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/