From acc4b7ccc133b64312e7ab1da3225b7945b1e13d Mon Sep 17 00:00:00 2001 From: Marvin Borner Date: Tue, 2 Mar 2021 19:04:53 +0100 Subject: very good this is --- kernel/Makefile | 2 +- kernel/features/load.c | 18 +- kernel/features/memory.c | 428 --------------------------------------------- kernel/features/mm.c | 436 ++++++++++++++++++++++++++++++++++++++++++++++ kernel/features/proc.c | 20 ++- kernel/features/syscall.c | 2 +- kernel/inc/memory.h | 80 --------- kernel/inc/mm.h | 87 +++++++++ kernel/inc/proc.h | 8 +- kernel/main.c | 2 +- 10 files changed, 557 insertions(+), 526 deletions(-) delete mode 100644 kernel/features/memory.c create mode 100644 kernel/features/mm.c delete mode 100644 kernel/inc/memory.h create mode 100644 kernel/inc/mm.h (limited to 'kernel') diff --git a/kernel/Makefile b/kernel/Makefile index 6763185..2db201b 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -10,7 +10,7 @@ COBJS = main.o \ drivers/ide.o \ drivers/timer.o \ drivers/rtl8139.o \ - features/memory.o \ + features/mm.o \ features/fs.o \ features/load.o \ features/proc.o \ diff --git a/kernel/features/load.c b/kernel/features/load.c index 8a4aae3..610abf8 100644 --- a/kernel/features/load.c +++ b/kernel/features/load.c @@ -3,14 +3,19 @@ #include #include #include +#include #include +#define PROC_STACK_SIZE 0x4000 + void proc_load(struct proc *proc, void *data) { - u32 stack = (u32)malloc(0x2000) + 0x1000; + u32 stack; + memory_alloc(proc->page_dir, PROC_STACK_SIZE, MEMORY_CLEAR, &stack); + u32 ptr = stack + PROC_STACK_SIZE - 1; - proc->regs.ebp = (u32)stack; - proc->regs.useresp = (u32)stack; + proc->regs.ebp = (u32)ptr; + proc->regs.useresp = (u32)ptr; proc->regs.eip = (u32)data; proc->entry = (u32)data; } @@ -19,12 +24,13 @@ int bin_load(const char *path, struct proc *proc) { struct stat s = { 0 }; vfs_stat(path, &s); - char *data = malloc(s.size); - if (!vfs_read(path, data, 0, s.size)) + u32 data; + memory_alloc(proc->page_dir, PAGE_ALIGN_UP(s.size), MEMORY_CLEAR, &data); + if (!vfs_read(path, (void *)data, 0, s.size)) return 1; strcpy(proc->name, path); - proc_load(proc, data); + proc_load(proc, (void *)data); return 0; } diff --git a/kernel/features/memory.c b/kernel/features/memory.c deleted file mode 100644 index 7813c56..0000000 --- a/kernel/features/memory.c +++ /dev/null @@ -1,428 +0,0 @@ -// Hugely inspired by the implementation in skiftOS: MIT License, Copyright (c) 2020 N. Van Bossuyt -// MIT License, Copyright (c) 2021 Marvin Borner - -#include -#include -#include -#include -#include - -#include - -/** - * Paging - */ - -void paging_disable(void) -{ - cr0_set(cr0_get() | 0x7fffffff); -} - -void paging_enable(void) -{ - cr0_set(cr0_get() | 0x80000000); -} - -void paging_switch_dir(u32 dir) -{ - cr3_set(dir); -} - -extern void paging_invalidate_tlb(void); - -/** - * Physical - */ - -static u32 memory_used = 0; -static u32 memory_total = 0; -static u8 memory[PAGE_COUNT * PAGE_COUNT / 8] = { 0 }; -#define PHYSICAL_IS_USED(addr) \ - (memory[(u32)(addr) / PAGE_SIZE / 8] & (1 << ((u32)(addr) / PAGE_SIZE % 8))) - -#define PHYSICAL_SET_USED(addr) \ - (memory[(u32)(addr) / PAGE_SIZE / 8] |= (1 << ((u32)(addr) / PAGE_SIZE % 8))) - -#define PHYSICAL_SET_FREE(addr) \ - (memory[(u32)(addr) / PAGE_SIZE / 8] &= ~(1 << ((u32)(addr) / PAGE_SIZE % 8))) - -u8 physical_is_used(u32 addr, u32 n) -{ - for (u32 i = 0; i < n; i++) { - if (PHYSICAL_IS_USED(addr + (i * PAGE_SIZE))) - return 1; - } - return 0; -} - -void physical_set_used(u32 addr, u32 n) -{ - for (u32 i = 0; i < n; i++) { - if (!PHYSICAL_IS_USED(addr + (i * PAGE_SIZE))) { - memory_used += PAGE_SIZE; - PHYSICAL_SET_USED(addr + (i * PAGE_SIZE)); - } - } -} - -void physical_set_free(u32 addr, u32 n) -{ - for (u32 i = 0; i < n; i++) { - if (PHYSICAL_IS_USED(addr + (i * PAGE_SIZE))) { - memory_used -= PAGE_SIZE; - PHYSICAL_SET_FREE(addr + (i * PAGE_SIZE)); - } - } -} - -u32 physical_alloc(u32 n) -{ - for (u32 i = 0; i < (memory_total / PAGE_SIZE); i++) { - u32 addr = i * PAGE_SIZE; - if (!physical_is_used(addr, n)) { - physical_set_used(addr, n); - return addr; - } - } - - panic("Out of physical memory!\n"); - return 0; -} - -void physical_free(u32 addr, u32 n) -{ - physical_set_free(addr, n); -} - -/** - * Virtual - */ - -#define PDI(vaddr) ((vaddr) >> 22) -#define PTI(vaddr) (((vaddr) >> 12) & 0x03ff) - -static struct page_dir kernel_dir ALIGNED(PAGE_SIZE) = { 0 }; -static struct page_table kernel_tables[256] ALIGNED(PAGE_SIZE) = { 0 }; - -u8 virtual_present(struct page_dir *dir, u32 vaddr) -{ - u32 pdi = PDI(vaddr); - u32 pti = PTI(vaddr); - - union page_dir_entry *dir_entry = &dir->entries[pdi]; - if (!dir_entry->bits.present) - return 0; - - struct page_table *table = (struct page_table *)(dir_entry->bits.address * PAGE_SIZE); - union page_table_entry *table_entry = &table->entries[pti]; - if (!table_entry->bits.present) - return 0; - - return 1; -} - -u32 virtual_to_physical(struct page_dir *dir, u32 vaddr) -{ - u32 pdi = PDI(vaddr); - u32 pti = PTI(vaddr); - - union page_dir_entry *dir_entry = &dir->entries[pdi]; - struct page_table *table = (struct page_table *)(dir_entry->bits.address * PAGE_SIZE); - union page_table_entry *table_entry = &table->entries[pti]; - - return (table_entry->bits.address * PAGE_SIZE) + (vaddr & (PAGE_SIZE - 1)); -} - -void memory_alloc_identity(struct page_dir *dir, u32 flags, u32 *out); -void virtual_map(struct page_dir *dir, u32 vaddr, u32 paddr, u32 n, u8 user) -{ - for (u32 i = 0; i < n; i++) { - u32 offset = i * PAGE_SIZE; - u32 pdi = PDI(vaddr + offset); - u32 pti = PTI(vaddr + offset); - - union page_dir_entry *dir_entry = &dir->entries[pdi]; - struct page_table *table = - (struct page_table *)(dir_entry->bits.address * PAGE_SIZE); - union page_table_entry *table_entry = &table->entries[pti]; - - if (!dir_entry->bits.present) { - memory_alloc_identity(dir, MEMORY_CLEAR, (u32 *)&table); - dir_entry->bits.present = 1; - dir_entry->bits.writable = 1; - dir_entry->bits.user = user; - dir_entry->bits.address = (u32)table >> 12; - } - - table_entry->bits.present = 1; - table_entry->bits.writable = 1; - table_entry->bits.user = user; - table_entry->bits.address = (paddr + offset) >> 12; - } - - paging_invalidate_tlb(); -} - -struct memory_range virtual_alloc(struct page_dir *dir, struct memory_range physical_range, - u32 flags) -{ - u8 is_user = flags & MEMORY_USER; - u32 vaddr = 0; - u32 size = 0; - for (u32 i = (is_user ? 256 : 1) * PAGE_COUNT; - i < (is_user ? PAGE_COUNT : 256) * PAGE_COUNT; i++) { - u32 addr = i * PAGE_SIZE; - if (!virtual_present(dir, addr)) { - if (size == 0) - vaddr = addr; - size += PAGE_SIZE; - if (size == physical_range.size) { - virtual_map(dir, vaddr, physical_range.base, - physical_range.size / PAGE_SIZE, is_user); - return memory_range(vaddr, size); - } - } else { - size = 0; - } - } - - panic("Out of virtual memory!\n"); - return memory_range(0, 0); -} - -void virtual_free(struct page_dir *dir, struct memory_range virtual_range) -{ - for (u32 i = 0; i < virtual_range.size / PAGE_SIZE; i++) { - u32 offset = i * PAGE_SIZE; - - u32 pdi = PDI(virtual_range.base + offset); - u32 pti = PTI(virtual_range.base + offset); - - union page_dir_entry *dir_entry = &dir->entries[pdi]; - struct page_table *table = - (struct page_table *)(dir_entry->bits.address * PAGE_SIZE); - union page_table_entry *table_entry = &table->entries[pti]; - - if (table_entry->bits.present) - table_entry->uint = 0; - } - - paging_invalidate_tlb(); -} - -/** - * Memory wrapper - */ - -extern u32 kernel_start; -extern u32 kernel_end; - -struct memory_range memory_range_from_address(u32 base, u32 size) -{ - u32 align = PAGE_SIZE - base % PAGE_SIZE; - - if (base % PAGE_SIZE == 0) { - align = 0; - } - - base += align; - size -= align; - - size -= size % PAGE_SIZE; - - return memory_range(base, size); -} - -struct memory_range memory_range_around_address(u32 base, u32 size) -{ - u32 align = base % PAGE_SIZE; - - base -= align; - size += align; - - size += PAGE_SIZE - size % PAGE_SIZE; - - return memory_range(base, size); -} - -static struct memory_range kernel_memory_range(void) -{ - return memory_range_around_address((u32)&kernel_start, - (u32)&kernel_end - (u32)&kernel_start); -} - -void memory_map_identity(struct page_dir *dir, struct memory_range range, u32 flags) -{ - assert(PAGE_ALIGNED(range.base) && PAGE_ALIGNED(range.size)); - - u32 page_count = range.size / PAGE_SIZE; - physical_set_used(range.base, page_count); - virtual_map(dir, range.base, range.base, page_count, flags & MEMORY_USER); - - if (flags & MEMORY_CLEAR) - memset((void *)range.base, 0, range.size); -} - -void memory_map(struct page_dir *dir, struct memory_range range, u32 flags) -{ - assert(PAGE_ALIGNED(range.base) && PAGE_ALIGNED(range.size)); - - for (u32 i = 0; i < range.size / PAGE_SIZE; i++) { - u32 vaddr = range.base + i * PAGE_SIZE; - if (!virtual_present(dir, vaddr)) { - u32 paddr = physical_alloc(1); - virtual_map(dir, vaddr, paddr, 1, flags & MEMORY_USER); - } - } - - if (flags & MEMORY_CLEAR) - memset((void *)range.base, 0, range.size); -} - -void memory_alloc_identity(struct page_dir *dir, u32 flags, u32 *out) -{ - for (u32 i = 1; i < 256 * PAGE_COUNT; i++) { - u32 addr = i * PAGE_SIZE; - if (!virtual_present(dir, addr) && !physical_is_used(addr, 1)) { - physical_set_used(addr, 1); - virtual_map(dir, addr, addr, 1, flags & MEMORY_USER); - - if (flags & MEMORY_CLEAR) - memset((void *)addr, 0, PAGE_SIZE); - - *out = addr; - - return; - } - } - - *out = 0; - panic("Out of memory!\n"); -} - -void memory_alloc(struct page_dir *dir, u32 size, u32 flags, u32 *out) -{ - assert(size && PAGE_ALIGNED(size)); - *out = 0; - - u32 page_count = size / PAGE_SIZE; - u32 paddr = physical_alloc(page_count); - assert(paddr); - u32 vaddr = virtual_alloc(dir, memory_range(paddr, size), flags).base; - assert(vaddr); - if (flags & MEMORY_CLEAR) - memset((void *)vaddr, 0, page_count * PAGE_SIZE); - *out = vaddr; -} - -void memory_free(struct page_dir *dir, struct memory_range range) -{ - assert(PAGE_ALIGNED(range.base) && PAGE_ALIGNED(range.size)); - - for (u32 i = 0; i < range.size / PAGE_SIZE; i++) { - u32 vaddr = range.base + i * PAGE_SIZE; - if (virtual_present(dir, vaddr)) { - physical_free(virtual_to_physical(dir, vaddr), 1); - virtual_free(dir, memory_range(vaddr, PAGE_SIZE)); - } - } -} - -struct page_dir *memory_dir_create(void) -{ - struct page_dir *dir = NULL; - memory_alloc(&kernel_dir, sizeof(*dir), MEMORY_CLEAR, (u32 *)&dir); - memset(dir, 0, sizeof(*dir)); - - for (u32 i = 0; i < 256; i++) { - union page_dir_entry *entry = &dir->entries[i]; - entry->bits.present = 1; - entry->bits.writable = 1; - entry->bits.user = 0; - entry->bits.address = (u32)&kernel_tables[i] / PAGE_SIZE; - } - - return dir; -} - -void memory_dir_destroy(struct page_dir *dir) -{ - for (u32 i = 256; i < PAGE_COUNT; i++) { - union page_dir_entry *dir_entry = &dir->entries[i]; - if (dir_entry->bits.present) { - struct page_table *table = - (struct page_table *)(dir_entry->bits.address * PAGE_SIZE); - for (u32 j = 0; j < PAGE_COUNT; j++) { - union page_table_entry *table_entry = &table->entries[j]; - if (table_entry->bits.present) - physical_free(table_entry->bits.address * PAGE_SIZE, 1); - } - - memory_free(&kernel_dir, memory_range((u32)table, sizeof(*table))); - } - } - memory_free(&kernel_dir, memory_range((u32)dir, sizeof(*dir))); -} - -void memory_dir_switch(struct page_dir *dir) -{ - paging_switch_dir(virtual_to_physical(&kernel_dir, (u32)dir)); -} - -void memory_initialize(struct mem_info *mem_info) -{ - for (u32 i = 0; i < 256; i++) { - union page_dir_entry *entry = &kernel_dir.entries[i]; - entry->bits.present = 1; - entry->bits.writable = 1; - entry->bits.user = 0; - entry->bits.address = (u32)&kernel_tables[i] / PAGE_SIZE; - } - - // Detect memory using E820 memory map - for (struct mmap_boot *p = mem_info->start; (u32)(p - mem_info->start) < mem_info->size; - p++) { - if (p->hbase || !p->acpi || !p->type) - continue; - - u32 size = p->lsize; - if (p->hsize) - size = U32_MAX - p->lbase; - - /* printf("Memory region: %x-%x\n", p->lbase, p->lbase + size); */ - if (p->type == MEMORY_AVAILABLE) { - physical_set_free(p->lbase, size / PAGE_SIZE); - memory_total += size; - } else if (p->type == MEMORY_DEFECT) { - printf("Defect memory at 0x%x-0x%x!\n", p->lbase, p->lbase + size); - } - } - - memory_used = 0; - printf("Detected memory: %dKiB (%dMiB)\n", memory_total >> 10, memory_total >> 20); - - // Map kernel - memory_map_identity(&kernel_dir, kernel_memory_range(), MEMORY_NONE); - - // Map kernel stack - memory_map_identity(&kernel_dir, - memory_range_around_address(STACK_START - STACK_SIZE, STACK_SIZE), - MEMORY_NONE); - - // Map kernel heap - memory_map_identity(&kernel_dir, memory_range_around_address(HEAP_START, HEAP_INIT_SIZE), - MEMORY_NONE); - - // Unmap NULL byte/page - virtual_free(&kernel_dir, memory_range(0, PAGE_SIZE)); - physical_set_used(0, 1); - - memory_dir_switch(&kernel_dir); - paging_enable(); -} - -void paging_install(struct mem_info *mem_info) -{ - memory_initialize(mem_info); - heap_init(HEAP_START); -} diff --git a/kernel/features/mm.c b/kernel/features/mm.c new file mode 100644 index 0000000..ccc2727 --- /dev/null +++ b/kernel/features/mm.c @@ -0,0 +1,436 @@ +// Hugely inspired by the implementation in skiftOS: MIT License, Copyright (c) 2020 N. Van Bossuyt +// MIT License, Copyright (c) 2021 Marvin Borner + +#include +#include +#include +#include +#include + +#include + +/** + * Paging + */ + +void paging_disable(void) +{ + cr0_set(cr0_get() | 0x7fffffff); +} + +void paging_enable(void) +{ + cr0_set(cr0_get() | 0x80000000); +} + +void paging_switch_dir(u32 dir) +{ + cr3_set(dir); +} + +extern void paging_invalidate_tlb(void); + +/** + * Physical + */ + +static u32 memory_used = 0; +static u32 memory_total = 0; +static u8 memory[PAGE_COUNT * PAGE_COUNT / 8] = { 0 }; +#define PHYSICAL_IS_USED(addr) \ + (memory[(u32)(addr) / PAGE_SIZE / 8] & (1 << ((u32)(addr) / PAGE_SIZE % 8))) + +#define PHYSICAL_SET_USED(addr) \ + (memory[(u32)(addr) / PAGE_SIZE / 8] |= (1 << ((u32)(addr) / PAGE_SIZE % 8))) + +#define PHYSICAL_SET_FREE(addr) \ + (memory[(u32)(addr) / PAGE_SIZE / 8] &= ~(1 << ((u32)(addr) / PAGE_SIZE % 8))) + +u8 physical_is_used(u32 addr, u32 n) +{ + for (u32 i = 0; i < n; i++) { + if (PHYSICAL_IS_USED(addr + (i * PAGE_SIZE))) + return 1; + } + return 0; +} + +void physical_set_used(u32 addr, u32 n) +{ + for (u32 i = 0; i < n; i++) { + if (!PHYSICAL_IS_USED(addr + (i * PAGE_SIZE))) { + memory_used += PAGE_SIZE; + PHYSICAL_SET_USED(addr + (i * PAGE_SIZE)); + } + } +} + +void physical_set_free(u32 addr, u32 n) +{ + for (u32 i = 0; i < n; i++) { + if (PHYSICAL_IS_USED(addr + (i * PAGE_SIZE))) { + memory_used -= PAGE_SIZE; + PHYSICAL_SET_FREE(addr + (i * PAGE_SIZE)); + } + } +} + +u32 physical_alloc(u32 n) +{ + for (u32 i = 0; i < (memory_total / PAGE_SIZE); i++) { + u32 addr = i * PAGE_SIZE; + if (!physical_is_used(addr, n)) { + physical_set_used(addr, n); + return addr; + } + } + + panic("Out of physical memory!\n"); + return 0; +} + +void physical_free(u32 addr, u32 n) +{ + physical_set_free(addr, n); +} + +/** + * Virtual + */ + +#define PDI(vaddr) ((vaddr) >> 22) +#define PTI(vaddr) (((vaddr) >> 12) & 0x03ff) + +static struct page_dir kernel_dir ALIGNED(PAGE_SIZE) = { 0 }; +static struct page_table kernel_tables[256] ALIGNED(PAGE_SIZE) = { 0 }; + +u8 virtual_present(struct page_dir *dir, u32 vaddr) +{ + u32 pdi = PDI(vaddr); + u32 pti = PTI(vaddr); + + union page_dir_entry *dir_entry = &dir->entries[pdi]; + if (!dir_entry->bits.present) + return 0; + + struct page_table *table = (struct page_table *)(dir_entry->bits.address * PAGE_SIZE); + union page_table_entry *table_entry = &table->entries[pti]; + if (!table_entry->bits.present) + return 0; + + return 1; +} + +u32 virtual_to_physical(struct page_dir *dir, u32 vaddr) +{ + u32 pdi = PDI(vaddr); + u32 pti = PTI(vaddr); + + union page_dir_entry *dir_entry = &dir->entries[pdi]; + struct page_table *table = (struct page_table *)(dir_entry->bits.address * PAGE_SIZE); + union page_table_entry *table_entry = &table->entries[pti]; + + return (table_entry->bits.address * PAGE_SIZE) + (vaddr & (PAGE_SIZE - 1)); +} + +void memory_alloc_identity(struct page_dir *dir, u32 flags, u32 *out); +void virtual_map(struct page_dir *dir, u32 vaddr, u32 paddr, u32 n, u8 user) +{ + for (u32 i = 0; i < n; i++) { + u32 offset = i * PAGE_SIZE; + u32 pdi = PDI(vaddr + offset); + u32 pti = PTI(vaddr + offset); + + union page_dir_entry *dir_entry = &dir->entries[pdi]; + struct page_table *table = + (struct page_table *)(dir_entry->bits.address * PAGE_SIZE); + union page_table_entry *table_entry = &table->entries[pti]; + + if (!dir_entry->bits.present) { + memory_alloc_identity(dir, MEMORY_CLEAR, (u32 *)&table); + dir_entry->bits.present = 1; + dir_entry->bits.writable = 1; + dir_entry->bits.user = user; + dir_entry->bits.address = (u32)table >> 12; + } + + table_entry->bits.present = 1; + table_entry->bits.writable = 1; + table_entry->bits.user = user; + table_entry->bits.address = (paddr + offset) >> 12; + } + + paging_invalidate_tlb(); +} + +struct memory_range virtual_alloc(struct page_dir *dir, struct memory_range physical_range, + u32 flags) +{ + u8 is_user = flags & MEMORY_USER; + u32 vaddr = 0; + u32 size = 0; + for (u32 i = (is_user ? 256 : 1) * PAGE_COUNT; + i < (is_user ? PAGE_COUNT : 256) * PAGE_COUNT; i++) { + u32 addr = i * PAGE_SIZE; + if (!virtual_present(dir, addr)) { + if (size == 0) + vaddr = addr; + size += PAGE_SIZE; + if (size == physical_range.size) { + virtual_map(dir, vaddr, physical_range.base, + physical_range.size / PAGE_SIZE, is_user); + return memory_range(vaddr, size); + } + } else { + size = 0; + } + } + + panic("Out of virtual memory!\n"); + return memory_range(0, 0); +} + +void virtual_free(struct page_dir *dir, struct memory_range virtual_range) +{ + for (u32 i = 0; i < virtual_range.size / PAGE_SIZE; i++) { + u32 offset = i * PAGE_SIZE; + + u32 pdi = PDI(virtual_range.base + offset); + u32 pti = PTI(virtual_range.base + offset); + + union page_dir_entry *dir_entry = &dir->entries[pdi]; + struct page_table *table = + (struct page_table *)(dir_entry->bits.address * PAGE_SIZE); + union page_table_entry *table_entry = &table->entries[pti]; + + if (table_entry->bits.present) + table_entry->uint = 0; + } + + paging_invalidate_tlb(); +} + +/** + * Memory wrapper + */ + +extern u32 kernel_start; +extern u32 kernel_end; + +struct memory_range memory_range_from_address(u32 base, u32 size) +{ + u32 align = PAGE_SIZE - base % PAGE_SIZE; + + if (base % PAGE_SIZE == 0) { + align = 0; + } + + base += align; + size -= align; + + size -= size % PAGE_SIZE; + + return memory_range(base, size); +} + +struct memory_range memory_range_around_address(u32 base, u32 size) +{ + u32 align = base % PAGE_SIZE; + + base -= align; + size += align; + + size += PAGE_SIZE - size % PAGE_SIZE; + + return memory_range(base, size); +} + +static struct memory_range kernel_memory_range(void) +{ + return memory_range_around_address((u32)&kernel_start, + (u32)&kernel_end - (u32)&kernel_start); +} + +void memory_map_identity(struct page_dir *dir, struct memory_range range, u32 flags) +{ + assert(PAGE_ALIGNED(range.base) && PAGE_ALIGNED(range.size)); + + u32 page_count = range.size / PAGE_SIZE; + physical_set_used(range.base, page_count); + virtual_map(dir, range.base, range.base, page_count, flags & MEMORY_USER); + + if (flags & MEMORY_CLEAR) + memset((void *)range.base, 0, range.size); +} + +void memory_map(struct page_dir *dir, struct memory_range range, u32 flags) +{ + assert(PAGE_ALIGNED(range.base) && PAGE_ALIGNED(range.size)); + + for (u32 i = 0; i < range.size / PAGE_SIZE; i++) { + u32 vaddr = range.base + i * PAGE_SIZE; + if (!virtual_present(dir, vaddr)) { + u32 paddr = physical_alloc(1); + virtual_map(dir, vaddr, paddr, 1, flags & MEMORY_USER); + } + } + + if (flags & MEMORY_CLEAR) + memset((void *)range.base, 0, range.size); +} + +void memory_alloc_identity(struct page_dir *dir, u32 flags, u32 *out) +{ + for (u32 i = 1; i < 256 * PAGE_COUNT; i++) { + u32 addr = i * PAGE_SIZE; + if (!virtual_present(dir, addr) && !physical_is_used(addr, 1)) { + physical_set_used(addr, 1); + virtual_map(dir, addr, addr, 1, flags & MEMORY_USER); + + if (flags & MEMORY_CLEAR) + memset((void *)addr, 0, PAGE_SIZE); + + *out = addr; + + return; + } + } + + *out = 0; + panic("Out of memory!\n"); +} + +void memory_alloc(struct page_dir *dir, u32 size, u32 flags, u32 *out) +{ + assert(size && PAGE_ALIGNED(size)); + *out = 0; + + u32 page_count = size / PAGE_SIZE; + u32 paddr = physical_alloc(page_count); + assert(paddr); + u32 vaddr = virtual_alloc(dir, memory_range(paddr, size), flags).base; + assert(vaddr); + if (flags & MEMORY_CLEAR) + memset((void *)vaddr, 0, page_count * PAGE_SIZE); + *out = vaddr; +} + +void memory_free(struct page_dir *dir, struct memory_range range) +{ + assert(PAGE_ALIGNED(range.base) && PAGE_ALIGNED(range.size)); + + for (u32 i = 0; i < range.size / PAGE_SIZE; i++) { + u32 vaddr = range.base + i * PAGE_SIZE; + if (virtual_present(dir, vaddr)) { + physical_free(virtual_to_physical(dir, vaddr), 1); + virtual_free(dir, memory_range(vaddr, PAGE_SIZE)); + } + } +} + +struct page_dir *memory_dir_create(void) +{ + struct page_dir *dir = NULL; + memory_alloc(&kernel_dir, sizeof(*dir), MEMORY_CLEAR, (u32 *)&dir); + memset(dir, 0, sizeof(*dir)); + + for (u32 i = 0; i < 256; i++) { + union page_dir_entry *entry = &dir->entries[i]; + entry->bits.present = 1; + entry->bits.writable = 1; + entry->bits.user = 0; + entry->bits.address = (u32)&kernel_tables[i] / PAGE_SIZE; + } + + return dir; +} + +void memory_dir_destroy(struct page_dir *dir) +{ + for (u32 i = 256; i < PAGE_COUNT; i++) { + union page_dir_entry *dir_entry = &dir->entries[i]; + if (dir_entry->bits.present) { + struct page_table *table = + (struct page_table *)(dir_entry->bits.address * PAGE_SIZE); + for (u32 j = 0; j < PAGE_COUNT; j++) { + union page_table_entry *table_entry = &table->entries[j]; + if (table_entry->bits.present) + physical_free(table_entry->bits.address * PAGE_SIZE, 1); + } + + memory_free(&kernel_dir, memory_range((u32)table, sizeof(*table))); + } + } + memory_free(&kernel_dir, memory_range((u32)dir, sizeof(*dir))); +} + +void memory_dir_switch(struct page_dir *dir) +{ + paging_switch_dir(virtual_to_physical(&kernel_dir, (u32)dir)); +} + +struct page_dir *memory_kernel_dir(void) +{ + return &kernel_dir; +} + +void memory_initialize(struct mem_info *mem_info) +{ + for (u32 i = 0; i < 256; i++) { + union page_dir_entry *entry = &kernel_dir.entries[i]; + entry->bits.present = 1; + entry->bits.writable = 1; + entry->bits.user = 0; + entry->bits.address = (u32)&kernel_tables[i] / PAGE_SIZE; + } + + // Detect memory using E820 memory map + for (struct mmap_boot *p = mem_info->start; (u32)(p - mem_info->start) < mem_info->size; + p++) { + if (p->hbase || !p->acpi || !p->type) + continue; + + u32 size = p->lsize; + if (p->hsize) + size = U32_MAX - p->lbase; + + /* printf("Memory region: %x-%x\n", p->lbase, p->lbase + size); */ + if (p->type == MEMORY_AVAILABLE) { + physical_set_free(p->lbase, size / PAGE_SIZE); + memory_total += size; + } else if (p->type == MEMORY_DEFECT) { + printf("Defect memory at 0x%x-0x%x!\n", p->lbase, p->lbase + size); + } + } + + memory_used = 0; + printf("Detected memory: %dKiB (%dMiB)\n", memory_total >> 10, memory_total >> 20); + + // Map kernel + memory_map_identity(&kernel_dir, kernel_memory_range(), MEMORY_NONE); + + // Map kernel stack + memory_map_identity(&kernel_dir, + memory_range_around_address(STACK_START - STACK_SIZE, STACK_SIZE), + MEMORY_NONE); + + // Map kernel heap + memory_map_identity(&kernel_dir, memory_range_around_address(HEAP_START, HEAP_INIT_SIZE), + MEMORY_NONE); + + // TODO: Map something, idk? Triple fault prevention? + memory_map_identity(&kernel_dir, memory_range_around_address(0x7000, 0x1000), MEMORY_NONE); + + // Unmap NULL byte/page + virtual_free(&kernel_dir, memory_range(0, PAGE_SIZE)); + physical_set_used(0, 1); + + memory_dir_switch(&kernel_dir); + paging_enable(); +} + +void paging_install(struct mem_info *mem_info) +{ + memory_initialize(mem_info); + heap_init(HEAP_START); +} diff --git a/kernel/features/proc.c b/kernel/features/proc.c index cdbe8b1..bbe675e 100644 --- a/kernel/features/proc.c +++ b/kernel/features/proc.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,7 @@ void scheduler(struct regs *regs) } memcpy(regs, &((struct proc *)current->data)->regs, sizeof(struct regs)); + memory_dir_switch(((struct proc *)current->data)->page_dir); if (regs->cs != GDT_USER_CODE_OFFSET) { regs->gs = GDT_USER_DATA_OFFSET; @@ -103,7 +105,7 @@ u8 proc_super(void) { struct proc *proc = proc_current(); if (proc) - return proc->super; + return proc->priv == PROC_PRIV_ROOT || proc->priv == PROC_PRIV_KERNEL; else if (current_pid == 0) return 1; // Kernel has super permissions else @@ -237,14 +239,19 @@ end: p->state = PROC_SLEEPING; } -struct proc *proc_make(void) +struct proc *proc_make(enum proc_priv priv) { struct proc *proc = zalloc(sizeof(*proc)); proc->pid = current_pid++; - proc->super = 0; + proc->priv = priv; proc->messages = stack_new(); proc->state = PROC_RUNNING; + if (priv == PROC_PRIV_KERNEL) + proc->page_dir = memory_kernel_dir(); + else + proc->page_dir = memory_dir_create(); + if (current) list_add(proc_list, proc); @@ -465,20 +472,20 @@ void proc_init(void) vfs_mount(dev, "/proc/"); // Idle proc - struct proc *kernel_proc = proc_make(); + struct proc *kernel_proc = proc_make(PROC_PRIV_NONE); void (*func)(void) = kernel_idle; proc_load(kernel_proc, *(void **)&func); strcpy(kernel_proc->name, "idle"); kernel_proc->state = PROC_SLEEPING; idle_proc = list_add(proc_list, kernel_proc); - struct node *new = list_add(proc_list, proc_make()); + // Init proc (root) + struct node *new = list_add(proc_list, proc_make(PROC_PRIV_ROOT)); bin_load("/bin/init", new->data); current = new; _eip = ((struct proc *)new->data)->regs.eip; _esp = ((struct proc *)new->data)->regs.useresp; - ((struct proc *)new->data)->super = 1; u32 argc = 2; char **argv = malloc(sizeof(*argv) * (argc + 1)); @@ -491,6 +498,7 @@ void proc_init(void) printf("Jumping to userspace!\n"); proc_jump_userspace(); + memory_dir_switch(((struct proc *)new->data)->page_dir); while (1) { }; } diff --git a/kernel/features/syscall.c b/kernel/features/syscall.c index 61c7479..b3e69e0 100644 --- a/kernel/features/syscall.c +++ b/kernel/features/syscall.c @@ -62,7 +62,7 @@ static void syscall_handler(struct regs *r) } case SYS_EXEC: { char *path = (char *)r->ebx; - struct proc *proc = proc_make(); + struct proc *proc = proc_make(PROC_PRIV_NONE); r->eax = (u32)bin_load(path, proc); u32 argc = 3; // TODO: Add argc evaluator char **argv = malloc(sizeof(*argv) * (argc + 1)); diff --git a/kernel/inc/memory.h b/kernel/inc/memory.h deleted file mode 100644 index 812b052..0000000 --- a/kernel/inc/memory.h +++ /dev/null @@ -1,80 +0,0 @@ -// MIT License, Copyright (c) 2021 Marvin Borner - -#ifndef PAGING_H -#define PAGING_H - -#include -#include - -/** - * Physical - */ - -/** - * Virtual - */ - -#define PAGE_SIZE 0x1000 -#define PAGE_COUNT 1024 -#define PAGE_ALIGN(x) ((x) + PAGE_SIZE - ((x) % PAGE_SIZE)) -#define PAGE_ALIGNED(x) ((x) % PAGE_SIZE == 0) - -union page_table_entry { - struct PACKED { - 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; - } bits; - u32 uint; -} PACKED; - -struct page_table { - union page_table_entry entries[PAGE_COUNT]; -} PACKED; - -union page_dir_entry { - struct PACKED { - 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; - } bits; - u32 uint; -} PACKED; - -struct page_dir { - union page_dir_entry entries[PAGE_COUNT]; -} PACKED; - -void paging_install(struct mem_info *mem_info); - -/** - * Memory wrappers - */ - -#define MEMORY_NONE (0 << 0) -#define MEMORY_USER (1 << 0) -#define MEMORY_CLEAR (1 << 1) -#define memory_range(base, size) ((struct memory_range){ (base), (size) }) - -struct memory_range { - u32 base; - u32 size; -}; - -#endif diff --git a/kernel/inc/mm.h b/kernel/inc/mm.h new file mode 100644 index 0000000..00d9e4b --- /dev/null +++ b/kernel/inc/mm.h @@ -0,0 +1,87 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef PAGING_H +#define PAGING_H + +#include +#include + +/** + * Physical + */ + +/** + * Virtual + */ + +#define PAGE_SIZE 0x1000 +#define PAGE_COUNT 1024 +#define PAGE_ALIGN(x) ((x) + PAGE_SIZE - ((x) % PAGE_SIZE)) +#define PAGE_ALIGNED(x) ((x) % PAGE_SIZE == 0) +#define PAGE_ALIGN_UP(x) (((x) % PAGE_SIZE == 0) ? (x) : (x) + PAGE_SIZE - ((x) % PAGE_SIZE)) +#define PAGE_ALIGN_DOWN(x) ((x) - ((x) % PAGE_SIZE)) + +union page_table_entry { + struct PACKED { + 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; + } bits; + u32 uint; +} PACKED; + +struct page_table { + union page_table_entry entries[PAGE_COUNT]; +} PACKED; + +union page_dir_entry { + struct PACKED { + 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; + } bits; + u32 uint; +} PACKED; + +struct page_dir { + union page_dir_entry entries[PAGE_COUNT]; +} PACKED; + +void paging_install(struct mem_info *mem_info); + +/** + * Memory wrappers + */ + +#define MEMORY_NONE (0 << 0) +#define MEMORY_USER (1 << 0) +#define MEMORY_CLEAR (1 << 1) +#define memory_range(base, size) ((struct memory_range){ (base), (size) }) + +struct memory_range { + u32 base; + u32 size; +}; + +struct page_dir *memory_dir_create(void); +void memory_dir_switch(struct page_dir *dir); +void memory_alloc(struct page_dir *dir, u32 size, u32 flags, u32 *out); +struct page_dir *memory_kernel_dir(void); + +#endif diff --git a/kernel/inc/proc.h b/kernel/inc/proc.h index 272a3ac..de4eb84 100644 --- a/kernel/inc/proc.h +++ b/kernel/inc/proc.h @@ -9,7 +9,7 @@ #include #include -#define PROC_QUANTUM 10 // Milliseconds or something // TODO +#define PROC_QUANTUM 42 // Milliseconds or something // TODO #define EFLAGS_ALWAYS 0x2 // Always one #define EFLAGS_INTERRUPTS 0x200 // Enable interrupts @@ -23,6 +23,7 @@ #define STREAM_MAX_SIZE 4096 enum stream_defaults { STREAM_IN, STREAM_OUT, STREAM_ERR, STREAM_LOG, STREAM_UNKNOWN = -1 }; +enum proc_priv { PROC_PRIV_NONE, PROC_PRIV_ROOT, PROC_PRIV_KERNEL }; enum proc_state { PROC_RUNNING, PROC_SLEEPING }; enum proc_wait_type { PROC_WAIT_DEV, PROC_WAIT_MSG }; @@ -47,9 +48,10 @@ struct stream { struct proc { u32 pid; u32 entry; - u8 super; + u8 priv; char name[32]; struct stream streams[4]; + struct page_dir *page_dir; struct regs regs; struct proc_wait wait; // dev_id enum proc_state state; @@ -67,6 +69,6 @@ void proc_yield(struct regs *r); void proc_clear_quantum(void); void proc_enable_waiting(u32 id, enum proc_wait_type type); void proc_wait_for(u32 id, enum proc_wait_type type, u32 func_ptr); -struct proc *proc_make(void); +struct proc *proc_make(enum proc_priv priv); #endif diff --git a/kernel/main.c b/kernel/main.c index 16ae619..b46db0d 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3