]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/kalloc.c
63b8aaffb88f45ba8b30c8a47046644eb1bf531a
[apple/xnu.git] / osfmk / kern / kalloc.c
1 /*
2 * Copyright (c) 2000-2011 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56 /*
57 */
58 /*
59 * File: kern/kalloc.c
60 * Author: Avadis Tevanian, Jr.
61 * Date: 1985
62 *
63 * General kernel memory allocator. This allocator is designed
64 * to be used by the kernel to manage dynamic memory fast.
65 */
66
67 #include <zone_debug.h>
68
69 #include <mach/boolean.h>
70 #include <mach/sdt.h>
71 #include <mach/machine/vm_types.h>
72 #include <mach/vm_param.h>
73 #include <kern/misc_protos.h>
74 #include <kern/zalloc.h>
75 #include <kern/kalloc.h>
76 #include <kern/ledger.h>
77 #include <vm/vm_kern.h>
78 #include <vm/vm_object.h>
79 #include <vm/vm_map.h>
80 #include <libkern/OSMalloc.h>
81 #include <sys/kdebug.h>
82
83 #include <san/kasan.h>
84
85 #ifdef MACH_BSD
86 zone_t kalloc_zone(vm_size_t);
87 #endif
88
89 #define KALLOC_MAP_SIZE_MIN (16 * 1024 * 1024)
90 #define KALLOC_MAP_SIZE_MAX (128 * 1024 * 1024)
91 vm_map_t kalloc_map;
92 vm_size_t kalloc_max;
93 vm_size_t kalloc_max_prerounded;
94 vm_size_t kalloc_kernmap_size; /* size of kallocs that can come from kernel map */
95
96 /* how many times we couldn't allocate out of kalloc_map and fell back to kernel_map */
97 unsigned long kalloc_fallback_count;
98
99 unsigned int kalloc_large_inuse;
100 vm_size_t kalloc_large_total;
101 vm_size_t kalloc_large_max;
102 vm_size_t kalloc_largest_allocated = 0;
103 uint64_t kalloc_large_sum;
104
105 int kalloc_fake_zone_index = -1; /* index of our fake zone in statistics arrays */
106
107 vm_offset_t kalloc_map_min;
108 vm_offset_t kalloc_map_max;
109
110 #ifdef MUTEX_ZONE
111 /*
112 * Diagnostic code to track mutexes separately rather than via the 2^ zones
113 */
114 zone_t lck_mtx_zone;
115 #endif
116
117 static void
118 KALLOC_ZINFO_SALLOC(vm_size_t bytes)
119 {
120 thread_t thr = current_thread();
121 ledger_debit(thr->t_ledger, task_ledgers.tkm_shared, bytes);
122 }
123
124 static void
125 KALLOC_ZINFO_SFREE(vm_size_t bytes)
126 {
127 thread_t thr = current_thread();
128 ledger_credit(thr->t_ledger, task_ledgers.tkm_shared, bytes);
129 }
130
131 /*
132 * All allocations of size less than kalloc_max are rounded to the next nearest
133 * sized zone. This allocator is built on top of the zone allocator. A zone
134 * is created for each potential size that we are willing to get in small
135 * blocks.
136 *
137 * We assume that kalloc_max is not greater than 64K;
138 *
139 * Note that kalloc_max is somewhat confusingly named. It represents the first
140 * power of two for which no zone exists. kalloc_max_prerounded is the
141 * smallest allocation size, before rounding, for which no zone exists.
142 *
143 * Also if the allocation size is more than kalloc_kernmap_size then allocate
144 * from kernel map rather than kalloc_map.
145 */
146
147 #define KALLOC_MINALIGN (1 << KALLOC_LOG2_MINALIGN)
148 #define KiB(x) (1024 * (x))
149
150 /*
151 * The k_zone_config table defines the configuration of zones on various platforms.
152 * The currently defined list of zones and their per-CPU caching behavior are as
153 * follows (X:zone not present; N:zone present no cpu-caching; Y:zone present with cpu-caching):
154 *
155 * Size macOS(64-bit) embedded(32-bit) embedded(64-bit)
156 *-------- ---------------- ---------------- ----------------
157 *
158 * 8 X Y X
159 * 16 Y Y Y
160 * 24 X Y X
161 * 32 Y Y Y
162 * 40 X Y X
163 * 48 Y Y Y
164 * 64 Y Y Y
165 * 72 X Y X
166 * 80 Y X Y
167 * 88 X Y X
168 * 96 Y X Y
169 * 112 X Y X
170 * 128 Y Y Y
171 * 160 Y X Y
172 * 192 Y Y Y
173 * 224 Y X Y
174 * 256 Y Y Y
175 * 288 Y Y Y
176 * 368 Y X Y
177 * 384 X Y X
178 * 400 Y X Y
179 * 440 X Y X
180 * 512 Y Y Y
181 * 576 Y N N
182 * 768 Y N N
183 * 1024 Y Y Y
184 * 1152 N N N
185 * 1280 N N N
186 * 1536 X N X
187 * 1664 N X N
188 * 2048 Y N N
189 * 2128 X N X
190 * 3072 X N X
191 * 4096 Y N N
192 * 6144 N N N
193 * 8192 Y N N
194 * 16384 N N N
195 * 32768 N N N
196 *
197 */
198 static const struct kalloc_zone_config {
199 bool kzc_caching;
200 int kzc_size;
201 const char *kzc_name;
202 } k_zone_config[] = {
203 #define KZC_ENTRY(SIZE, caching) { .kzc_caching = (caching), .kzc_size = (SIZE), .kzc_name = "kalloc." #SIZE }
204
205 #if CONFIG_EMBEDDED
206
207 #if KALLOC_MINSIZE == 16 && KALLOC_LOG2_MINALIGN == 4
208 /* Zone config for embedded 64-bit platforms */
209 KZC_ENTRY(16, true),
210 KZC_ENTRY(32, true),
211 KZC_ENTRY(48, true),
212 KZC_ENTRY(64, true),
213 KZC_ENTRY(80, true),
214 KZC_ENTRY(96, true),
215 KZC_ENTRY(128, true),
216 KZC_ENTRY(160, true),
217 KZC_ENTRY(192, true),
218 KZC_ENTRY(224, true),
219 KZC_ENTRY(256, true),
220 KZC_ENTRY(288, true),
221 KZC_ENTRY(368, true),
222 KZC_ENTRY(400, true),
223 KZC_ENTRY(512, true),
224 KZC_ENTRY(576, false),
225 KZC_ENTRY(768, false),
226 KZC_ENTRY(1024, true),
227 KZC_ENTRY(1152, false),
228 KZC_ENTRY(1280, false),
229 KZC_ENTRY(1664, false),
230 KZC_ENTRY(2048, false),
231 KZC_ENTRY(4096, false),
232 KZC_ENTRY(6144, false),
233 KZC_ENTRY(8192, false),
234 KZC_ENTRY(16384, false),
235 KZC_ENTRY(32768, false),
236
237 #elif KALLOC_MINSIZE == 8 && KALLOC_LOG2_MINALIGN == 3
238 /* Zone config for embedded 32-bit platforms */
239 KZC_ENTRY(8, true),
240 KZC_ENTRY(16, true),
241 KZC_ENTRY(24, true),
242 KZC_ENTRY(32, true),
243 KZC_ENTRY(40, true),
244 KZC_ENTRY(48, true),
245 KZC_ENTRY(64, true),
246 KZC_ENTRY(72, true),
247 KZC_ENTRY(88, true),
248 KZC_ENTRY(112, true),
249 KZC_ENTRY(128, true),
250 KZC_ENTRY(192, true),
251 KZC_ENTRY(256, true),
252 KZC_ENTRY(288, true),
253 KZC_ENTRY(384, true),
254 KZC_ENTRY(440, true),
255 KZC_ENTRY(512, true),
256 KZC_ENTRY(576, false),
257 KZC_ENTRY(768, false),
258 KZC_ENTRY(1024, true),
259 KZC_ENTRY(1152, false),
260 KZC_ENTRY(1280, false),
261 KZC_ENTRY(1536, false),
262 KZC_ENTRY(2048, false),
263 KZC_ENTRY(2128, false),
264 KZC_ENTRY(3072, false),
265 KZC_ENTRY(4096, false),
266 KZC_ENTRY(6144, false),
267 KZC_ENTRY(8192, false),
268 KZC_ENTRY(16384, false),
269 KZC_ENTRY(32768, false),
270
271 #else
272 #error missing or invalid zone size parameters for kalloc
273 #endif
274
275 #else /* CONFIG_EMBEDDED */
276
277 /* Zone config for macOS 64-bit platforms */
278 KZC_ENTRY(16, true),
279 KZC_ENTRY(32, true),
280 KZC_ENTRY(48, true),
281 KZC_ENTRY(64, true),
282 KZC_ENTRY(80, true),
283 KZC_ENTRY(96, true),
284 KZC_ENTRY(128, true),
285 KZC_ENTRY(160, true),
286 KZC_ENTRY(192, true),
287 KZC_ENTRY(224, true),
288 KZC_ENTRY(256, true),
289 KZC_ENTRY(288, true),
290 KZC_ENTRY(368, true),
291 KZC_ENTRY(400, true),
292 KZC_ENTRY(512, true),
293 KZC_ENTRY(576, true),
294 KZC_ENTRY(768, true),
295 KZC_ENTRY(1024, true),
296 KZC_ENTRY(1152, false),
297 KZC_ENTRY(1280, false),
298 KZC_ENTRY(1664, false),
299 KZC_ENTRY(2048, true),
300 KZC_ENTRY(4096, true),
301 KZC_ENTRY(6144, false),
302 KZC_ENTRY(8192, true),
303 KZC_ENTRY(16384, false),
304 KZC_ENTRY(32768, false),
305
306 #endif /* CONFIG_EMBEDDED */
307
308 #undef KZC_ENTRY
309 };
310
311 #define MAX_K_ZONE (int)(sizeof(k_zone_config) / sizeof(k_zone_config[0]))
312
313 /*
314 * Many kalloc() allocations are for small structures containing a few
315 * pointers and longs - the k_zone_dlut[] direct lookup table, indexed by
316 * size normalized to the minimum alignment, finds the right zone index
317 * for them in one dereference.
318 */
319
320 #define INDEX_ZDLUT(size) \
321 (((size) + KALLOC_MINALIGN - 1) / KALLOC_MINALIGN)
322 #define N_K_ZDLUT (2048 / KALLOC_MINALIGN)
323 /* covers sizes [0 .. 2048 - KALLOC_MINALIGN] */
324 #define MAX_SIZE_ZDLUT ((N_K_ZDLUT - 1) * KALLOC_MINALIGN)
325
326 static int8_t k_zone_dlut[N_K_ZDLUT]; /* table of indices into k_zone[] */
327
328 /*
329 * If there's no hit in the DLUT, then start searching from k_zindex_start.
330 */
331 static int k_zindex_start;
332
333 static zone_t k_zone[MAX_K_ZONE];
334
335 /* #define KALLOC_DEBUG 1 */
336
337 /* forward declarations */
338
339 lck_grp_t kalloc_lck_grp;
340 lck_mtx_t kalloc_lock;
341
342 #define kalloc_spin_lock() lck_mtx_lock_spin(&kalloc_lock)
343 #define kalloc_unlock() lck_mtx_unlock(&kalloc_lock)
344
345
346 /* OSMalloc local data declarations */
347 static
348 queue_head_t OSMalloc_tag_list;
349
350 lck_grp_t *OSMalloc_tag_lck_grp;
351 lck_mtx_t OSMalloc_tag_lock;
352
353 #define OSMalloc_tag_spin_lock() lck_mtx_lock_spin(&OSMalloc_tag_lock)
354 #define OSMalloc_tag_unlock() lck_mtx_unlock(&OSMalloc_tag_lock)
355
356
357 /* OSMalloc forward declarations */
358 void OSMalloc_init(void);
359 void OSMalloc_Tagref(OSMallocTag tag);
360 void OSMalloc_Tagrele(OSMallocTag tag);
361
362 /*
363 * Initialize the memory allocator. This should be called only
364 * once on a system wide basis (i.e. first processor to get here
365 * does the initialization).
366 *
367 * This initializes all of the zones.
368 */
369
370 void
371 kalloc_init(
372 void)
373 {
374 kern_return_t retval;
375 vm_offset_t min;
376 vm_size_t size, kalloc_map_size;
377 vm_map_kernel_flags_t vmk_flags;
378
379 /*
380 * Scale the kalloc_map_size to physical memory size: stay below
381 * 1/8th the total zone map size, or 128 MB (for a 32-bit kernel).
382 */
383 kalloc_map_size = (vm_size_t)(sane_size >> 5);
384 #if !__LP64__
385 if (kalloc_map_size > KALLOC_MAP_SIZE_MAX) {
386 kalloc_map_size = KALLOC_MAP_SIZE_MAX;
387 }
388 #endif /* !__LP64__ */
389 if (kalloc_map_size < KALLOC_MAP_SIZE_MIN) {
390 kalloc_map_size = KALLOC_MAP_SIZE_MIN;
391 }
392
393 vmk_flags = VM_MAP_KERNEL_FLAGS_NONE;
394 vmk_flags.vmkf_permanent = TRUE;
395
396 retval = kmem_suballoc(kernel_map, &min, kalloc_map_size,
397 FALSE,
398 (VM_FLAGS_ANYWHERE),
399 vmk_flags,
400 VM_KERN_MEMORY_KALLOC,
401 &kalloc_map);
402
403 if (retval != KERN_SUCCESS) {
404 panic("kalloc_init: kmem_suballoc failed");
405 }
406
407 kalloc_map_min = min;
408 kalloc_map_max = min + kalloc_map_size - 1;
409
410 /*
411 * Create zones up to a least 4 pages because small page-multiples are
412 * common allocations. Also ensure that zones up to size 16KB bytes exist.
413 * This is desirable because messages are allocated with kalloc(), and
414 * messages up through size 8192 are common.
415 */
416 kalloc_max = PAGE_SIZE << 2;
417 if (kalloc_max < KiB(16)) {
418 kalloc_max = KiB(16);
419 }
420 assert(kalloc_max <= KiB(64)); /* assumption made in size arrays */
421
422 kalloc_max_prerounded = kalloc_max / 2 + 1;
423 /* allocations larger than 16 times kalloc_max go directly to kernel map */
424 kalloc_kernmap_size = (kalloc_max * 16) + 1;
425 kalloc_largest_allocated = kalloc_kernmap_size;
426
427 /*
428 * Allocate a zone for each size we are going to handle.
429 */
430 for (int i = 0; i < MAX_K_ZONE && (size = k_zone_config[i].kzc_size) < kalloc_max; i++) {
431 k_zone[i] = zinit(size, size, size, k_zone_config[i].kzc_name);
432
433 /*
434 * Don't charge the caller for the allocation, as we aren't sure how
435 * the memory will be handled.
436 */
437 zone_change(k_zone[i], Z_CALLERACCT, FALSE);
438 #if VM_MAX_TAG_ZONES
439 if (zone_tagging_on) {
440 zone_change(k_zone[i], Z_TAGS_ENABLED, TRUE);
441 }
442 #endif
443 zone_change(k_zone[i], Z_KASAN_QUARANTINE, FALSE);
444 if (k_zone_config[i].kzc_caching) {
445 zone_change(k_zone[i], Z_CACHING_ENABLED, TRUE);
446 }
447 }
448
449 /*
450 * Build the Direct LookUp Table for small allocations
451 */
452 size = 0;
453 for (int i = 0; i <= N_K_ZDLUT; i++, size += KALLOC_MINALIGN) {
454 int zindex = 0;
455
456 while ((vm_size_t)k_zone_config[zindex].kzc_size < size) {
457 zindex++;
458 }
459
460 if (i == N_K_ZDLUT) {
461 k_zindex_start = zindex;
462 break;
463 }
464 k_zone_dlut[i] = (int8_t)zindex;
465 }
466
467 #ifdef KALLOC_DEBUG
468 printf("kalloc_init: k_zindex_start %d\n", k_zindex_start);
469
470 /*
471 * Do a quick synthesis to see how well/badly we can
472 * find-a-zone for a given size.
473 * Useful when debugging/tweaking the array of zone sizes.
474 * Cache misses probably more critical than compare-branches!
475 */
476 for (int i = 0; i < MAX_K_ZONE; i++) {
477 vm_size_t testsize = (vm_size_t)k_zone_config[i].kzc_size - 1;
478 int compare = 0;
479 int zindex;
480
481 if (testsize < MAX_SIZE_ZDLUT) {
482 compare += 1; /* 'if' (T) */
483
484 long dindex = INDEX_ZDLUT(testsize);
485 zindex = (int)k_zone_dlut[dindex];
486 } else if (testsize < kalloc_max_prerounded) {
487 compare += 2; /* 'if' (F), 'if' (T) */
488
489 zindex = k_zindex_start;
490 while ((vm_size_t)k_zone_config[zindex].kzc_size < testsize) {
491 zindex++;
492 compare++; /* 'while' (T) */
493 }
494 compare++; /* 'while' (F) */
495 } else {
496 break; /* not zone-backed */
497 }
498 zone_t z = k_zone[zindex];
499 printf("kalloc_init: req size %4lu: %11s took %d compare%s\n",
500 (unsigned long)testsize, z->zone_name, compare,
501 compare == 1 ? "" : "s");
502 }
503 #endif
504
505 lck_grp_init(&kalloc_lck_grp, "kalloc.large", LCK_GRP_ATTR_NULL);
506 lck_mtx_init(&kalloc_lock, &kalloc_lck_grp, LCK_ATTR_NULL);
507 OSMalloc_init();
508 #ifdef MUTEX_ZONE
509 lck_mtx_zone = zinit(sizeof(struct _lck_mtx_), 1024 * 256, 4096, "lck_mtx");
510 #endif
511 }
512
513 /*
514 * Given an allocation size, return the kalloc zone it belongs to.
515 * Direct LookUp Table variant.
516 */
517 static __inline zone_t
518 get_zone_dlut(vm_size_t size)
519 {
520 long dindex = INDEX_ZDLUT(size);
521 int zindex = (int)k_zone_dlut[dindex];
522 return k_zone[zindex];
523 }
524
525 /* As above, but linear search k_zone_config[] for the next zone that fits. */
526
527 static __inline zone_t
528 get_zone_search(vm_size_t size, int zindex)
529 {
530 assert(size < kalloc_max_prerounded);
531
532 while ((vm_size_t)k_zone_config[zindex].kzc_size < size) {
533 zindex++;
534 }
535
536 assert(zindex < MAX_K_ZONE &&
537 (vm_size_t)k_zone_config[zindex].kzc_size < kalloc_max);
538
539 return k_zone[zindex];
540 }
541
542 static vm_size_t
543 vm_map_lookup_kalloc_entry_locked(
544 vm_map_t map,
545 void *addr)
546 {
547 boolean_t ret;
548 vm_map_entry_t vm_entry = NULL;
549
550 ret = vm_map_lookup_entry(map, (vm_map_offset_t)addr, &vm_entry);
551 if (!ret) {
552 panic("Attempting to lookup/free an address not allocated via kalloc! (vm_map_lookup_entry() failed map: %p, addr: %p)\n",
553 map, addr);
554 }
555 if (vm_entry->vme_start != (vm_map_offset_t)addr) {
556 panic("Attempting to lookup/free the middle of a kalloc'ed element! (map: %p, addr: %p, entry: %p)\n",
557 map, addr, vm_entry);
558 }
559 if (!vm_entry->vme_atomic) {
560 panic("Attempting to lookup/free an address not managed by kalloc! (map: %p, addr: %p, entry: %p)\n",
561 map, addr, vm_entry);
562 }
563 return vm_entry->vme_end - vm_entry->vme_start;
564 }
565
566 #if KASAN_KALLOC
567 /*
568 * KASAN kalloc stashes the original user-requested size away in the poisoned
569 * area. Return that directly.
570 */
571 vm_size_t
572 kalloc_size(void *addr)
573 {
574 (void)vm_map_lookup_kalloc_entry_locked; /* silence warning */
575 return kasan_user_size((vm_offset_t)addr);
576 }
577 #else
578 vm_size_t
579 kalloc_size(
580 void *addr)
581 {
582 vm_map_t map;
583 vm_size_t size;
584
585 size = zone_element_size(addr, NULL);
586 if (size) {
587 return size;
588 }
589 if (((vm_offset_t)addr >= kalloc_map_min) && ((vm_offset_t)addr < kalloc_map_max)) {
590 map = kalloc_map;
591 } else {
592 map = kernel_map;
593 }
594 vm_map_lock_read(map);
595 size = vm_map_lookup_kalloc_entry_locked(map, addr);
596 vm_map_unlock_read(map);
597 return size;
598 }
599 #endif
600
601 vm_size_t
602 kalloc_bucket_size(
603 vm_size_t size)
604 {
605 zone_t z;
606 vm_map_t map;
607
608 if (size < MAX_SIZE_ZDLUT) {
609 z = get_zone_dlut(size);
610 return z->elem_size;
611 }
612
613 if (size < kalloc_max_prerounded) {
614 z = get_zone_search(size, k_zindex_start);
615 return z->elem_size;
616 }
617
618 if (size >= kalloc_kernmap_size) {
619 map = kernel_map;
620 } else {
621 map = kalloc_map;
622 }
623
624 return vm_map_round_page(size, VM_MAP_PAGE_MASK(map));
625 }
626
627 #if KASAN_KALLOC
628 vm_size_t
629 (kfree_addr)(void *addr)
630 {
631 vm_size_t origsz = kalloc_size(addr);
632 kfree(addr, origsz);
633 return origsz;
634 }
635 #else
636 vm_size_t
637 (kfree_addr)(
638 void *addr)
639 {
640 vm_map_t map;
641 vm_size_t size = 0;
642 kern_return_t ret;
643 zone_t z;
644
645 size = zone_element_size(addr, &z);
646 if (size) {
647 DTRACE_VM3(kfree, vm_size_t, -1, vm_size_t, z->elem_size, void*, addr);
648 zfree(z, addr);
649 return size;
650 }
651
652 if (((vm_offset_t)addr >= kalloc_map_min) && ((vm_offset_t)addr < kalloc_map_max)) {
653 map = kalloc_map;
654 } else {
655 map = kernel_map;
656 }
657 if ((vm_offset_t)addr < VM_MIN_KERNEL_AND_KEXT_ADDRESS) {
658 panic("kfree on an address not in the kernel & kext address range! addr: %p\n", addr);
659 }
660
661 vm_map_lock(map);
662 size = vm_map_lookup_kalloc_entry_locked(map, addr);
663 ret = vm_map_remove_locked(map,
664 vm_map_trunc_page((vm_map_offset_t)addr,
665 VM_MAP_PAGE_MASK(map)),
666 vm_map_round_page((vm_map_offset_t)addr + size,
667 VM_MAP_PAGE_MASK(map)),
668 VM_MAP_REMOVE_KUNWIRE);
669 if (ret != KERN_SUCCESS) {
670 panic("vm_map_remove_locked() failed for kalloc vm_entry! addr: %p, map: %p ret: %d\n",
671 addr, map, ret);
672 }
673 vm_map_unlock(map);
674 DTRACE_VM3(kfree, vm_size_t, -1, vm_size_t, size, void*, addr);
675
676 kalloc_spin_lock();
677 kalloc_large_total -= size;
678 kalloc_large_inuse--;
679 kalloc_unlock();
680
681 KALLOC_ZINFO_SFREE(size);
682 return size;
683 }
684 #endif
685
686 void *
687 kalloc_canblock(
688 vm_size_t * psize,
689 boolean_t canblock,
690 vm_allocation_site_t * site)
691 {
692 zone_t z;
693 vm_size_t size;
694 void *addr;
695 vm_tag_t tag;
696
697 tag = VM_KERN_MEMORY_KALLOC;
698 size = *psize;
699
700 #if KASAN_KALLOC
701 /* expand the allocation to accomodate redzones */
702 vm_size_t req_size = size;
703 size = kasan_alloc_resize(req_size);
704 #endif
705
706 if (size < MAX_SIZE_ZDLUT) {
707 z = get_zone_dlut(size);
708 } else if (size < kalloc_max_prerounded) {
709 z = get_zone_search(size, k_zindex_start);
710 } else {
711 /*
712 * If size is too large for a zone, then use kmem_alloc.
713 * (We use kmem_alloc instead of kmem_alloc_kobject so that
714 * krealloc can use kmem_realloc.)
715 */
716 vm_map_t alloc_map;
717
718 /* kmem_alloc could block so we return if noblock */
719 if (!canblock) {
720 return NULL;
721 }
722
723 #if KASAN_KALLOC
724 /* large allocation - use guard pages instead of small redzones */
725 size = round_page(req_size + 2 * PAGE_SIZE);
726 assert(size >= MAX_SIZE_ZDLUT && size >= kalloc_max_prerounded);
727 #endif
728
729 if (size >= kalloc_kernmap_size) {
730 alloc_map = kernel_map;
731 } else {
732 alloc_map = kalloc_map;
733 }
734
735 if (site) {
736 tag = vm_tag_alloc(site);
737 }
738
739 if (kmem_alloc_flags(alloc_map, (vm_offset_t *)&addr, size, tag, KMA_ATOMIC) != KERN_SUCCESS) {
740 if (alloc_map != kernel_map) {
741 if (kalloc_fallback_count++ == 0) {
742 printf("%s: falling back to kernel_map\n", __func__);
743 }
744 if (kmem_alloc_flags(kernel_map, (vm_offset_t *)&addr, size, tag, KMA_ATOMIC) != KERN_SUCCESS) {
745 addr = NULL;
746 }
747 } else {
748 addr = NULL;
749 }
750 }
751
752 if (addr != NULL) {
753 kalloc_spin_lock();
754 /*
755 * Thread-safe version of the workaround for 4740071
756 * (a double FREE())
757 */
758 if (size > kalloc_largest_allocated) {
759 kalloc_largest_allocated = size;
760 }
761
762 kalloc_large_inuse++;
763 kalloc_large_total += size;
764 kalloc_large_sum += size;
765
766 if (kalloc_large_total > kalloc_large_max) {
767 kalloc_large_max = kalloc_large_total;
768 }
769
770 kalloc_unlock();
771
772 KALLOC_ZINFO_SALLOC(size);
773 }
774 #if KASAN_KALLOC
775 /* fixup the return address to skip the redzone */
776 addr = (void *)kasan_alloc((vm_offset_t)addr, size, req_size, PAGE_SIZE);
777 #else
778 *psize = round_page(size);
779 #endif
780 DTRACE_VM3(kalloc, vm_size_t, size, vm_size_t, *psize, void*, addr);
781 return addr;
782 }
783 #ifdef KALLOC_DEBUG
784 if (size > z->elem_size) {
785 panic("%s: z %p (%s) but requested size %lu", __func__,
786 z, z->zone_name, (unsigned long)size);
787 }
788 #endif
789
790 assert(size <= z->elem_size);
791
792 #if VM_MAX_TAG_ZONES
793 if (z->tags && site) {
794 tag = vm_tag_alloc(site);
795 if (!canblock && !vm_allocation_zone_totals[tag]) {
796 tag = VM_KERN_MEMORY_KALLOC;
797 }
798 }
799 #endif
800
801 addr = zalloc_canblock_tag(z, canblock, size, tag);
802
803 #if KASAN_KALLOC
804 /* fixup the return address to skip the redzone */
805 addr = (void *)kasan_alloc((vm_offset_t)addr, z->elem_size, req_size, KASAN_GUARD_SIZE);
806
807 /* For KASan, the redzone lives in any additional space, so don't
808 * expand the allocation. */
809 #else
810 *psize = z->elem_size;
811 #endif
812
813 DTRACE_VM3(kalloc, vm_size_t, size, vm_size_t, *psize, void*, addr);
814 return addr;
815 }
816
817 void *
818 kalloc_external(
819 vm_size_t size);
820 void *
821 kalloc_external(
822 vm_size_t size)
823 {
824 return kalloc_tag_bt(size, VM_KERN_MEMORY_KALLOC);
825 }
826
827 void
828 (kfree)(
829 void *data,
830 vm_size_t size)
831 {
832 zone_t z;
833
834 #if KASAN_KALLOC
835 /*
836 * Resize back to the real allocation size and hand off to the KASan
837 * quarantine. `data` may then point to a different allocation.
838 */
839 vm_size_t user_size = size;
840 kasan_check_free((vm_address_t)data, size, KASAN_HEAP_KALLOC);
841 data = (void *)kasan_dealloc((vm_address_t)data, &size);
842 kasan_free(&data, &size, KASAN_HEAP_KALLOC, NULL, user_size, true);
843 if (!data) {
844 return;
845 }
846 #endif
847
848 if (size < MAX_SIZE_ZDLUT) {
849 z = get_zone_dlut(size);
850 } else if (size < kalloc_max_prerounded) {
851 z = get_zone_search(size, k_zindex_start);
852 } else {
853 /* if size was too large for a zone, then use kmem_free */
854
855 vm_map_t alloc_map = kernel_map;
856
857 if ((((vm_offset_t) data) >= kalloc_map_min) && (((vm_offset_t) data) <= kalloc_map_max)) {
858 alloc_map = kalloc_map;
859 }
860 if (size > kalloc_largest_allocated) {
861 panic("kfree: size %lu > kalloc_largest_allocated %lu", (unsigned long)size, (unsigned long)kalloc_largest_allocated);
862 }
863 kmem_free(alloc_map, (vm_offset_t)data, size);
864 kalloc_spin_lock();
865
866 kalloc_large_total -= size;
867 kalloc_large_inuse--;
868
869 kalloc_unlock();
870
871 #if !KASAN_KALLOC
872 DTRACE_VM3(kfree, vm_size_t, size, vm_size_t, size, void*, data);
873 #endif
874
875 KALLOC_ZINFO_SFREE(size);
876 return;
877 }
878
879 /* free to the appropriate zone */
880 #ifdef KALLOC_DEBUG
881 if (size > z->elem_size) {
882 panic("%s: z %p (%s) but requested size %lu", __func__,
883 z, z->zone_name, (unsigned long)size);
884 }
885 #endif
886 assert(size <= z->elem_size);
887 #if !KASAN_KALLOC
888 DTRACE_VM3(kfree, vm_size_t, size, vm_size_t, z->elem_size, void*, data);
889 #endif
890 zfree(z, data);
891 }
892
893 #ifdef MACH_BSD
894 zone_t
895 kalloc_zone(
896 vm_size_t size)
897 {
898 if (size < MAX_SIZE_ZDLUT) {
899 return get_zone_dlut(size);
900 }
901 if (size <= kalloc_max) {
902 return get_zone_search(size, k_zindex_start);
903 }
904 return ZONE_NULL;
905 }
906 #endif
907
908 void
909 OSMalloc_init(
910 void)
911 {
912 queue_init(&OSMalloc_tag_list);
913
914 OSMalloc_tag_lck_grp = lck_grp_alloc_init("OSMalloc_tag", LCK_GRP_ATTR_NULL);
915 lck_mtx_init(&OSMalloc_tag_lock, OSMalloc_tag_lck_grp, LCK_ATTR_NULL);
916 }
917
918 OSMallocTag
919 OSMalloc_Tagalloc(
920 const char *str,
921 uint32_t flags)
922 {
923 OSMallocTag OSMTag;
924
925 OSMTag = (OSMallocTag)kalloc(sizeof(*OSMTag));
926
927 bzero((void *)OSMTag, sizeof(*OSMTag));
928
929 if (flags & OSMT_PAGEABLE) {
930 OSMTag->OSMT_attr = OSMT_ATTR_PAGEABLE;
931 }
932
933 OSMTag->OSMT_refcnt = 1;
934
935 strlcpy(OSMTag->OSMT_name, str, OSMT_MAX_NAME);
936
937 OSMalloc_tag_spin_lock();
938 enqueue_tail(&OSMalloc_tag_list, (queue_entry_t)OSMTag);
939 OSMalloc_tag_unlock();
940 OSMTag->OSMT_state = OSMT_VALID;
941 return OSMTag;
942 }
943
944 void
945 OSMalloc_Tagref(
946 OSMallocTag tag)
947 {
948 if (!((tag->OSMT_state & OSMT_VALID_MASK) == OSMT_VALID)) {
949 panic("OSMalloc_Tagref():'%s' has bad state 0x%08X\n", tag->OSMT_name, tag->OSMT_state);
950 }
951
952 (void)hw_atomic_add(&tag->OSMT_refcnt, 1);
953 }
954
955 void
956 OSMalloc_Tagrele(
957 OSMallocTag tag)
958 {
959 if (!((tag->OSMT_state & OSMT_VALID_MASK) == OSMT_VALID)) {
960 panic("OSMalloc_Tagref():'%s' has bad state 0x%08X\n", tag->OSMT_name, tag->OSMT_state);
961 }
962
963 if (hw_atomic_sub(&tag->OSMT_refcnt, 1) == 0) {
964 if (hw_compare_and_store(OSMT_VALID | OSMT_RELEASED, OSMT_VALID | OSMT_RELEASED, &tag->OSMT_state)) {
965 OSMalloc_tag_spin_lock();
966 (void)remque((queue_entry_t)tag);
967 OSMalloc_tag_unlock();
968 kfree(tag, sizeof(*tag));
969 } else {
970 panic("OSMalloc_Tagrele():'%s' has refcnt 0\n", tag->OSMT_name);
971 }
972 }
973 }
974
975 void
976 OSMalloc_Tagfree(
977 OSMallocTag tag)
978 {
979 if (!hw_compare_and_store(OSMT_VALID, OSMT_VALID | OSMT_RELEASED, &tag->OSMT_state)) {
980 panic("OSMalloc_Tagfree():'%s' has bad state 0x%08X \n", tag->OSMT_name, tag->OSMT_state);
981 }
982
983 if (hw_atomic_sub(&tag->OSMT_refcnt, 1) == 0) {
984 OSMalloc_tag_spin_lock();
985 (void)remque((queue_entry_t)tag);
986 OSMalloc_tag_unlock();
987 kfree(tag, sizeof(*tag));
988 }
989 }
990
991 void *
992 OSMalloc(
993 uint32_t size,
994 OSMallocTag tag)
995 {
996 void *addr = NULL;
997 kern_return_t kr;
998
999 OSMalloc_Tagref(tag);
1000 if ((tag->OSMT_attr & OSMT_PAGEABLE)
1001 && (size & ~PAGE_MASK)) {
1002 if ((kr = kmem_alloc_pageable_external(kernel_map, (vm_offset_t *)&addr, size)) != KERN_SUCCESS) {
1003 addr = NULL;
1004 }
1005 } else {
1006 addr = kalloc_tag_bt((vm_size_t)size, VM_KERN_MEMORY_KALLOC);
1007 }
1008
1009 if (!addr) {
1010 OSMalloc_Tagrele(tag);
1011 }
1012
1013 return addr;
1014 }
1015
1016 void *
1017 OSMalloc_nowait(
1018 uint32_t size,
1019 OSMallocTag tag)
1020 {
1021 void *addr = NULL;
1022
1023 if (tag->OSMT_attr & OSMT_PAGEABLE) {
1024 return NULL;
1025 }
1026
1027 OSMalloc_Tagref(tag);
1028 /* XXX: use non-blocking kalloc for now */
1029 addr = kalloc_noblock_tag_bt((vm_size_t)size, VM_KERN_MEMORY_KALLOC);
1030 if (addr == NULL) {
1031 OSMalloc_Tagrele(tag);
1032 }
1033
1034 return addr;
1035 }
1036
1037 void *
1038 OSMalloc_noblock(
1039 uint32_t size,
1040 OSMallocTag tag)
1041 {
1042 void *addr = NULL;
1043
1044 if (tag->OSMT_attr & OSMT_PAGEABLE) {
1045 return NULL;
1046 }
1047
1048 OSMalloc_Tagref(tag);
1049 addr = kalloc_noblock_tag_bt((vm_size_t)size, VM_KERN_MEMORY_KALLOC);
1050 if (addr == NULL) {
1051 OSMalloc_Tagrele(tag);
1052 }
1053
1054 return addr;
1055 }
1056
1057 void
1058 OSFree(
1059 void *addr,
1060 uint32_t size,
1061 OSMallocTag tag)
1062 {
1063 if ((tag->OSMT_attr & OSMT_PAGEABLE)
1064 && (size & ~PAGE_MASK)) {
1065 kmem_free(kernel_map, (vm_offset_t)addr, size);
1066 } else {
1067 kfree(addr, size);
1068 }
1069
1070 OSMalloc_Tagrele(tag);
1071 }
1072
1073 uint32_t
1074 OSMalloc_size(
1075 void *addr)
1076 {
1077 return (uint32_t)kalloc_size(addr);
1078 }