1#include <math/align.h>
2#include <mem/alloc_or_die.h>
3#include <mem/page.h>
4
5#include "internal.h"
6
7static _Atomic uint8_t *order_map_entry_for(vaddr_t vaddr, bool *high_bits) {
8 kassert(kmalloc_ptr_in_slab_validate((void *) vaddr));
9 vaddr_t vptr_relative = vaddr - SLAB_HEAP_START;
10 vaddr_t aligned_2mb = ALIGN_DOWN(vptr_relative, PAGE_2MB);
11 vaddr_t aligned_4mb = ALIGN_DOWN(vptr_relative, PAGE_2MB * 2);
12 *high_bits = aligned_2mb != aligned_4mb;
13 return &slab_global.order_map[aligned_4mb / (PAGE_2MB * 2)];
14}
15
16uint8_t slab_order_map_get(vaddr_t vaddr) {
17 bool get_high;
18 uint8_t byte = *order_map_entry_for(vaddr, high_bits: &get_high);
19 if (get_high) {
20 return byte >> 4;
21 } else {
22 return byte & 0xF;
23 }
24}
25
26void slab_order_map_set(vaddr_t vaddr, uint8_t order) {
27 order &= 0xF;
28 bool set_high;
29 _Atomic uint8_t *bptr = order_map_entry_for(vaddr, high_bits: &set_high);
30
31 uint8_t first_mask = set_high ? 0xF : 0xF0;
32 order = set_high ? order << 4 : order;
33
34 atomic_fetch_and(bptr, first_mask);
35 atomic_fetch_or(bptr, order);
36}
37
38void slab_order_map_init(void) {
39 size_t range = SLAB_HEAP_END - SLAB_HEAP_START;
40 size_t n4mb_blocks = range / (PAGE_2MB * 2);
41 size_t bytes_needed = n4mb_blocks;
42 slab_global.order_map =
43 alloc_or_die(simple_alloc(slab_global.vas, bytes_needed));
44
45 uint8_t set_to = SLAB_POW2_ORDER_EMPTY << 4 | SLAB_POW2_ORDER_EMPTY;
46 memset(slab_global.order_map, set_to, bytes_needed);
47}
48