| 1 | #include <math/align.h> |
| 2 | #include <mem/alloc_or_die.h> |
| 3 | #include <mem/page.h> |
| 4 | |
| 5 | #include "internal.h" |
| 6 | |
| 7 | static _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 | |
| 16 | uint8_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 | |
| 26 | void 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 | |
| 38 | void 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 | |