1 /*
2 * Copyright (c) 2016 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <ztest.h>
8 #include <kernel_internal.h>
9 #include <irq_offload.h>
10 #include "test_mheap.h"
11
12 #define STACK_SIZE (512 + CONFIG_TEST_EXTRA_STACKSIZE)
13 #define OVERFLOW_SIZE SIZE_MAX
14
15 K_SEM_DEFINE(thread_sem, 0, 1);
16 K_THREAD_STACK_DEFINE(tstack, STACK_SIZE);
17 struct k_thread tdata;
18
tIsr_malloc_and_free(void * data)19 static void tIsr_malloc_and_free(void *data)
20 {
21 ARG_UNUSED(data);
22 void *ptr;
23
24 ptr = (char *)z_thread_malloc(BLK_SIZE_MIN);
25 zassert_not_null(ptr, "bytes allocation failed from system pool");
26 k_free(ptr);
27 }
28
thread_entry(void * p1,void * p2,void * p3)29 static void thread_entry(void *p1, void *p2, void *p3)
30 {
31 void *ptr;
32
33 k_current_get()->resource_pool = NULL;
34
35 ptr = (char *)z_thread_malloc(BLK_SIZE_MIN);
36 zassert_is_null(ptr, "bytes allocation failed from system pool");
37
38 k_sem_give(&thread_sem);
39 }
40
41 /*test cases*/
42
43 /**
44 * @brief Test to demonstrate k_malloc() and k_free() API usage
45 *
46 * @ingroup kernel_heap_tests
47 *
48 * @details The test allocates 4 blocks from heap memory pool
49 * using k_malloc() API. It also tries to allocate a block of size
50 * 64 bytes which fails as all the memory is allocated up. It then
51 * validates k_free() API by freeing up all the blocks which were
52 * allocated from the heap memory.
53 *
54 * @see k_malloc()
55 */
test_mheap_malloc_free(void)56 void test_mheap_malloc_free(void)
57 {
58 void *block[2 * BLK_NUM_MAX], *block_fail;
59 int nb;
60
61 for (nb = 0; nb < ARRAY_SIZE(block); nb++) {
62 /**
63 * TESTPOINT: This routine provides traditional malloc()
64 * semantics. Memory is allocated from the heap memory pool.
65 */
66 block[nb] = k_malloc(BLK_SIZE_MIN);
67 if (block[nb] == NULL) {
68 break;
69 }
70 }
71
72 block_fail = k_malloc(BLK_SIZE_MIN);
73 /** TESTPOINT: Return NULL if fail.*/
74 zassert_is_null(block_fail, NULL);
75
76 for (int i = 0; i < nb; i++) {
77 /**
78 * TESTPOINT: This routine provides traditional free()
79 * semantics. The memory being returned must have been allocated
80 * from the heap memory pool.
81 */
82 k_free(block[i]);
83 }
84 /** TESTPOINT: If ptr is NULL, no operation is performed.*/
85 k_free(NULL);
86
87 /** TESTPOINT: Return NULL if fail.*/
88 block_fail = k_malloc(OVERFLOW_SIZE);
89 zassert_is_null(block_fail, NULL);
90 }
91
92 #define NMEMB 8
93 #define SIZE 16
94 #define BOUNDS (NMEMB * SIZE)
95
96 /**
97 * @brief Test to demonstrate k_calloc() API functionality.
98 *
99 * @ingroup kernel_heap_tests
100 *
101 * @details The test validates k_calloc() API. When requesting a
102 * huge size of space or a space larger than heap memory,
103 * the API will return NULL. The 8 blocks of memory of
104 * size 16 bytes are allocated by k_calloc() API. When allocated using
105 * k_calloc() the memory buffers have to be zeroed. Check is done, if the
106 * blocks are memset to 0 and read/write is allowed. The test is then
107 * teared up by freeing all the blocks allocated.
108 *
109 * @see k_calloc()
110 */
test_mheap_calloc(void)111 void test_mheap_calloc(void)
112 {
113 char *mem;
114
115 /* Requesting a huge size to validate overflow */
116 mem = k_calloc(NMEMB, OVERFLOW_SIZE);
117 zassert_is_null(mem, "calloc operation failed");
118
119 /* Requesting a space large than heap memory lead to failure */
120 mem = k_calloc(NMEMB * 3, SIZE);
121 zassert_is_null(mem, "calloc operation failed");
122
123 mem = k_calloc(NMEMB, SIZE);
124 zassert_not_null(mem, "calloc operation failed");
125
126 /* Memory should be zeroed and not crash us if we read/write to it */
127 for (int i = 0; i < BOUNDS; i++) {
128 zassert_equal(mem[i], 0, NULL);
129 mem[i] = 1;
130 }
131
132 k_free(mem);
133 }
134
test_k_aligned_alloc(void)135 void test_k_aligned_alloc(void)
136 {
137 void *r;
138
139 /*
140 * Allow sizes that are not necessarily a multiple of the
141 * alignment. The backing allocator would naturally round up to
142 * some minimal block size. This would make k_aligned_alloc()
143 * more like posix_memalign() instead of aligned_alloc(), but
144 * the benefit is that k_malloc() can then just be a wrapper
145 * around k_aligned_alloc().
146 */
147 r = k_aligned_alloc(sizeof(void *), 1);
148 /* allocation succeeds */
149 zassert_not_equal(NULL, r, "aligned alloc of 1 byte failed");
150 /* r is suitably aligned */
151 zassert_equal(0, (uintptr_t)r % sizeof(void *),
152 "%p not %u-byte-aligned",
153 r, sizeof(void *));
154 k_free(r);
155
156 /* allocate with > 8 byte alignment */
157 r = k_aligned_alloc(16, 1);
158 /* allocation succeeds */
159 zassert_not_equal(NULL, r, "16-byte-aligned alloc failed");
160 /* r is suitably aligned */
161 zassert_equal(0, (uintptr_t)r % 16,
162 "%p not 16-byte-aligned", r);
163 k_free(r);
164 }
165
166 /**
167 * @brief Validate allocation and free from system heap memory pool.
168
169 * @details Set heap memory as resource pool. It will success when alloc
170 * a block of memory smaller than the pool and will fail when alloc
171 * a block of memory larger than the pool.
172 *
173 * @ingroup kernel_heap_tests
174 *
175 * @see k_thread_system_pool_assign(), z_thread_malloc(), k_free()
176 */
test_sys_heap_mem_pool_assign(void)177 void test_sys_heap_mem_pool_assign(void)
178 {
179 if (!IS_ENABLED(CONFIG_MULTITHREADING)) {
180 return;
181 }
182
183 void *ptr;
184
185 k_thread_system_pool_assign(k_current_get());
186 ptr = (char *)z_thread_malloc(BLK_SIZE_MIN/2);
187 zassert_not_null(ptr, "bytes allocation failed from system pool");
188 k_free(ptr);
189
190 zassert_is_null((char *)z_thread_malloc(BLK_SIZE_MAX * 2),
191 "overflow check failed");
192 }
193
194 /**
195 * @brief Validate allocation and free from system heap memory pool
196 * in isr context.
197 *
198 * @details When in isr context, the kernel will successfully alloc a block of
199 * memory because in this situation, the kernel will assign the heap memory
200 * as resource pool.
201 *
202 * @ingroup kernel_heap_tests
203 *
204 * @see z_thread_malloc(), k_free()
205 */
test_malloc_in_isr(void)206 void test_malloc_in_isr(void)
207 {
208 if (!IS_ENABLED(CONFIG_IRQ_OFFLOAD)) {
209 return;
210 }
211
212 irq_offload((irq_offload_routine_t)tIsr_malloc_and_free, NULL);
213 }
214
215 /**
216 * @brief Validate allocation and free failure when thread's resource pool
217 * is not assigned.
218 *
219 * @details When a thread's resource pool is not assigned, alloc memory will fail.
220 *
221 * @ingroup kernel_heap_tests
222 *
223 * @see z_thread_malloc()
224 */
test_malloc_in_thread(void)225 void test_malloc_in_thread(void)
226 {
227 if (!IS_ENABLED(CONFIG_MULTITHREADING)) {
228 return;
229 }
230
231 k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
232 thread_entry, NULL, NULL, NULL,
233 0, 0, K_NO_WAIT);
234
235 k_sem_take(&thread_sem, K_FOREVER);
236
237 k_thread_abort(tid);
238 }
239