From 1d64e8364737d085e2acdff2c7e79614638f8b08 Mon Sep 17 00:00:00 2001 From: Arnau478 Date: Mon, 18 Jul 2022 21:28:03 +0200 Subject: [PATCH] Physical memory manager --- src/kernel/entry.asm | 1 + src/kernel/lib/memory.c | 27 ++----- src/kernel/lib/memory.h | 9 +-- src/kernel/main.c | 28 +++++++- src/kernel/mm/pmm.c | 153 ++++++++++++++++++++++++++++++++++++++++ src/kernel/mm/pmm.h | 24 +++++++ src/kernel/multiboot.h | 96 +++++++++++++++++++++++++ src/kernel/shell.c | 6 -- 8 files changed, 308 insertions(+), 36 deletions(-) create mode 100644 src/kernel/mm/pmm.c create mode 100644 src/kernel/mm/pmm.h create mode 100644 src/kernel/multiboot.h diff --git a/src/kernel/entry.asm b/src/kernel/entry.asm index 03257f6..5c87c33 100644 --- a/src/kernel/entry.asm +++ b/src/kernel/entry.asm @@ -26,6 +26,7 @@ call_kmain: ; Enable interrupts sti ; Call kernel + push ebx ; pointer to multiboot info call kmain ; If on qemu, shutdown push 0x2000 diff --git a/src/kernel/lib/memory.c b/src/kernel/lib/memory.c index 53a08ef..027766a 100644 --- a/src/kernel/lib/memory.c +++ b/src/kernel/lib/memory.c @@ -1,27 +1,10 @@ -#include -#include #include "memory.h" -static void *g_free_memory = ALLOC_START; - -void *kmalloc(size_t size){ - void *ptr = g_free_memory; - g_free_memory += size; - return ptr; +void memset(void *s, uint8_t c, size_t n){ + uint8_t *p = s; + while(n--) *(p++) = c; } -void *kcalloc(size_t count, size_t size){ - void *ptr = g_free_memory; - size *= count; - g_free_memory += size; - for(int i = 0; i < size; i++){ - ((uint8_t *)ptr)[i] = 0; - } - return ptr; -} - -void memcpy(uint8_t *source, uint8_t *dest, size_t count){ - for(size_t i = 0; i < count; i++){ - dest[i] = source[i]; - } +void memcpy(void *dest, void *src, size_t n){ + while(n--) ((uint8_t *)dest)[n] = ((uint8_t *)src)[n]; } diff --git a/src/kernel/lib/memory.h b/src/kernel/lib/memory.h index 8f8117f..9117d18 100644 --- a/src/kernel/lib/memory.h +++ b/src/kernel/lib/memory.h @@ -3,10 +3,5 @@ #include #include -#define ALLOC_START (void *)0x1000 - -void *kmalloc(size_t size); -// TODO: void kfree(void *ptr); -void *kcalloc(size_t count, size_t size); - -void memcpy(uint8_t *source, uint8_t *dest, size_t count); +void memset(void *ptr, uint8_t val, size_t n); +void memcpy(void *dest, void *src, size_t n); diff --git a/src/kernel/main.c b/src/kernel/main.c index 343b536..ca6665c 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -5,20 +5,46 @@ #include "drivers/keyboard.h" #include "drivers/serial.h" #include "fs/vfs.h" +#include "mm/pmm.h" +#include "multiboot.h" -void __attribute__((cdecl)) kmain(uint64_t magic, uint64_t addr){ +extern uint8_t end; // Kernel end + +void __attribute__((cdecl)) kmain(multiboot_info_t *multiboot_info){ // Clear screen clear_screen(); // Initialize chip-specific hardware hal_initialize(); + // Initialize physical memory manager + uint32_t mem_size = 1024 + multiboot_info->mem_lower + multiboot_info->mem_upper*64; + + pmm_initialize(mem_size, (int)(&end)); + + for(int i = 0; i < multiboot_info->mmap_length; i += sizeof(multiboot_memory_map_t)){ + multiboot_memory_map_t *memory_map = (multiboot_memory_map_t *)(multiboot_info->mmap_addr + i); + printf("Start Addr: 0x%x%x | Length: 0x%x%x | Size: 0x%x | Type: %i\n", memory_map->addr_h, memory_map->addr_l, memory_map->len_h, memory_map->len_l, memory_map->size, memory_map->type); + + if(memory_map->type == 1){ + pmm_init_region(memory_map->addr_l, memory_map->len_l); + } + } + + pmm_deinit_region(0x100000, (int)(&end) - 0x100000); // Deinit the section the kernel is in + // Initialize drivers timer_initialize(); keyboard_initialize(); // Initialize FS vfs_initialize(); + + // PMM test code + uint32_t *p1 = (uint32_t *)pmm_alloc_block(); + printf("Allocated p1 at: 0x%x\n", p1); + uint32_t *p2 = (uint32_t *)pmm_alloc_block(); + printf("Allocated p2 at: 0x%x\n", p2); for(;;); } diff --git a/src/kernel/mm/pmm.c b/src/kernel/mm/pmm.c new file mode 100644 index 0000000..9d4498a --- /dev/null +++ b/src/kernel/mm/pmm.c @@ -0,0 +1,153 @@ +#include +#include "pmm.h" +#include "../lib/memory.h" + +static uint32_t g_pmm_memory_size = 0; +static uint32_t g_pmm_used_blocks = 0; +static uint32_t g_pmm_max_blocks = 0; +static uint32_t *g_pmm_memory_map = 0; + +static inline void pmm_map_set(int bit){ + g_pmm_memory_map[bit / 32] |= (1 << (bit % 32)); +} + +static inline void pmm_map_unset(int bit){ + g_pmm_memory_map[bit / 32] &= ~(1 << (bit % 32)); +} + +static inline bool pmm_map_get(int bit){ + return g_pmm_memory_map[bit / 32] & (1 << (bit % 32)); +} + +int pmm_map_first_free(){ + for(uint32_t i = 0; i < pmm_get_block_count() / 32; i++){ + if(g_pmm_memory_map[i] != 0xffffffff){ + for(int j = 0; j < 32; j++){ + if(!(g_pmm_memory_map[i] & (1 << j))){ + return i*4*8+j; + } + } + } + } + return -1; +} + +int pmm_map_first_free_s(size_t size){ + if(size == 0) return -1; + if(size == 1) return pmm_map_first_free(); + + for(uint32_t i = 0; i < pmm_get_block_count() / 32; i++){ + if(g_pmm_memory_map[i] != 0xffffffff){ + for(int j = 0; j < 32; j++){ + int bit = 1 << j; + if(!(g_pmm_memory_map[i] & bit)){ + int start_bit = i*32; + start_bit+=bit; + + uint32_t free = 0; + for(uint32_t count = 0; count <= size; count++){ + if(!pmm_map_get(start_bit+count)) free++; + if(free == size) return i*4*8+j; + } + } + } + } + } + return -1; +} + +void pmm_initialize(size_t mem_size, phys_addr bitmap){ + g_pmm_memory_size = mem_size; + g_pmm_memory_map = (uint32_t *)bitmap; + g_pmm_max_blocks = (pmm_get_memory_size()*1024) / PMM_BLOCK_SIZE; + g_pmm_used_blocks = g_pmm_max_blocks; + + // FIXME + memset(g_pmm_memory_map, 0xFF, pmm_get_block_count() / PMM_BLOCKS_PER_BYTE); +} + +void pmm_init_region(phys_addr base, size_t size){ + int align = base / PMM_BLOCK_SIZE; + int blocks = size / PMM_BLOCK_SIZE; + + for(; blocks >= 0; blocks--){ + pmm_map_unset(align++); + g_pmm_used_blocks--; + } + + pmm_map_set(0); // First block always set +} + +void pmm_deinit_region(phys_addr base, size_t size){ + int align = base / PMM_BLOCK_SIZE; + int blocks = size / PMM_BLOCK_SIZE; + + for(; blocks >= 0; blocks--){ + pmm_map_set(align++); + g_pmm_used_blocks++; + } + + pmm_map_set(0); // First block always set +} + +void *pmm_alloc_block(){ + if(pmm_get_free_block_count() <= 0) return 0; // Out of memory + + int frame = pmm_map_first_free(); + if(frame == -1) return 0; // Out of memory + + pmm_map_set(frame); + + phys_addr addr = frame * PMM_BLOCK_SIZE; + g_pmm_used_blocks++; + + return (void *)addr; +} + +void pmm_free_block(void *p){ + phys_addr addr = (phys_addr)p; + int frame = addr / PMM_BLOCK_SIZE; + + pmm_map_unset(frame); + + g_pmm_used_blocks--; +} + +void *pmm_alloc_blocks(size_t size){ + if(pmm_get_free_block_count() <= size) return 0; // Out of memory + + int frame = pmm_map_first_free_s(size); + if(frame == -1) return 0; // Out of memory + + for(uint32_t i = 0; i < size; i++) pmm_map_set(frame+i); + + phys_addr addr = frame * PMM_BLOCK_SIZE; + g_pmm_used_blocks += size; + + return (void *)addr; +} + +void pmm_free_blocks(void *p, size_t size){ + phys_addr addr = (phys_addr)p; + int frame = addr / PMM_BLOCK_SIZE; + + for(uint32_t i = 0; i < size; i++) pmm_map_unset(frame+i); + + g_pmm_used_blocks -= size; +} + +size_t pmm_get_memory_size(){ + return g_pmm_memory_size; +} + +uint32_t pmm_get_block_count(){ + return g_pmm_max_blocks; +} + +uint32_t pmm_get_used_block_count(){ + return g_pmm_used_blocks; +} + +uint32_t pmm_get_free_block_count(){ + return g_pmm_max_blocks - g_pmm_used_blocks; +} diff --git a/src/kernel/mm/pmm.h b/src/kernel/mm/pmm.h new file mode 100644 index 0000000..3ad6f88 --- /dev/null +++ b/src/kernel/mm/pmm.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +#define PMM_BLOCKS_PER_BYTE 8 +#define PMM_BLOCK_SIZE 4096 +#define PMM_BLOCK_ALIGN PMM_BLOCK_SIZE + +typedef uint32_t phys_addr; + +int pmm_map_first_free(); +int pmm_map_first_free_s(size_t size); +void pmm_initialize(size_t mem_size, phys_addr bitmap); +void pmm_init_region(phys_addr base, size_t size); +void pmm_deinit_region(phys_addr base, size_t size); +void *pmm_alloc_block(); +void pmm_free_block(void *p); +void *pmm_alloc_blocks(size_t size); +void pmm_free_blocks(void *p, size_t size); +size_t pmm_get_memory_size(); +uint32_t pmm_get_block_count(); +uint32_t pmm_get_used_block_count(); +uint32_t pmm_get_free_block_count(); diff --git a/src/kernel/multiboot.h b/src/kernel/multiboot.h new file mode 100644 index 0000000..c988051 --- /dev/null +++ b/src/kernel/multiboot.h @@ -0,0 +1,96 @@ +#pragma once + +#include + +typedef struct{ + uint32_t size; + uint32_t addr_l; + uint32_t addr_h; + uint32_t len_l; + uint32_t len_h; + uint32_t type; +} __attribute__((packed)) multiboot_memory_map_t; + +typedef struct{ + uint32_t tabsize; + uint32_t strsize; + uint32_t addr; + uint32_t reserved; +} multiboot_aout_symbol_table_t; + +typedef struct{ + uint32_t num; + uint32_t size; + uint32_t addr; + uint32_t shndx; +} multiboot_elf_section_header_table_t; + +typedef struct{ + /* Multiboot info version number */ + uint32_t flags; + + /* Available memory from BIOS */ + uint32_t mem_lower; + uint32_t mem_upper; + + /* "root" partition */ + uint32_t boot_device; + + /* Kernel command line */ + uint32_t cmdline; + + /* Boot-Module list */ + uint32_t mods_count; + uint32_t mods_addr; + + union{ + multiboot_aout_symbol_table_t aout_sym; + multiboot_elf_section_header_table_t elf_sec; + } u; + + /* Memory Mapping buffer */ + uint32_t mmap_length; + uint32_t mmap_addr; + + /* Drive Info buffer */ + uint32_t drives_length; + uint32_t drives_addr; + + /* ROM configuration table */ + uint32_t config_table; + + /* Boot Loader Name */ + uint32_t boot_loader_name; + + /* APM table */ + uint32_t apm_table; + + /* Video */ + uint32_t vbe_control_info; + uint32_t vbe_mode_info; + uint16_t vbe_mode; + uint16_t vbe_interface_seg; + uint16_t vbe_interface_off; + uint16_t vbe_interface_len; + + uint64_t framebuffer_addr; // FIXME: This may fail, as we are not in 64 bit (long) mode + uint32_t framebuffer_pitch; + uint32_t framebuffer_width; + uint32_t framebuffer_height; + uint8_t framebuffer_bpp; + uint8_t framebuffer_type; + union{ + struct{ + uint32_t framebuffer_palette_addr; + uint16_t framebuffer_palette_num_colors; + }; + struct{ + uint8_t framebuffer_red_field_position; + uint8_t framebuffer_red_mask_size; + uint8_t framebuffer_green_field_position; + uint8_t framebuffer_green_mask_size; + uint8_t framebuffer_blue_field_position; + uint8_t framebuffer_blue_mask_size; + }; + }; +} __attribute__((packed)) multiboot_info_t; diff --git a/src/kernel/shell.c b/src/kernel/shell.c index a3b4c22..0a66579 100644 --- a/src/kernel/shell.c +++ b/src/kernel/shell.c @@ -14,12 +14,6 @@ int shell_run(char *cmd){ else if(!strcmp(cmd, "version")){ printf("%s\n", OS_VERSION); } - else if(!strcmp(cmd, "malloc")){ - printf("Allocated 10 bytes:\n%x\n", kmalloc(10)); - } - else if(!strcmp(cmd, "calloc")){ - printf("Allocated and zeroed 10 chars:\n%x\n", kcalloc(10, sizeof(char))); - } else if(!strcmp(cmd, "clear")){ clear_screen(); }