Virtual memory voodo behavior.
Posted: Sun Jul 10, 2016 8:26 am
This is so damn weird..
I'm implementing a virtual memory manager for "kernel space" (i.e. higher 1GB in my 4GB RAM) that i could use it for my 'kmalloc'.
I already have a physical memory manager, i already identity mapped the first 4MB of my RAM(kernel is in the first 2MB, but just in case..)
I already mapped the higher 1GB to my kernel physical memory addresses.
Now i'm implementing a 'virtual page alloactor' that uses a phyiscal page allocator in the background, and only maps it to the correct page directory entry, and page table index.
Now for the problem:
My physical memory alloactor returned an address of an available page:
available_page_addr has a value of 0x190000, and i'm OR'ing it with 0x3, so after calling the second function, the value will be:
0x190003.
This is a valid address, and since is within the first 4MB of my RAM, so i can access it even without mapping it to the higher 1GB, because of the identity map i've already done.
So, this is valid and prints the value that i expect:
Now for the complex part...
I have limited my kernel heap to 512MB size, so in fact, i have 512 / 4 page tables(since each page table maps 4MB).
So i declare my page tables statically:
kernel_page_table is an array of 128 arrays of size (1024 * sizeof(int)), i.e. each array is 4096 bytes,
AND IS ALIGNED TO PAGE BOUNDARY!
I start my management from addresss 0xc0400000, entry 769 in my kernel page directory.
So one would say, in order to map the physical address 'available_page_addr', to virtual address 0xc0400000,
i shall do:
Or, after calculating:
So far so good?
Well, this code is suppose to work:
But a bloody triple fault is thrown by QEMU.
I'll refresh your memory again:
- The physical page address is page aligned: 0x190000
- The page table address is aligned(gcc attribute), and its addresss, just in case, is: 0x104000
- the value of the kernel page directory in entry 769 is 0x104003, i.e. the first page table, OR'd with 3.
- the value of the first page table in index 0 is 0x190003, i.e. the physical page OR'd with 3.
Any ideas why?
I'm implementing a virtual memory manager for "kernel space" (i.e. higher 1GB in my 4GB RAM) that i could use it for my 'kmalloc'.
I already have a physical memory manager, i already identity mapped the first 4MB of my RAM(kernel is in the first 2MB, but just in case..)
I already mapped the higher 1GB to my kernel physical memory addresses.
Now i'm implementing a 'virtual page alloactor' that uses a phyiscal page allocator in the background, and only maps it to the correct page directory entry, and page table index.
Now for the problem:
My physical memory alloactor returned an address of an available page:
Code: Select all
available_page_addr = allocate_physical_page();
make_present_read_write_supervisor(&available_page_addr);
0x190003.
This is a valid address, and since is within the first 4MB of my RAM, so i can access it even without mapping it to the higher 1GB, because of the identity map i've already done.
So, this is valid and prints the value that i expect:
Code: Select all
printf("%x\n", *(int*)physical_page_addr = 5);
I have limited my kernel heap to 512MB size, so in fact, i have 512 / 4 page tables(since each page table maps 4MB).
So i declare my page tables statically:
Code: Select all
typedef unsigned int page_pointer_t;
page_pointer_t kernel_page_tables[512 / 4][1024] __attribute__((aligned(4096));
AND IS ALIGNED TO PAGE BOUNDARY!
I start my management from addresss 0xc0400000, entry 769 in my kernel page directory.
So one would say, in order to map the physical address 'available_page_addr', to virtual address 0xc0400000,
i shall do:
Code: Select all
//First map the page table for 0xc0400000 - +4MB
//And bitwise OR it with 0x3
kernel_page_directory[0xc0400000 >> 22] = kernel_page_tables | 0x3;
//Map the physical page address, it is already OR'd with 0x3
kernel_page_directory[0xc0400000 >> 22][(0xc0400000 >> 12) & 0x3ff] = (page_pointer_t)physical_page_addr;
Code: Select all
kernel_page_directory[769][0] = (page_pointer_t)physical_page_addr;
Well, this code is suppose to work:
Code: Select all
*((char*)0xc0400000) = 0x5;
I'll refresh your memory again:
- The physical page address is page aligned: 0x190000
- The page table address is aligned(gcc attribute), and its addresss, just in case, is: 0x104000
- the value of the kernel page directory in entry 769 is 0x104003, i.e. the first page table, OR'd with 3.
- the value of the first page table in index 0 is 0x190003, i.e. the physical page OR'd with 3.
Any ideas why?