aboutsummaryrefslogtreecommitdiff
path: root/src/kernel/memory/paging.c
diff options
context:
space:
mode:
authorMarvin Borner2020-06-01 23:30:40 +0200
committerMarvin Borner2020-06-01 23:30:40 +0200
commit0b3b63ffdedb2e37e0732c09eb0e967e256f0d71 (patch)
treef92a97a59e15d699b2594d3d313214f241ae8565 /src/kernel/memory/paging.c
parent5782d6b0c10b322d78c5d1284cbd4199d2e0f7ce (diff)
Very clean mmap approach
Sorry for the previous commit messages, I was kind of frustrated.
Diffstat (limited to 'src/kernel/memory/paging.c')
-rw-r--r--src/kernel/memory/paging.c241
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