Voxia OS v0.0.1
Hobby Project Operating System Targeting x86-64
Loading...
Searching...
No Matches
kalloc.c
Go to the documentation of this file.
1#include "libk/serial.h"
5#include <autoconf.h>
6#include <hal/cpu/core.h>
7#include <hal/cpu/irq_lock.h>
8#include <hal/cpu/paging.h>
10#include <spinlock.h>
11#include <str.h>
12#include <type.h>
14#define MAX_FREED_VADDRS 512
15
16typedef struct {
18 size_t size; /* BLOCK_SIZE (page) */
20
22 /* free-list heads */
23 void* c_64;
24 void* c_128;
25 void* c_256;
26 void* c_512;
27 void* c_1024;
28 void* c_2048;
29
30 /* jumlah slot tersedia di masing-masing bucket */
31 size_t c_64_count;
37
39
40 /* padding agar tiap entry tidak berbagi cache line */
41 uint8_t _pad[64 - (sizeof(void*) * 6 + sizeof(size_t) * 6 +
42 sizeof(spinlock_t)) %
43 64];
44} __attribute__((aligned(64)));
45
46static struct kalloc_cpu_cache cpu_caches[VOXIA_MAX_CORE];
47
49
51
53static size_t freed_vaddr_count = 0;
54
55static inline uintptr_t lock_irqsave(spinlock_t* lk) {
56 uintptr_t flags = irq_save(); /* disable IRQ, simpan flags */
57 spin_acquire(lk);
58 return flags;
59}
60
61static inline void unlock_irqrestore(spinlock_t* lk, uintptr_t flags) {
62 spin_release(lk);
64}
65
66static void setup_redzone(void* ptr, size_t size) {
67 uint32_t* p = (uint32_t*)ptr;
68 for (size_t i = 0; i < size / sizeof(uint32_t); i++)
70}
71
72static int check_redzone(void* ptr, size_t size) {
73 uint32_t* p = (uint32_t*)ptr;
74 for (size_t i = 0; i < size / sizeof(uint32_t); i++) {
75 if (p[i] != KALLOC_REDZONE_MAGIC)
76 return 0;
77 }
78 return 1;
79}
80
81static uintptr_t vaddr_alloc_locked(size_t page_count) {
82 for (size_t i = 0; i < freed_vaddr_count; i++) {
83 if (freed_vaddrs[i].size >= page_count) {
84 uintptr_t va = freed_vaddrs[i].addr;
85 freed_vaddrs[i].addr += page_count * BLOCK_SIZE;
86 freed_vaddrs[i].size -= page_count;
87 if (freed_vaddrs[i].size == 0)
88 freed_vaddrs[i] =
90 return va;
91 }
92 }
93 /* Bump allocator */
95 kalloc_next_addr += page_count * BLOCK_SIZE;
96 return va;
97}
98
99static void* alloc_page_locked(void) {
105 return (void*)virt;
106}
107
108#define KALLOC_REFILL(BUCKET) \
109 static void refill_##BUCKET(struct kalloc_cpu_cache* cc, \
110 uintptr_t* gflags) { \
111 \
112 spin_acquire(&kalloc_global_lock); \
113 void* page = alloc_page_locked(); \
114 spin_release(&kalloc_global_lock); \
115 \
116 for (int i = 0; i < (int)(BLOCK_SIZE / BUCKET); i++) { \
117 void* slot = \
118 (void*)((uintptr_t)page + (size_t)i * BUCKET); \
119 *(void**)slot = cc->c_##BUCKET; \
120 cc->c_##BUCKET = slot; \
121 cc->c_##BUCKET##_count++; \
122 } \
123 (void)gflags; /* tidak dipakai di sini, tapi perlu untuk macro \
124 */ \
125 }
132KALLOC_REFILL(2048)
134#define KALLOC_SLAB_ALLOC(BUCKET) \
135 do { \
136 uint32_t cpu = get_current_core_data()->core_id; \
137 struct kalloc_cpu_cache* cc = &cpu_caches[cpu]; \
138 uintptr_t flags = lock_irqsave(&cc->lock); \
139 if (cc->c_##BUCKET##_count == 0) \
140 refill_##BUCKET(cc, &flags); \
141 void* slot = cc->c_##BUCKET; \
142 cc->c_##BUCKET = *(void**)slot; \
143 cc->c_##BUCKET##_count--; \
144 unlock_irqrestore(&cc->lock, flags); \
145 \
146 kalloc_metadata_t* meta = (kalloc_metadata_t*)slot; \
147 meta->size = size; \
148 meta->magic = KALLOC_REDZONE_MAGIC; \
149 \
150 void* red_before = \
151 (void*)((uintptr_t)slot + sizeof(kalloc_metadata_t)); \
152 setup_redzone(red_before, KALLOC_REDZONE_SIZE); \
153 \
154 void* data = \
155 (void*)((uintptr_t)red_before + KALLOC_REDZONE_SIZE); \
156 void* red_after = (void*)((uintptr_t)data + size); \
157 setup_redzone(red_after, KALLOC_REDZONE_SIZE); \
158 \
159 return data; \
160 } while (0)
162KERNEL_API void* kalloc(size_t size) {
163 if (size == 0)
164 return NULL;
165
166 /* Check if we can fit in slab buckets with metadata + red zones */
167 size_t metadata_overhead =
169
170 if (size + metadata_overhead <= 64) {
172 } else if (size + metadata_overhead <= 128) {
174 } else if (size + metadata_overhead <= 256) {
176 } else if (size + metadata_overhead <= 512) {
178 } else if (size + metadata_overhead <= 1024) {
179 KALLOC_SLAB_ALLOC(1024);
180 } else if (size + metadata_overhead <= 2048) {
181 KALLOC_SLAB_ALLOC(2048);
182 }
183
184 /* Large alloc (> 2048 byte), or doesn't fit in slab */
185 size_t total_size = size + metadata_overhead;
186 size_t page_count = ALIGN_UP(total_size, BLOCK_SIZE) / BLOCK_SIZE;
187
189
190 uintptr_t phys = (uintptr_t)phys_base_alloc(page_count);
191 uintptr_t virt = vaddr_alloc_locked(page_count);
192
193 vxMultipleMmap(paging_get_highest_page_map(), virt, phys, page_count,
195 vma_register(get_kernel_vmm_page(), phys, virt,
196 page_count * BLOCK_SIZE);
197
199
200 /* Setup layout: [metadata] [red_before] [data] [red_after] */
202 meta->size = size;
204
205 void* red_before = (void*)((uintptr_t)virt + sizeof(kalloc_metadata_t));
207
208 void* data = (void*)((uintptr_t)red_before + KALLOC_REDZONE_SIZE);
209 void* red_after = (void*)((uintptr_t)data + size);
211
212 return data;
213}
214
215KERNEL_API void kfree(void* ptr, size_t size) {
216 if (ptr == NULL || size == 0)
217 return;
218
219 uint32_t cpu = get_current_core_data()->core_id;
220 struct kalloc_cpu_cache* cc = &cpu_caches[cpu];
221 uintptr_t cpu_flags = lock_irqsave(&cc->lock);
222
223 /* Check metadata at offset from pointer */
224 kalloc_metadata_t* meta =
227 if (meta->magic != KALLOC_REDZONE_MAGIC) {
228 unlock_irqrestore(&cc->lock, cpu_flags);
229 LOG2_WARN("KALLOC", "metadata failed");
230 return;
231 }
232
233 /* Verify red zones */
234 void* red_before = (void*)((uintptr_t)meta + sizeof(kalloc_metadata_t));
235 if (!check_redzone(red_before, KALLOC_REDZONE_SIZE)) {
236 unlock_irqrestore(&cc->lock, cpu_flags);
237 LOG2_WARN("KALLOC", "red zone overllaping");
238 return;
239 }
240
241 void* red_after = (void*)((uintptr_t)ptr + meta->size);
242 if (!check_redzone(red_after, KALLOC_REDZONE_SIZE)) {
243 unlock_irqrestore(&cc->lock, cpu_flags);
244 LOG2_WARN("KALLOC", "red zone overllaping");
245 return;
246 }
247
248 size_t metadata_overhead =
250
251 if (size + metadata_overhead <= 64) {
252 void* slot = (void*)meta;
253 memset(slot, 0, 64);
254 *(void**)slot = cc->c_64;
255 cc->c_64 = slot;
256 cc->c_64_count++;
257 unlock_irqrestore(&cc->lock, cpu_flags);
258 } else if (size + metadata_overhead <= 128) {
259 void* slot = (void*)meta;
260 memset(slot, 0, 128);
261 *(void**)slot = cc->c_128;
262 cc->c_128 = slot;
263 cc->c_128_count++;
264 unlock_irqrestore(&cc->lock, cpu_flags);
265 } else if (size + metadata_overhead <= 256) {
266 void* slot = (void*)meta;
267 memset(slot, 0, 256);
268 *(void**)slot = cc->c_256;
269 cc->c_256 = slot;
270 cc->c_256_count++;
271 unlock_irqrestore(&cc->lock, cpu_flags);
272 } else if (size + metadata_overhead <= 512) {
273 void* slot = (void*)meta;
274 memset(slot, 0, 512);
275 *(void**)slot = cc->c_512;
276 cc->c_512 = slot;
277 cc->c_512_count++;
278 unlock_irqrestore(&cc->lock, cpu_flags);
279 } else if (size + metadata_overhead <= 1024) {
280 void* slot = (void*)meta;
281 memset(slot, 0, 1024);
282 *(void**)slot = cc->c_1024;
283 cc->c_1024 = slot;
284 cc->c_1024_count++;
285 unlock_irqrestore(&cc->lock, cpu_flags);
286 } else if (size + metadata_overhead <= 2048) {
287 void* slot = (void*)meta;
288 memset(slot, 0, 2048);
289 *(void**)slot = cc->c_2048;
290 cc->c_2048 = slot;
291 cc->c_2048_count++;
292 unlock_irqrestore(&cc->lock, cpu_flags);
293 } else {
294 unlock_irqrestore(&cc->lock, cpu_flags);
295
297
298 size_t total_size = size + metadata_overhead;
299 memset(meta, 0, total_size);
300
302 if (!v) {
304 return;
305 }
306
307 size_t page_count =
308 ALIGN_UP(total_size, BLOCK_SIZE) / BLOCK_SIZE;
309
310 vxPhysBaseFree((void*)v->phys_address, page_count);
312 (uintptr_t)meta, page_count);
314
317 .addr = (uintptr_t)meta,
318 .size = page_count,
319 };
320 }
321
323 }
324}
325
326KERNEL_API void kfree2(void* ptr) {
327 if (ptr == NULL)
328 return;
329
330 uint32_t cpu = get_current_core_data()->core_id;
331 struct kalloc_cpu_cache* cc = &cpu_caches[cpu];
332 uintptr_t cpu_flags = lock_irqsave(&cc->lock);
333
334 /* Check metadata at offset from pointer */
335 kalloc_metadata_t* meta =
338 if (meta->magic != KALLOC_REDZONE_MAGIC) {
339 unlock_irqrestore(&cc->lock, cpu_flags);
340 return;
341 }
342
343 auto size = meta->size;
344
345 /* Verify red zones */
346 void* red_before = (void*)((uintptr_t)meta + sizeof(kalloc_metadata_t));
347 if (!check_redzone(red_before, KALLOC_REDZONE_SIZE)) {
348 unlock_irqrestore(&cc->lock, cpu_flags);
349 LOG2_WARN("KALLOC", "red zone overllaping");
350 return;
351 }
352
353 void* red_after = (void*)((uintptr_t)ptr + meta->size);
354 if (!check_redzone(red_after, KALLOC_REDZONE_SIZE)) {
355 unlock_irqrestore(&cc->lock, cpu_flags);
356 LOG2_WARN("KALLOC", "red zone overllaping");
357 return;
358 }
359
360 size_t metadata_overhead =
362
363 if (size + metadata_overhead <= 64) {
364 void* slot = (void*)meta;
365 memset(slot, 0, 64);
366 *(void**)slot = cc->c_64;
367 cc->c_64 = slot;
368 cc->c_64_count++;
369 unlock_irqrestore(&cc->lock, cpu_flags);
370 } else if (size + metadata_overhead <= 128) {
371 void* slot = (void*)meta;
372 memset(slot, 0, 128);
373 *(void**)slot = cc->c_128;
374 cc->c_128 = slot;
375 cc->c_128_count++;
376 unlock_irqrestore(&cc->lock, cpu_flags);
377 } else if (size + metadata_overhead <= 256) {
378 void* slot = (void*)meta;
379 memset(slot, 0, 256);
380 *(void**)slot = cc->c_256;
381 cc->c_256 = slot;
382 cc->c_256_count++;
383 unlock_irqrestore(&cc->lock, cpu_flags);
384 } else if (size + metadata_overhead <= 512) {
385 void* slot = (void*)meta;
386 memset(slot, 0, 512);
387 *(void**)slot = cc->c_512;
388 cc->c_512 = slot;
389 cc->c_512_count++;
390 unlock_irqrestore(&cc->lock, cpu_flags);
391 } else if (size + metadata_overhead <= 1024) {
392 void* slot = (void*)meta;
393 memset(slot, 0, 1024);
394 *(void**)slot = cc->c_1024;
395 cc->c_1024 = slot;
396 cc->c_1024_count++;
397 unlock_irqrestore(&cc->lock, cpu_flags);
398 } else if (size + metadata_overhead <= 2048) {
399 void* slot = (void*)meta;
400 memset(slot, 0, 2048);
401 *(void**)slot = cc->c_2048;
402 cc->c_2048 = slot;
403 cc->c_2048_count++;
404 unlock_irqrestore(&cc->lock, cpu_flags);
405 } else {
406 unlock_irqrestore(&cc->lock, cpu_flags);
407
409
410 size_t total_size = size + metadata_overhead;
411 memset(meta, 0, total_size);
412
414 if (!v) {
416 return;
417 }
418
419 size_t page_count =
420 ALIGN_UP(total_size, BLOCK_SIZE) / BLOCK_SIZE;
421 // serial2_printf("page count %d\n", page_count);
422
423 vxPhysBaseFree((void*)v->phys_address, page_count);
425 (uintptr_t)meta, page_count);
427
430 .addr = (uintptr_t)meta,
431 .size = page_count,
432 };
433 }
434
436 }
437}
each_core_data * get_current_core_data(void)
Definition core.c:54
struct fs_data data
Definition filesystem.h:1
uint16_t flags
Definition thread.h:5
typedef __attribute__
Definition msi.c:47
static void irq_restore(uintptr_t flags)
Definition irq_lock.h:20
static uintptr_t irq_save(void)
Definition irq_lock.h:6
static uintptr_t kalloc_next_addr
Definition kalloc.c:50
#define KALLOC_REFILL(BUCKET)
Definition kalloc.c:108
static uintptr_t vaddr_alloc_locked(size_t page_count)
Definition kalloc.c:81
static size_t freed_vaddr_count
Definition kalloc.c:53
static freed_t freed_vaddrs[512]
Definition kalloc.c:52
static void * alloc_page_locked(void)
Definition kalloc.c:99
static struct kalloc_cpu_cache cpu_caches[VOXIA_MAX_CORE]
Definition kalloc.c:46
#define KALLOC_SLAB_ALLOC(BUCKET)
Definition kalloc.c:133
static uintptr_t lock_irqsave(spinlock_t *lk)
Definition kalloc.c:55
static int check_redzone(void *ptr, size_t size)
Definition kalloc.c:72
#define MAX_FREED_VADDRS
Definition kalloc.c:14
static spinlock_t kalloc_global_lock
Definition kalloc.c:48
static void setup_redzone(void *ptr, size_t size)
Definition kalloc.c:66
static void unlock_irqrestore(spinlock_t *lk, uintptr_t flags)
Definition kalloc.c:61
void kfree(void *ptr, size_t size)
void * kalloc(size_t size)
#define KALLOC_REDZONE_SIZE
Definition kalloc.h:10
void kfree2(void *ptr)
#define KALLOC_REDZONE_MAGIC
Definition kalloc.h:11
#define ALIGN_UP(x, align)
Definition memory_utils.h:6
page_t paging_get_highest_page_map(void)
Definition paging.c:463
void vxMmap(page_t page_dir, uint64_t virt, uint64_t phys, uint64_t flags)
Definition paging.c:223
void paging_unmap_fill(page_t page_dir, uint64_t virt, size_t size)
Definition paging.c:451
void vxMultipleMmap(page_t page_dir, uint64_t virt, uint64_t phys, uint64_t size, uint64_t flags)
Definition paging.c:340
#define PAGE_PRESENT
Definition paging.h:34
#define PAGE_USER
Definition paging.h:36
#define PAGE_WRITABLE
Definition paging.h:35
void * phys_base_alloc(uint64_t block)
void vxPhysBaseFree(void *ptr, uint64_t size)
#define BLOCK_SIZE
#define LOG2_WARN(mod, fmt,...)
Definition serial.h:40
void spin_acquire(spinlock_t *lock)
Definition spinlock.c:8
void spin_release(spinlock_t *lock)
Definition spinlock.c:19
void memset(void *ptr, int value, size_t num)
size_t size
Definition kalloc.c:18
uintptr_t addr
Definition kalloc.c:17
void * c_1024
Definition kalloc.c:27
size_t c_256_count
Definition kalloc.c:33
void * c_64
Definition kalloc.c:23
spinlock_t lock
Definition kalloc.c:38
void * c_512
Definition kalloc.c:26
uint8_t _pad[64 -(sizeof(void *) *6+sizeof(size_t) *6+sizeof(spinlock_t)) % 64]
Definition kalloc.c:43
void * c_128
Definition kalloc.c:24
size_t c_64_count
Definition kalloc.c:31
size_t c_1024_count
Definition kalloc.c:35
void * c_256
Definition kalloc.c:25
size_t c_512_count
Definition kalloc.c:34
size_t c_128_count
Definition kalloc.c:32
size_t c_2048_count
Definition kalloc.c:36
void * c_2048
Definition kalloc.c:28
uint32_t magic
Definition kalloc.h:20
uintptr_t phys_address
Definition vm_manager.h:39
#define NULL
Definition type.h:76
unsigned int uint32_t
Definition type.h:19
#define KERNEL_API
Definition type.h:93
unsigned long uintptr_t
Definition type.h:73
unsigned char uint8_t
Definition type.h:7
virtual_memory_t * vma_find(struct virtual_memory_page *page, uintptr_t virt_addr)
Definition vm_manager.c:117
void vma_register(struct virtual_memory_page *page, uintptr_t phys_address, uintptr_t virt_addr, size_t size)
Definition vm_manager.c:101
void vma_unregister(struct virtual_memory_page *page, uintptr_t virt_addr)
Definition vm_manager.c:126
struct virtual_memory_page * get_kernel_vmm_page()
struct virtual_memory virtual_memory_t
Definition vm_manager.h:35
@ KALLOC_BASE_ADDR
Definition vm_manager.h:18
size_t size
Definition vnode.h:3
struct xhci_slot_ctx slot
Definition xhci.hpp:0
uint64_t ptr
Definition xhci.hpp:0