Skip to content

Commit fe477ea

Browse files
dcpleungandrewboie
authored andcommitted
kernel: userspace: aligned memory allocation for dynamic objects
This allows allocating dynamic kernel objects with memory alignment requirements. The first candidate is for thread objects where, on some architectures, it must be aligned for saving/restoring registers. Signed-off-by: Daniel Leung <[email protected]>
1 parent 0c9f969 commit fe477ea

File tree

2 files changed

+92
-13
lines changed

2 files changed

+92
-13
lines changed

include/sys/kobject.h

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,12 +267,37 @@ __syscall void *k_object_alloc(enum k_objects otype);
267267
* and may be freed later by passing the actual object pointer (found
268268
* in the returned z_object's 'name' member) to k_object_free().
269269
*
270+
* @param align Required memory alignment for the allocated object
270271
* @param size Size of the allocated object
271272
* @return NULL on insufficient memory
272273
* @return A pointer to the associated z_object that is installed in the
273274
* kernel object tables
274275
*/
275-
struct z_object *z_dynamic_object_create(size_t size);
276+
struct z_object *z_dynamic_object_aligned_create(size_t align, size_t size);
277+
278+
/**
279+
* Allocate memory and install as a generic kernel object
280+
*
281+
* This is a low-level function to allocate some memory, and register that
282+
* allocated memory in the kernel object lookup tables with type K_OBJ_ANY.
283+
* Initialization state and thread permissions will be cleared. The
284+
* returned z_object's data value will be uninitialized.
285+
*
286+
* Most users will want to use k_object_alloc() instead.
287+
*
288+
* Memory allocated will be drawn from the calling thread's reasource pool
289+
* and may be freed later by passing the actual object pointer (found
290+
* in the returned z_object's 'name' member) to k_object_free().
291+
*
292+
* @param size Size of the allocated object
293+
* @return NULL on insufficient memory
294+
* @return A pointer to the associated z_object that is installed in the
295+
* kernel object tables
296+
*/
297+
static inline struct z_object *z_dynamic_object_create(size_t size)
298+
{
299+
return z_dynamic_object_aligned_create(0, size);
300+
}
276301

277302
/**
278303
* Free a kernel object previously allocated with k_object_alloc()
@@ -293,6 +318,15 @@ static inline void *z_impl_k_object_alloc(enum k_objects otype)
293318
return NULL;
294319
}
295320

321+
static inline struct z_object *z_dynamic_object_aligned_create(size_t align,
322+
size_t size)
323+
{
324+
ARG_UNUSED(align);
325+
ARG_UNUSED(size);
326+
327+
return NULL;
328+
}
329+
296330
static inline struct z_object *z_dynamic_object_create(size_t size)
297331
{
298332
ARG_UNUSED(size);

kernel/userspace.c

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,35 @@ uint8_t *z_priv_stack_find(k_thread_stack_t *stack)
110110
#endif /* CONFIG_GEN_PRIV_STACKS */
111111

112112
#ifdef CONFIG_DYNAMIC_OBJECTS
113+
114+
/*
115+
* Note that dyn_obj->data is where the kernel object resides
116+
* so it is the one that actually needs to be aligned.
117+
* Due to the need to get the the fields inside struct dyn_obj
118+
* from kernel object pointers (i.e. from data[]), the offset
119+
* from data[] needs to be fixed at build time. Therefore,
120+
* data[] is declared with __aligned(), such that when dyn_obj
121+
* is allocated with alignment, data[] is also aligned.
122+
* Due to this requirement, data[] needs to be aligned with
123+
* the maximum alignment needed for all kernel objects
124+
* (hence the following DYN_OBJ_DATA_ALIGN).
125+
*/
126+
#ifdef ARCH_DYMANIC_OBJ_K_THREAD_ALIGNMENT
127+
#define DYN_OBJ_DATA_ALIGN_K_THREAD (ARCH_DYMANIC_OBJ_K_THREAD_ALIGNMENT)
128+
#else
129+
#define DYN_OBJ_DATA_ALIGN_K_THREAD (sizeof(void *))
130+
#endif
131+
132+
#define DYN_OBJ_DATA_ALIGN \
133+
MAX(DYN_OBJ_DATA_ALIGN_K_THREAD, (sizeof(void *)))
134+
113135
struct dyn_obj {
114136
struct z_object kobj;
115137
sys_dnode_t obj_list;
116138
struct rbnode node; /* must be immediately before data member */
117-
uint8_t data[]; /* The object itself */
139+
140+
/* The object itself */
141+
uint8_t data[] __aligned(DYN_OBJ_DATA_ALIGN_K_THREAD);
118142
};
119143

120144
extern struct z_object *z_object_gperf_find(const void *obj);
@@ -156,6 +180,26 @@ static size_t obj_size_get(enum k_objects otype)
156180
return ret;
157181
}
158182

183+
static size_t obj_align_get(enum k_objects otype)
184+
{
185+
size_t ret;
186+
187+
switch (otype) {
188+
case K_OBJ_THREAD:
189+
#ifdef ARCH_DYMANIC_OBJ_K_THREAD_ALIGNMENT
190+
ret = ARCH_DYMANIC_OBJ_K_THREAD_ALIGNMENT;
191+
#else
192+
ret = sizeof(void *);
193+
#endif
194+
break;
195+
default:
196+
ret = sizeof(void *);
197+
break;
198+
}
199+
200+
return ret;
201+
}
202+
159203
static bool node_lessthan(struct rbnode *a, struct rbnode *b)
160204
{
161205
return a < b;
@@ -166,6 +210,13 @@ static inline struct dyn_obj *node_to_dyn_obj(struct rbnode *node)
166210
return CONTAINER_OF(node, struct dyn_obj, node);
167211
}
168212

213+
static inline struct rbnode *dyn_obj_to_node(void *obj)
214+
{
215+
struct dyn_obj *dobj = CONTAINER_OF(obj, struct dyn_obj, data);
216+
217+
return &dobj->node;
218+
}
219+
169220
static struct dyn_obj *dyn_object_find(void *obj)
170221
{
171222
struct rbnode *node;
@@ -176,7 +227,7 @@ static struct dyn_obj *dyn_object_find(void *obj)
176227
* so just a little arithmetic is necessary to locate the
177228
* corresponding struct rbnode
178229
*/
179-
node = (struct rbnode *)((char *)obj - sizeof(struct rbnode));
230+
node = dyn_obj_to_node(obj);
180231

181232
k_spinlock_key_t key = k_spin_lock(&lists_lock);
182233
if (rb_contains(&obj_rb_tree, node)) {
@@ -252,11 +303,11 @@ static void thread_idx_free(uintptr_t tidx)
252303
sys_bitfield_set_bit((mem_addr_t)_thread_idx_map, tidx);
253304
}
254305

255-
struct z_object *z_dynamic_object_create(size_t size)
306+
struct z_object *z_dynamic_object_aligned_create(size_t align, size_t size)
256307
{
257308
struct dyn_obj *dyn;
258309

259-
dyn = z_thread_malloc(sizeof(*dyn) + size);
310+
dyn = z_thread_aligned_alloc(align, sizeof(*dyn) + size);
260311
if (dyn == NULL) {
261312
LOG_ERR("could not allocate kernel object, out of memory");
262313
return NULL;
@@ -288,13 +339,6 @@ void *z_impl_k_object_alloc(enum k_objects otype)
288339

289340
switch (otype) {
290341
case K_OBJ_THREAD:
291-
/* aligned allocator required for X86 and X86_64 */
292-
if (IS_ENABLED(CONFIG_X86) || IS_ENABLED(CONFIG_X86_64)) {
293-
LOG_ERR("object type '%s' forbidden on x86 and x86_64",
294-
otype_to_str(otype));
295-
return NULL;
296-
}
297-
298342
if (!thread_idx_alloc(&tidx)) {
299343
LOG_ERR("out of free thread indexes");
300344
return NULL;
@@ -313,7 +357,8 @@ void *z_impl_k_object_alloc(enum k_objects otype)
313357
break;
314358
}
315359

316-
zo = z_dynamic_object_create(obj_size_get(otype));
360+
zo = z_dynamic_object_aligned_create(obj_align_get(otype),
361+
obj_size_get(otype));
317362
if (zo == NULL) {
318363
return NULL;
319364
}

0 commit comments

Comments
 (0)