Skip to content

Commit

Permalink
add and remove (i.e. rewrite) pmm code again
Browse files Browse the repository at this point in the history
  • Loading branch information
brvtalcake committed Oct 31, 2024
1 parent b6c4d87 commit 1030091
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 125 deletions.
23 changes: 23 additions & 0 deletions zerOS/include/kernel/compiler/struct.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#ifndef zerOS_KERNEL_COMPILER_STRUCT_H_INCLUDED
#define zerOS_KERNEL_COMPILER_STRUCT_H_INCLUDED

#undef sizeof_field
/**
* @def sizeof_field(type, field)
* @brief Get the size of a field in a struct.
* @param type The type of the struct.
* @param field The field in the struct.
*/
#define sizeof_field(type, field) sizeof(((type*)0)->field)

#undef container_of
/**
* @def container_of(ptr, type, field)
* @brief Get the container of a field in a struct.
* @param ptr The pointer to the field.
* @param type The type of the struct.
* @param field The field in the struct.
*/
#define container_of(ptr, type, field) ((type*)((char*)(ptr) - offsetof(type, field)))

#endif
2 changes: 2 additions & 0 deletions zerOS/include/kernel/data/bitset.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ static_assert(
typedef zerOS_BITSET_UNDERLYING_TYPE* bitset_t;

// TODO (fixme): All bitset operation are dependent on the underlying type being used
// TODO: Make `set_all` and `clear_all` functions accept the size of bits instead of the size of zerOS_BITSET_UNDERLYING_TYPE
// composing the bitset

static inline void zerOS_bitset_set(bitset_t bitset, size_t bit)
{
Expand Down
45 changes: 37 additions & 8 deletions zerOS/include/kernel/memory/align.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,42 @@
#ifndef zerOS_KERNEL_MEMORY_ALIGN_H_INCLUDED
#define zerOS_KERNEL_MEMORY_ALIGN_H_INCLUDED

#undef ALIGN_UP
/**
* @def ALIGN_UP(x, align)
* @brief Aligns a value up to the specified alignment.
* @param x The value to align.
* @param align The alignment to use.
*/
#define ALIGN_UP(x, align) (((x) + (align) - 1) & ~((align) - 1))
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdalign.h>

#include <misc/unique_ident.h>

static inline bool zerOS_is_pow_two(uintptr_t x)
{
if (unlikely(x == 0))
return false;
return (x & (x - 1)) == 0;
}

static inline uintptr_t zerOS_align_up(uintptr_t x, size_t align)
{
if (likely(zerOS_is_pow_two(align)))
return (x + (align - 1)) & ~(align - 1);
else
return x + ((align - (x % align)) % align);
}

static inline uintptr_t zerOS_align_down(uintptr_t x, size_t align)
{
if (likely(zerOS_is_pow_two(align)))
return x & ~(align - 1);
else
return x - (x % align);
}

static inline uintptr_t zerOS_is_aligned(uintptr_t x, size_t align)
{
if (likely(zerOS_is_pow_two(align)))
return (x & (align - 1)) == 0;
else
return x % align == 0;
}

#endif
7 changes: 7 additions & 0 deletions zerOS/include/kernel/multitasking/atomics.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
#include <stdint.h>
#include <stdatomic.h>

#include <machine/path.h>
#include MK_MACHINE_PATH(fast_data_types.h)

typedef atomic_flag zerOS_spinlock_t;
typedef _Atomic(zerOS_fast_uint_t) zerOS_semaphore_t;

#undef zerOS_SPINLOCK_INIT
#define zerOS_SPINLOCK_INIT ATOMIC_FLAG_INIT
Expand All @@ -15,4 +19,7 @@ typedef atomic_flag zerOS_spinlock_t;
#undef zerOS_spinlock_release
#define zerOS_spinlock_release(lock) atomic_flag_clear_explicit(lock, memory_order_release)

#undef zerOS_SEMAPHORE_INIT
#define zerOS_SEMAPHORE_INIT (0)

#endif
2 changes: 2 additions & 0 deletions zerOS/include/machine/common/x86_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdalign.h>
#include <x86intrin.h>

#include <klibc/misc.h>
Expand All @@ -20,6 +21,7 @@ typedef uint_fast32_t zerOS_fast_uint_t;

static constexpr size_t zerOS_fast_uint_size = sizeof(zerOS_fast_uint_t);
static constexpr size_t zerOS_fast_uint_bits = zerOS_fast_uint_size * 8;
static constexpr size_t zerOS_fast_uint_align = alignof(zerOS_fast_uint_t);

static constexpr zerOS_fast_uint_t zerOS_fast_uint_max = UINT_FAST32_MAX;

Expand Down
2 changes: 0 additions & 2 deletions zerOS/src/kernel/cpu/misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,5 @@ extern void zerOS_hcf(void)
{
zerOS_cli();
while (true)
{
zerOS_halt();
}
}
210 changes: 95 additions & 115 deletions zerOS/src/kernel/memory/pmm.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <kernel/printk.h>
#include <kernel/limine_data.h>
#include <kernel/memory/align.h>
#include <kernel/memory/paging.h>
#include <kernel/data/bitset.h>
#include <kernel/cpu/misc.h>
Expand All @@ -20,164 +21,143 @@
#include <klibc/alloca.h>
#include <klibc/string.h>

// TODO: Make this struct accept size in number of bits (i.e. number of pages) instead of size in number of zerOS_BITSET_UNDERLYING_TYPE elements
struct pmm_basic_manager
{
size_t limine_entry_index; ///< The index of the limine entry.
size_t base_page_index; ///< The index of the first page, in physical memory.
bitset_t bitmap; ///< The bitmap.
bitset_t bitmap_physaddr; ///< The physical address of the bitmap.
size_t next_free; ///< The index of the next free page, in the bitmap.
size_t size; ///< The size of the bitmap, in pages.
size_t size; ///< The size of the bitmap, in bitmap elements (i.e. page_count / zerOS_fast_uint_bits or size_in_bytes / sizeof(zerOS_fast_uint_t)).
};

static struct pmm_basic_manager pmm_main_managers[zerOS_CONFIG_MAX_USABLE_MEMORY_REGIONS];

static uintptr_t get_cr3(void)
static inline size_t calc_bitmap_size(size_t page_count)
{
uintptr_t ret;
asm volatile(
"mov %%cr3, %0" : "=r"(ret)
);
return ret;
if (page_count % zerOS_fast_uint_bits != 0)
{
zerOS_early_printk(
"zerOS: unhandled code path: page count "
"is not a multiple of zerOS_fast_uint_bits\n"
);
zerOS_hcf();
}
const size_t bitmap_elem_count = page_count / zerOS_fast_uint_bits;
return bitmap_elem_count * sizeof(zerOS_fast_uint_t);
}

/**
* @brief Gives a location where the bitmap shall reside.
* @param bitmap_size The size of the bitmap in bytes.
* @param memmap_index_out The index of the memory map entry where the bitmap is located.
* @return A proper (physical) address for the start of the bitmap.
* @warning This function is only to be used in the early paging setup.
*/
static uint64_t get_bitmap_location(size_t bitmap_size, size_t* memmap_index_out, size_t* needed_pages)
// Returns the index of the memory map entry where the bitmap will be located
static size_t find_proper_bitmaps_loc(size_t* manageable, size_t manageable_count, size_t memory_needs)
{
struct limine_memmap_response* memmap_resp = (struct limine_memmap_response*) zerOS_get_limine_data(zerOS_LIMINE_MEMMAP_RESPONSE);
const size_t count = memmap_resp->entry_count;

bool found = false;
uint64_t entry_top, entry_base;

*needed_pages = (bitmap_size / zerOS_PAGE_SIZE) + 1;
zerOS_early_printk("zerOS: needed pages: %u\n", EPRI_CAST(u, *needed_pages));

for (size_t where = count; where != 0 && !found; --where)
for (size_t i = 0; i < manageable_count; i++)
{
struct limine_memmap_entry* entry = (struct limine_memmap_entry*) zerOS_get_limine_data(zerOS_LIMINE_MEMMAP_ENTRY, where - 1);
entry_base = entry->base;
entry_top = entry_base + entry->length;

if (entry->type == LIMINE_MEMMAP_USABLE &&
entry->length >= bitmap_size &&
entry_top <= UINT64_C(4) * GiB)
{
*memmap_index_out = where - 1;
found = true;
}
struct limine_memmap_entry* entry = (struct limine_memmap_entry*) zerOS_get_limine_data(zerOS_LIMINE_MEMMAP_ENTRY, manageable[i]);
const uint64_t entry_top = entry->base + entry->length;

if (entry->type == LIMINE_MEMMAP_USABLE && entry->length >= memory_needs && entry_top <= UINT64_C(4) * GiB)
return i;
}

if (!found)
return (uint64_t)-1;

return entry_top - bitmap_size;
// don't bother returning an error value
// this shall not happen anyways, so just hang with an error message
zerOS_early_printk("zerOS: error: failed to find a suitable location for the bitmaps\n");
zerOS_hcf();
}

// Simply count the number of free usable and bootloader reclaimable pages
static size_t get_managed_mem_size(void)
static void init_basic_managers(
const uint64_t hhdm_offset,
struct limine_memmap_entry* bitmap_entry,
size_t* manageable, size_t* needs, size_t manageable_count,
size_t needs_sum
)
{
struct limine_memmap_response* memmap_resp = (struct limine_memmap_response*) zerOS_get_limine_data(zerOS_LIMINE_MEMMAP_RESPONSE);
struct limine_memmap_entry* memmap = (struct limine_memmap_entry*) zerOS_get_limine_data(zerOS_LIMINE_MEMMAP_ENTRY, (size_t)0);
const size_t memmap_entry_count = memmap_resp->entry_count;
intptr_t current_offset = bitmap_entry->base + bitmap_entry->length;
for (size_t i = manageable_count; i != 0; --i)
{
const size_t realind = i - 1;
struct limine_memmap_entry* entry = (struct limine_memmap_entry*) zerOS_get_limine_data(zerOS_LIMINE_MEMMAP_ENTRY, manageable[realind]);

size_t count = 0;
current_offset -= (intptr_t)(needs[realind]);

memset(pmm_main_managers, 0, zerOS_CONFIG_MAX_USABLE_MEMORY_REGIONS * sizeof(struct pmm_basic_manager));
struct pmm_basic_manager* manager = &pmm_main_managers[realind];
manager->limine_entry_index = manageable[realind];
manager->base_page_index = entry->base / zerOS_PAGE_SIZE;
manager->size = needs[realind] / sizeof(zerOS_fast_uint_t);
manager->bitmap_physaddr = (bitset_t)current_offset;
manager->bitmap = (bitset_t)(hhdm_offset + current_offset);
manager->next_free = 0;

size_t manager_index = 0;
for (size_t i = 0; i < memmap_entry_count; i++)
{
struct limine_memmap_entry* entry = (struct limine_memmap_entry*) zerOS_get_limine_data(zerOS_LIMINE_MEMMAP_ENTRY, i);
if (entry->type == LIMINE_MEMMAP_USABLE || entry->type == LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE)
if (entry->type == LIMINE_MEMMAP_USABLE)
zerOS_bitset_clear_all(manager->bitmap, manager->size);
else if (entry->type == LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE)
zerOS_bitset_set_all(manager->bitmap, manager->size);

if (entry == bitmap_entry)
{
uint64_t div = entry->length / zerOS_PAGE_SIZE;
uint64_t mod = entry->length % zerOS_PAGE_SIZE;
if (unlikely(mod != 0))
{
zerOS_early_printk("zerOS: error: memmap entry length is not a multiple of the page size\n");
zerOS_hcf();
}
count += div;
pmm_main_managers[manager_index].limine_entry_index = i;
pmm_main_managers[manager_index].base_page_index = entry->base / zerOS_PAGE_SIZE;
const size_t max_managed_page_index = (entry->length / zerOS_PAGE_SIZE);
const size_t occupied_pages = (needs_sum / zerOS_PAGE_SIZE) + ((needs_sum % zerOS_PAGE_SIZE) != 0 ? 1 : 0);
for (size_t j = 0; j < occupied_pages; j++)
zerOS_bitset_set(manager->bitmap, j);
}
}
}

return count;
static size_t __static_do_sum(size_t* arr, size_t count)
{
size_t sum = 0;
for (size_t i = 0; i < count; i++)
sum += arr[i];
return sum;
}

extern bool zerOS_init_pmm(void)
{
struct limine_hhdm_response* hhdm = (struct limine_hhdm_response*) zerOS_get_limine_data(zerOS_LIMINE_HHDM_RESPONSE);
const uint64_t hhdm_offset = hhdm->offset;

// In number of pages
const size_t physmem = get_managed_mem_size();
zerOS_early_printk("zerOS: found %u pages of usable memory\n", EPRI_CAST(u, physmem));

// zerOS_fast_uint_bits pages per zerOS_fast_uint_t
const size_t in_bytes = (physmem / zerOS_fast_uint_bits) + 1;
zerOS_early_printk("zerOS: bitmap size: %u bytes\n", EPRI_CAST(u, in_bytes));

const size_t bitmap_size = in_bytes * sizeof(zerOS_fast_uint_t);
zerOS_early_printk("zerOS: bitmap size: %u bytes\n", EPRI_CAST(u, bitmap_size));

size_t bitmap_memmap_index, bitmap_pages;
const uint64_t bitmap_phys_loc = get_bitmap_location(bitmap_size, &bitmap_memmap_index, &bitmap_pages);
if (bitmap_phys_loc == (uint64_t)-1)
{
zerOS_early_printk("zerOS: error: failed to find a suitable location for the bitmap\n");
zerOS_hcf();
}
zerOS_early_printk("zerOS: bitmap physical location: 0x%x\n", EPRI_CAST(x, bitmap_phys_loc));

const uint64_t bitmap_virt_loc = hhdm_offset + bitmap_phys_loc;
zerOS_early_printk("zerOS: bitmap virtual location: 0x%x\n", EPRI_CAST(x, bitmap_virt_loc));
size_t manageable[zerOS_CONFIG_MAX_USABLE_MEMORY_REGIONS];
size_t manageable_count = 0;

// in bytes
size_t memory_needs[zerOS_CONFIG_MAX_USABLE_MEMORY_REGIONS];

pmm_main_managers.bitmap = (bitset_t)((uintptr_t)bitmap_virt_loc);
pmm_main_managers.bitmap_physaddr = (bitset_t)((uintptr_t)bitmap_phys_loc);
pmm_main_managers.size = bitmap_size / sizeof(zerOS_fast_uint_t);
pmm_main_managers.next_free = 0;
struct limine_memmap_response* memmap_resp = (struct limine_memmap_response*) zerOS_get_limine_data(zerOS_LIMINE_MEMMAP_RESPONSE);
const size_t memmap_entry_count = memmap_resp->entry_count;

bool managed_by(const struct pmm_basic_manager* bm, size_t ind)
{
for (size_t _i = 0; _i < bm->managed_entry_count; ++_i)
{
if (bm->managed_entries[_i] == ind)
return true;
}
return false;
};

// By default, set all `LIMINE_MEMMAP_USABLE` pages as free,
// and all `LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE` pages as used
// Also mark the bitmap itself as used
size_t page_index = 0;
for (size_t i = 0; i < pmm_main_managers.managed_entry_count; i++)
for (size_t i = 0; i < memmap_entry_count; i++)
{
struct limine_memmap_entry* entry = managed_entry_get_limine_entry(&pmm_main_managers, i);
if (entry->type == LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE)
struct limine_memmap_entry* entry = (struct limine_memmap_entry*) zerOS_get_limine_data(zerOS_LIMINE_MEMMAP_ENTRY, i);
if (entry->type == LIMINE_MEMMAP_USABLE || entry->type == LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE)
{
const size_t end_cond = page_index + (entry->length / zerOS_PAGE_SIZE);
while (page_index < end_cond)
const uint64_t div = entry->length / zerOS_PAGE_SIZE,
mod = entry->length % zerOS_PAGE_SIZE;
if (unlikely(mod != 0))
{
zerOS_bitset_set(pmm_main_managers.bitmap, page_index);
++page_index;
zerOS_early_printk("zerOS: error: memmap entry length is not a multiple of the page size\n");
zerOS_hcf();
}
}
else if (entry->type == LIMINE_MEMMAP_USABLE)
{

size_t bmsize = calc_bitmap_size(div);
//pmm_main_managers[manageable_count].limine_entry_index = i;
//pmm_main_managers[manageable_count].base_page_index = entry->base / zerOS_PAGE_SIZE;
//pmm_main_managers[manageable_count].size = bmsize / sizeof(zerOS_fast_uint_t);
manageable[manageable_count] = i;
memory_needs[manageable_count] = bmsize;
++manageable_count;
}
}

return true;

const size_t sum = __static_do_sum(memory_needs, manageable_count);
const size_t bitmap_loc = find_proper_bitmaps_loc(manageable, manageable_count, sum);
struct limine_memmap_entry* bitmap_entry = (struct limine_memmap_entry*) zerOS_get_limine_data(zerOS_LIMINE_MEMMAP_ENTRY, bitmap_loc);

init_basic_managers(
hhdm_offset, bitmap_entry,
manageable, memory_needs,
manageable_count, sum
);
}

extern bool zerOS_pmm_alloc_frames(uintptr_t* filled, size_t count)
Expand Down

0 comments on commit 1030091

Please sign in to comment.