Skip to content

Commit

Permalink
pmm: Initial NBBS implementation.
Browse files Browse the repository at this point in the history
Signed-off-by: TunaCici <[email protected]>
  • Loading branch information
TunaCici committed May 12, 2024
1 parent 3c86119 commit b0f974b
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 29 deletions.
23 changes: 20 additions & 3 deletions Kernel/Include/Memory/NBBS.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,21 @@

#define EXP2(n) (0x1ULL << (n))
#define LOG2_LOWER(n) (64ULL - __builtin_clzll(n) - 1ULL) // 64 bit
#define CAS(addr, cmp, val) __atomic_compare_exchange_n(addr, cmp, val, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)

#define FAD(ptr, val) __atomic_add_fetch(ptr, val, __ATOMIC_SEQ_CST)
#define BCAS(ptr, expected, desired) __atomic_compare_exchange_n(ptr, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
#define VCAS(ptr, expected, desired) __atomic_compare_exchange_n(ptr, expected, desired, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ? (*expected) : 0

#define LEVEL(n) LOG2_LOWER(n)

#define TRY_AGAIN_BEGIN(release_count) \
do { \
uint32_t ts = release_count;

#define TRY_AGAIN_END(release_count) \
} while (ts != release_count);


/*
* Public APIs
*
Expand All @@ -53,7 +64,8 @@ void nb_free(void *addr);
*/

uint32_t try_alloc(uint32_t node);
void freenode(uint32_t node, uint32_t level);
void freenode(uint32_t node, uint32_t upper_bound);
void free_unmark(uint32_t node, uint32_t upper_bound);


/*
Expand All @@ -62,6 +74,11 @@ void freenode(uint32_t node, uint32_t level);
* TODO:? Explain.
*/

static inline uint8_t set_coal(uint8_t val, uint32_t child)
{
return ((uint8_t) (val | (COAL_LEFT >> (child % 2))));
}

static inline uint8_t clean_coal(uint8_t val, uint32_t child)
{
return ((uint8_t) (val & !(COAL_LEFT >> (child % 2))));
Expand All @@ -74,7 +91,7 @@ static inline uint8_t mark(uint8_t val, uint32_t child)

static inline uint8_t unmark(uint8_t val, uint32_t child)
{
return ((uint8_t) (val & !((COAL_LEFT | OCC_LEFT) >> (child % 2))));
return ((uint8_t) (val & !((OCC_LEFT | COAL_LEFT) >> (child % 2))));
}

static inline uint8_t is_coal(uint8_t val, uint32_t child)
Expand Down
23 changes: 14 additions & 9 deletions Kernel/Main.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,18 +89,23 @@ void kmain(boot_sysinfo* boot_params)

klog("[kmain] nb_alloc\n");

for (int i = 0; i < 10; i++) {
uint64_t *bruh = nb_alloc(4096);
uint64_t *bruh = nb_alloc(4096);

if (bruh) {
klog("[kmain] nb_alloc ok (0x%p)\n", bruh);
} else {
klog("[kmain] nb_alloc fail\n");
}

ksleep(1000);
if (bruh) {
klog("[kmain] nb_alloc ok (0x%p)\n", bruh);
} else {
klog("[kmain] nb_alloc fail\n");
}

nb_free(bruh);

bruh = nb_alloc(4096);

if (bruh) {
klog("[kmain] nb_alloc ok (0x%p)\n", bruh);
} else {
klog("[kmain] nb_alloc fail\n");
}

/* 2. Init PMM */
// klog("[kmain] Initializing physical memory manager...\n");
Expand Down
104 changes: 87 additions & 17 deletions Kernel/Memory/NBBS.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@

static volatile uint8_t *tree = 0;
static volatile uint32_t *index = 0;
static volatile uint64_t base_address = 0;

static volatile uint32_t depth = 0;
static volatile uint64_t tree_size = 0; /* bytes */
static volatile uint64_t index_size = 0; /* bytes */

static volatile uint64_t base_address = 0;
static volatile uint64_t total_memory = 0;
static volatile uint64_t max_level = 0;
static volatile uint32_t depth = 0;
static volatile uint64_t base_level = 0;
static volatile uint64_t min_size = 0;
static volatile uint64_t max_size = 0;
static volatile uint32_t release_count = 0;

int nb_init(uint64_t base, uint64_t size)
{
Expand All @@ -41,14 +42,11 @@ int nb_init(uint64_t base, uint64_t size)
total_memory = size;
min_size = PAGE_SIZE;
depth = LOG2_LOWER(total_memory / min_size);
max_level = 0;
max_size = EXP2(depth - max_level) * min_size;
base_level = 0;
max_size = EXP2(depth - base_level) * min_size;

/* Calculate required tree size */
uint32_t total_nodes = 1; // we have garbage node at idx 0
for (uint32_t i = 0; i <= depth; i++) {
total_nodes += (total_memory / (EXP2(i) * min_size));
}
/* Calculate required tree size - root node is at index 1 */
uint32_t total_nodes = EXP2(depth + 1);

/* Calculate required index size */
uint32_t total_pages = (total_memory / min_size);
Expand Down Expand Up @@ -80,17 +78,17 @@ int nb_init(uint64_t base, uint64_t size)

uint32_t try_alloc(uint32_t node)
{
/* Try to mark as BUSY */
/* Occupy the node */
uint8_t free = 0;
if (!CAS(&tree[node], &free, BUSY)) {
if (!BCAS(&tree[node], &free, BUSY)) {
return node;
}

uint32_t current = node;
uint32_t child = 0;

/* Propagate info about the occupancy up to the ancestor node(s) */
while (max_level < LEVEL(current)) {
/* Propagate the info about the occupancy up to the ancestor node(s) */
while (base_level < LEVEL(current)) {
child = current;
current = current >> 1;

Expand All @@ -107,7 +105,7 @@ uint32_t try_alloc(uint32_t node)

new_val = clean_coal(curr_val, child);
new_val = mark(new_val, child);
} while (!CAS(&tree[current], &curr_val, new_val));
} while (!BCAS(&tree[current], &curr_val, new_val));
}

return 0;
Expand All @@ -123,6 +121,8 @@ void* nb_alloc(uint64_t size)
size = min_size;
}

nb_alloc_again:;
uint32_t ts = release_count;
uint32_t level = LOG2_LOWER(total_memory / size);

if (depth < level) {
Expand Down Expand Up @@ -154,18 +154,88 @@ void* nb_alloc(uint64_t size)
}
}

/* A release occured, try again */
if (ts != release_count) {
goto nb_alloc_again;
}

return (void*) 0;

}

void freenode(uint32_t node, uint32_t level)
void free_unmark(uint32_t node, uint32_t upper_bound)
{
uint32_t current = node;
uint32_t child = 0;

uint8_t curr_val = 0;
uint8_t new_val = 0;

do {
child = current;
current = current >> 1;

do {
curr_val = tree[current];

if (!is_coal(curr_val, child)) {
return;
}

new_val = unmark(curr_val, child);
} while (!BCAS(&tree[current], &curr_val, new_val));
} while (upper_bound < LEVEL(current) && !is_occ_buddy(new_val, child));
}

void freenode(uint32_t node, uint32_t upper_bound)
{
/* TODO: should I check for double frees? */
if (is_free(tree[node])) {
return;
}

/* Phase 1. Ancestors of the node are marked as coalescing */
uint32_t current = node >> 1;
uint32_t child = node;

while (base_level < LEVEL(child)) {
uint8_t curr_val = 0;
uint8_t new_val = 0;
uint8_t old_val = 0;

do {
curr_val = tree[current];
new_val = set_coal(curr_val, child);
old_val = VCAS(&tree[current], &curr_val, new_val);
} while (old_val != curr_val);

if (is_occ_buddy(old_val, child) && !is_coal_buddy(old_val, child)) {
break;
}

child = current;
current = current >> 1;
}

/* Phase 2. Mark the node as free */
tree[node] = 0;

/* Phase 3. Propagate node release upward and possibly merge buddies */
if (LEVEL(node) != base_level) {
free_unmark(node, upper_bound);
}
}

void nb_free(void *addr)
{
/* Range check (is this necessary?) */
uint64_t u_addr = (uint64_t) addr;
if (u_addr < base_address || (base_address + total_memory) < u_addr) {
return;
}

uint32_t n = (u_addr - base_address) / min_size;
freenode(index[n], base_level);
FAD(&release_count, 1);
}


Expand Down

0 comments on commit b0f974b

Please sign in to comment.