Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 17 additions & 15 deletions src/kernel/memory_management/include/physical_memory/manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,22 +54,24 @@ static inline memory_region_t phys_mem_reg_to_reg(physical_memory_region_t pmr)
/// @ingroup kmm
/// @ingroup pmm
typedef enum : u8 {
FRAME_SIZE_4KiB = 0,
FRAME_SIZE_8KiB = 1,
FRAME_SIZE_16KiB = 2,
FRAME_SIZE_32KiB = 3,
FRAME_SIZE_64KiB = 4,
FRAME_SIZE_128KiB = 5,
FRAME_SIZE_256KiB = 6,
FRAME_SIZE_512KiB = 7,
FRAME_SIZE_1MiB = 8,
FRAME_SIZE_2MiB = 9,
FRAME_SIZE_1GiB = 18,
} frame_size_t; // NOTE: value of frame_size_t is (4KiB << frame_size)
FRAME_ORDER_4KiB = 0,
FRAME_ORDER_8KiB = 1,
FRAME_ORDER_16KiB = 2,
FRAME_ORDER_32KiB = 3,
FRAME_ORDER_64KiB = 4,
FRAME_ORDER_128KiB = 5,
FRAME_ORDER_256KiB = 6,
FRAME_ORDER_512KiB = 7,
FRAME_ORDER_1MiB = 8,
FRAME_ORDER_2MiB = 9,
FRAME_ORDER_1GiB = 18,
} frame_order_t; // NOTE: value is the order of 4KiB frames (frame count = 1 << order)

#define PAGE_SIZE 0x1000UL

/// @ingroup kmm
/// @ingroup pmm
u64 phys_mem_get_frame_size_in_bytes(frame_size_t fs);
u64 phys_mem_get_frame_size_in_bytes(frame_order_t fs);

/**
* @ingroup kmm
Expand Down Expand Up @@ -97,14 +99,14 @@ error_t phys_mem_init(const physical_memory_region_t* pmrs, size_t pmr_count, co
* @retval ERR_OUT_OF_MEMORY The block of specified size was not able to be allocated
* */
[[gnu::nonnull]]
error_t phys_mem_alloc_frame(frame_size_t frame_size, phys_addr_t* addrOUT);
error_t phys_mem_alloc_frame(frame_order_t frame_size, phys_addr_t* addrOUT);

/**
* @ingroup kmm
* @ingroup pmm
* @retval ERR_NONE
* @retval ERR_NOT_VALID The address being freed was reported as not allocated
* */
error_t phys_mem_free_frame(phys_addr_t addr);
error_t phys_mem_free_frame(frame_order_t frame_size, phys_addr_t addr);

#endif //! BIGOS_KERNEL_MEMORY_MANAGMENT_PHYSICAL_MEMORY_MANAGMENT
161 changes: 139 additions & 22 deletions src/kernel/memory_management/physical_memory/allocator.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,151 @@

#include "memory_management/include/physical_memory/manager.h"
#include "stdbigos/error.h"
#include "stdbigos/math.h"
#include "stdbigos/string.h"

error_t pmallocator_get_header(memory_area_t area, const memory_area_t* reserved_areas, u32 count,
typedef struct {
uintptr_t area_base_addr;
size_t area_size;
u64 bitmap[];
} pmallocator_header_t;

typedef struct {
size_t first_bit;
size_t bit_count;
} bitmap_range_t;

static void bitmap_set(u64* bitmap, size_t bit) {
bitmap[bit / 64] |= (1ULL << (bit % 64));
}

static void bitmap_clear(u64* bitmap, size_t bit) {
bitmap[bit / 64] &= ~(1ULL << (bit % 64));
}

static bool bitmap_test(const u64* bitmap, size_t bit) {
return bitmap[bit / 64] & (1ULL << (bit % 64));
}

static void bitmap_set_range(u64* bitmap, size_t start, size_t count) {
for (size_t j = start; j < start + count; ++j) {
bitmap_set(bitmap, j);
}
}

static size_t calculate_header_size(memory_area_t area) {
const size_t bitmap_bits = area.size / PAGE_SIZE;
const size_t bitmap_bytes = ALIGN_UP(bitmap_bits, 64) / 8;
const size_t total = sizeof(pmallocator_header_t) + bitmap_bytes;
return ALIGN_UP(total, PAGE_SIZE);
}

static bitmap_range_t addr_range_to_bitmap_range(uintptr_t range_addr, size_t range_size, uintptr_t base_addr) {
const uintptr_t aligned_start = ALIGN_DOWN(range_addr, PAGE_SIZE);
const uintptr_t aligned_end = ALIGN_UP(range_addr + range_size, PAGE_SIZE);

bitmap_range_t result = {
.first_bit = (aligned_start - base_addr) / PAGE_SIZE,
.bit_count = (aligned_end - aligned_start) / PAGE_SIZE,
};
return result;
}

error_t pmallocator_get_header(memory_area_t area, const memory_area_t* reserved_areas, u32 reserved_areas_count,
memory_area_t* headerOUT) {
(void)area;
(void)reserved_areas;
(void)count;
(void)headerOUT;
return ERR_NOT_IMPLEMENTED;
const size_t header_size = calculate_header_size(area);

for (uintptr_t i = area.addr; i + header_size <= area.addr + area.size; i += PAGE_SIZE) {
memory_area_t potential_header = {
.addr = i,
.size = header_size,
};
bool overlaps_reserved = false;
for (u32 j = 0; j < reserved_areas_count; ++j) {
if (do_memory_areas_overlap(potential_header, reserved_areas[j])) {
overlaps_reserved = true;
break;
}
}
if (!overlaps_reserved) {
*headerOUT = potential_header;
return ERR_NONE;
}
}

return ERR_NOT_ENOUGH_MEMORY;
}

error_t pmallocator_init_region(memory_area_t area, memory_region_t header, const memory_area_t* reserved_areas,
u32 count) {
(void)area;
(void)header;
(void)reserved_areas;
(void)count;
return ERR_NOT_IMPLEMENTED;
error_t pmallocator_init_region(memory_area_t area, memory_region_t header_region, const memory_area_t* reserved_areas,
u32 reserved_areas_count) {
pmallocator_header_t* header = header_region.addr;
header->area_size = area.size;
header->area_base_addr = area.addr;

const size_t header_size = calculate_header_size(area);
const size_t bitmap_size = header_size - sizeof(pmallocator_header_t);

memset(header->bitmap, 0, bitmap_size);

for (u32 i = 0; i < reserved_areas_count; ++i) {
memory_area_t reserved_area = reserved_areas[i];
bitmap_range_t bitmap_range = addr_range_to_bitmap_range(reserved_area.addr, reserved_area.size, area.addr);

bitmap_set_range(header->bitmap, bitmap_range.first_bit, bitmap_range.bit_count);
}

bitmap_range_t bitmap_range =
addr_range_to_bitmap_range((uintptr_t)header_region.addr, header_region.size, area.addr);
bitmap_set_range(header->bitmap, bitmap_range.first_bit, bitmap_range.bit_count);

return ERR_NONE;
}

error_t pmallocator_allocate(u8 frame_order, memory_region_t header, phys_addr_t* addrOUT) {
(void)frame_order;
*addrOUT = *addrOUT;
(void)header;
return ERR_NOT_IMPLEMENTED;
error_t pmallocator_allocate(frame_order_t frame_order, memory_region_t header_region, phys_addr_t* addrOUT) {
Copy link
Collaborator

@qbojj qbojj Mar 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be wrapped in a critical section (both signals and for other harts).
For now you can add a blank implementation on hal_critical_section_{begin/end} to the hal and just call them here.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when hal is merged, just do hal_enable_irq/hal_disable_irq and add a FIXME: use a real critical section

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was decided there will be no parallelism, so no need for critical section (but interrupt disablement is still required)

pmallocator_header_t* header = header_region.addr;

const size_t bitmap_bits = header->area_size / PAGE_SIZE;
const size_t frame_count = 1ULL << frame_order;

for (size_t i = 0; i + frame_count <= bitmap_bits; i += frame_count) {
bool all_free = true;

for (size_t j = i; j < i + frame_count; ++j) {
if (bitmap_test(header->bitmap, j)) {
all_free = false;
break;
}
}

if (all_free) {
bitmap_set_range(header->bitmap, i, frame_count);
*addrOUT = (phys_addr_t)(header->area_base_addr + (i * PAGE_SIZE));
return ERR_NONE;
}
}

return ERR_NOT_ENOUGH_MEMORY;
}

error_t pmallocator_free(phys_addr_t addr, memory_region_t header) {
(void)addr;
(void)header;
return ERR_NOT_IMPLEMENTED;
error_t pmallocator_free(frame_order_t frame_order, phys_addr_t addr, memory_region_t header_region) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

pmallocator_header_t* header = header_region.addr;

const size_t frame_count = 1ULL << frame_order;
const uintptr_t phys_addr = (uintptr_t)addr;
const size_t addr_bit = (phys_addr - header->area_base_addr) / PAGE_SIZE;
const size_t total_pages = header->area_size / PAGE_SIZE;

if (phys_addr < header->area_base_addr || addr_bit + frame_count > total_pages)
return ERR_OUT_OF_BOUNDS;

for (size_t j = addr_bit; j < addr_bit + frame_count; ++j) {
if (!bitmap_test(header->bitmap, j))
return ERR_NOT_VALID;
}

for (size_t j = addr_bit; j < addr_bit + frame_count; ++j) {
bitmap_clear(header->bitmap, j);
}

return ERR_NONE;
}
44 changes: 23 additions & 21 deletions src/kernel/memory_management/physical_memory/allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,69 +12,71 @@
* @ingroup kmm
* @ingroup palloc
*
* @brief Looks for an area of suitable size and alignmnet to store all metadata about the @p area that the allocator
* @brief Looks for an area of suitable size and alignment to store all metadata about the @p area that the allocator
* needs
*
* @param area The phiscal memory area to allocate from. Will be aligned to at least 4KiB boundry
* @param area The physical memory area to allocate from. Will be aligned to at least 4KiB boundary
* @param reserved_areas An array of reserved areas from which allocations are not allowed
* @param count The count of reserved areas
* @param reserved_areas_count The count of reserved areas
*
* @retval ERR_NONE Success
* @retval ERR_BAD_ARG if @p reserved_areas is null and @p count is non zero or vice versa.
* @retval ERR_BAD_ARG if @p reserved_areas is null and @p reserved_areas_count is non zero or vice versa.
* */
[[gnu::nonnull(4)]]
error_t pmallocator_get_header(memory_area_t area, const memory_area_t* reserved_areas, u32 count,
error_t pmallocator_get_header(memory_area_t area, const memory_area_t* reserved_areas, u32 reserved_areas_count,
memory_area_t* headerOUT);

/**
* @ingroup kmm
* @ingroup palloc
*
* @param area The phiscal memory area to allocate from. Will be aligned to at least 4KiB boundry
* @param header A memory region of size at least `pmallocator_get_header_size(@p area)` aligned to 4KiB boundry
* @param area The physical memory area to allocate from. Will be aligned to at least 4KiB boundary
* @param header_region A memory region of size at least `pmallocator_get_header_size(@p area)` aligned to 4KiB
* boundary
* @param reserved_areas An array of reserved areas from which allocations are not allowed
* @param count The count of reserved areas
* @param reserved_areas_count The count of reserved areas
*
* @retval ERR_NONE Success
* @retval ERR_BAD_ARG if @p reserved_areas is null and @p count is non zero or vice versa.
* @retval ERR_BAD_ARG if @p reserved_areas is null and @p reserved_areas_count is non zero or vice versa.
*
* @note The header region overlaps with area, it must be marked and not be allocated from.
* area.
* @note All pointers will break upon change of address space, because this is initialized before and will be used
* after the change, no pointers can be stored inside the `header` region.
* */
error_t pmallocator_init_region(memory_area_t area, memory_region_t header, const memory_area_t* reserved_areas,
u32 count);
error_t pmallocator_init_region(memory_area_t area, memory_region_t header_region, const memory_area_t* reserved_areas,
u32 reserved_areas_count);

/**
* @ingroup kmm
* @ingroup palloc
*
* @param frame_order The frame size gives as `(1 << frame_order)`
* @param addrOUT Pointer the the variable to which the return address will be written to.
* The return address will be aligned to the frame size
* @param header
* @param frame_order The number of 4KiB frames to allocate is `(1 << frame_order)`
* @param header_region
* @param addrOUT Pointer to the variable to which the return address will be written to.
* The return address will be aligned to the allocation size
*
* @retval ERR_NONE Success
* @retval ERR_NOT_VALID The requested frame size is not supported by the allocator
* @retval ERR_PHYSICAL_MEMORY_FULL Not enough memory in the area represented by @p header to allocate a frame of
* @retval ERR_NOT_VALID The requested frame order is not supported by the allocator
* @retval ERR_NOT_ENOUGH_MEMORY Not enough memory in the area represented by @p header_region to allocate a frame of
* desired size
*
* @note 4KiB frame (or @p frame_order = 12) must be a valid frame size.
* @note FRAME_ORDER_4KiB (order 0) must be a valid frame order.
* */
[[gnu::nonnull]]
error_t pmallocator_allocate(u8 frame_order, memory_region_t header, phys_addr_t* addrOUT);
error_t pmallocator_allocate(frame_order_t frame_order, memory_region_t header_region, phys_addr_t* addrOUT);

/**
* @ingroup kmm
* @ingroup palloc
*
* @param frame_order
* @param addr
* @param header
* @param header_region
*
* @retval ERR_NONE Success
* @retval ERR_NOT_VALID The area represented by @p addr is already free.
* */
error_t pmallocator_free(phys_addr_t addr, memory_region_t header);
error_t pmallocator_free(frame_order_t frame_order, phys_addr_t addr, memory_region_t header_region);

#endif
18 changes: 9 additions & 9 deletions src/kernel/memory_management/physical_memory/manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ static error_t store_header(physical_memory_region_t header) {
} else {
physical_memory_region_t new_reg = {
.addr = nullptr,
.size = phys_mem_get_frame_size_in_bytes(FRAME_SIZE_4KiB),
.size = PAGE_SIZE,
};
error_t err = phys_mem_alloc_frame(FRAME_SIZE_4KiB, &new_reg.addr);
error_t err = phys_mem_alloc_frame(FRAME_ORDER_4KiB, &new_reg.addr);
if (err)
return err;
err = init_header_storage_node(new_reg);
Expand All @@ -73,7 +73,7 @@ static error_t store_header(physical_memory_region_t header) {
// Public
// ==========================================

u64 phys_mem_get_frame_size_in_bytes(frame_size_t fs) {
u64 phys_mem_get_frame_size_in_bytes(frame_order_t fs) {
const u64 size_4KiB = 0x1000;
return (size_4KiB << fs);
}
Expand Down Expand Up @@ -113,10 +113,10 @@ error_t phys_mem_init(const physical_memory_region_t* pmrs, size_t pmr_count, co
}
if (g_root_header_storage_node == nullptr) {
physical_memory_region_t new_reg = {
.size = phys_mem_get_frame_size_in_bytes(FRAME_SIZE_4KiB),
.size = PAGE_SIZE,
.addr = nullptr,
};
err = pmallocator_allocate(12, header_region, &new_reg.addr);
err = pmallocator_allocate(FRAME_ORDER_4KiB, header_region, &new_reg.addr);
// NOTE: Since we failed to allocate the smallest possible frame size, we assume that this region is
// useless.
if (err) {
Expand Down Expand Up @@ -149,13 +149,13 @@ error_t phys_mem_init(const physical_memory_region_t* pmrs, size_t pmr_count, co
}
// NOLINTEND readability-function-cognitive-complexity

error_t phys_mem_alloc_frame(frame_size_t frame_size, phys_addr_t* addrOUT) {
error_t phys_mem_alloc_frame(frame_order_t frame_size, phys_addr_t* addrOUT) {
u32 idx = 0;
physical_memory_region_t header_pmr;
while (get_header_pmr(idx, &header_pmr) == ERR_NONE) {
memory_region_t header_region = phys_mem_reg_to_reg(header_pmr);
phys_addr_t frame_data = nullptr;
error_t err = pmallocator_allocate(frame_size + 12, header_region, &frame_data);
error_t err = pmallocator_allocate(frame_size, header_region, &frame_data);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we know why the +12 was removed?

if (err) {
++idx;
continue;
Expand All @@ -169,12 +169,12 @@ error_t phys_mem_alloc_frame(frame_size_t frame_size, phys_addr_t* addrOUT) {
return ERR_OUT_OF_MEMORY;
}

error_t phys_mem_free_frame(phys_addr_t addr) {
error_t phys_mem_free_frame(frame_order_t frame_size, phys_addr_t addr) {
u32 idx = 0;
physical_memory_region_t header_pmr;
while (get_header_pmr(idx, &header_pmr) == ERR_NONE) {
memory_region_t header_region = phys_mem_reg_to_reg(header_pmr);
error_t err = pmallocator_free(addr, header_region);
error_t err = pmallocator_free(frame_size, addr, header_region);
if (err) {
++idx;
continue;
Expand Down
Loading