From: cross@spitfire.i.gajendra.net   
      
   In article <34818e6d-23a5-4c02-a6ef-6dfeaaf1ce3fn@googlegroups.com>,   
   × × ×¨× × × ×ˇ× × × × wrote:   
   >First of all, thank you all for replying, I really appreciate it.   
   >   
   >James:   
   >> If in 32-bit mode do you have a page directory and the requisite initial   
   >page tables set up (or the equivalent) and do they identity-map the code   
   >location you are running at? Are they all marked Present and are all   
   >their other bits correct?   
   >   
   >Yes, I mean no instructions are happening after I set CR0. Didn't know it   
   needs to JMP to a new line of code after it, I thought the jump at   
   >the end of the scope of the function is enough, but it makes a lot of sense I   
   should identity-map the kernel's code into virtual mode. But I   
   >reckon it's not my only problem there.   
      
   This is for x86, but the same principle applies generally: once   
   you turn on paging by setting the PG bit in %cr0, the next   
   instruction must necessarily come from an address that is mapped   
   in the address space described by the page tables that you are   
   pointing to in %cr3. There is no jumping around permitted; the   
   next instruction is either mapped or you get a page fault.   
      
   Perhaps you were thinking of a long-jump between segments?   
   Once you're turning on 32-bit paging, that's not generally at   
   play anymore.   
      
   Further, the IDT and page fault handler must also be properly   
   mapped.   
      
   This implies that, at the moment you turn on paging, you must   
   have an identity mapping for the code that is doing the enabling   
   logic. Once you've set that up, you can jump pretty much   
   anywhere that's mapped and executable, and get rid of the   
   identity mapping, etc.   
      
   >Yes, I'm in 32-bit mode. No, I don't have an initial page tables setup, but   
   if I'm not mistaken, that shouldn't cause the whole system reboot   
   >thing, until I'm trying to do a memory-based operation, and then it should   
   call for a page fault.   
      
   Fetching the next instruction is a memory-based operation. :-)   
   So is jumping to a page fault handler. So is jumping to the   
   double fault handler when your page fault handler itself faults.   
   The last resort is a triple-fault, which is almost certainly   
   what the CPU is doing.   
      
   >Although now I realize that if I'm saying the function's ending is equivalent   
   to a jump, it means I am trying to execute a memory-based   
   >operation, so yeah, it might be it.   
      
   It could be _any_ instruction; it's the fetch that's killing   
   your program.   
      
   >Yes, the handler for page fault is correct, the code just doesn't get to it.   
   I loaded CR3, as you can see in the code.   
   >   
   >I believe for GDT specifically the CPU is not using paging for the address,   
   but it does for JMP operations.   
      
   The GDTR stores a linear address; similarly with other CPU   
   resident tables such as the IDTR, LDTR, etc. The TSS must also   
   be in the linear address space. That means that they must all   
   be in the virtual address space you are creating when you enable   
   paging, and that the various CPU registers are loaded with the   
   virtual address of the table structures.   
      
   The exception is %cr3, which must hold the _physical_ address   
   of the page table root. Similarly, the PDT entries must be   
   filled with the physical addresses of the PTs, which must also   
   hold the physical addresses of the pages they map.   
      
   >I did do a page fault handler. I've tried including asm file, it is a bit   
   easier but it's not that different.   
   >   
   >Joe, I think Waldek is right.   
   >   
   >Alex:   
   >>If your page tables aren't properly set up, your kernel will almost certainly   
   >triple-fault and reset because it itself uses page tables to access memory.   
   When you screw up your page tables, memory accesses either won't   
   >work at all due to permissions or will read/write wrong memory cells, not the   
   ones you're expeting.   
   >   
   >Yeah, but I thought it would call for a page fault, not reboot the system   
   over and over again. I think James is right about his guess about   
   >not identity-mapping the kernel's code as the reason for its rebooting.   
      
   That is almost certainly correct.   
      
   >>Are you setting up 4KB pages or 4MB pages? You can't magically have both.   
   For 4KB pages you aren't setting up any page tables or you're not   
   >showing your code for this.   
   >4KB. You're right, I'm not setting up page tables, but again it should do a   
   page fault IMO.   
      
   Think of it this way: how does the CPU find the fault handler?   
   What mode is the CPU in, and what address space is the fault   
   handler in when paging is enabled?   
      
   >>Also, with PDT_SIZE=1024, (i>>22) is always 0. For 4MB pages you probably   
   want (i<<22) here.   
   >Oh, I forgot that I need to shift left, you're right.   
   >Why are you talking specifically about 4MB pages? Isn't it right for 4KB too?   
      
   No, 4KiB pages shift the PFN (Page Frame Number) 12 bits to the   
   left. The page offset (byte offset within the page) is 12 bits   
   and hence 4096 (2^12 == 1 << 12 == 4096).   
      
   x86 page directories for 32-bit paging (where PDEs and PTEs are   
   32-bits wide) cover the full 4GiB of the 32-bit address space.   
   Think of the page tables as a two-level radix tree; each node in   
   the tree is 4KiB with 1024 (32-bit) entries. Given a 32-bit   
   virtual address, the index in the PDE for the corresponding PT   
   is the top 10 bits of the address; a single PDE thus covers 4MiB   
   of address space. The index in the PT selecting an actual page   
   of memory is the next 10 bits, and the offset in the page is the   
   bottom 12 bits. Note that each node in the tree is not just   
   4096 bytes wide, it's also aligned to a 4096-byte boundary; thus   
   the bottom 12 bits for PDEs and PTEs are free for control bits   
   (and some reserved for software use).   
      
   So what you likely want is a single PDT pointing to PTs and a   
   however-many PTs pointing to 4KiB pages. Again, make sure you   
   are filling in the PDEs and PTEs with _physical_ addresses of   
   whatever they point to, since the MMU works in the physical   
   address space. Note that you can cover the entire virtual   
   address space with a little over 4MiB of RAM devoted to tables.   
      
   >(Also, this setup is just for placeholding, they're obviously not real page   
   tables)   
      
   It's best to get a handle on how the hardware works first, then   
   get more elaborate.   
      
    - Dan C.   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   
|