3 * @author Lunaixsky (zelong56@gmail.com)
4 * @brief A simplified cake(slab) allocator.
5 * P.s. I call it cake as slab sounds more 'ridge' to me. :)
9 * @copyright Copyright (c) 2022
13 #include <klibc/string.h>
14 #include <lunaix/mm/cake.h>
15 #include <lunaix/mm/pmm.h>
16 #include <lunaix/mm/vmm.h>
17 #include <lunaix/spike.h>
18 #include <lunaix/syslog.h>
22 #define CACHE_LINE_SIZE 128
24 struct cake_pile master_pile;
26 struct llist_header piles = { .next = &piles, .prev = &piles };
29 __alloc_cake(unsigned int cake_pg)
31 uintptr_t pa = pmm_alloc_cpage(KERNEL_PID, cake_pg, 0);
32 return vmm_vmap(pa, cake_pg * PG_SIZE, PG_PREM_RW);
36 __new_cake(struct cake_pile* pile)
38 struct cake_s* cake = __alloc_cake(pile->pg_per_cake);
40 int max_piece = pile->pieces_per_cake;
42 cake->first_piece = (void*)((uintptr_t)cake + pile->offset);
45 piece_index_t* free_list = &cake->free_list;
46 for (size_t i = 0; i < max_piece - 1; i++) {
49 free_list[max_piece - 1] = EO_FREE_PIECE;
51 llist_append(&pile->free, &cake->cakes);
57 __init_pile(struct cake_pile* pile,
59 unsigned int piece_size,
60 unsigned int pg_per_cake,
63 unsigned int offset = sizeof(long);
66 if ((options & PILE_CACHELINE)) {
67 // 对齐到128字节缓存行大小,主要用于DMA
68 offset = CACHE_LINE_SIZE;
71 piece_size = ROUNDUP(piece_size, offset);
72 *pile = (struct cake_pile){ .piece_size = piece_size,
75 (pg_per_cake * PG_SIZE) /
76 (piece_size + sizeof(piece_index_t)),
77 .pg_per_cake = pg_per_cake };
79 unsigned int free_list_size = pile->pieces_per_cake * sizeof(piece_index_t);
81 pile->offset = ROUNDUP(sizeof(struct cake_s) + free_list_size, offset);
82 pile->pieces_per_cake -= ICEIL((pile->offset - free_list_size), piece_size);
84 strncpy(&pile->pile_name, name, PILE_NAME_MAXLEN);
86 llist_init_head(&pile->free);
87 llist_init_head(&pile->full);
88 llist_init_head(&pile->partial);
89 llist_append(&piles, &pile->piles);
95 __init_pile(&master_pile, "pinkamina", sizeof(master_pile), 1, 0);
99 cake_new_pile(char* name,
100 unsigned int piece_size,
101 unsigned int pg_per_cake,
104 struct cake_pile* pile = (struct cake_pile*)cake_grab(&master_pile);
106 __init_pile(pile, name, piece_size, pg_per_cake, options);
112 cake_grab(struct cake_pile* pile)
114 struct cake_s *pos, *n;
115 if (!llist_empty(&pile->partial)) {
116 pos = list_entry(pile->partial.next, typeof(*pos), cakes);
117 } else if (llist_empty(&pile->free)) {
118 pos = __new_cake(pile);
120 pos = list_entry(pile->free.next, typeof(*pos), cakes);
123 piece_index_t found_index = pos->next_free;
124 pos->next_free = pos->free_list[found_index];
126 pile->alloced_pieces++;
128 llist_delete(&pos->cakes);
129 if (pos->next_free == EO_FREE_PIECE) {
130 llist_append(&pile->full, &pos->cakes);
132 llist_append(&pile->partial, &pos->cakes);
135 return (void*)((uintptr_t)pos->first_piece +
136 found_index * pile->piece_size);
140 cake_release(struct cake_pile* pile, void* area)
142 piece_index_t piece_index;
143 struct cake_s *pos, *n;
144 struct llist_header* hdrs[2] = { &pile->full, &pile->partial };
146 for (size_t i = 0; i < 2; i++) {
147 llist_for_each(pos, n, hdrs[i], cakes)
149 if (pos->first_piece > area) {
153 (uintptr_t)(area - pos->first_piece) / pile->piece_size;
154 if (piece_index < pile->pieces_per_cake) {
163 pos->free_list[piece_index] = pos->next_free;
164 pos->next_free = piece_index;
166 pile->alloced_pieces--;
169 if (!pos->used_pieces) {
170 llist_append(&pile->free, &pos->cakes);
172 llist_append(&pile->partial, &pos->cakes);
181 kprintf(KDEBUG "<name> <cake> <pg/c> <p/c> <alloced>\n");
183 struct cake_pile *pos, *n;
184 llist_for_each(pos, n, &piles, piles)
186 kprintf("%s %d %d %d %d\n",
190 pos->pieces_per_cake,
191 pos->alloced_pieces);