aboutsummaryrefslogtreecommitdiff
path: root/kernel/mm/physical_mm/physical_mm.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/mm/physical_mm/physical_mm.c')
-rw-r--r--kernel/mm/physical_mm/physical_mm.c93
1 files changed, 75 insertions, 18 deletions
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;
}