Hi,
agdever wrote:Now, the virtual machine is crashing again and again and restarting
Sorry - I had to be somewhere else and rushed things earlier. I saw "kernel_directory
= (unsigned int) address;" and thought you were using "address += PAGE_SIZE;" as a simple physical memory manager during early boot (until later in boot when kernel initialises a proper memory manager after paging is enabled). Now I see that I was mistaken - you're using "kmalloc_a()" to allocate a physical page for the page directory, which means that you should probably also be using "kmalloc_a()" to allocate a physical page for each page table; like this:
Code: Select all
void init_paging() {
unsigned int* kernel_directory = (unsigned int*)kmalloc_a(sizeof(unsigned int*) * TABLES_PER_DIRECTORY);
int i, j, address = 0;
for(i = 0; i < TABLES_PER_DIRECTORY; i++) {
kernel_directory[i] = (unsigned int*)kmalloc_a(sizeof(unsigned int*) * PAGES_PER_TABLE);
unsigned int* table = (unsigned int*) kernel_directory[i];
for(j = 0; j < PAGES_PER_TABLE; j++) {
table[j] = address | 5; // accessible by all, r/w, present
address += PAGE_SIZE;
}
kernel_directory[i] |= 5; // same
}
I also notice that you're mapping the first 4 GiB of the physical address space into the virtual address space, so that it's effectively identical to not using paging at all. This is relatively silly (all it does is waste RAM for page tables, etc).
Typically you want to map the kernel from where it is in physical memory (e.g. physical address 0x00100000) to where you actually want it (e.g. the virtual address 0xC0000000); and then have a single identity mapped page for a tiny little piece of code that does "write_cr0(read_cr0() | 0x80000001);" and jumps to where the kernel actually is; then you want to unmap that single identity mapped page so that all of "user-space" (all of the virtual address space from 0x000000000 to 0xBFFFFFFFF) contains nothing at all (so that it's nice and clean, ready for when you start a process). You also have to figure out what to do with the current stack (easiest is to discard the old stack and initialise a new one in kernel space after).
Note that the initial code to setup paging (and the initial physical memory manager) probably should be written in pure assembly language; partly because it's running at the wrong address (because kernel hasn't been mapped where it should be yet) and partly because you can't change the stack while a C function is relying on it. This is why most people either have a very simple initial physical memory manager that's used before paging is enabled, or just use RAM that was reserved in the ".bss" to avoid having any initial physical memory manager; and then have a proper physical memory manager that's used after paging is enabled.
Cheers,
Brendan