diff options
author | Marvin Borner | 2020-06-01 23:30:40 +0200 |
---|---|---|
committer | Marvin Borner | 2020-06-01 23:30:40 +0200 |
commit | 0b3b63ffdedb2e37e0732c09eb0e967e256f0d71 (patch) | |
tree | f92a97a59e15d699b2594d3d313214f241ae8565 /src/kernel/memory | |
parent | 5782d6b0c10b322d78c5d1284cbd4199d2e0f7ce (diff) |
Very clean mmap approach
Sorry for the previous commit messages, I was kind of frustrated.
Diffstat (limited to 'src/kernel/memory')
-rw-r--r-- | src/kernel/memory/alloc.c | 8 | ||||
-rw-r--r-- | src/kernel/memory/mmap.c | 106 | ||||
-rw-r--r-- | src/kernel/memory/mmap.h | 18 | ||||
-rw-r--r-- | src/kernel/memory/paging.c | 241 | ||||
-rw-r--r-- | src/kernel/memory/paging.h | 90 |
5 files changed, 230 insertions, 233 deletions
diff --git a/src/kernel/memory/alloc.c b/src/kernel/memory/alloc.c index d1d8b47..4f76080 100644 --- a/src/kernel/memory/alloc.c +++ b/src/kernel/memory/alloc.c @@ -1,6 +1,7 @@ #include <io/io.h> #include <lib/lib.h> #include <memory/alloc.h> +#include <memory/mmap.h> #include <memory/paging.h> #include <stddef.h> #include <stdint.h> @@ -22,13 +23,13 @@ int liballoc_unlock() void *liballoc_alloc(u32 p) { - u32 ptr = paging_alloc_pages((u32)p); + u32 ptr = kmalloc_frames((u32)p); return (void *)ptr; } int liballoc_free(void *ptr, u32 p) { - paging_set_free((u32)ptr, (u32)p); + kfree_frames((u32)ptr, (u32)p); return 0; } @@ -96,8 +97,7 @@ static long long l_possible_overruns = 0; static void *liballoc_memset(void *s, int c, u32 n) { - u32 i; - for (i = 0; i < n; i++) + for (u32 i = 0; i < n; i++) ((char *)s)[i] = c; return s; diff --git a/src/kernel/memory/mmap.c b/src/kernel/memory/mmap.c new file mode 100644 index 0000000..ab021b8 --- /dev/null +++ b/src/kernel/memory/mmap.c @@ -0,0 +1,106 @@ +#include <memory/mmap.h> +#include <stddef.h> +#include <stdint.h> +#include <system.h> + +#define FRAME_SIZE 0x1000 +#define FRAME_COUNT (total_memory / 4) +#define FRAME_TABLE_SIZE (FRAME_COUNT / 32) + +#define FREE 0x0 +#define USED 0x1 + +void *kmalloc(u32 size); + +extern u32 kernel_end; +u32 kernel_end_address = (u32)&kernel_end; + +u32 total_memory; + +u32 *frame_table; + +void *kmalloc(u32 size) +{ + void *ret; + + ret = (void *)kernel_end_address; + kernel_end_address += size; + + return ret; +} + +// TODO: Efficiency +void *kmalloc_frames(u32 num) +{ + u8 found; + + for (u32 i = 0; i < FRAME_COUNT; i++) { + found = 1; + for (u32 j = 0; j < num; j++) { + if (mmap_index_check(i + j) == USED) { + found = 0; + break; + } + } + if (found) { + for (u32 j = 0; j < num; j++) { + mmap_index_set_used(i + j); + } + return (void *)(i * FRAME_SIZE); + } + } + + warn("Not enough frames"); + return NULL; +} + +void kfree_frames(void *ptr, u32 num) +{ + u32 address = (u32)ptr; + u32 i = address; + + while (i < address + (num * FRAME_SIZE)) { + mmap_address_set_free(address); + i += FRAME_SIZE; + } +} + +u8 mmap_index_check(u32 n) +{ + return (frame_table[n / 32] >> (n % 32)) & 0x1; +} + +void mmap_init(u32 size) +{ + total_memory = size; + frame_table = kmalloc(FRAME_TABLE_SIZE); +} + +void mmap_init_finalize() +{ + // TODO: Efficiency + //memset(frame_table, 0xFF, (&kernel_end / FRAME_SIZE) / 8); + for (u32 i = 0; i < kernel_end_address; i += FRAME_SIZE) { + mmap_address_set_used(i); + } +} + +void mmap_address_set_free(u32 address) +{ + frame_table[(address / FRAME_SIZE) / 32] &= ~(1 << ((address / FRAME_SIZE) % 32)); +} + +void mmap_address_set_used(u32 address) +{ + frame_table[(address / FRAME_SIZE) / 32] |= (1 << ((address / FRAME_SIZE) % 32)); +} + +void mmap_index_set_free(u32 n) +{ + frame_table[n / 32] &= ~(1 << (n % 32)); +} + +void mmap_index_set_used(u32 n) +{ + frame_table[n / 32] |= 1 << (n % 32); +}
\ No newline at end of file diff --git a/src/kernel/memory/mmap.h b/src/kernel/memory/mmap.h new file mode 100644 index 0000000..1de801f --- /dev/null +++ b/src/kernel/memory/mmap.h @@ -0,0 +1,18 @@ +#ifndef MELVIX_MMAP +#define MELVIX_MMAP + +#include <stdint.h> + +void *kmalloc_frames(u32 num); +void kfree_frames(void *ptr, u32 num); + +u8 mmap_check(u32 n); +void mmap_init(u32 size); +void mmap_init_finalize(); +void mmap_address_set_free(u32 address); +void mmap_address_set_used(u32 address); +u8 mmap_index_check(u32 n); +void mmap_index_set_free(u32 n); +void mmap_index_set_used(u32 n); + +#endif
\ No newline at end of file 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 diff --git a/src/kernel/memory/paging.h b/src/kernel/memory/paging.h index 29d584c..ac0dbfa 100644 --- a/src/kernel/memory/paging.h +++ b/src/kernel/memory/paging.h @@ -3,56 +3,58 @@ #include <stdint.h> -#define PAGE_ALIGN 4096 +#define PAGE_SIZE 0x1000 #define PAGE_COUNT 1024 -#define PAGE_SIZE PAGE_ALIGN *PAGE_COUNT - -#define PD_PRESENT 1 << 0 -#define PD_RW 1 << 1 -#define PD_USER 1 << 2 -#define PD_WRITETHR 1 << 3 -#define PD_CACHE_D 1 << 4 -#define PD_ACCESSED 1 << 5 -#define PD_4M_PAGE 1 << 7 - -#define PT_PRESENT 1 << 0 -#define PT_RW 1 << 1 -#define PT_USER 1 << 2 -#define PT_WRITETHR 1 << 3 -#define PT_CACHE_D 1 << 4 -#define PT_ACCESSED 1 << 5 -#define PT_DIRTY 1 << 6 -#define PT_GLOBAL 1 << 8 -#define PT_USED 1 << 9 - -u32 **page_directory __attribute__((aligned(PAGE_ALIGN))); -u32 kernel_page_tables[PAGE_COUNT][PAGE_COUNT] __attribute__((aligned(PAGE_ALIGN))); +#define SHIFT(address) ((address) >> 12) +#define UNSHIFT(address) ((address) << 12) + int paging_enabled; +struct page_table_entry { + u32 present : 1; + u32 writable : 1; + u32 user : 1; + u32 write_through : 1; + u32 cache_disable : 1; + u32 accessed : 1; + u32 dirty : 1; + u32 attribute : 1; + u32 global : 1; + u32 available : 3; + u32 address : 20; +} __attribute__((packed)); + +struct page_table { + struct page_table_entry entries[PAGE_COUNT]; +}; + +struct page_dir_entry { + u32 present : 1; + u32 writable : 1; + u32 user : 1; + u32 write_through : 1; + u32 cache_disable : 1; + u32 accessed : 1; + u32 reserved : 1; + u32 page_size : 1; + u32 global : 1; + u32 available : 3; + u32 address : 20; +} __attribute__((packed)); + +struct page_dir { + struct page_dir_entry entries[PAGE_COUNT]; +}; + void paging_install(); void paging_enable(); void paging_disable(); +void paging_switch_directory(u32 dir); -u32 **paging_make_directory(); -void paging_remove_directory(u32 **dir); -void paging_switch_directory(u32 **dir); - -void paging_map(u32 phy, u32 virt, u16 flags); -void paging_map_user(u32 phy, u32 virt); -u32 paging_get_phys(u32 virt); -u16 paging_get_flags(u32 virt); -u32 paging_get_used_pages(); - -void paging_set_flags(u32 virt, u32 count, u16 flags); -void paging_set_flag_up(u32 virt, u32 count, u32 flag); -void paging_set_flag_down(u32 virt, u32 count, u32 flag); -void paging_set_present(u32 virt, u32 count); -void paging_set_absent(u32 virt, u32 count); -void paging_set_used(u32 virt, u32 count); -void paging_set_free(u32 virt, u32 count); -void paging_set_user(u32 virt, u32 count); - -u32 paging_find_pages(u32 count); -u32 paging_alloc_pages(u32 count); +struct page_table_entry *paging_get_page(u32 address, struct page_dir *page_dir); +void paging_frame_alloc(struct page_table_entry *page); +void paging_frame_free(struct page_table_entry *page); +struct page_dir *paging_make_dir(); +void paging_free_dir(); #endif
\ No newline at end of file |