regression: elf loading
[lunaix-os.git] / lunaix-os / kernel / mm / cake.c
1 /**
2  * @file cake.c
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. :)
6  * @version 0.1
7  * @date 2022-07-02
8  *
9  * @copyright Copyright (c) 2022
10  *
11  */
12
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>
19
20 LOG_MODULE("CAKE")
21
22 #define CACHE_LINE_SIZE 128
23
24 struct cake_pile master_pile;
25
26 struct llist_header piles = { .next = &piles, .prev = &piles };
27
28 void*
29 __alloc_cake(unsigned int cake_pg)
30 {
31     uintptr_t pa = pmm_alloc_cpage(KERNEL_PID, cake_pg, 0);
32     if (!pa) {
33         return NULL;
34     }
35     return vmm_vmap(pa, cake_pg * PG_SIZE, PG_PREM_RW);
36 }
37
38 struct cake_s*
39 __new_cake(struct cake_pile* pile)
40 {
41     struct cake_s* cake = __alloc_cake(pile->pg_per_cake);
42
43     if (!cake) {
44         return NULL;
45     }
46
47     int max_piece = pile->pieces_per_cake;
48
49     cake->first_piece = (void*)((uintptr_t)cake + pile->offset);
50     cake->next_free = 0;
51     pile->cakes_count++;
52
53     piece_index_t* free_list = cake->free_list;
54     for (size_t i = 0; i < max_piece - 1; i++) {
55         free_list[i] = i + 1;
56     }
57     free_list[max_piece - 1] = EO_FREE_PIECE;
58
59     llist_append(&pile->free, &cake->cakes);
60
61     return cake;
62 }
63
64 void
65 __init_pile(struct cake_pile* pile,
66             char* name,
67             unsigned int piece_size,
68             unsigned int pg_per_cake,
69             int options)
70 {
71     if (!pile) {
72         return;
73     }
74
75     unsigned int offset = sizeof(long);
76
77     // 默认每块儿蛋糕对齐到地址总线宽度
78     if ((options & PILE_CACHELINE)) {
79         // 对齐到128字节缓存行大小,主要用于DMA
80         offset = CACHE_LINE_SIZE;
81     }
82
83     piece_size = ROUNDUP(piece_size, offset);
84     *pile = (struct cake_pile){ .piece_size = piece_size,
85                                 .cakes_count = 1,
86                                 .pieces_per_cake =
87                                   (pg_per_cake * PG_SIZE) /
88                                   (piece_size + sizeof(piece_index_t)),
89                                 .pg_per_cake = pg_per_cake };
90
91     unsigned int free_list_size = pile->pieces_per_cake * sizeof(piece_index_t);
92
93     pile->offset = ROUNDUP(sizeof(struct cake_s) + free_list_size, offset);
94     pile->pieces_per_cake -= ICEIL((pile->offset - free_list_size), piece_size);
95
96     strncpy(pile->pile_name, name, PILE_NAME_MAXLEN);
97
98     llist_init_head(&pile->free);
99     llist_init_head(&pile->full);
100     llist_init_head(&pile->partial);
101     llist_append(&piles, &pile->piles);
102 }
103
104 void
105 cake_init()
106 {
107     __init_pile(&master_pile, "pinkamina", sizeof(master_pile), 1, 0);
108 }
109
110 struct cake_pile*
111 cake_new_pile(char* name,
112               unsigned int piece_size,
113               unsigned int pg_per_cake,
114               int options)
115 {
116     struct cake_pile* pile = (struct cake_pile*)cake_grab(&master_pile);
117
118     __init_pile(pile, name, piece_size, pg_per_cake, options);
119
120     return pile;
121 }
122
123 void
124 cake_set_constructor(struct cake_pile* pile, pile_cb ctor)
125 {
126     pile->ctor = ctor;
127 }
128
129 void*
130 cake_grab(struct cake_pile* pile)
131 {
132     struct cake_s *pos, *n;
133     if (!llist_empty(&pile->partial)) {
134         pos = list_entry(pile->partial.next, typeof(*pos), cakes);
135     } else if (llist_empty(&pile->free)) {
136         pos = __new_cake(pile);
137     } else {
138         pos = list_entry(pile->free.next, typeof(*pos), cakes);
139     }
140
141     if (!pos)
142         return NULL;
143
144     piece_index_t found_index = pos->next_free;
145     pos->next_free = pos->free_list[found_index];
146     pos->used_pieces++;
147     pile->alloced_pieces++;
148
149     llist_delete(&pos->cakes);
150     if (pos->next_free == EO_FREE_PIECE) {
151         llist_append(&pile->full, &pos->cakes);
152     } else {
153         llist_append(&pile->partial, &pos->cakes);
154     }
155
156     void* ptr =
157       (void*)((uintptr_t)pos->first_piece + found_index * pile->piece_size);
158
159     if (pile->ctor) {
160         pile->ctor(pile, ptr);
161     }
162
163     return ptr;
164 }
165
166 int
167 cake_release(struct cake_pile* pile, void* area)
168 {
169     piece_index_t piece_index;
170     struct cake_s *pos, *n;
171     struct llist_header* hdrs[2] = { &pile->full, &pile->partial };
172
173     for (size_t i = 0; i < 2; i++) {
174         llist_for_each(pos, n, hdrs[i], cakes)
175         {
176             if (pos->first_piece > area) {
177                 continue;
178             }
179             piece_index =
180               (uintptr_t)(area - pos->first_piece) / pile->piece_size;
181             if (piece_index < pile->pieces_per_cake) {
182                 goto found;
183             }
184         }
185     }
186
187     return 0;
188
189 found:
190     pos->free_list[piece_index] = pos->next_free;
191     pos->next_free = piece_index;
192     pos->used_pieces--;
193     pile->alloced_pieces--;
194
195     llist_delete(&pos->cakes);
196     if (!pos->used_pieces) {
197         llist_append(&pile->free, &pos->cakes);
198     } else {
199         llist_append(&pile->partial, &pos->cakes);
200     }
201
202     return 1;
203 }
204
205 void
206 cake_ctor_zeroing(struct cake_pile* pile, void* piece)
207 {
208     memset(piece, 0, pile->piece_size);
209 }