diff options
author | Raghuram Subramani <raghus2247@gmail.com> | 2025-01-08 13:11:25 -0500 |
---|---|---|
committer | Raghuram Subramani <raghus2247@gmail.com> | 2025-01-08 13:12:30 -0500 |
commit | 973a7e37feba88f7e0a94372d6e54d9243b32d21 (patch) | |
tree | 56afa9b4eb4eca0c8263a208c40fafac94a11917 | |
parent | c755557d0f85bd98200da263d50f9b2f552efe4b (diff) |
kernel: mm: physical_mm: Initialize free memory regions
-rw-r--r-- | kernel/include/drivers/vga_text_buffer.h | 2 | ||||
-rw-r--r-- | kernel/include/kernel/io.h | 4 | ||||
-rw-r--r-- | kernel/include/mm/physical_mm.h | 15 | ||||
-rw-r--r-- | kernel/mm/physical_mm/physical_mm.c | 93 |
4 files changed, 83 insertions, 31 deletions
diff --git a/kernel/include/drivers/vga_text_buffer.h b/kernel/include/drivers/vga_text_buffer.h index de498a3..74b77b9 100644 --- a/kernel/include/drivers/vga_text_buffer.h +++ b/kernel/include/drivers/vga_text_buffer.h @@ -68,6 +68,6 @@ bool vga_text_buffer_is_initialized(void); void vga_text_buffer_initialize(void); void vga_text_buffer_write_char(const char); void vga_text_buffer_write_string(const char *); -void vga_text_buffer_printf(const char *string, ...); +void vga_text_buffer_printf(const char *, ...); #endif diff --git a/kernel/include/kernel/io.h b/kernel/include/kernel/io.h index f58bd2d..952784d 100644 --- a/kernel/include/kernel/io.h +++ b/kernel/include/kernel/io.h @@ -21,7 +21,7 @@ #include <stdint.h> -uint8_t inb(uint16_t port); -void outb(uint16_t port, uint8_t val); +uint8_t inb(uint16_t); +void outb(uint16_t, uint8_t); #endif diff --git a/kernel/include/mm/physical_mm.h b/kernel/include/mm/physical_mm.h index 7bda283..8438286 100644 --- a/kernel/include/mm/physical_mm.h +++ b/kernel/include/mm/physical_mm.h @@ -23,20 +23,15 @@ #include <common.h> -/* - * A byte has 8 bits, hence we can store information for up to 8 blocks at a - * time - */ -#define BLOCKS_PER_BYTE 8 - /* TODO: Update this to 2MiB when PAE is enabled */ -#define BLOCK_SIZE 4 * KiB - -#define BLOCK_ALIGN BLOCK_SIZE +#define BLOCK_SIZE (4 * KiB) #define BITMAP_ENTRY_SIZE 32 +/* TODO: This is the maximum number of blocks for a 4GiB system. */ +#define MAX_BLOCKS 1048576 + void physical_mm_init(void); -uint32_t mmap_find_first_free(void); +uint32_t physical_mm_find_first_free_block(void); #endif diff --git a/kernel/mm/physical_mm/physical_mm.c b/kernel/mm/physical_mm/physical_mm.c index 407aad6..5bbe1f7 100644 --- a/kernel/mm/physical_mm/physical_mm.c +++ b/kernel/mm/physical_mm/physical_mm.c @@ -2,6 +2,8 @@ * https://web.archive.org/web/20190316115948/http://www.brokenthorn.com/Resources/OSDev17.html */ +/* TODO: Stack based allocation? */ + #include <stdbool.h> #include <stdint.h> @@ -15,15 +17,13 @@ extern uint32_t kernel_start; extern uint32_t kernel_end; -uint32_t block_count; -uint32_t *memory_map; +uint32_t block_count = 0; +uint32_t total_free_blocks = 0; +uint32_t memory_map[MAX_BLOCKS]; -void -physical_mm_init(void) +ALWAYS_INLINE static void +physical_mm_log_memory_map(free_memory_regions_t *free_memory_regions) { - free_memory_regions_t *free_memory_regions = memory_map_get_free_regions(); - - /* TODO: Initialize these free memory regions */ printk("\nphysical_mm", "Free Memory Regions:"); for (int i = 0; i < free_memory_regions->n_regions; i++) printk("physical_mm", @@ -31,36 +31,94 @@ physical_mm_init(void) free_memory_regions->region_list[i]->addr_low, free_memory_regions->region_list[i]->len_low); - /* TODO: De-initialize region used by the kernel */ printk("\nphysical_mm", "Kernel region:"); printk("physical_mm", "Start: 0x%x", &kernel_start); printk("physical_mm", "End: 0x%x", &kernel_end); printk("physical_mm", - "Size: 0x%x", + "Size: 0x%x", ((uint32_t) &kernel_end) - ((uint32_t) &kernel_start)); } -ALWAYS_INLINE void -physical_mm_set(const uint32_t bit) +/* Marks the block as 'used' */ +ALWAYS_INLINE static void +physical_mm_set_unusable(const uint32_t bit) { uint32_t memory_map_index = bit / BITMAP_ENTRY_SIZE; uint32_t bitmask = 1 << (bit % BITMAP_ENTRY_SIZE); memory_map[memory_map_index] |= bitmask; } -ALWAYS_INLINE void -physical_mm_unset(const uint32_t bit) +/* Marks the block as 'unused' */ +ALWAYS_INLINE static void +physical_mm_set_usable(const uint32_t bit) { uint32_t memory_map_index = bit / BITMAP_ENTRY_SIZE; uint32_t bitmask = 1 << (bit % BITMAP_ENTRY_SIZE); memory_map[memory_map_index] &= ~bitmask; } +ALWAYS_INLINE static void +physical_mm_initialize_region(uint32_t start, uint32_t length) +{ + /* Get the location of the start address in the bitmap */ + uint32_t bit = start / BLOCK_SIZE; + uint32_t n_blocks = length / BLOCK_SIZE; + + for (; n_blocks > 0; n_blocks--) { + physical_mm_set_usable(bit++); + total_free_blocks++; + } + + /* First block is always unusable (first 64 KiB) */ + physical_mm_set_unusable(0); +} + +ALWAYS_INLINE static void +physical_mm_deinitialize_region(uint32_t start, uint32_t length) +{ + uint32_t align = start / BLOCK_SIZE; + uint32_t n_blocks = length / BLOCK_SIZE; + + if (length % BLOCK_SIZE > 0) + n_blocks++; + + for (; n_blocks > 0; n_blocks--) { + physical_mm_set_unusable(align++); + total_free_blocks--; + } +} + +void +physical_mm_init(void) +{ + free_memory_regions_t *free_memory_regions = memory_map_get_free_regions(); + physical_mm_log_memory_map(free_memory_regions); + + /* All blocks are initially unusable */ + for (uint32_t i = 0; i < MAX_BLOCKS; i++) + memory_map[i] = 0xffffffff; + + uint32_t total_free_memory = 0; + for (int i = 0; i < free_memory_regions->n_regions; i++) { + multiboot_memory_map_t *region = free_memory_regions->region_list[i]; + total_free_memory += region->len_low; + physical_mm_initialize_region(region->addr_low, region->len_low); + } + + physical_mm_deinitialize_region((uint32_t) &kernel_start, + ((uint32_t) &kernel_end) + - ((uint32_t) &kernel_start)); + + block_count = total_free_memory / BLOCK_SIZE; + printk("\nphysical_mm", "Total blocks: 0x%x", block_count); + printk("physical_mm", "Total free blocks: 0x%x", total_free_blocks); +} + /* Returns: * True if the bit is unset (block isn't in use) - * False if the bit is used (block is in use) + * False if the bit is set (block is in use) */ -ALWAYS_INLINE bool +ALWAYS_INLINE static bool physical_mm_test_bit(const uint32_t bit) { uint32_t memory_map_index = bit / BITMAP_ENTRY_SIZE; @@ -69,16 +127,15 @@ physical_mm_test_bit(const uint32_t bit) } uint32_t -physical_mm_find_first_free(void) +physical_mm_find_first_free_block(void) { for (uint32_t i = 0; i < block_count / BITMAP_ENTRY_SIZE; i++) - /* All blocks in the entry aren't in use */ + /* At least one block in the entry isn't in use */ if (memory_map[i] != 0xffffffff) /* Test each bit to see if it's zero */ for (uint32_t j = 0; j < BITMAP_ENTRY_SIZE; j++) if (physical_mm_test_bit(i * BITMAP_ENTRY_SIZE + j)) return i * BITMAP_ENTRY_SIZE + j; - ASSERT_NOT_REACHED(); return -1; } |