1 /*
2 * Copyright (c) 2017 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <kernel.h>
8 #include <string.h>
9 #include <sys/math_extras.h>
10 #include <sys/util.h>
11
z_heap_aligned_alloc(struct k_heap * heap,size_t align,size_t size)12 static void *z_heap_aligned_alloc(struct k_heap *heap, size_t align, size_t size)
13 {
14 void *mem;
15 struct k_heap **heap_ref;
16 size_t __align;
17
18 /*
19 * Adjust the size to make room for our heap reference.
20 * Merge a rewind bit with align value (see sys_heap_aligned_alloc()).
21 * This allows for storing the heap pointer right below the aligned
22 * boundary without wasting any memory.
23 */
24 if (size_add_overflow(size, sizeof(heap_ref), &size)) {
25 return NULL;
26 }
27 __align = align | sizeof(heap_ref);
28
29 mem = k_heap_aligned_alloc(heap, __align, size, K_NO_WAIT);
30 if (mem == NULL) {
31 return NULL;
32 }
33
34 heap_ref = mem;
35 *heap_ref = heap;
36 mem = ++heap_ref;
37 __ASSERT(align == 0 || ((uintptr_t)mem & (align - 1)) == 0,
38 "misaligned memory at %p (align = %zu)", mem, align);
39
40 return mem;
41 }
42
k_free(void * ptr)43 void k_free(void *ptr)
44 {
45 struct k_heap **heap_ref;
46
47 if (ptr != NULL) {
48 heap_ref = ptr;
49 ptr = --heap_ref;
50
51 SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_heap_sys, k_free, *heap_ref);
52
53 k_heap_free(*heap_ref, ptr);
54
55 SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_heap_sys, k_free, *heap_ref);
56 }
57 }
58
59 #if (CONFIG_HEAP_MEM_POOL_SIZE > 0)
60
61 K_HEAP_DEFINE(_system_heap, CONFIG_HEAP_MEM_POOL_SIZE);
62 #define _SYSTEM_HEAP (&_system_heap)
63
k_aligned_alloc(size_t align,size_t size)64 void *k_aligned_alloc(size_t align, size_t size)
65 {
66 __ASSERT(align / sizeof(void *) >= 1
67 && (align % sizeof(void *)) == 0,
68 "align must be a multiple of sizeof(void *)");
69
70 __ASSERT((align & (align - 1)) == 0,
71 "align must be a power of 2");
72
73 SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_heap_sys, k_aligned_alloc, _SYSTEM_HEAP);
74
75 void *ret = z_heap_aligned_alloc(_SYSTEM_HEAP, align, size);
76
77 SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_heap_sys, k_aligned_alloc, _SYSTEM_HEAP, ret);
78
79 return ret;
80 }
81
k_malloc(size_t size)82 void *k_malloc(size_t size)
83 {
84 SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_heap_sys, k_malloc, _SYSTEM_HEAP);
85
86 void *ret = k_aligned_alloc(sizeof(void *), size);
87
88 SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_heap_sys, k_malloc, _SYSTEM_HEAP, ret);
89
90 return ret;
91 }
92
k_calloc(size_t nmemb,size_t size)93 void *k_calloc(size_t nmemb, size_t size)
94 {
95 void *ret;
96 size_t bounds;
97
98 SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_heap_sys, k_calloc, _SYSTEM_HEAP);
99
100 if (size_mul_overflow(nmemb, size, &bounds)) {
101 SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_heap_sys, k_calloc, _SYSTEM_HEAP, NULL);
102
103 return NULL;
104 }
105
106 ret = k_malloc(bounds);
107 if (ret != NULL) {
108 (void)memset(ret, 0, bounds);
109 }
110
111 SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_heap_sys, k_calloc, _SYSTEM_HEAP, ret);
112
113 return ret;
114 }
115
k_thread_system_pool_assign(struct k_thread * thread)116 void k_thread_system_pool_assign(struct k_thread *thread)
117 {
118 thread->resource_pool = _SYSTEM_HEAP;
119 }
120 #else
121 #define _SYSTEM_HEAP NULL
122 #endif
123
z_thread_aligned_alloc(size_t align,size_t size)124 void *z_thread_aligned_alloc(size_t align, size_t size)
125 {
126 void *ret;
127 struct k_heap *heap;
128
129 if (k_is_in_isr()) {
130 heap = _SYSTEM_HEAP;
131 } else {
132 heap = _current->resource_pool;
133 }
134
135 if (heap != NULL) {
136 ret = z_heap_aligned_alloc(heap, align, size);
137 } else {
138 ret = NULL;
139 }
140
141 return ret;
142 }
143