1 /*
2  * Copyright (c) 2017 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <string.h>
9 #include <zephyr/sys/math_extras.h>
10 #include <zephyr/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 		--heap_ref;
50 		ptr = heap_ref;
51 
52 		SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_heap_sys, k_free, *heap_ref, heap_ref);
53 
54 		k_heap_free(*heap_ref, ptr);
55 
56 		SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_heap_sys, k_free, *heap_ref, heap_ref);
57 	}
58 }
59 
60 #if (K_HEAP_MEM_POOL_SIZE > 0)
61 
62 K_HEAP_DEFINE(_system_heap, K_HEAP_MEM_POOL_SIZE);
63 #define _SYSTEM_HEAP (&_system_heap)
64 
k_aligned_alloc(size_t align,size_t size)65 void *k_aligned_alloc(size_t align, size_t size)
66 {
67 	__ASSERT(align / sizeof(void *) >= 1
68 		&& (align % sizeof(void *)) == 0,
69 		"align must be a multiple of sizeof(void *)");
70 
71 	__ASSERT((align & (align - 1)) == 0,
72 		"align must be a power of 2");
73 
74 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_heap_sys, k_aligned_alloc, _SYSTEM_HEAP);
75 
76 	void *ret = z_heap_aligned_alloc(_SYSTEM_HEAP, align, size);
77 
78 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_heap_sys, k_aligned_alloc, _SYSTEM_HEAP, ret);
79 
80 	return ret;
81 }
82 
k_malloc(size_t size)83 void *k_malloc(size_t size)
84 {
85 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_heap_sys, k_malloc, _SYSTEM_HEAP);
86 
87 	void *ret = k_aligned_alloc(sizeof(void *), size);
88 
89 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_heap_sys, k_malloc, _SYSTEM_HEAP, ret);
90 
91 	return ret;
92 }
93 
k_calloc(size_t nmemb,size_t size)94 void *k_calloc(size_t nmemb, size_t size)
95 {
96 	void *ret;
97 	size_t bounds;
98 
99 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_heap_sys, k_calloc, _SYSTEM_HEAP);
100 
101 	if (size_mul_overflow(nmemb, size, &bounds)) {
102 		SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_heap_sys, k_calloc, _SYSTEM_HEAP, NULL);
103 
104 		return NULL;
105 	}
106 
107 	ret = k_malloc(bounds);
108 	if (ret != NULL) {
109 		(void)memset(ret, 0, bounds);
110 	}
111 
112 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_heap_sys, k_calloc, _SYSTEM_HEAP, ret);
113 
114 	return ret;
115 }
116 
k_realloc(void * ptr,size_t size)117 void *k_realloc(void *ptr, size_t size)
118 {
119 	struct k_heap *heap, **heap_ref;
120 	void *ret;
121 
122 	if (size == 0) {
123 		k_free(ptr);
124 		return NULL;
125 	}
126 	if (ptr == NULL) {
127 		return k_malloc(size);
128 	}
129 	heap_ref = ptr;
130 	ptr = --heap_ref;
131 	heap = *heap_ref;
132 
133 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_heap_sys, k_realloc, heap, ptr);
134 
135 	if (size_add_overflow(size, sizeof(heap_ref), &size)) {
136 		SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_heap_sys, k_realloc, heap, ptr, NULL);
137 		return NULL;
138 	}
139 
140 	ret = k_heap_realloc(heap, ptr, size, K_NO_WAIT);
141 
142 	if (ret != NULL) {
143 		heap_ref = ret;
144 		ret = ++heap_ref;
145 	}
146 
147 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_heap_sys, k_realloc, heap, ptr, ret);
148 
149 	return ret;
150 }
151 
k_thread_system_pool_assign(struct k_thread * thread)152 void k_thread_system_pool_assign(struct k_thread *thread)
153 {
154 	thread->resource_pool = _SYSTEM_HEAP;
155 }
156 #else
157 #define _SYSTEM_HEAP	NULL
158 #endif /* K_HEAP_MEM_POOL_SIZE */
159 
z_thread_aligned_alloc(size_t align,size_t size)160 void *z_thread_aligned_alloc(size_t align, size_t size)
161 {
162 	void *ret;
163 	struct k_heap *heap;
164 
165 	if (k_is_in_isr()) {
166 		heap = _SYSTEM_HEAP;
167 	} else {
168 		heap = _current->resource_pool;
169 	}
170 
171 	if (heap != NULL) {
172 		ret = z_heap_aligned_alloc(heap, align, size);
173 	} else {
174 		ret = NULL;
175 	}
176 
177 	return ret;
178 }
179