diff options
Diffstat (limited to 'src/kernel/memory/paging.c')
-rw-r--r-- | src/kernel/memory/paging.c | 241 |
1 files changed, 56 insertions, 185 deletions
diff --git a/src/kernel/memory/paging.c b/src/kernel/memory/paging.c index 0e2cea4..1d9f6b1 100644 --- a/src/kernel/memory/paging.c +++ b/src/kernel/memory/paging.c @@ -1,238 +1,109 @@ +#include <io/io.h> #include <lib/lib.h> -#include <memory/alloc.h> +#include <memory/mmap.h> #include <memory/paging.h> #include <stdint.h> #include <system.h> -u32 kernel_page_directory[PAGE_COUNT] __attribute__((aligned(PAGE_ALIGN))); -u32 kernel_page_tables[PAGE_COUNT][PAGE_COUNT] __attribute__((aligned(PAGE_ALIGN))); -u32 *temp_dir[PAGE_COUNT] __attribute__((aligned(PAGE_ALIGN))); - -u32 **page_directory __attribute__((aligned(PAGE_ALIGN))); - -void paging_init(u32 **dir) -{ - //log("%d", paging_get_used_pages()); - for (u32 i = 0; i < PAGE_COUNT; i++) { - dir[i] = kernel_page_tables[i]; - for (u32 j = 0; j < PAGE_COUNT; j++) { - dir[i][j] = kernel_page_tables[i][j]; - } - } -} - -void paging_kernel_init() -{ - for (u32 i = 0; i < PAGE_COUNT; i++) - for (u32 j = 0; j < PAGE_COUNT; j++) - kernel_page_tables[i][j] = - ((j * PAGE_ALIGN) + (i * PAGE_SIZE)) | PT_RW | PT_USER; - - for (u32 i = 0; i < PAGE_COUNT; i++) - kernel_page_directory[i] = - ((u32)kernel_page_tables[i]) | PD_RW | PD_PRESENT | PD_USER; - - page_directory = temp_dir; - for (u32 i = 0; i < PAGE_COUNT; i++) { - page_directory[i] = kernel_page_tables[i]; - for (u32 j = 0; j < PAGE_COUNT; j++) { - page_directory[i][j] = kernel_page_tables[i][j]; - } - } -} +struct page_dir *kernel_page_directory; void paging_install() { - paging_switch_directory((u32 **)kernel_page_directory); - paging_kernel_init(); - - if (!memory_init()) - paging_set_present(0, memory_get_all() >> 3); - paging_set_used(0, ((u32)&kernel_end >> 12) + 1); - - paging_enable(); - log("Installed paging"); - - // Test! - u32 *a = malloc(PAGE_ALIGN); - u32 *b = malloc(PAGE_ALIGN); - free(b); - free(a); - u32 *c = malloc(2048); - assert(a == c); - c[42] = 0x4242; - assert(c[42] == 0x4242); - free(c); - info("Malloc test succeeded!"); -} + memory_init(); -u32 **paging_make_directory() -{ - /* u32 **dir = valloc(PAGE_COUNT * sizeof(*dir)); */ - /* dir[0] = malloc(PAGE_COUNT * PAGE_COUNT * sizeof(**dir)); */ - /* for (u32 i = 1; i < PAGE_COUNT; i++) */ - /* dir[i] = dir[0] + i * PAGE_COUNT; */ - u32 **dir = valloc(PAGE_COUNT * sizeof(*dir)); - for (u32 i = 0; i < PAGE_COUNT; i++) - dir[i] = malloc(PAGE_COUNT + sizeof(**dir)); + struct page_table *page_table; + page_table = kmalloc_frames(1); + memset(page_table, 0, sizeof(struct page_table)); for (u32 i = 0; i < PAGE_COUNT; i++) { - dir[i] = kernel_page_directory[i]; - /* for (u32 j = 0; j < PAGE_COUNT; j++) { */ - /* dir[i][j] = (&kernel_page_directory[i])[j]; */ - /* } */ + page_table->entries[i].present = 1; + page_table->entries[i].writable = 1; + page_table->entries[i].address = SHIFT(i * PAGE_SIZE); } - paging_switch_directory(dir); - log("%d", 42); + kernel_page_directory = kmalloc_frames(1); + memset(kernel_page_directory, 0, sizeof(struct page_dir)); + kernel_page_directory->entries[0].present = 1; + kernel_page_directory->entries[0].writable = 1; + kernel_page_directory->entries[0].address = SHIFT((u32)page_table); - return dir; -} - -void paging_remove_directory(u32 **dir) -{ - // TODO: Fix freeing of directory by calculating aligned offset - free(dir[0]); - free(dir); + paging_switch_directory((u32)kernel_page_directory); + paging_enable(); + info("Installed paging"); } void paging_disable() { - u32 cr0; - asm("mov %%cr0, %0" : "=r"(cr0)); + u32 cr0 = cr0_get(); cr0 &= 0x7fffffff; - asm("mov %0, %%cr0" ::"r"(cr0)); + cr0_set(cr0); paging_enabled = 0; } void paging_enable() { - u32 cr0; - asm("mov %%cr0, %0" : "=r"(cr0)); + u32 cr0 = cr0_get(); cr0 |= 0x80000000; - asm("mov %0, %%cr0" ::"r"(cr0)); + cr0_set(cr0); paging_enabled = 1; } -void paging_switch_directory(u32 **dir) -{ - page_directory = dir; - asm("mov %0, %%cr3" ::"r"(dir)); -} - -void invlpg(u32 addr) -{ - asm("invlpg (%0)" ::"r"(addr) : "memory"); -} - -void paging_map(u32 phy, u32 virt, u16 flags) -{ - u32 pdi = virt >> 22; - u32 pti = virt >> 12 & 0x03FF; - page_directory[pdi][pti] = phy | flags; - invlpg(virt); -} - -void paging_map_user(u32 phy, u32 virt) +void paging_switch_directory(u32 dir) { - u32 pdi = virt >> 22; - /* u32 pti = virt >> 12 & 0x03FF; */ - for (int i = 0; i < 1024; i++) { - page_directory[pdi][i] = phy | PT_RW | PT_PRESENT | PT_USER; - phy += 4096; - } - invlpg(virt); + cr3_set(dir); } -u32 paging_get_phys(u32 virt) +struct page_table_entry *paging_get_page(u32 address, struct page_dir *page_dir) { - u32 pdi = virt >> 22; - u32 pti = (virt >> 12) & 0x03FF; - return page_directory[pdi][pti] & 0xFFFFF000; -} + struct page_table *page_table; -u16 paging_get_flags(u32 virt) -{ - u32 pdi = virt >> 22; - u32 pti = (virt >> 12) & 0x03FF; - return page_directory[pdi][pti] & 0xFFF; -} + address /= PAGE_SIZE; + u32 n = address / PAGE_COUNT; -void paging_set_flag_up(u32 virt, u32 count, u32 flag) -{ - //debug("Setting flag %b for %d tables", flag, count); - u32 page_n = virt / PAGE_ALIGN; - for (u32 i = page_n; i < page_n + count; i++) { - page_directory[i / PAGE_COUNT][i % PAGE_COUNT] |= flag; - invlpg(i * PAGE_ALIGN); - } -} + if (page_dir->entries[n].present == 0) { + page_table = kmalloc_frames(1); + memset(page_table, 0, sizeof(struct page_table)); -void paging_set_flag_down(u32 virt, u32 count, u32 flag) -{ - u32 page_n = virt / PAGE_ALIGN; - for (u32 i = page_n; i < page_n + count; i++) { - page_directory[i / PAGE_COUNT][i % PAGE_COUNT] &= ~flag; - invlpg(i * PAGE_ALIGN); + page_dir->entries[n].address = SHIFT((u32)page_table); + page_dir->entries[n].present = 1; + page_dir->entries[n].writable = 1; + page_dir->entries[n].user = 1; + } else { + page_table = (void *)UNSHIFT(page_dir->entries[n].address); } -} -void paging_set_present(u32 virt, u32 count) -{ - paging_set_flag_up(virt, count, PT_PRESENT); + return &page_table->entries[address % PAGE_COUNT]; } -void paging_set_absent(u32 virt, u32 count) +void paging_frame_alloc(struct page_table_entry *page) { - paging_set_flag_down(virt, count, PT_PRESENT); -} + void *ptr = kmalloc_frames(1); -void paging_set_used(u32 virt, u32 count) -{ - paging_set_flag_up(virt, count, PT_USED); + if (page->address != 0) { + warn("Page is already allocated"); + return; + } + page->address = SHIFT((u32)ptr); + page->present = 1; + page->user = 1; } -void paging_set_free(u32 virt, u32 count) +void paging_frame_free(struct page_table_entry *page) { - paging_set_flag_down(virt, count, PT_USED); + kfree_frames((void *)UNSHIFT(page->address), 1); + memset((void *)page, 0, sizeof(struct page_table_entry)); } -u32 paging_find_pages(u32 count) +struct page_dir *paging_make_dir() { - u32 continuous = 0; - u32 start_dir = 0; - u32 start_page = 0; - for (u32 i = 0; i < PAGE_COUNT; i++) { - for (u32 j = 0; j < PAGE_COUNT; j++) { - if (!(page_directory[i][j] & PT_PRESENT) || - (page_directory[i][j] & PT_USED)) { - continuous = 0; - start_dir = i; - start_page = j + 1; - } else { - if (++continuous == count) - return (start_dir * PAGE_SIZE) + (start_page * PAGE_ALIGN); - } - } - } + struct page_dir *ret = kmalloc_frames(1); - panic("Out of memory!"); - return 0; -} + memcpy(ret, kernel_page_directory, sizeof(struct page_dir)); -u32 paging_alloc_pages(u32 count) -{ - u32 ptr = paging_find_pages(count); - paging_set_used(ptr, count); - return ptr; + return ret; } -u32 paging_get_used_pages() +void paging_free_dir(struct page_dir *page_dir) { - u32 n = 0; - for (u32 i = 0; i < PAGE_COUNT; i++) - for (u32 j = 0; j < PAGE_COUNT; j++) - if (page_directory[i][j] & PT_USED) - n++; - return n; + kfree_frames(page_dir, 1); }
\ No newline at end of file |