1/* @title: Allocator Parameters */
2#pragma once
3#include <bitflag.h>
4#include <compiler/core.h>
5#include <compiler/wrapper.h>
6#include <console/printf.h>
7#include <log.h>
8#include <mem/alloc_api_internal.h>
9#include <stdbool.h>
10#include <stddef.h>
11#include <stdint.h>
12
13/*
14 * TL;DR:
15 *
16 * FLAGS: TELL THE ALLOCATOR WHAT
17 * KIND OF MEMORY YOU WANT
18 *
19 * BEHAVIORS: TELL THE ALLOCATOR WHAT IT IS ALLOWED
20 * TO DO TO GET THAT MEMORY
21 *
22 * PRIORITIES: TELL THE ALLOCATOR HOW MUCH YOU
23 * WANT YOUR ALLOCATION TO SUCCEED
24 */
25
26/* ─────────────────────────── ALLOC FLAGS ─────────────────────────── */
27
28#define ALLOC_LOCALITY_SHIFT 25
29#define ALLOC_CLASS_SHIFT 28
30#define ALLOC_CLASS_MASK 0xF
31
32/* The larger the locality, the closer it must be */
33#define ALLOC_LOCALITY_MAX 7
34#define ALLOC_LOCALITY_MIN 0
35#define ALLOC_LOCALITY_MASK 0x7
36
37#define ALLOC_LOCALITY_FROM_FLAGS(flags) \
38 (((flags) >> ALLOC_LOCALITY_SHIFT) & ALLOC_LOCALITY_MASK)
39
40#define ALLOC_LOCALITY_TO_FLAGS(locality) \
41 (((locality) & ALLOC_LOCALITY_MASK) << ALLOC_LOCALITY_SHIFT)
42
43#define ALLOC_FLAG_TEST(flags, mask) (flags & mask)
44#define ALLOC_FLAG_CLASS(flags) \
45 ((flags >> ALLOC_CLASS_SHIFT) & ALLOC_CLASS_MASK)
46
47#define ALLOC_FLAG_EX_JOIN(subsys, flag) ALLOC_FLAG_EX_##subsys##_##flag
48#define ALLOC_FLAG_EX(subsys, flag) ALLOC_FLAG_EX_JOIN(subsys, flag)
49
50/* alloc_flags: 32 bit bitflags
51 *
52 * ┌──────────────────────────────────────────────────────┐
53 * Bits │ 31..28 27..24 23..20 19..16 15..12 11..8 7..4 3..0 │
54 * Use │ %%%% ###* AAAA AAAA **** **** ***Z MPFC │
55 * └──────────────────────────────────────────────────────┘
56 *
57 * C - "Prefer cache alignment"
58 *
59 * F - "Allow flexible NUMA locality"
60 *
61 * P - "Allow memory to be pageable"
62 *
63 * M - "Allow memory to be movable"
64 *
65 * Z - Zero on alloc, memory is zeroed
66 *
67 * ### - Locality bits
68 *
69 * %%%% - Allocation class bits
70 *
71 * A - Unused (available)
72 * * - Unused (unavailable)
73 *
74 */
75
76/* Flags define properties regarding
77 * the memory the allocator will return */
78enum alloc_flags : uint32_t {
79 /* Cache alignment */
80 ALLOC_FLAG_PREFER_CACHE_ALIGNED = (1 << 0),
81 ALLOC_FLAG_NO_CACHE_ALIGN = 0,
82
83 /* Flexible locality */
84 ALLOC_FLAG_FLEXIBLE_LOCALITY = (1 << 1),
85 ALLOC_FLAG_STRICT_LOCALITY = 0,
86
87 /* Pageable */
88 ALLOC_FLAG_PAGEABLE = (1 << 2),
89 ALLOC_FLAG_NONPAGEABLE = 0,
90
91 /* Movable */
92 ALLOC_FLAG_MOVABLE = (1 << 3),
93 ALLOC_FLAG_NONMOVABLE = 0,
94
95 /* Zero on alloc */
96 ALLOC_FLAG_ZERO_ON_ALLOC = (1 << 4),
97 ALLOC_FLAG_NON_ZERO = 0,
98
99 /* Allocation classes */
100 ALLOC_FLAG_CLASS_DEFAULT = (1 << ALLOC_CLASS_SHIFT),
101 ALLOC_FLAG_CLASS_INTERLEAVED = (2 << ALLOC_CLASS_SHIFT),
102 ALLOC_FLAG_CLASS_HIGH_BANDWIDTH = (3 << ALLOC_CLASS_SHIFT),
103};
104
105/* Bits 16..23 are available, this gives the 0-indexed Nth available bit */
106BITFLAG_AVAILABLE_DECLARE(enum alloc_flags, ALLOC_FLAG, BITFLAG_RANGE(16, 23));
107#define ALLOC_FLAG_AVAIL_BIT(n) BITFLAG_AVAIL_BIT(ALLOC_FLAG, n)
108
109struct alloc_flag_ex_desc {
110 const char *subsystem;
111 const char *flag_name;
112 enum alloc_flags flag; /* Just that flag */
113};
114
115#ifdef DEBUG_ALLOC_PARAM
116#define ALLOC_FLAG_EX_REGISTER(subsys, name) \
117 static LINKER_SECTION_OBJECT(struct alloc_flag_ex_desc, \
118 alloc_flag_ex_descs) \
119 __alloc_flag_desc_##subsys##_##name = { \
120 .subsystem = #subsys, \
121 .flag_name = #name, \
122 .flag = ALLOC_FLAG_EX(subsys, name)}
123#else
124#define ALLOC_FLAG_EX_REGISTER(subsys, name)
125#endif
126
127/* ────────────── ALLOC FLAG WRAPPERS ────────────── */
128
129#define ALLOC_FLAGS_NONE 0
130
131/* Bits 6..15 and 24 */
132#define ALLOC_FLAGS_UNAVAILABLE_BITS ((1 << 24) | (0x3FFU << 6))
133
134#define ALLOC_FLAGS_DEFAULT \
135 (ALLOC_FLAG_CLASS_DEFAULT | ALLOC_FLAG_FLEXIBLE_LOCALITY | \
136 ALLOC_FLAG_NONMOVABLE | ALLOC_FLAG_NONPAGEABLE | \
137 ALLOC_FLAG_NO_CACHE_ALIGN | ALLOC_LOCALITY_TO_FLAGS(ALLOC_LOCALITY_MIN))
138#define ALLOC_FLAGS_ZERO (ALLOC_FLAGS_DEFAULT | ALLOC_FLAG_ZERO_ON_ALLOC)
139#define ALLOC_ZERO .flags = ALLOC_FLAGS_ZERO
140
141#define ALLOC_FLAGS_PAGEABLE \
142 ALLOC_FLAG_PAGEABLE | ALLOC_FLAG_CLASS_DEFAULT | \
143 ALLOC_FLAG_FLEXIBLE_LOCALITY
144
145#define ALLOC_FLAGS_VALID(flags) (((flags) & ALLOC_FLAGS_UNAVAILABLE_BITS) == 0)
146
147static inline bool alloc_flags_valid(enum alloc_flags flags) {
148 return ALLOC_FLAGS_VALID(flags);
149}
150
151/* ─────────────────────────── ALLOC BEHAVIORS ─────────────────────────── */
152
153#define ALLOC_BEHAVIOR_FLAG_SHIFT 4
154#define ALLOC_BEHAVIOR_MASK (0xF)
155#define ALLOC_BEHAVIOR_AVAILABLE_SHIFT 12
156
157/* Bits 12..15 are available, this gives the 0-indexed Nth available bit */
158#define ALLOC_BEHAVIOR_AVAIL_BIT(n) (1 << (ALLOC_BEHAVIOR_AVAILABLE_SHIFT + n))
159
160/* alloc_behavior: 16 bits for a behavior and flags
161 *
162 * ┌───────────────────────────┐
163 * Bits │ 15..12 11..8 7..4 3..0 │
164 * Use │ AAAA **** **MF %%%% │
165 * └───────────────────────────┘
166 *
167 * %%%% - Allocation behavior bits
168 *
169 * F - "Prefer fast allocation" -- may fail fast/early
170 * M - Perform "minimal" allocation -- e.g. do not bother with
171 * new slab cache construction
172 * A - Unused (Available)
173 * * - Unused (Unavailable)
174 *
175 */
176
177/* Behaviors define what the allocator is
178 * allowed to do in a given invocation. */
179
180/* Allocation behavior restricts flags. If non-faulting behaviors
181 * are selected, then the allocator cannot allocate pageable memory */
182enum alloc_behavior : uint16_t {
183 ALLOC_BEHAVIOR_NORMAL,
184 ALLOC_BEHAVIOR_NMI_SAFE,
185 ALLOC_BEHAVIOR_IRQ_SAFE,
186 ALLOC_BEHAVIOR_FAULT_SAFE,
187 ALLOC_BEHAVIOR_NO_BLOCK,
188 ALLOC_BEHAVIOR_NO_APC,
189 ALLOC_BEHAVIOR_MAX,
190 ALLOC_BEHAVIOR_FLAG_FAST = 1 << ALLOC_BEHAVIOR_FLAG_SHIFT,
191
192 /* Used by various allocators to prevent
193 * recursion in things they interact with */
194 ALLOC_BEHAVIOR_FLAG_MINIMAL = 1 << (ALLOC_BEHAVIOR_FLAG_SHIFT + 1),
195
196};
197#define ALLOC_BEHAVIOR_DEFAULT ALLOC_BEHAVIOR_NORMAL
198
199/* ─────────────────────────── ALLOC PRIORITIES ─────────────────────────── */
200
201#define ALLOC_PRIORITY_STEP 8
202#define ALLOC_PRIORITY_HALFSTEP (ALLOC_PRIORITY_STEP / 2)
203#define ALLOC_PRIORITY_ABOVE(p) ((p) + ALLOC_PRIORITY_HALFSTEP)
204#define ALLOC_PRIORITY_BELOW(p) ((p) - ALLOC_PRIORITY_HALFSTEP)
205
206/* alloc_priority: 16 bit bitflags
207 *
208 * Do note that with allocation priorities, the default ones given are
209 * in increments of 8. This gives allocators room to interpret the priorities
210 * as a continuous curve instead of discrete steps.
211 *
212 * ┌──────────────────────────┐
213 * Bits │ 15..12 11..8 7..4 3..0 │
214 * Use │ AAAA AAAA %%%% %%%% │
215 * └──────────────────────────┘
216 *
217 * %%%% - Priority
218 * A - Unused (available)
219 * * - Unused (unavailable)
220 *
221 */
222enum alloc_priority : uint16_t {
223 ALLOC_PRIORITY_MIN = 0,
224 ALLOC_PRIORITY_LOW = 8,
225 ALLOC_PRIORITY_NORMAL = 16,
226 ALLOC_PRIORITY_HIGH = 24,
227 ALLOC_PRIORITY_CRITICAL = 32,
228 ALLOC_PRIORITY_MAX = ALLOC_PRIORITY_CRITICAL,
229};
230static_assert(ALLOC_PRIORITY_MAX < 256);
231
232#define ALLOC_PRIORITY_BITMAP_DECLARE(name) \
233 BITMAP_DECLARE(name, ALLOC_PRIORITY_MAX)
234
235/* TODO: */
236#define ALLOC_PRIORITY_DEFAULT ALLOC_PRIORITY_MIN
237
238struct alloc_params {
239 enum alloc_flags flags;
240 enum alloc_behavior behavior;
241 enum alloc_priority priority;
242};
243
244struct alloc_capabilities {
245 enum alloc_flags flags; /* A bitmask */
246 enum alloc_behavior behaviors; /* Bitmask 1 << base */
247 enum alloc_behavior behavior_flags; /* Bitmask for remaining flags */
248 enum alloc_priority priorities; /* Supported priorities, 1 << base bitmap */
249};
250
251#define ALLOC_FLAG_EX_DESC_MAX 8
252size_t
253alloc_flag_ex_get_desc(enum alloc_flags flag,
254 struct alloc_flag_ex_desc out[ALLOC_FLAG_EX_DESC_MAX]);
255
256#define ALLOC_BEHAVIOR_BASE(raw) ((raw) & ALLOC_BEHAVIOR_MASK)
257
258#define ALLOC_BEHAVIOR_MAY_FAULT(raw) \
259 (ALLOC_BEHAVIOR_BASE(raw) != ALLOC_BEHAVIOR_IRQ_SAFE && \
260 ALLOC_BEHAVIOR_BASE(raw) != ALLOC_BEHAVIOR_FAULT_SAFE)
261
262#define ALLOC_BEHAVIOR_MAY_BLOCK(raw) \
263 (ALLOC_BEHAVIOR_BASE(raw) != ALLOC_BEHAVIOR_IRQ_SAFE && \
264 ALLOC_BEHAVIOR_BASE(raw) != ALLOC_BEHAVIOR_NO_BLOCK)
265
266#define ALLOC_BEHAVIOR_IS_ISR_SAFE(raw) \
267 (ALLOC_BEHAVIOR_BASE(raw) == ALLOC_BEHAVIOR_IRQ_SAFE || \
268 ALLOC_BEHAVIOR_BASE(raw) == ALLOC_BEHAVIOR_NMI_SAFE)
269
270#define ALLOC_FLAGS_CAN_FAULT(flags) \
271 (((flags) & (ALLOC_FLAG_PAGEABLE | ALLOC_FLAG_MOVABLE)) != 0)
272
273/* Check that flags and behavior are in agreement */
274#define ALLOC_FLAGS_BEHAVIOR_VALID(flags, behavior) \
275 (!(!ALLOC_BEHAVIOR_MAY_FAULT(behavior) && ALLOC_FLAGS_CAN_FAULT(flags)) && \
276 !(ALLOC_BEHAVIOR_IS_ISR_SAFE(behavior) && \
277 ((flags) & ALLOC_FLAG_PAGEABLE) != 0))
278
279static inline enum alloc_behavior alloc_behavior_base(enum alloc_behavior raw) {
280 return ALLOC_BEHAVIOR_BASE(raw);
281}
282
283static inline bool alloc_behavior_may_fault(enum alloc_behavior raw) {
284 return ALLOC_BEHAVIOR_MAY_FAULT(raw);
285}
286
287static inline bool alloc_behavior_may_block(enum alloc_behavior raw) {
288 return ALLOC_BEHAVIOR_MAY_BLOCK(raw);
289}
290
291static inline bool alloc_behavior_is_isr_safe(enum alloc_behavior raw) {
292 return ALLOC_BEHAVIOR_IS_ISR_SAFE(raw);
293}
294
295/* Fast hint: should this allocation prefer short paths? */
296static inline bool alloc_behavior_is_fast(enum alloc_behavior raw) {
297 return (raw & ALLOC_BEHAVIOR_FLAG_FAST);
298}
299
300static inline bool alloc_flag_behavior_verify(struct alloc_params params) {
301 return ALLOC_FLAGS_BEHAVIOR_VALID(params.flags, params.behavior);
302}
303
304/* TODO: Rework these into capabilities */
305static inline void alloc_request_sanitize(struct alloc_params *params) {
306 if (!alloc_flag_behavior_verify(params: *params)) {
307 if (alloc_behavior_is_isr_safe(raw: params->behavior) ||
308 !alloc_behavior_may_fault(raw: params->behavior)) {
309 params->flags &= ~(ALLOC_FLAG_PAGEABLE | ALLOC_FLAG_MOVABLE);
310 params->flags |= ALLOC_FLAG_NONPAGEABLE;
311 }
312 }
313}
314