Branch data Line data Source code
1 : : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 : : /*
3 : : * Copyright 2013-2019 IBM Corp.
4 : : */
5 : :
6 : : #include <config.h>
7 : : #include <stdbool.h>
8 : : #include <stdint.h>
9 : :
10 : : /* The lock backtrace structures consume too much room on the skiboot heap */
11 : : #undef DEBUG_LOCKS_BACKTRACE
12 : :
13 : : #define BITS_PER_LONG (sizeof(long) * 8)
14 : :
15 : : #include "dummy-cpu.h"
16 : :
17 : : #include <stdlib.h>
18 : : #include <string.h>
19 : :
20 : : /* Use these before we override definitions below. */
21 : 1 : static void *real_malloc(size_t size)
22 : : {
23 : 1 : return malloc(size);
24 : : }
25 : :
26 : 1 : static inline void real_free(void *p)
27 : : {
28 : 1 : return free(p);
29 : : }
30 : :
31 : : #undef malloc
32 : : #undef free
33 : : #undef realloc
34 : :
35 : : #include <skiboot.h>
36 : :
37 : : #define is_rodata(p) true
38 : :
39 : : #include "../mem_region.c"
40 : : #include "../malloc.c"
41 : : #include "../device.c"
42 : :
43 : : #include <assert.h>
44 : : #include <stdio.h>
45 : :
46 : : struct dt_node *dt_root;
47 : : enum proc_chip_quirks proc_chip_quirks;
48 : :
49 : 10 : void lock_caller(struct lock *l, const char *caller)
50 : : {
51 : : (void)caller;
52 : 10 : assert(!l->lock_val);
53 : 10 : l->lock_val++;
54 : 10 : }
55 : :
56 : 10 : void unlock(struct lock *l)
57 : : {
58 : 10 : assert(l->lock_val);
59 : 10 : l->lock_val--;
60 : 10 : }
61 : :
62 : 131336 : bool lock_held_by_me(struct lock *l)
63 : : {
64 : 131336 : return l->lock_val;
65 : : }
66 : :
67 : : #define TEST_HEAP_ORDER 16
68 : : #define TEST_HEAP_SIZE (1ULL << TEST_HEAP_ORDER)
69 : :
70 : 20 : static bool heap_empty(void)
71 : : {
72 : 20 : const struct alloc_hdr *h = region_start(&skiboot_heap);
73 : 20 : return h->num_longs == skiboot_heap.len / sizeof(long);
74 : : }
75 : :
76 : 1 : int main(void)
77 : : {
78 : : char *test_heap;
79 : : void *p, *ptrs[100];
80 : : size_t i;
81 : : struct mem_region *r;
82 : :
83 : : /* Use malloc for the heap, so valgrind can find issues. */
84 : 1 : test_heap = real_malloc(TEST_HEAP_SIZE);
85 : 1 : skiboot_heap.start = (unsigned long)test_heap;
86 : 1 : skiboot_heap.len = TEST_HEAP_SIZE;
87 : :
88 : 1 : lock(&skiboot_heap.free_list_lock);
89 : :
90 : : /* Allocations of various sizes. */
91 : 17 : for (i = 0; i < TEST_HEAP_ORDER; i++) {
92 : 16 : p = mem_alloc(&skiboot_heap, 1ULL << i, 1, "here");
93 : 16 : assert(p);
94 : 16 : assert(mem_check(&skiboot_heap));
95 : 16 : assert(!strcmp(((struct alloc_hdr *)p)[-1].location, "here"));
96 : 16 : assert(p > (void *)test_heap);
97 : 16 : assert(p + (1ULL << i) <= (void *)test_heap + TEST_HEAP_SIZE);
98 : 16 : assert(mem_allocated_size(p) >= 1ULL << i);
99 : 16 : mem_free(&skiboot_heap, p, "freed");
100 : 16 : assert(heap_empty());
101 : 16 : assert(mem_check(&skiboot_heap));
102 : 16 : assert(!strcmp(((struct alloc_hdr *)p)[-1].location, "freed"));
103 : : }
104 : 1 : p = mem_alloc(&skiboot_heap, 1ULL << i, 1, "here");
105 : 1 : assert(!p);
106 : 1 : mem_free(&skiboot_heap, p, "freed");
107 : 1 : assert(heap_empty());
108 : 1 : assert(mem_check(&skiboot_heap));
109 : :
110 : : /* Allocations of various alignments: use small alloc first. */
111 : 1 : ptrs[0] = mem_alloc(&skiboot_heap, 1, 1, "small");
112 : 1 : for (i = 0; ; i++) {
113 : 19 : p = mem_alloc(&skiboot_heap, 1, 1ULL << i, "here");
114 : 19 : assert(mem_check(&skiboot_heap));
115 : : /* We will eventually fail... */
116 : 19 : if (!p) {
117 : 1 : assert(i >= TEST_HEAP_ORDER);
118 : 1 : break;
119 : : }
120 : 18 : assert(p);
121 : 18 : assert((long)p % (1ULL << i) == 0);
122 : 18 : assert(p > (void *)test_heap);
123 : 18 : assert(p + 1 <= (void *)test_heap + TEST_HEAP_SIZE);
124 : 18 : mem_free(&skiboot_heap, p, "freed");
125 : 18 : assert(mem_check(&skiboot_heap));
126 : : }
127 : 1 : mem_free(&skiboot_heap, ptrs[0], "small freed");
128 : 1 : assert(heap_empty());
129 : 1 : assert(mem_check(&skiboot_heap));
130 : :
131 : : /* Many little allocations, freed in reverse order. */
132 : 101 : for (i = 0; i < 100; i++) {
133 : 100 : ptrs[i] = mem_alloc(&skiboot_heap, sizeof(long), 1, "here");
134 : 100 : assert(ptrs[i]);
135 : 100 : assert(ptrs[i] > (void *)test_heap);
136 : 100 : assert(ptrs[i] + sizeof(long)
137 : : <= (void *)test_heap + TEST_HEAP_SIZE);
138 : 100 : assert(mem_check(&skiboot_heap));
139 : : }
140 : 1 : mem_dump_free();
141 : 101 : for (i = 0; i < 100; i++)
142 : 100 : mem_free(&skiboot_heap, ptrs[100 - 1 - i], "freed");
143 : :
144 : 1 : assert(heap_empty());
145 : 1 : assert(mem_check(&skiboot_heap));
146 : :
147 : : /* Check the prev_free gets updated properly. */
148 : 1 : ptrs[0] = mem_alloc(&skiboot_heap, sizeof(long), 1, "ptrs[0]");
149 : 1 : ptrs[1] = mem_alloc(&skiboot_heap, sizeof(long), 1, "ptrs[1]");
150 : 1 : assert(ptrs[1] > ptrs[0]);
151 : 1 : mem_free(&skiboot_heap, ptrs[0], "ptrs[0] free");
152 : 1 : assert(mem_check(&skiboot_heap));
153 : 1 : ptrs[0] = mem_alloc(&skiboot_heap, sizeof(long), 1, "ptrs[0] again");
154 : 1 : assert(mem_check(&skiboot_heap));
155 : 1 : mem_free(&skiboot_heap, ptrs[1], "ptrs[1] free");
156 : 1 : mem_free(&skiboot_heap, ptrs[0], "ptrs[0] free");
157 : 1 : assert(mem_check(&skiboot_heap));
158 : 1 : assert(heap_empty());
159 : :
160 : : #if 0
161 : : printf("Heap map:\n");
162 : : for (i = 0; i < TEST_HEAP_SIZE / sizeof(long); i++) {
163 : : printf("%u", test_bit(skiboot_heap.bitmap, i));
164 : : if (i % 64 == 63)
165 : : printf("\n");
166 : : else if (i % 8 == 7)
167 : : printf(" ");
168 : : }
169 : : #endif
170 : :
171 : : /* Simple enlargement, then free */
172 : 1 : p = mem_alloc(&skiboot_heap, 1, 1, "one byte");
173 : 1 : assert(p);
174 : 1 : assert(mem_resize(&skiboot_heap, p, 100, "hundred bytes"));
175 : 1 : assert(mem_allocated_size(p) >= 100);
176 : 1 : assert(mem_check(&skiboot_heap));
177 : 1 : assert(!strcmp(((struct alloc_hdr *)p)[-1].location, "hundred bytes"));
178 : 1 : mem_free(&skiboot_heap, p, "freed");
179 : :
180 : : /* Simple shrink, then free */
181 : 1 : p = mem_alloc(&skiboot_heap, 100, 1, "100 bytes");
182 : 1 : assert(p);
183 : 1 : assert(mem_resize(&skiboot_heap, p, 1, "1 byte"));
184 : 1 : assert(mem_allocated_size(p) < 100);
185 : 1 : assert(mem_check(&skiboot_heap));
186 : 1 : assert(!strcmp(((struct alloc_hdr *)p)[-1].location, "1 byte"));
187 : 1 : mem_free(&skiboot_heap, p, "freed");
188 : :
189 : : /* Lots of resizing (enlarge). */
190 : 1 : p = mem_alloc(&skiboot_heap, 1, 1, "one byte");
191 : 1 : assert(p);
192 : 65521 : for (i = 1; i <= TEST_HEAP_SIZE - sizeof(struct alloc_hdr); i++) {
193 : 65520 : assert(mem_resize(&skiboot_heap, p, i, "enlarge"));
194 : 65520 : assert(mem_allocated_size(p) >= i);
195 : 65520 : assert(mem_check(&skiboot_heap));
196 : : }
197 : :
198 : : /* Can't make it larger though. */
199 : 1 : assert(!mem_resize(&skiboot_heap, p, i, "enlarge"));
200 : :
201 : 65521 : for (i = TEST_HEAP_SIZE - sizeof(struct alloc_hdr); i > 0; i--) {
202 : 65520 : assert(mem_resize(&skiboot_heap, p, i, "shrink"));
203 : 65520 : assert(mem_check(&skiboot_heap));
204 : : }
205 : :
206 : 1 : mem_free(&skiboot_heap, p, "freed");
207 : 1 : assert(mem_check(&skiboot_heap));
208 : :
209 : 1 : unlock(&skiboot_heap.free_list_lock);
210 : :
211 : : /* lock the regions list */
212 : 1 : lock(&mem_region_lock);
213 : : /* Test splitting of a region. */
214 : 1 : r = new_region("base", (unsigned long)test_heap,
215 : : TEST_HEAP_SIZE, NULL, REGION_SKIBOOT_HEAP);
216 : 1 : assert(add_region(r));
217 : 1 : r = new_region("splitter", (unsigned long)test_heap + TEST_HEAP_SIZE/4,
218 : : TEST_HEAP_SIZE/2, NULL, REGION_RESERVED);
219 : 1 : assert(add_region(r));
220 : : /* Now we should have *three* regions. */
221 : 1 : i = 0;
222 : 4 : list_for_each(®ions, r, list) {
223 : 3 : if (region_start(r) == test_heap) {
224 : 1 : assert(r->len == TEST_HEAP_SIZE/4);
225 : 1 : assert(strcmp(r->name, "base") == 0);
226 : 1 : assert(r->type == REGION_SKIBOOT_HEAP);
227 : 2 : } else if (region_start(r) == test_heap + TEST_HEAP_SIZE / 4) {
228 : 1 : assert(r->len == TEST_HEAP_SIZE/2);
229 : 1 : assert(strcmp(r->name, "splitter") == 0);
230 : 1 : assert(r->type == REGION_RESERVED);
231 : 1 : assert(!r->free_list.n.next);
232 : 1 : } else if (region_start(r) == test_heap + TEST_HEAP_SIZE/4*3) {
233 : 1 : assert(r->len == TEST_HEAP_SIZE/4);
234 : 1 : assert(strcmp(r->name, "base") == 0);
235 : 1 : assert(r->type == REGION_SKIBOOT_HEAP);
236 : : } else
237 : 0 : abort();
238 : 3 : assert(mem_check(r));
239 : 3 : i++;
240 : : }
241 : 1 : mem_dump_free();
242 : 1 : assert(i == 3);
243 : 4 : while ((r = list_pop(®ions, struct mem_region, list)) != NULL) {
244 : 3 : lock(&skiboot_heap.free_list_lock);
245 : 3 : mem_free(&skiboot_heap, r, __location__);
246 : 3 : unlock(&skiboot_heap.free_list_lock);
247 : : }
248 : 1 : unlock(&mem_region_lock);
249 : 1 : assert(skiboot_heap.free_list_lock.lock_val == 0);
250 : 1 : real_free(test_heap);
251 : 1 : return 0;
252 : : }
|