diff options
Diffstat (limited to 'kernel/arch')
-rw-r--r-- | kernel/arch/i386/mmu.c | 72 |
1 files changed, 58 insertions, 14 deletions
diff --git a/kernel/arch/i386/mmu.c b/kernel/arch/i386/mmu.c index 1e00f17..d46b077 100644 --- a/kernel/arch/i386/mmu.c +++ b/kernel/arch/i386/mmu.c @@ -1,6 +1,5 @@ #include <assert.h> #include <cpu/arch_inst.h> -#include <ksbrk.h> #include <log.h> #include <math.h> #include <mmu.h> @@ -26,8 +25,9 @@ u32 *tmp_small_frames = tmp_array; extern uintptr_t data_end; void change_frame(u32 frame, int on); -int get_free_frame(u32 *frame); +int get_free_frames(u32 *frame, size_t num_frames); int allocate_frame(Page *page, int rw, int is_kernel); +int mmu_allocate_kernel_linear_virtual_to_physical_mapping(void *rc, size_t n); static int create_kernel_table(int table_index) { u32 physical; @@ -53,7 +53,7 @@ static int create_kernel_table(int table_index) { return 1; } -void *ksbrk(size_t s) { +void *ksbrk(size_t s, int enforce_linear) { uintptr_t rc = (uintptr_t)align_page((void *)data_end); data_end += s; data_end = (uintptr_t)align_page((void *)data_end); @@ -70,11 +70,18 @@ void *ksbrk(size_t s) { if (!create_kernel_table(table_index)) { return NULL; } - return ksbrk(s); + return ksbrk(s, enforce_linear); } - if (!mmu_allocate_shared_kernel_region((void *)rc, - (data_end - (uintptr_t)rc))) { - return NULL; + if (enforce_linear) { + if (!mmu_allocate_kernel_linear_virtual_to_physical_mapping( + (void *)rc, (data_end - (uintptr_t)rc))) { + return NULL; + } + } else { + if (!mmu_allocate_shared_kernel_region((void *)rc, + (data_end - (uintptr_t)rc))) { + return NULL; + } } get_fast_insecure_random(rc, s); assert(((uintptr_t)rc % PAGE_SIZE) == 0); @@ -82,7 +89,7 @@ void *ksbrk(size_t s) { } void *ksbrk_physical(size_t s, void **physical) { - void *r = ksbrk(s); + void *r = ksbrk(s, 1); if (!r) { return NULL; } @@ -147,7 +154,8 @@ void mmu_free_pages(void *a, u32 n) { } u32 start_frame_search = 1; -int get_free_frame(u32 *frame) { +int get_free_frames(u32 *frame, size_t num_frames) { + size_t counter = num_frames; u32 i = start_frame_search; for (; i < INDEX_FROM_BIT(num_array_frames * 32); i++) { if (tmp_small_frames[i] == 0xFFFFFFFF) { @@ -155,9 +163,15 @@ int get_free_frame(u32 *frame) { } for (u32 c = 0; c < 32; c++) { - if (!(tmp_small_frames[i] & ((u32)1 << c))) { - start_frame_search = i; - *frame = i * 32 + c; + if ((tmp_small_frames[i] & ((u32)1 << c))) { + counter = num_frames; + continue; + } + start_frame_search = min(start_frame_search, i); + + counter--; + if (0 == counter) { + *frame = i * 32 + c - (num_frames - 1); return 1; } } @@ -211,7 +225,7 @@ PageTable *clone_table(u32 src_index, PageDirectory *src_directory, continue; } u32 frame_address; - if (!get_free_frame(&frame_address)) { + if (!get_free_frames(&frame_address, 1)) { kmalloc_align_free(new_table, sizeof(PageTable)); return NULL; } @@ -277,6 +291,9 @@ PageDirectory *clone_directory(PageDirectory *original) { } u32 offset = (u32)new_directory->physical_tables - (u32)new_directory; new_directory->physical_address = physical_address + offset; + assert( + new_directory->physical_address == + (uintptr_t)virtual_to_physical((uintptr_t)new_directory + offset, NULL)); for (int i = 0; i < 1024; i++) { if (!original->tables[i] && !kernel_directory->tables[i]) { @@ -320,6 +337,33 @@ PageDirectory *clone_directory(PageDirectory *original) { return new_directory; } +int mmu_allocate_kernel_linear_virtual_to_physical_mapping(void *rc, size_t n) { + size_t num_pages = align_page(n) / PAGE_SIZE; + + u32 start_frame; + if (!get_free_frames(&start_frame, num_pages)) { + goto mmu_allocate_shared_kernel_region_error; + } + + for (size_t i = 0; i < num_pages; i++) { + Page *p = get_page((void *)(rc + i * 0x1000), NULL, PAGE_ALLOCATE, 0); + if (!p) { + goto mmu_allocate_shared_kernel_region_error; + } + assert(!p->present); + p->present = 1; + p->rw = 1; + p->user = 0; + p->frame = start_frame + i; + assert(write_to_frame(p->frame * 0x1000, 1)); + } + flush_tlb(); + return 1; +mmu_allocate_shared_kernel_region_error: + mmu_free_address_range(rc, n, NULL); + return 0; +} + int mmu_allocate_shared_kernel_region(void *rc, size_t n) { size_t num_pages = n / PAGE_SIZE; for (size_t i = 0; i <= num_pages; i++) { @@ -436,7 +480,7 @@ int allocate_frame(Page *page, int rw, int is_kernel) { return 0; } u32 frame_address; - if (!get_free_frame(&frame_address)) { + if (!get_free_frames(&frame_address, 1)) { return 0; } assert(write_to_frame(frame_address * 0x1000, 1)); |