| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: subr_kmem.c,v 1.78 2020/01/25 15:08:40 ad Exp $ */ | | 1 | /* $NetBSD: subr_kmem.c,v 1.79 2020/03/08 00:31:19 ad Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2009-2020 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2009-2020 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Andrew Doran and Maxime Villard. | | 8 | * by Andrew Doran and Maxime Villard. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -52,43 +52,43 @@ | | | @@ -52,43 +52,43 @@ |
52 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 52 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
53 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 53 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
54 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 54 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
55 | * SUCH DAMAGE. | | 55 | * SUCH DAMAGE. |
56 | */ | | 56 | */ |
57 | | | 57 | |
58 | /* | | 58 | /* |
59 | * Allocator of kernel wired memory. This allocator has some debug features | | 59 | * Allocator of kernel wired memory. This allocator has some debug features |
60 | * enabled with "option DIAGNOSTIC" and "option DEBUG". | | 60 | * enabled with "option DIAGNOSTIC" and "option DEBUG". |
61 | */ | | 61 | */ |
62 | | | 62 | |
63 | /* | | 63 | /* |
64 | * KMEM_SIZE: detect alloc/free size mismatch bugs. | | 64 | * KMEM_SIZE: detect alloc/free size mismatch bugs. |
65 | * Prefix each allocations with a fixed-sized, aligned header and record | | 65 | * Append to each allocation a fixed-sized footer and record the exact |
66 | * the exact user-requested allocation size in it. When freeing, compare | | 66 | * user-requested allocation size in it. When freeing, compare it with |
67 | * it with kmem_free's "size" argument. | | 67 | * kmem_free's "size" argument. |
68 | * | | 68 | * |
69 | * This option is enabled on DIAGNOSTIC. | | 69 | * This option is enabled on DIAGNOSTIC. |
70 | * | | 70 | * |
71 | * |CHUNK|CHUNK|CHUNK|CHUNK|CHUNK|CHUNK|CHUNK|CHUNK|CHUNK|CHUNK| | | 71 | * |CHUNK|CHUNK|CHUNK|CHUNK|CHUNK|CHUNK|CHUNK|CHUNK|CHUNK| | |
72 | * +-----+-----+-----+-----+-----+-----+-----+-----+-----+---+-+ | | 72 | * +-----+-----+-----+-----+-----+-----+-----+-----+-----+-+ |
73 | * |/////| | | | | | | | | |U| | | 73 | * | | | | | | | | |/////|U| |
74 | * |/HSZ/| | | | | | | | | |U| | | 74 | * | | | | | | | | |/HSZ/|U| |
75 | * |/////| | | | | | | | | |U| | | 75 | * | | | | | | | | |/////|U| |
76 | * +-----+-----+-----+-----+-----+-----+-----+-----+-----+---+-+ | | 76 | * +-----+-----+-----+-----+-----+-----+-----+-----+-----+-+ |
77 | * |Size | Buffer usable by the caller (requested size) |Unused\ | | 77 | * | Buffer usable by the caller (requested size) |Size |Unused |
78 | */ | | 78 | */ |
79 | | | 79 | |
80 | #include <sys/cdefs.h> | | 80 | #include <sys/cdefs.h> |
81 | __KERNEL_RCSID(0, "$NetBSD: subr_kmem.c,v 1.78 2020/01/25 15:08:40 ad Exp $"); | | 81 | __KERNEL_RCSID(0, "$NetBSD: subr_kmem.c,v 1.79 2020/03/08 00:31:19 ad Exp $"); |
82 | | | 82 | |
83 | #ifdef _KERNEL_OPT | | 83 | #ifdef _KERNEL_OPT |
84 | #include "opt_kmem.h" | | 84 | #include "opt_kmem.h" |
85 | #endif | | 85 | #endif |
86 | | | 86 | |
87 | #include <sys/param.h> | | 87 | #include <sys/param.h> |
88 | #include <sys/callback.h> | | 88 | #include <sys/callback.h> |
89 | #include <sys/kmem.h> | | 89 | #include <sys/kmem.h> |
90 | #include <sys/pool.h> | | 90 | #include <sys/pool.h> |
91 | #include <sys/debug.h> | | 91 | #include <sys/debug.h> |
92 | #include <sys/lockdebug.h> | | 92 | #include <sys/lockdebug.h> |
93 | #include <sys/cpu.h> | | 93 | #include <sys/cpu.h> |
94 | #include <sys/asan.h> | | 94 | #include <sys/asan.h> |
| @@ -158,30 +158,27 @@ static size_t kmem_cache_maxidx __read_m | | | @@ -158,30 +158,27 @@ static size_t kmem_cache_maxidx __read_m |
158 | | | 158 | |
159 | static pool_cache_t kmem_cache_big[KMEM_CACHE_BIG_COUNT] __cacheline_aligned; | | 159 | static pool_cache_t kmem_cache_big[KMEM_CACHE_BIG_COUNT] __cacheline_aligned; |
160 | static size_t kmem_cache_big_maxidx __read_mostly; | | 160 | static size_t kmem_cache_big_maxidx __read_mostly; |
161 | | | 161 | |
162 | #if defined(DIAGNOSTIC) && defined(_HARDKERNEL) | | 162 | #if defined(DIAGNOSTIC) && defined(_HARDKERNEL) |
163 | #define KMEM_SIZE | | 163 | #define KMEM_SIZE |
164 | #endif | | 164 | #endif |
165 | | | 165 | |
166 | #if defined(DEBUG) && defined(_HARDKERNEL) | | 166 | #if defined(DEBUG) && defined(_HARDKERNEL) |
167 | static void *kmem_freecheck; | | 167 | static void *kmem_freecheck; |
168 | #endif | | 168 | #endif |
169 | | | 169 | |
170 | #if defined(KMEM_SIZE) | | 170 | #if defined(KMEM_SIZE) |
171 | struct kmem_header { | | 171 | #define SIZE_SIZE sizeof(size_t) |
172 | size_t size; | | | |
173 | } __aligned(KMEM_ALIGN); | | | |
174 | #define SIZE_SIZE sizeof(struct kmem_header) | | | |
175 | static void kmem_size_set(void *, size_t); | | 172 | static void kmem_size_set(void *, size_t); |
176 | static void kmem_size_check(void *, size_t); | | 173 | static void kmem_size_check(void *, size_t); |
177 | #else | | 174 | #else |
178 | #define SIZE_SIZE 0 | | 175 | #define SIZE_SIZE 0 |
179 | #define kmem_size_set(p, sz) /* nothing */ | | 176 | #define kmem_size_set(p, sz) /* nothing */ |
180 | #define kmem_size_check(p, sz) /* nothing */ | | 177 | #define kmem_size_check(p, sz) /* nothing */ |
181 | #endif | | 178 | #endif |
182 | | | 179 | |
183 | CTASSERT(KM_SLEEP == PR_WAITOK); | | 180 | CTASSERT(KM_SLEEP == PR_WAITOK); |
184 | CTASSERT(KM_NOSLEEP == PR_NOWAIT); | | 181 | CTASSERT(KM_NOSLEEP == PR_NOWAIT); |
185 | | | 182 | |
186 | /* | | 183 | /* |
187 | * kmem_intr_alloc: allocate wired memory. | | 184 | * kmem_intr_alloc: allocate wired memory. |
| @@ -219,27 +216,26 @@ kmem_intr_alloc(size_t requested_size, k | | | @@ -219,27 +216,26 @@ kmem_intr_alloc(size_t requested_size, k |
219 | | VM_INSTANTFIT, (vmem_addr_t *)&p); | | 216 | | VM_INSTANTFIT, (vmem_addr_t *)&p); |
220 | if (ret) { | | 217 | if (ret) { |
221 | return NULL; | | 218 | return NULL; |
222 | } | | 219 | } |
223 | FREECHECK_OUT(&kmem_freecheck, p); | | 220 | FREECHECK_OUT(&kmem_freecheck, p); |
224 | return p; | | 221 | return p; |
225 | } | | 222 | } |
226 | | | 223 | |
227 | p = pool_cache_get(pc, kmflags); | | 224 | p = pool_cache_get(pc, kmflags); |
228 | | | 225 | |
229 | if (__predict_true(p != NULL)) { | | 226 | if (__predict_true(p != NULL)) { |
230 | FREECHECK_OUT(&kmem_freecheck, p); | | 227 | FREECHECK_OUT(&kmem_freecheck, p); |
231 | kmem_size_set(p, requested_size); | | 228 | kmem_size_set(p, requested_size); |
232 | p += SIZE_SIZE; | | | |
233 | kasan_mark(p, origsize, size, KASAN_KMEM_REDZONE); | | 229 | kasan_mark(p, origsize, size, KASAN_KMEM_REDZONE); |
234 | return p; | | 230 | return p; |
235 | } | | 231 | } |
236 | return p; | | 232 | return p; |
237 | } | | 233 | } |
238 | | | 234 | |
239 | /* | | 235 | /* |
240 | * kmem_intr_zalloc: allocate zeroed wired memory. | | 236 | * kmem_intr_zalloc: allocate zeroed wired memory. |
241 | */ | | 237 | */ |
242 | void * | | 238 | void * |
243 | kmem_intr_zalloc(size_t size, km_flag_t kmflags) | | 239 | kmem_intr_zalloc(size_t size, km_flag_t kmflags) |
244 | { | | 240 | { |
245 | void *p; | | 241 | void *p; |
| @@ -273,27 +269,26 @@ kmem_intr_free(void *p, size_t requested | | | @@ -273,27 +269,26 @@ kmem_intr_free(void *p, size_t requested |
273 | pc = kmem_cache[index]; | | 269 | pc = kmem_cache[index]; |
274 | } else if ((index = ((allocsz - 1) >> KMEM_BIG_SHIFT)) | | 270 | } else if ((index = ((allocsz - 1) >> KMEM_BIG_SHIFT)) |
275 | < kmem_cache_big_maxidx) { | | 271 | < kmem_cache_big_maxidx) { |
276 | pc = kmem_cache_big[index]; | | 272 | pc = kmem_cache_big[index]; |
277 | } else { | | 273 | } else { |
278 | FREECHECK_IN(&kmem_freecheck, p); | | 274 | FREECHECK_IN(&kmem_freecheck, p); |
279 | uvm_km_kmem_free(kmem_va_arena, (vaddr_t)p, | | 275 | uvm_km_kmem_free(kmem_va_arena, (vaddr_t)p, |
280 | round_page(size)); | | 276 | round_page(size)); |
281 | return; | | 277 | return; |
282 | } | | 278 | } |
283 | | | 279 | |
284 | kasan_mark(p, size, size, 0); | | 280 | kasan_mark(p, size, size, 0); |
285 | | | 281 | |
286 | p = (uint8_t *)p - SIZE_SIZE; | | | |
287 | kmem_size_check(p, requested_size); | | 282 | kmem_size_check(p, requested_size); |
288 | FREECHECK_IN(&kmem_freecheck, p); | | 283 | FREECHECK_IN(&kmem_freecheck, p); |
289 | LOCKDEBUG_MEM_CHECK(p, size); | | 284 | LOCKDEBUG_MEM_CHECK(p, size); |
290 | | | 285 | |
291 | pool_cache_put(pc, p); | | 286 | pool_cache_put(pc, p); |
292 | } | | 287 | } |
293 | | | 288 | |
294 | /* -------------------------------- Kmem API -------------------------------- */ | | 289 | /* -------------------------------- Kmem API -------------------------------- */ |
295 | | | 290 | |
296 | /* | | 291 | /* |
297 | * kmem_alloc: allocate wired memory. | | 292 | * kmem_alloc: allocate wired memory. |
298 | * => must not be called from interrupt context. | | 293 | * => must not be called from interrupt context. |
299 | */ | | 294 | */ |
| @@ -475,35 +470,31 @@ kmem_strfree(char *str) | | | @@ -475,35 +470,31 @@ kmem_strfree(char *str) |
475 | { | | 470 | { |
476 | if (str == NULL) | | 471 | if (str == NULL) |
477 | return; | | 472 | return; |
478 | | | 473 | |
479 | kmem_free(str, strlen(str) + 1); | | 474 | kmem_free(str, strlen(str) + 1); |
480 | } | | 475 | } |
481 | | | 476 | |
482 | /* --------------------------- DEBUG / DIAGNOSTIC --------------------------- */ | | 477 | /* --------------------------- DEBUG / DIAGNOSTIC --------------------------- */ |
483 | | | 478 | |
484 | #if defined(KMEM_SIZE) | | 479 | #if defined(KMEM_SIZE) |
485 | static void | | 480 | static void |
486 | kmem_size_set(void *p, size_t sz) | | 481 | kmem_size_set(void *p, size_t sz) |
487 | { | | 482 | { |
488 | struct kmem_header *hd; | | 483 | memcpy((size_t *)((uintptr_t)p + sz), &sz, sizeof(size_t)); |
489 | hd = (struct kmem_header *)p; | | | |
490 | hd->size = sz; | | | |
491 | } | | 484 | } |
492 | | | 485 | |
493 | static void | | 486 | static void |
494 | kmem_size_check(void *p, size_t sz) | | 487 | kmem_size_check(void *p, size_t sz) |
495 | { | | 488 | { |
496 | struct kmem_header *hd; | | | |
497 | size_t hsz; | | 489 | size_t hsz; |
498 | | | 490 | |
499 | hd = (struct kmem_header *)p; | | 491 | memcpy(&hsz, (size_t *)((uintptr_t)p + sz), sizeof(size_t)); |
500 | hsz = hd->size; | | | |
501 | | | 492 | |
502 | if (hsz != sz) { | | 493 | if (hsz != sz) { |
503 | panic("kmem_free(%p, %zu) != allocated size %zu", | | 494 | panic("kmem_free(%p, %zu) != allocated size %zu; overwrote?", |
504 | (const uint8_t *)p + SIZE_SIZE, sz, hsz); | | 495 | p, sz, hsz); |
505 | } | | 496 | } |
506 | | | 497 | |
507 | hd->size = -1; | | 498 | memset((size_t *)((uintptr_t)p + sz), 0xff, sizeof(size_t)); |
508 | } | | 499 | } |
509 | #endif /* defined(KMEM_SIZE) */ | | 500 | #endif /* defined(KMEM_SIZE) */ |