diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/SOURCES | 2 | ||||
-rw-r--r-- | firmware/buflib_malloc.c | 251 | ||||
-rw-r--r-- | firmware/export/config.h | 1 | ||||
-rw-r--r-- | firmware/include/buflib.h | 2 | ||||
-rw-r--r-- | firmware/include/buflib_malloc.h | 53 |
5 files changed, 309 insertions, 0 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES index 02e962c0c3..7e2ffb323e 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES | |||
@@ -6,6 +6,8 @@ events.c | |||
6 | backlight.c | 6 | backlight.c |
7 | #if CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MEMPOOL | 7 | #if CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MEMPOOL |
8 | buflib_mempool.c | 8 | buflib_mempool.c |
9 | #elif CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MALLOC | ||
10 | buflib_malloc.c | ||
9 | #endif | 11 | #endif |
10 | core_alloc.c | 12 | core_alloc.c |
11 | general.c | 13 | general.c |
diff --git a/firmware/buflib_malloc.c b/firmware/buflib_malloc.c new file mode 100644 index 0000000000..fdc2b5b925 --- /dev/null +++ b/firmware/buflib_malloc.c | |||
@@ -0,0 +1,251 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2023 Aidan MacDonald | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | /* | ||
23 | * Malloc backed buflib. This is intended for debugging rather than for | ||
24 | * serious use - the buffer passed to the context is wasted, and memory | ||
25 | * is acquired from malloc() instead. The main point is to make ASAN more | ||
26 | * effective by isolating buflib allocations from each other. | ||
27 | * | ||
28 | * Currently this is a bare-minimum implementation, it doesn't even run | ||
29 | * buflib callbacks since it never moves anything. It could later be | ||
30 | * extended with stress-testing options, for example by randomly moving | ||
31 | * allocations around. | ||
32 | */ | ||
33 | |||
34 | #include "buflib.h" | ||
35 | #include "panic.h" | ||
36 | #include <stdlib.h> | ||
37 | |||
38 | static struct buflib_malloc_handle *get_free_handle(struct buflib_context *ctx) | ||
39 | { | ||
40 | struct buflib_malloc_handle *h; | ||
41 | for (size_t i = 0; i < ctx->num_allocs; ++i) | ||
42 | { | ||
43 | h = &ctx->allocs[i]; | ||
44 | if (h->size == 0) | ||
45 | return h; | ||
46 | } | ||
47 | |||
48 | ctx->num_allocs++; | ||
49 | ctx->allocs = realloc(ctx->allocs, ctx->num_allocs * sizeof(*ctx->allocs)); | ||
50 | if (!ctx->allocs) | ||
51 | panicf("buflib %p handle OOM", ctx); | ||
52 | |||
53 | h = &ctx->allocs[ctx->num_allocs - 1]; | ||
54 | h->size = 0; | ||
55 | return h; | ||
56 | } | ||
57 | |||
58 | static int get_handle_num(struct buflib_context *ctx, | ||
59 | struct buflib_malloc_handle *handle) | ||
60 | { | ||
61 | return (handle - ctx->allocs) + 1; | ||
62 | } | ||
63 | |||
64 | static struct buflib_malloc_handle *get_handle(struct buflib_context *ctx, | ||
65 | int handle) | ||
66 | { | ||
67 | return &ctx->allocs[handle - 1]; | ||
68 | } | ||
69 | |||
70 | struct buflib_callbacks buflib_ops_locked = { | ||
71 | .move_callback = NULL, | ||
72 | .shrink_callback = NULL, | ||
73 | .sync_callback = NULL, | ||
74 | }; | ||
75 | |||
76 | void buflib_init(struct buflib_context *ctx, void *buf, size_t size) | ||
77 | { | ||
78 | ctx->allocs = NULL; | ||
79 | ctx->num_allocs = 0; | ||
80 | ctx->buf = buf; | ||
81 | ctx->bufsize = size; | ||
82 | } | ||
83 | |||
84 | size_t buflib_available(struct buflib_context *ctx) | ||
85 | { | ||
86 | return ctx->bufsize; | ||
87 | } | ||
88 | |||
89 | size_t buflib_allocatable(struct buflib_context *ctx) | ||
90 | { | ||
91 | return ctx->bufsize; | ||
92 | } | ||
93 | |||
94 | bool buflib_context_relocate(struct buflib_context *ctx, void *buf) | ||
95 | { | ||
96 | ctx->buf = buf; | ||
97 | return true; | ||
98 | } | ||
99 | |||
100 | int buflib_alloc(struct buflib_context *ctx, size_t size) | ||
101 | { | ||
102 | return buflib_alloc_ex(ctx, size, NULL); | ||
103 | } | ||
104 | |||
105 | int buflib_alloc_ex(struct buflib_context *ctx, size_t size, | ||
106 | struct buflib_callbacks *ops) | ||
107 | { | ||
108 | struct buflib_malloc_handle *handle = get_free_handle(ctx); | ||
109 | |||
110 | handle->data = malloc(size); | ||
111 | handle->user = handle->data; | ||
112 | handle->size = size; | ||
113 | handle->pin_count = 0; | ||
114 | handle->ops = ops; | ||
115 | |||
116 | if (!handle->data) | ||
117 | panicf("buflib %p data OOM", ctx); | ||
118 | |||
119 | return get_handle_num(ctx, handle); | ||
120 | } | ||
121 | |||
122 | int buflib_alloc_maximum(struct buflib_context* ctx, | ||
123 | size_t *size, struct buflib_callbacks *ops) | ||
124 | { | ||
125 | *size = ctx->bufsize; | ||
126 | |||
127 | return buflib_alloc_ex(ctx, *size, ops); | ||
128 | } | ||
129 | |||
130 | bool buflib_shrink(struct buflib_context *ctx, int handle, | ||
131 | void *newstart, size_t new_size) | ||
132 | { | ||
133 | struct buflib_malloc_handle *h = get_handle(ctx, handle); | ||
134 | if (newstart < h->user || new_size > h->size - (newstart - h->user)) | ||
135 | return false; | ||
136 | |||
137 | /* XXX: this might be allowed, but what would be the point... */ | ||
138 | if (new_size == 0) | ||
139 | { | ||
140 | panicf("weird shrink"); | ||
141 | return false; | ||
142 | } | ||
143 | |||
144 | /* due to buflib semantics we must not realloc */ | ||
145 | h->user = newstart; | ||
146 | h->size = new_size; | ||
147 | return true; | ||
148 | } | ||
149 | |||
150 | void buflib_pin(struct buflib_context *ctx, int handle) | ||
151 | { | ||
152 | struct buflib_malloc_handle *h = get_handle(ctx, handle); | ||
153 | |||
154 | h->pin_count++; | ||
155 | } | ||
156 | |||
157 | void buflib_unpin(struct buflib_context *ctx, int handle) | ||
158 | { | ||
159 | struct buflib_malloc_handle *h = get_handle(ctx, handle); | ||
160 | |||
161 | h->pin_count--; | ||
162 | } | ||
163 | |||
164 | unsigned buflib_pin_count(struct buflib_context *ctx, int handle) | ||
165 | { | ||
166 | struct buflib_malloc_handle *h = get_handle(ctx, handle); | ||
167 | |||
168 | return h->pin_count; | ||
169 | } | ||
170 | |||
171 | int buflib_free(struct buflib_context *ctx, int handle) | ||
172 | { | ||
173 | if (handle <= 0) | ||
174 | return 0; | ||
175 | |||
176 | struct buflib_malloc_handle *h = get_handle(ctx, handle); | ||
177 | |||
178 | free(h->data); | ||
179 | h->size = 0; | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | #ifdef BUFLIB_DEBUG_GET_DATA | ||
185 | void *buflib_get_data(struct buflib_context *ctx, int handle) | ||
186 | { | ||
187 | /* kind of silly since it's better for ASAN to catch this but... */ | ||
188 | if (handle <= 0 || handle > ctx->num_allocs) | ||
189 | panicf("buflib %p: invalid handle %d", ctx, handle); | ||
190 | |||
191 | struct buflib_malloc_handle *h = get_handle(ctx, handle); | ||
192 | if (h->user == NULL) | ||
193 | panicf("buflib %p: handle %d use after free", ctx, handle); | ||
194 | |||
195 | return h->user; | ||
196 | } | ||
197 | #endif | ||
198 | |||
199 | void *buflib_buffer_out(struct buflib_context *ctx, size_t *size) | ||
200 | { | ||
201 | if (*size == 0) | ||
202 | *size = ctx->bufsize; | ||
203 | |||
204 | void *ret = ctx->buf; | ||
205 | |||
206 | ctx->buf += *size; | ||
207 | return ret; | ||
208 | } | ||
209 | |||
210 | void buflib_buffer_in(struct buflib_context *ctx, int size) | ||
211 | { | ||
212 | ctx->buf -= size; | ||
213 | } | ||
214 | |||
215 | #ifdef BUFLIB_DEBUG_PRINT | ||
216 | int buflib_get_num_blocks(struct buflib_context *ctx) | ||
217 | { | ||
218 | return ctx->num_allocs; | ||
219 | } | ||
220 | |||
221 | bool buflib_print_block_at(struct buflib_context *ctx, int block_num, | ||
222 | char *buf, size_t bufsize) | ||
223 | { | ||
224 | if (block_num >= ctx->num_allocs) | ||
225 | { | ||
226 | if (bufsize > 0) | ||
227 | *buf = '\0'; | ||
228 | return false; | ||
229 | } | ||
230 | |||
231 | struct buflib_malloc_handle *handle = &ctx->allocs[block_num]; | ||
232 | if (handle->data) | ||
233 | { | ||
234 | snprintf(buf, bufsize, "%03d addr:%8p length:%zu", | ||
235 | block_num, handle->data, handle->size); | ||
236 | } | ||
237 | else | ||
238 | { | ||
239 | snprintf(buf, bufsize, "%03d (unallocated)", block_num); | ||
240 | } | ||
241 | |||
242 | return true; | ||
243 | } | ||
244 | #endif | ||
245 | |||
246 | #ifdef BUFLIB_DEBUG_CHECK_VALID | ||
247 | void buflib_check_valid(struct buflib_context *ctx) | ||
248 | { | ||
249 | (void)ctx; | ||
250 | } | ||
251 | #endif | ||
diff --git a/firmware/export/config.h b/firmware/export/config.h index d8674c40f2..2ec0b7878f 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h | |||
@@ -382,6 +382,7 @@ Lyre prototype 1 */ | |||
382 | 382 | ||
383 | /* CONFIG_BUFLIB_BACKEND */ | 383 | /* CONFIG_BUFLIB_BACKEND */ |
384 | #define BUFLIB_BACKEND_MEMPOOL 0 /* Default memory pool backed buflib */ | 384 | #define BUFLIB_BACKEND_MEMPOOL 0 /* Default memory pool backed buflib */ |
385 | #define BUFLIB_BACKEND_MALLOC 1 /* malloc() buflib (for debugging) */ | ||
385 | 386 | ||
386 | /* now go and pick yours */ | 387 | /* now go and pick yours */ |
387 | #if defined(IRIVER_H100) | 388 | #if defined(IRIVER_H100) |
diff --git a/firmware/include/buflib.h b/firmware/include/buflib.h index 32a5a6abe0..c4865b6d9b 100644 --- a/firmware/include/buflib.h +++ b/firmware/include/buflib.h | |||
@@ -380,6 +380,8 @@ void buflib_check_valid(struct buflib_context *ctx); | |||
380 | 380 | ||
381 | #if CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MEMPOOL | 381 | #if CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MEMPOOL |
382 | #include "buflib_mempool.h" | 382 | #include "buflib_mempool.h" |
383 | #elif CONFIG_BUFLIB_BACKEND == BUFLIB_BACKEND_MALLOC | ||
384 | #include "buflib_malloc.h" | ||
383 | #endif | 385 | #endif |
384 | 386 | ||
385 | #ifndef BUFLIB_ALLOC_OVERHEAD | 387 | #ifndef BUFLIB_ALLOC_OVERHEAD |
diff --git a/firmware/include/buflib_malloc.h b/firmware/include/buflib_malloc.h new file mode 100644 index 0000000000..32c837e7b7 --- /dev/null +++ b/firmware/include/buflib_malloc.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2023 Aidan MacDonald | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef _BUFLIB_MALLOC_H_ | ||
22 | #define _BUFLIB_MALLOC_H_ | ||
23 | |||
24 | #ifndef _BUFLIB_H_ | ||
25 | # error "include buflib.h instead" | ||
26 | #endif | ||
27 | |||
28 | struct buflib_malloc_handle | ||
29 | { | ||
30 | void *data; | ||
31 | void *user; | ||
32 | size_t size; | ||
33 | unsigned int pin_count; | ||
34 | struct buflib_callbacks *ops; | ||
35 | }; | ||
36 | |||
37 | struct buflib_context | ||
38 | { | ||
39 | struct buflib_malloc_handle *allocs; | ||
40 | size_t num_allocs; | ||
41 | |||
42 | void *buf; | ||
43 | size_t bufsize; | ||
44 | }; | ||
45 | |||
46 | #ifndef BUFLIB_DEBUG_GET_DATA | ||
47 | static inline void *buflib_get_data(struct buflib_context *ctx, int handle) | ||
48 | { | ||
49 | return ctx->allocs[handle - 1].user; | ||
50 | } | ||
51 | #endif | ||
52 | |||
53 | #endif /* _BUFLIB_MALLOC_H_ */ | ||