Hi!
I'd like to leave several notes that might help you with your issue.
First, what is the value of cr3? gdb printout suggests that the
value of "kernel_directory" variable is 0x0000C000:
Code: Select all
Breakpoint 1, switch_page_directory (dir=0xc000) at kernel/paging.c:170
Looking at your code, it seems to me that kernel_directory points to a data structure that contains, at least, these two arrays:
- An array that stores the virtual addresses of your allocated page tables (called tables[]).
- An array that stores page entries to your page tables (called tablesPhysical[]).
The second array is what we call a
page directory. Each page entry consists of flags +
physical address of a page table. If you go to that page table, you shall find other 1024 page entries that actually point to actual memory frames. Each page entry consists of flags +
physical address of an actual memory frame.
However, there seems to be some confusion in the comments above...
Code: Select all
dir->tablesPhysical[table_idx] = tmp | 0x7; // PRESENT, RW, US.
This peaceful line of code sets the flag of an entry in the page directory
, not page table. However, you are referring to the part of the wiki article that talks about page table entries, not page directory entries:
BluCode wrote:goku420 wrote:
Setting user/supervisor bit sets user mode, not the other way around.
goku420 wrote:Code: Select all
dir->tablesPhysical[table_idx] = tmp | 0x7; // PRESENT, RW, US.
Again, this sets user mode.
I have a feeling that you copy/pasted some of James Molloy's code which contains gotchas for the unobservant.
And what is the issue with setting user mode? Would that cause the kernel to reset? According to the wiki 'If the bit is set, then the page may be accessed by all' so that shouldn't be a problem.
Yes I am reusing his code, but as far as I can tell what you pointed out won't have a significant effect.
So, if I understand your code correctly, I expect that your page directory actually contains one entry [at index 0]: 0x0000F007. It obviously points to a page table at 0x0000F000, and the flags PRESENT, RW, and US are all set (and it's OK).
Now if we go to your page table at 0x0000F000, we should see entries to actual memory frames. This is related to line 159:
Code: Select all
// Kernel code is readable but not writeable from userspace.
alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
You pass 0 and 0 to alloc_frame(), which means: set US but please don't set RW. Thus, you will have only US and PRESENT flags set [i.e, 0x05]:
Code: Select all
(gdb) x 0xf000
0xf000: 0x00000005
(gdb) x 0xf004
0xf004: 0x00001005
(gdb) x 0xf008
0xf008: 0x00002005
(gdb) x 0xf030
0xf030: 0x0000c005
(gdb) x 0xf03c
0xf03c: 0x0000f005
(gdb) x 0xf040
0xf040: 0x00000000
This seems sensible to me. If the flag of your first page directory entry is 0x7 and the flags of your page entries are 0x5, then your US flag is actually set correctly.
BluCode wrote:I see, do you have any idea as to how I can fix my flags? I'm afraid that I really don't have much idea what I'm doing here yet.
In my point of view, your flags are OK.
So how can we make sure that the flags are set correctly? print the value of cr3, not kernel_directory variable. I believe (according to your gdb outputs) that kernel_directory points to 0xC000, which is the base for a data structure that holds the two arrays explained above. It seems to me that the first array (the virtual addresses of page tables) is actually based at 0xC000, while the second one might be at 0xD000 or 0xE000. We want this second one.
Code: Select all
(gdb) x kernel_directory
0xc000: 0x0000f000
^ This prints the first entry of kernel_directory->tables[] (the first array). We actually want the first entry of kernel_directory->tablesPhysical[] (the second array), since this actually what your processor sees and translates as a page directory. Remember how you have loaded cr3:
Code: Select all
172 asm volatile("mov %0, %%cr3":: "r"(&dir->tablesPhysical));
-----------------------------------------------
Now let's move to another point...
BluCode wrote:Code: Select all
(qemu) info mem
0000000000000000-0000000000010000 0000000000010000 -r-
(qemu)
Which leads me to believe that for some reason it isn't paging enough of the memory, but I don't really know. When I use x in gdb to inspect the page tables at 0x0000, 0x1000, 0x2000 etc I get very different results for each. I hope you can do something more with this info.
Code: Select all
// Defined in kheap.c
extern u32int placement_address;
Code: Select all
// We need to identity map (phys addr = virt addr) from
// 0x0 to the end of used memory, so we can access this
// transparently, as if paging wasn't enabled.
// NOTE that we use a while loop here deliberately.
// inside the loop body we actually change placement_address
// by calling kmalloc(). A while loop causes this to be
// computed on-the-fly rather than once at the start.
int i = 0;
while (i < placement_address)
{
// Kernel code is readable but not writeable from userspace.
alloc_frame( get_page(i, 1, kernel_directory), 0, 0);
i += 0x1000;
}
Could you please check the value of "placement_address" variable?