]>
Commit | Line | Data |
---|---|---|
f427ee49 A |
1 | /* |
2 | * Copyright (c) 2000-2020 Apple 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 | #ifndef _KERN_ZALLOC_INTERNAL_H_ | |
60 | #define _KERN_ZALLOC_INTERNAL_H_ | |
61 | ||
62 | #include <kern/zalloc.h> | |
63 | #include <kern/locks.h> | |
64 | #include <kern/btlog.h> | |
65 | #include <kern/simple_lock.h> | |
f427ee49 A |
66 | |
67 | #include <os/atomic_private.h> | |
c3c9b80d | 68 | #include <sys/queue.h> |
f427ee49 A |
69 | |
70 | #if KASAN | |
f427ee49 | 71 | #include <san/kasan.h> |
c3c9b80d | 72 | #include <kern/spl.h> |
f427ee49 A |
73 | #endif /* !KASAN */ |
74 | ||
f427ee49 A |
75 | /*! |
76 | * @file <kern/zalloc_internal.h> | |
77 | * | |
78 | * @abstract | |
79 | * Exposes some guts of zalloc to interact with the VM, debugging, copyio and | |
80 | * kalloc subsystems. | |
81 | */ | |
82 | ||
83 | __BEGIN_DECLS | |
84 | ||
85 | #pragma GCC visibility push(hidden) | |
86 | ||
87 | #if CONFIG_GZALLOC | |
88 | typedef struct gzalloc_data { | |
89 | uint32_t gzfc_index; | |
90 | vm_offset_t *gzfc; | |
91 | } gzalloc_data_t; | |
92 | #endif | |
93 | ||
94 | /* | |
95 | * A zone is a collection of fixed size blocks for which there | |
96 | * is fast allocation/deallocation access. Kernel routines can | |
97 | * use zones to manage data structures dynamically, creating a zone | |
98 | * for each type of data structure to be managed. | |
99 | * | |
100 | */ | |
101 | ||
102 | /*! | |
103 | * @typedef zone_pva_t | |
104 | * | |
105 | * @brief | |
106 | * Type used to point to a page virtual address in the zone allocator. | |
107 | * | |
108 | * @description | |
109 | * - Valid pages have the top bit set. | |
110 | * - 0 represents the "NULL" page | |
111 | * - non 0 values with the top bit cleared do not represent any valid page. | |
112 | * the zone freelists use this space to encode "queue" addresses. | |
113 | */ | |
114 | typedef struct zone_packed_virtual_address { | |
115 | uint32_t packed_address; | |
116 | } zone_pva_t; | |
117 | ||
118 | /*! | |
119 | * @struct zone_stats | |
120 | * | |
121 | * @abstract | |
122 | * Per-cpu structure used for basic zone stats. | |
123 | * | |
124 | * @discussion | |
125 | * The values aren't scaled for per-cpu zones. | |
126 | */ | |
127 | struct zone_stats { | |
128 | uint64_t zs_mem_allocated; | |
129 | uint64_t zs_mem_freed; | |
c3c9b80d A |
130 | uint32_t zs_poison_seqno; /* counter for poisoning every N frees */ |
131 | uint32_t zs_alloc_rr; /* allocation rr bias */ | |
f427ee49 A |
132 | }; |
133 | ||
c3c9b80d A |
134 | STAILQ_HEAD(zone_depot, zone_magazine); |
135 | ||
f427ee49 A |
136 | struct zone { |
137 | /* | |
138 | * Readonly / rarely written fields | |
139 | */ | |
140 | ||
141 | /* | |
142 | * The first 4 fields match a zone_view. | |
143 | * | |
144 | * z_self points back to the zone when the zone is initialized, | |
145 | * or is NULL else. | |
146 | */ | |
147 | struct zone *z_self; | |
148 | zone_stats_t z_stats; | |
149 | const char *z_name; | |
150 | struct zone_view *z_views; | |
f427ee49 | 151 | |
c3c9b80d A |
152 | struct thread *z_expander; |
153 | struct zone_cache *__zpercpu z_pcpu_cache; | |
f427ee49 | 154 | |
c3c9b80d A |
155 | uint16_t z_chunk_pages; /* size used for more memory in pages */ |
156 | uint16_t z_chunk_elems; /* count of allocations per chunk */ | |
157 | uint16_t z_elems_rsv; /* maintain a free reserve of elements */ | |
158 | uint16_t z_elem_size; /* size of an element */ | |
f427ee49 A |
159 | |
160 | uint64_t | |
161 | /* | |
162 | * Lifecycle state (Mutable after creation) | |
163 | */ | |
c3c9b80d A |
164 | z_destroyed :1, /* zone is (being) destroyed */ |
165 | z_async_refilling :1, /* asynchronous allocation pending? */ | |
166 | z_replenish_wait :1, /* someone is waiting on the replenish thread */ | |
167 | z_expanding_wait :1, /* is thread waiting for expansion? */ | |
168 | z_expander_vm_priv :1, /* a vm privileged thread is expanding */ | |
f427ee49 A |
169 | |
170 | /* | |
171 | * Security sensitive configuration bits | |
172 | */ | |
c3c9b80d A |
173 | z_allows_foreign :1, /* allow non-zalloc space */ |
174 | z_destructible :1, /* zone can be zdestroy()ed */ | |
f427ee49 | 175 | kalloc_heap :2, /* zone_kheap_id_t when part of a kalloc heap */ |
c3c9b80d A |
176 | z_noencrypt :1, /* do not encrypt pages when hibernating */ |
177 | z_submap_idx :2, /* a Z_SUBMAP_IDX_* value */ | |
178 | z_va_sequester :1, /* page sequester: no VA reuse with other zones */ | |
179 | z_free_zeroes :1, /* clear memory of elements on free and assert on alloc */ | |
f427ee49 A |
180 | |
181 | /* | |
182 | * Behavior configuration bits | |
183 | */ | |
c3c9b80d A |
184 | z_percpu :1, /* the zone is percpu */ |
185 | z_permanent :1, /* the zone allocations are permanent */ | |
186 | z_replenishes :1, /* uses the async replenish mechanism for VM */ | |
187 | z_nocaching :1, /* disallow zone caching for this zone */ | |
f427ee49 | 188 | collectable :1, /* garbage collect empty pages */ |
f427ee49 A |
189 | exhaustible :1, /* merely return if empty? */ |
190 | expandable :1, /* expand zone (with message)? */ | |
191 | no_callout :1, | |
f427ee49 A |
192 | |
193 | _reserved :26, | |
194 | ||
195 | /* | |
196 | * Debugging features | |
197 | */ | |
198 | alignment_required :1, /* element alignment needs to be preserved */ | |
199 | gzalloc_tracked :1, /* this zone is tracked by gzalloc */ | |
200 | gzalloc_exempt :1, /* this zone doesn't participate with gzalloc */ | |
201 | kasan_fakestacks :1, | |
202 | kasan_noquarantine :1, /* whether to use the kasan quarantine */ | |
203 | tag_zone_index :7, | |
204 | tags :1, | |
205 | tags_inline :1, | |
206 | zleak_on :1, /* Are we collecting allocation information? */ | |
207 | zone_logging :1; /* Enable zone logging for this zone. */ | |
208 | ||
209 | /* | |
210 | * often mutated fields | |
211 | */ | |
212 | ||
c3c9b80d A |
213 | lck_spin_t z_lock; |
214 | struct zone_depot z_recirc; | |
215 | ||
216 | /* | |
217 | * Page accounting (wired / VA) | |
218 | * | |
219 | * Those numbers are unscaled for z_percpu zones | |
220 | * (zone_scale_for_percpu() needs to be used to find the true value). | |
221 | */ | |
222 | uint32_t z_wired_max; /* how large can this zone grow */ | |
223 | uint32_t z_wired_hwm; /* z_wired_cur high watermark */ | |
224 | uint32_t z_wired_cur; /* number of pages used by this zone */ | |
225 | uint32_t z_wired_empty; /* pages collectable by GC */ | |
226 | uint32_t z_va_cur; /* amount of VA used by this zone */ | |
f427ee49 A |
227 | |
228 | /* | |
229 | * list of metadata structs, which maintain per-page free element lists | |
230 | * | |
231 | * Note: Due to the index packing in page metadata, | |
232 | * these pointers can't be at the beginning of the zone struct. | |
233 | */ | |
c3c9b80d A |
234 | zone_pva_t z_pageq_empty; /* populated, completely empty pages */ |
235 | zone_pva_t z_pageq_partial;/* populated, partially filled pages */ | |
236 | zone_pva_t z_pageq_full; /* populated, completely full pages */ | |
237 | zone_pva_t z_pageq_va; /* non-populated VA pages */ | |
238 | ||
239 | /* | |
240 | * Zone statistics | |
241 | * | |
242 | * z_contention_wma: | |
243 | * weighted moving average of the number of contentions per second, | |
244 | * in Z_CONTENTION_WMA_UNIT units (fixed point decimal). | |
245 | * | |
246 | * z_contention_cur: | |
247 | * count of recorded contentions that will be fused in z_contention_wma | |
248 | * at the next period. | |
249 | * | |
250 | * z_recirc_cur: | |
251 | * number of magazines in the recirculation depot. | |
252 | * | |
253 | * z_elems_free: | |
254 | * number of free elements in the zone. | |
255 | * | |
256 | * z_elems_{min,max}: | |
257 | * tracks the low/high watermark of z_elems_free for the current | |
258 | * weighted moving average period. | |
259 | * | |
260 | * z_elems_free_wss: | |
261 | * weighted moving average of the (z_elems_free_max - z_elems_free_min) | |
262 | * amplited which is used by the GC for trim operations. | |
263 | * | |
264 | * z_elems_avail: | |
265 | * number of elements in the zone (at all). | |
266 | */ | |
267 | #define Z_CONTENTION_WMA_UNIT (1u << 8) | |
268 | uint32_t z_contention_wma; | |
269 | uint32_t z_contention_cur; | |
270 | uint32_t z_recirc_cur; | |
271 | uint32_t z_elems_free_max; | |
272 | uint32_t z_elems_free_wss; | |
273 | uint32_t z_elems_free_min; | |
274 | uint32_t z_elems_free; /* Number of free elements */ | |
275 | uint32_t z_elems_avail; /* Number of elements available */ | |
f427ee49 A |
276 | |
277 | #if CONFIG_ZLEAKS | |
278 | uint32_t zleak_capture; /* per-zone counter for capturing every N allocations */ | |
279 | #endif | |
280 | #if CONFIG_GZALLOC | |
281 | gzalloc_data_t gz; | |
282 | #endif | |
283 | #if KASAN_ZALLOC | |
c3c9b80d A |
284 | uint32_t z_kasan_redzone; |
285 | spl_t z_kasan_spl; | |
f427ee49 A |
286 | #endif |
287 | #if DEBUG || DEVELOPMENT || CONFIG_ZLEAKS | |
288 | /* zone logging structure to hold stacks and element references to those stacks. */ | |
289 | btlog_t *zlog_btlog; | |
290 | #endif | |
291 | }; | |
292 | ||
293 | ||
294 | __options_decl(zone_security_options_t, uint64_t, { | |
295 | /* | |
296 | * Zsecurity option to enable sequestering VA of zones | |
297 | */ | |
298 | ZSECURITY_OPTIONS_SEQUESTER = 0x00000001, | |
299 | /* | |
300 | * Zsecurity option to enable creating separate kalloc zones for | |
301 | * bags of bytes | |
302 | */ | |
303 | ZSECURITY_OPTIONS_SUBMAP_USER_DATA = 0x00000004, | |
304 | /* | |
305 | * Zsecurity option to enable sequestering of kalloc zones used by | |
306 | * kexts (KHEAP_KEXT heap) | |
307 | */ | |
308 | ZSECURITY_OPTIONS_SEQUESTER_KEXT_KALLOC = 0x00000008, | |
309 | /* | |
310 | * Zsecurity option to enable strict free of iokit objects to zone | |
311 | * or heap they were allocated from. | |
312 | */ | |
313 | ZSECURITY_OPTIONS_STRICT_IOKIT_FREE = 0x00000010, | |
314 | }); | |
315 | ||
316 | #define KALLOC_MINALIGN (1 << KALLOC_LOG2_MINALIGN) | |
317 | #define KALLOC_DLUT_SIZE (2048 / KALLOC_MINALIGN) | |
318 | ||
319 | struct kheap_zones { | |
320 | struct kalloc_zone_cfg *cfg; | |
321 | struct kalloc_heap *views; | |
322 | zone_kheap_id_t heap_id; | |
323 | uint16_t max_k_zone; | |
324 | uint8_t dlut[KALLOC_DLUT_SIZE]; /* table of indices into k_zone[] */ | |
325 | uint8_t k_zindex_start; | |
326 | /* If there's no hit in the DLUT, then start searching from k_zindex_start. */ | |
327 | zone_t *k_zone; | |
328 | }; | |
329 | ||
330 | extern zone_security_options_t zsecurity_options; | |
c3c9b80d | 331 | extern zone_id_t _Atomic num_zones; |
f427ee49 A |
332 | extern uint32_t zone_view_count; |
333 | extern struct zone zone_array[]; | |
f427ee49 | 334 | extern const char * const kalloc_heap_names[KHEAP_ID_COUNT]; |
c3c9b80d A |
335 | extern bool panic_include_zprint; |
336 | #if CONFIG_ZLEAKS | |
337 | extern bool panic_include_ztrace; | |
338 | extern struct ztrace *top_ztrace; | |
339 | #endif | |
340 | extern mach_memory_info_t *panic_kext_memory_info; | |
341 | extern vm_size_t panic_kext_memory_size; | |
342 | extern unsigned int zone_map_jetsam_limit; | |
f427ee49 A |
343 | |
344 | #define zone_index_foreach(i) \ | |
c3c9b80d | 345 | for (zone_id_t i = 1, num_zones_##i = os_atomic_load(&num_zones, acquire); \ |
f427ee49 A |
346 | i < num_zones_##i; i++) |
347 | ||
c3c9b80d A |
348 | #define zone_foreach(z) \ |
349 | for (zone_t z = &zone_array[1], \ | |
350 | last_zone_##z = &zone_array[os_atomic_load(&num_zones, acquire)]; \ | |
351 | z < last_zone_##z; z++) | |
352 | ||
353 | struct zone_map_range { | |
354 | vm_offset_t min_address; | |
355 | vm_offset_t max_address; | |
356 | } __attribute__((aligned(2 * sizeof(vm_offset_t)))); | |
357 | ||
f427ee49 A |
358 | __pure2 |
359 | static inline vm_offset_t | |
360 | zone_elem_size(zone_t zone) | |
361 | { | |
362 | return zone->z_elem_size; | |
363 | } | |
364 | ||
365 | static inline uint32_t | |
366 | zone_count_allocated(zone_t zone) | |
367 | { | |
c3c9b80d A |
368 | return zone->z_elems_avail - zone->z_elems_free; |
369 | } | |
370 | ||
371 | static inline vm_size_t | |
372 | zone_scale_for_percpu(zone_t zone, vm_size_t size) | |
373 | { | |
374 | if (zone->z_percpu) { | |
375 | size *= zpercpu_count(); | |
376 | } | |
377 | return size; | |
f427ee49 A |
378 | } |
379 | ||
380 | static inline vm_size_t | |
381 | zone_size_wired(zone_t zone) | |
382 | { | |
383 | /* | |
384 | * this either require the zone lock, | |
385 | * or to be used for statistics purposes only. | |
386 | */ | |
c3c9b80d A |
387 | vm_size_t size = ptoa(os_atomic_load(&zone->z_wired_cur, relaxed)); |
388 | return zone_scale_for_percpu(zone, size); | |
f427ee49 A |
389 | } |
390 | ||
391 | static inline vm_size_t | |
392 | zone_size_free(zone_t zone) | |
393 | { | |
c3c9b80d A |
394 | return zone_scale_for_percpu(zone, |
395 | (vm_size_t)zone->z_elem_size * zone->z_elems_free); | |
f427ee49 A |
396 | } |
397 | ||
398 | static inline vm_size_t | |
399 | zone_size_allocated(zone_t zone) | |
400 | { | |
c3c9b80d A |
401 | return zone_scale_for_percpu(zone, |
402 | (vm_size_t)zone->z_elem_size * zone_count_allocated(zone)); | |
f427ee49 A |
403 | } |
404 | ||
405 | static inline vm_size_t | |
406 | zone_size_wasted(zone_t zone) | |
407 | { | |
c3c9b80d A |
408 | return zone_size_wired(zone) - zone_scale_for_percpu(zone, |
409 | (vm_size_t)zone->z_elem_size * zone->z_elems_avail); | |
f427ee49 A |
410 | } |
411 | ||
412 | /* | |
413 | * For sysctl kern.zones_collectable_bytes used by memory_maintenance to check if a | |
414 | * userspace reboot is needed. The only other way to query for this information | |
415 | * is via mach_memory_info() which is unavailable on release kernels. | |
416 | */ | |
417 | extern uint64_t get_zones_collectable_bytes(void); | |
418 | ||
c3c9b80d A |
419 | /*! |
420 | * @enum zone_gc_level_t | |
421 | * | |
422 | * @const ZONE_GC_TRIM | |
423 | * Request a trimming GC: it will trim allocations in excess | |
424 | * of the working set size estimate only. | |
425 | * | |
426 | * @const ZONE_GC_DRAIN | |
427 | * Request a draining GC: this is an aggressive mode that will | |
428 | * cause all caches to be drained and all free pages returned to the system. | |
429 | * | |
430 | * @const ZONE_GC_JETSAM | |
431 | * Request to consider a jetsam, and then fallback to @c ZONE_GC_TRIM or | |
432 | * @c ZONE_GC_DRAIN depending on the state of the zone map. | |
433 | * To avoid deadlocks, only @c vm_pageout_garbage_collect() should ever | |
434 | * request a @c ZONE_GC_JETSAM level. | |
435 | */ | |
436 | __enum_closed_decl(zone_gc_level_t, uint32_t, { | |
437 | ZONE_GC_TRIM, | |
438 | ZONE_GC_DRAIN, | |
439 | ZONE_GC_JETSAM, | |
440 | }); | |
441 | ||
442 | /*! | |
443 | * @function zone_gc | |
444 | * | |
445 | * @brief | |
446 | * Reduces memory used by zones by trimming caches and freelists. | |
f427ee49 | 447 | * |
c3c9b80d A |
448 | * @discussion |
449 | * @c zone_gc() is called: | |
450 | * - by the pageout daemon when the system needs more free pages. | |
451 | * - by the VM when contiguous page allocation requests get stuck | |
452 | * (see vm_page_find_contiguous()). | |
453 | * | |
454 | * @param level The zone GC level requested. | |
455 | */ | |
456 | extern void zone_gc(zone_gc_level_t level); | |
457 | ||
458 | extern void zone_gc_trim(void); | |
459 | extern void zone_gc_drain(void); | |
460 | ||
461 | #define ZONE_WSS_UPDATE_PERIOD 10 | |
462 | /*! | |
463 | * @function compute_zone_working_set_size | |
464 | * | |
465 | * @brief | |
466 | * Recomputes the working set size for every zone | |
467 | * | |
468 | * @discussion | |
469 | * This runs about every @c ZONE_WSS_UPDATE_PERIOD seconds (10), | |
470 | * computing an exponential moving average with a weight of 75%, | |
471 | * so that the history of the last minute is the dominating factor. | |
f427ee49 | 472 | */ |
c3c9b80d | 473 | extern void compute_zone_working_set_size(void *); |
f427ee49 A |
474 | |
475 | /* Debug logging for zone-map-exhaustion jetsams. */ | |
476 | extern void get_zone_map_size(uint64_t *current_size, uint64_t *capacity); | |
477 | extern void get_largest_zone_info(char *zone_name, size_t zone_name_len, uint64_t *zone_size); | |
478 | ||
479 | /* Bootstrap zone module (create zone zone) */ | |
480 | extern void zone_bootstrap(void); | |
481 | ||
c3c9b80d A |
482 | /*! |
483 | * @function zone_foreign_mem_init | |
484 | * | |
485 | * @brief | |
f427ee49 A |
486 | * Steal memory from pmap (prior to initialization of zalloc) |
487 | * for the special vm zones that allow foreign memory and store | |
c3c9b80d | 488 | * the range so as to facilitate range checking in zfree. |
f427ee49 A |
489 | */ |
490 | __startup_func | |
c3c9b80d A |
491 | extern vm_offset_t zone_foreign_mem_init( |
492 | vm_size_t size); | |
f427ee49 | 493 | |
c3c9b80d A |
494 | /*! |
495 | * @function zone_get_foreign_alloc_size | |
496 | * | |
497 | * @brief | |
498 | * Compute the correct size (greater than @c ptoa(min_pages)) that is a multiple | |
499 | * of the allocation granule for the zone with the given creation flags and | |
500 | * element size. | |
f427ee49 A |
501 | */ |
502 | __startup_func | |
503 | extern vm_size_t zone_get_foreign_alloc_size( | |
504 | const char *name __unused, | |
505 | vm_size_t elem_size, | |
506 | zone_create_flags_t flags, | |
507 | uint16_t min_pages); | |
508 | ||
c3c9b80d A |
509 | /*! |
510 | * @function zone_cram_foreign | |
511 | * | |
512 | * @brief | |
513 | * Cram memory allocated with @c zone_foreign_mem_init() into a zone. | |
514 | * | |
515 | * @param zone The zone to cram memory into. | |
516 | * @param newmem The base address for the memory to cram. | |
517 | * @param size The size of the memory to cram into the zone. | |
518 | */ | |
519 | __startup_func | |
520 | extern void zone_cram_foreign( | |
521 | zone_t zone, | |
522 | vm_offset_t newmem, | |
523 | vm_size_t size); | |
524 | ||
f427ee49 A |
525 | extern bool zone_maps_owned( |
526 | vm_address_t addr, | |
527 | vm_size_t size); | |
528 | ||
529 | extern void zone_map_sizes( | |
530 | vm_map_size_t *psize, | |
531 | vm_map_size_t *pfree, | |
532 | vm_map_size_t *plargest_free); | |
533 | ||
c3c9b80d A |
534 | extern bool |
535 | zone_map_nearing_exhaustion(void); | |
f427ee49 A |
536 | |
537 | #if defined(__LP64__) | |
538 | #define ZONE_POISON 0xdeadbeefdeadbeef | |
539 | #else | |
540 | #define ZONE_POISON 0xdeadbeef | |
541 | #endif | |
542 | ||
f427ee49 A |
543 | static inline vm_tag_t |
544 | zalloc_flags_get_tag(zalloc_flags_t flags) | |
545 | { | |
546 | return (vm_tag_t)((flags & Z_VM_TAG_MASK) >> Z_VM_TAG_SHIFT); | |
547 | } | |
548 | ||
549 | extern void *zalloc_ext( | |
550 | zone_t zone, | |
551 | zone_stats_t zstats, | |
c3c9b80d | 552 | zalloc_flags_t flags); |
f427ee49 A |
553 | |
554 | extern void zfree_ext( | |
555 | zone_t zone, | |
556 | zone_stats_t zstats, | |
557 | void *addr); | |
558 | ||
c3c9b80d A |
559 | /*! |
560 | * @function zone_replenish_configure | |
561 | * | |
562 | * @brief | |
563 | * Used by zones backing the VM to maintain a reserve of free elements. | |
564 | * | |
565 | * @discussion | |
566 | * This function should not be used by anyone else than the VM. | |
f427ee49 | 567 | */ |
c3c9b80d | 568 | extern void zone_replenish_configure( |
f427ee49 A |
569 | zone_t zone); |
570 | ||
571 | extern vm_size_t zone_element_size( | |
572 | void *addr, | |
573 | zone_t *z); | |
574 | ||
575 | /*! | |
576 | * @function zone_owns | |
577 | * | |
578 | * @abstract | |
579 | * This function is a soft version of zone_require that checks if a given | |
580 | * pointer belongs to the specified zone and should not be used outside | |
581 | * allocator code. | |
582 | * | |
583 | * @discussion | |
584 | * Note that zone_owns() can only work with: | |
585 | * - zones not allowing foreign memory | |
586 | * - zones in the general submap. | |
587 | * | |
588 | * @param zone the zone the address needs to belong to. | |
589 | * @param addr the element address to check. | |
590 | */ | |
591 | extern bool zone_owns( | |
592 | zone_t zone, | |
593 | void *addr); | |
594 | ||
595 | /* | |
596 | * Structure for keeping track of a backtrace, used for leak detection. | |
597 | * This is in the .h file because it is used during panic, see kern/debug.c | |
598 | * A non-zero size indicates that the trace is in use. | |
599 | */ | |
600 | struct ztrace { | |
601 | vm_size_t zt_size; /* How much memory are all the allocations referring to this trace taking up? */ | |
602 | uint32_t zt_depth; /* depth of stack (0 to MAX_ZTRACE_DEPTH) */ | |
603 | void* zt_stack[MAX_ZTRACE_DEPTH]; /* series of return addresses from OSBacktrace */ | |
604 | uint32_t zt_collisions; /* How many times did a different stack land here while it was occupied? */ | |
605 | uint32_t zt_hit_count; /* for determining effectiveness of hash function */ | |
606 | }; | |
607 | ||
608 | #ifndef VM_MAX_TAG_ZONES | |
609 | #error MAX_TAG_ZONES | |
610 | #endif | |
611 | #if VM_MAX_TAG_ZONES | |
612 | ||
613 | extern uint32_t zone_index_from_tag_index( | |
614 | uint32_t tag_zone_index, | |
615 | vm_size_t *elem_size); | |
616 | ||
617 | #endif /* VM_MAX_TAG_ZONES */ | |
618 | ||
c3c9b80d A |
619 | static inline void |
620 | zone_lock(zone_t zone) | |
621 | { | |
622 | #if KASAN_ZALLOC | |
623 | spl_t s = 0; | |
624 | if (zone->kasan_fakestacks) { | |
625 | s = splsched(); | |
626 | } | |
627 | #endif /* KASAN_ZALLOC */ | |
628 | lck_spin_lock(&zone->z_lock); | |
629 | #if KASAN_ZALLOC | |
630 | zone->z_kasan_spl = s; | |
631 | #endif /* KASAN_ZALLOC */ | |
632 | } | |
633 | ||
634 | static inline void | |
635 | zone_unlock(zone_t zone) | |
636 | { | |
637 | #if KASAN_ZALLOC | |
638 | spl_t s = zone->z_kasan_spl; | |
639 | zone->z_kasan_spl = 0; | |
640 | #endif /* KASAN_ZALLOC */ | |
641 | lck_spin_unlock(&zone->z_lock); | |
642 | #if KASAN_ZALLOC | |
643 | if (zone->kasan_fakestacks) { | |
644 | splx(s); | |
645 | } | |
646 | #endif /* KASAN_ZALLOC */ | |
647 | } | |
f427ee49 A |
648 | |
649 | #if CONFIG_GZALLOC | |
650 | void gzalloc_init(vm_size_t); | |
651 | void gzalloc_zone_init(zone_t); | |
652 | void gzalloc_empty_free_cache(zone_t); | |
653 | boolean_t gzalloc_enabled(void); | |
654 | ||
655 | vm_offset_t gzalloc_alloc(zone_t, zone_stats_t zstats, zalloc_flags_t flags); | |
656 | void gzalloc_free(zone_t, zone_stats_t zstats, void *); | |
657 | boolean_t gzalloc_element_size(void *, zone_t *, vm_size_t *); | |
658 | #endif /* CONFIG_GZALLOC */ | |
659 | ||
660 | #define MAX_ZONE_NAME 32 /* max length of a zone name we can take from the boot-args */ | |
661 | int track_this_zone(const char *zonename, const char *logname); | |
662 | ||
663 | #if DEBUG || DEVELOPMENT | |
664 | extern boolean_t run_zone_test(void); | |
665 | extern void zone_gc_replenish_test(void); | |
666 | extern void zone_alloc_replenish_test(void); | |
667 | extern vm_size_t zone_element_info(void *addr, vm_tag_t * ptag); | |
668 | extern bool zalloc_disable_copyio_check; | |
669 | #else | |
670 | #define zalloc_disable_copyio_check false | |
671 | #endif /* DEBUG || DEVELOPMENT */ | |
672 | ||
673 | #pragma GCC visibility pop | |
674 | ||
675 | __END_DECLS | |
676 | ||
677 | #endif /* _KERN_ZALLOC_INTERNAL_H_ */ |