1

In my paging code, qemu restarts because of some of the inline assembly. It could be something else, but removing the assembly causes the program to work fine. Alternatively, it could be possible that some of the earlier code is causing paging to initialize incorrectly. Here is the Paging Init Function:

void paging_init(){
    //Enable Paging
    uint32 cr0;
    memset(g_page_directory, 0, sizeof(page_directory_t) * 1024);
    memset(g_page_tables, 0, sizeof(page_table_t) * 1024);
    
    // Set All page directories to have rw and u/s access (only by kernel)
    for(int i = 0; i < 1024; i++){
        g_page_directory[i].user_supervisor = 1;
        g_page_directory[i].read_write = 1;
    }
    
    // fill all the entries in page table to map all 4MB memory
    for (int i = 0; i < 1024; i++) {
        g_page_tables[i].present = 1;
        g_page_tables[i].read_write = 1;
        g_page_tables[i].user_supervisor = 1;
        g_page_tables[i].frame = (i * PAGE_SIZE) >> 12;
    }
    
    // set first page directory to be accessed with frame 0x11a(kernel region address)
    g_page_directory[0].present = 1;
    g_page_directory[0].accessed = 0;
    g_page_directory[0].user_supervisor = 1;
    g_page_directory[0].frame = 0x11a;
    //Register Page Fault Handler
    isr_register_interrupt_handler(14, page_fault_handler);

    // set cr3 point to page directory
    asm volatile("mov %0, %%cr3" ::"r"(g_page_directory));
    
    // set bit in cr0 to enable paging
    asm volatile("mov %%cr0, %0": "=r"(cr0));
    cr0 = cr0 | 0x80000000;
    asm volatile("mov %0, %%cr0" ::"r"(cr0));
}

QEMU restarts because of these lines of inline assembly:

    // set cr3 point to page directory
    asm volatile("mov %0, %%cr3" ::"r"(g_page_directory));
    
    // set bit in cr0 to enable paging
    asm volatile("mov %%cr0, %0": "=r"(cr0));
    cr0 = cr0 | 0x80000000;
    asm volatile("mov %0, %%cr0" ::"r"(cr0));

How can I fix this error?

Edit (here are the typedefs):

// Page Directory Struct
typedef struct {
    uint32 present :1;
    uint32 read_write :1;
    uint32 user_supervisor :1;
    uint32 write_through :1;
    uint32 cache_disable :1;
    uint32 accessed :1;
    uint32 dirty :1;
    uint32 page_size :1;
    uint32 global :1;
    uint32 available :3;
    uint32 frame :20;
} page_directory_t;

// Page Table
typedef struct {
    uint32 present :1;
    uint32 read_write :1;
    uint32 user_supervisor :1;
    uint32 write_through :1;
    uint32 cache_disable :1;
    uint32 accessed :1;
    uint32 dirty :1;
    uint32 page_size :1;
    uint32 global :1;
    uint32 available :3;
    uint32 frame :20;
} page_table_t;

Edit: Code Sample with paging code (Some of the names of structs are different but code is all the same other than that): https://filebin.net/hql1zrigj8dgbmto

xingharvey
  • 131
  • 6
  • How are `g_page_tables` and `g_page_directory` defined? Both type and address please. – Timothy Baldwin Aug 12 '23 at 23:27
  • You're missing a `"memory"` clobber on your asm statements: GCC could defer the stores to global variables until after the asm statements. [How can I indicate that the memory \*pointed\* to by an inline ASM argument may be used?](https://stackoverflow.com/q/56432259) . (But it probably wouldn't, so that's probably not the only problem in your code. i.e. it probably does compile the way you expect, even though your code fails to require that.) – Peter Cordes Aug 12 '23 at 23:28
  • 1
    When you single-step this code with a debugger, what fault is raised? If GDB attached to QEMU (or QEMU's logs) don't tell you, then try Bochs; its build-in debugger should show you the initial fault, and presumably a failed attempt to run a double-fault handler resulting in a triple fault and reboot. – Peter Cordes Aug 12 '23 at 23:30
  • 1
    It sets the frame field of the page directory to a hard-coded value. It should be the address of the page table. – prl Aug 13 '23 at 00:58
  • Are you sure that your code, data, stack, gdt, idt, etc. are all in the first 4 MB of physical memory? You may need more than one page table. – prl Aug 13 '23 at 01:00
  • It fails at the lines `cr0 = cr0 | 0x80000000; asm volatile("mov %0, %%cr0" ::"r"(cr0));` – xingharvey Aug 13 '23 at 17:48
  • Can you put all your code and Makefile/build script onto Github so we can look at everything and build it. Often problems like this aren't in the code being shown. I'm with the other commenter about `g_page_directory[0].frame = 0x11a;` setting the page frame to a hard coded value. – Michael Petch Aug 13 '23 at 18:36
  • Ok, I have a minimal example here: https://filebin.net/hql1zrigj8dgbmto – xingharvey Aug 13 '23 at 19:08
  • So looking at your code, as we observed you hard coded the first page directory entry's frame to 0x11a. This is problematic especially if the location changes. Change it to `g_page_directory[0].frame = ((uint32)g_page_tables >> 12);` and see what happens. Since you are only mapping the first 4MiB of virtual memory, any memory beyond 4MiB will generate a page fault. – Michael Petch Aug 13 '23 at 20:38
  • That seems to work, how would I map the rest of the memory, or is it not needed? – xingharvey Aug 13 '23 at 20:59
  • If your kernel and everything else fits in 4MiB you don't need to but the moment you need more virtual memory for whatever reason you will have to create more page tables and add more entries to the page directory. – Michael Petch Aug 13 '23 at 21:03

1 Answers1

1

Ok, adding g_page_directory[0].frame = ((uint32)g_page_tables >> 12); helped, and the code went without errors. Thanks!

xingharvey
  • 131
  • 6