xref: /xnu-10063.121.3/osfmk/kern/zalloc_internal.h (revision 2c2f96dc2b9a4408a43d3150ae9c105355ca3daa)
1*2c2f96dcSApple OSS Distributions /*
2*2c2f96dcSApple OSS Distributions  * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
3*2c2f96dcSApple OSS Distributions  *
4*2c2f96dcSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*2c2f96dcSApple OSS Distributions  *
6*2c2f96dcSApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*2c2f96dcSApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*2c2f96dcSApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*2c2f96dcSApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*2c2f96dcSApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*2c2f96dcSApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*2c2f96dcSApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*2c2f96dcSApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*2c2f96dcSApple OSS Distributions  *
15*2c2f96dcSApple OSS Distributions  * Please obtain a copy of the License at
16*2c2f96dcSApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*2c2f96dcSApple OSS Distributions  *
18*2c2f96dcSApple OSS Distributions  * The Original Code and all software distributed under the License are
19*2c2f96dcSApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*2c2f96dcSApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*2c2f96dcSApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*2c2f96dcSApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*2c2f96dcSApple OSS Distributions  * Please see the License for the specific language governing rights and
24*2c2f96dcSApple OSS Distributions  * limitations under the License.
25*2c2f96dcSApple OSS Distributions  *
26*2c2f96dcSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*2c2f96dcSApple OSS Distributions  */
28*2c2f96dcSApple OSS Distributions /*
29*2c2f96dcSApple OSS Distributions  * @OSF_COPYRIGHT@
30*2c2f96dcSApple OSS Distributions  */
31*2c2f96dcSApple OSS Distributions /*
32*2c2f96dcSApple OSS Distributions  * Mach Operating System
33*2c2f96dcSApple OSS Distributions  * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
34*2c2f96dcSApple OSS Distributions  * All Rights Reserved.
35*2c2f96dcSApple OSS Distributions  *
36*2c2f96dcSApple OSS Distributions  * Permission to use, copy, modify and distribute this software and its
37*2c2f96dcSApple OSS Distributions  * documentation is hereby granted, provided that both the copyright
38*2c2f96dcSApple OSS Distributions  * notice and this permission notice appear in all copies of the
39*2c2f96dcSApple OSS Distributions  * software, derivative works or modified versions, and any portions
40*2c2f96dcSApple OSS Distributions  * thereof, and that both notices appear in supporting documentation.
41*2c2f96dcSApple OSS Distributions  *
42*2c2f96dcSApple OSS Distributions  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43*2c2f96dcSApple OSS Distributions  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44*2c2f96dcSApple OSS Distributions  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45*2c2f96dcSApple OSS Distributions  *
46*2c2f96dcSApple OSS Distributions  * Carnegie Mellon requests users of this software to return to
47*2c2f96dcSApple OSS Distributions  *
48*2c2f96dcSApple OSS Distributions  *  Software Distribution Coordinator  or  [email protected]
49*2c2f96dcSApple OSS Distributions  *  School of Computer Science
50*2c2f96dcSApple OSS Distributions  *  Carnegie Mellon University
51*2c2f96dcSApple OSS Distributions  *  Pittsburgh PA 15213-3890
52*2c2f96dcSApple OSS Distributions  *
53*2c2f96dcSApple OSS Distributions  * any improvements or extensions that they make and grant Carnegie Mellon
54*2c2f96dcSApple OSS Distributions  * the rights to redistribute these changes.
55*2c2f96dcSApple OSS Distributions  */
56*2c2f96dcSApple OSS Distributions /*
57*2c2f96dcSApple OSS Distributions  */
58*2c2f96dcSApple OSS Distributions 
59*2c2f96dcSApple OSS Distributions #ifndef _KERN_ZALLOC_INTERNAL_H_
60*2c2f96dcSApple OSS Distributions #define _KERN_ZALLOC_INTERNAL_H_
61*2c2f96dcSApple OSS Distributions 
62*2c2f96dcSApple OSS Distributions #include <kern/zalloc.h>
63*2c2f96dcSApple OSS Distributions #include <kern/locks.h>
64*2c2f96dcSApple OSS Distributions #include <kern/simple_lock.h>
65*2c2f96dcSApple OSS Distributions 
66*2c2f96dcSApple OSS Distributions #include <os/atomic_private.h>
67*2c2f96dcSApple OSS Distributions #include <sys/queue.h>
68*2c2f96dcSApple OSS Distributions #include <vm/vm_map_internal.h>
69*2c2f96dcSApple OSS Distributions 
70*2c2f96dcSApple OSS Distributions #if KASAN
71*2c2f96dcSApple OSS Distributions #include <san/kasan.h>
72*2c2f96dcSApple OSS Distributions #include <kern/spl.h>
73*2c2f96dcSApple OSS Distributions #endif /* !KASAN */
74*2c2f96dcSApple OSS Distributions 
75*2c2f96dcSApple OSS Distributions /*
76*2c2f96dcSApple OSS Distributions  * Disable zalloc zero validation under kasan as it is
77*2c2f96dcSApple OSS Distributions  * double-duty with what kasan already does.
78*2c2f96dcSApple OSS Distributions  */
79*2c2f96dcSApple OSS Distributions #if KASAN
80*2c2f96dcSApple OSS Distributions #define ZALLOC_ENABLE_ZERO_CHECK        0
81*2c2f96dcSApple OSS Distributions #else
82*2c2f96dcSApple OSS Distributions #define ZALLOC_ENABLE_ZERO_CHECK        1
83*2c2f96dcSApple OSS Distributions #endif
84*2c2f96dcSApple OSS Distributions 
85*2c2f96dcSApple OSS Distributions #if KASAN
86*2c2f96dcSApple OSS Distributions #define ZALLOC_ENABLE_LOGGING           0
87*2c2f96dcSApple OSS Distributions #elif DEBUG || DEVELOPMENT
88*2c2f96dcSApple OSS Distributions #define ZALLOC_ENABLE_LOGGING           1
89*2c2f96dcSApple OSS Distributions #else
90*2c2f96dcSApple OSS Distributions #define ZALLOC_ENABLE_LOGGING           0
91*2c2f96dcSApple OSS Distributions #endif
92*2c2f96dcSApple OSS Distributions 
93*2c2f96dcSApple OSS Distributions /*!
94*2c2f96dcSApple OSS Distributions  * @file <kern/zalloc_internal.h>
95*2c2f96dcSApple OSS Distributions  *
96*2c2f96dcSApple OSS Distributions  * @abstract
97*2c2f96dcSApple OSS Distributions  * Exposes some guts of zalloc to interact with the VM, debugging, copyio and
98*2c2f96dcSApple OSS Distributions  * kalloc subsystems.
99*2c2f96dcSApple OSS Distributions  */
100*2c2f96dcSApple OSS Distributions 
101*2c2f96dcSApple OSS Distributions __BEGIN_DECLS
102*2c2f96dcSApple OSS Distributions 
103*2c2f96dcSApple OSS Distributions #pragma GCC visibility push(hidden)
104*2c2f96dcSApple OSS Distributions 
105*2c2f96dcSApple OSS Distributions /*
106*2c2f96dcSApple OSS Distributions  *	A zone is a collection of fixed size blocks for which there
107*2c2f96dcSApple OSS Distributions  *	is fast allocation/deallocation access.  Kernel routines can
108*2c2f96dcSApple OSS Distributions  *	use zones to manage data structures dynamically, creating a zone
109*2c2f96dcSApple OSS Distributions  *	for each type of data structure to be managed.
110*2c2f96dcSApple OSS Distributions  *
111*2c2f96dcSApple OSS Distributions  */
112*2c2f96dcSApple OSS Distributions 
113*2c2f96dcSApple OSS Distributions /*!
114*2c2f96dcSApple OSS Distributions  * @typedef zone_pva_t
115*2c2f96dcSApple OSS Distributions  *
116*2c2f96dcSApple OSS Distributions  * @brief
117*2c2f96dcSApple OSS Distributions  * Type used to point to a page virtual address in the zone allocator.
118*2c2f96dcSApple OSS Distributions  *
119*2c2f96dcSApple OSS Distributions  * @description
120*2c2f96dcSApple OSS Distributions  * - Valid pages have the top bit set.
121*2c2f96dcSApple OSS Distributions  * - 0 represents the "NULL" page
122*2c2f96dcSApple OSS Distributions  * - non 0 values with the top bit cleared represent queue heads,
123*2c2f96dcSApple OSS Distributions  *   indexed from the beginning of the __DATA section of the kernel.
124*2c2f96dcSApple OSS Distributions  *   (see zone_pageq_base).
125*2c2f96dcSApple OSS Distributions  */
126*2c2f96dcSApple OSS Distributions typedef struct zone_packed_virtual_address {
127*2c2f96dcSApple OSS Distributions 	uint32_t packed_address;
128*2c2f96dcSApple OSS Distributions } zone_pva_t;
129*2c2f96dcSApple OSS Distributions 
130*2c2f96dcSApple OSS Distributions /*!
131*2c2f96dcSApple OSS Distributions  * @struct zone_stats
132*2c2f96dcSApple OSS Distributions  *
133*2c2f96dcSApple OSS Distributions  * @abstract
134*2c2f96dcSApple OSS Distributions  * Per-cpu structure used for basic zone stats.
135*2c2f96dcSApple OSS Distributions  *
136*2c2f96dcSApple OSS Distributions  * @discussion
137*2c2f96dcSApple OSS Distributions  * The values aren't scaled for per-cpu zones.
138*2c2f96dcSApple OSS Distributions  */
139*2c2f96dcSApple OSS Distributions struct zone_stats {
140*2c2f96dcSApple OSS Distributions 	uint64_t            zs_mem_allocated;
141*2c2f96dcSApple OSS Distributions 	uint64_t            zs_mem_freed;
142*2c2f96dcSApple OSS Distributions 	uint64_t            zs_alloc_fail;
143*2c2f96dcSApple OSS Distributions 	uint32_t            zs_alloc_rr;     /* allocation rr bias */
144*2c2f96dcSApple OSS Distributions 	uint32_t _Atomic    zs_alloc_not_shared;
145*2c2f96dcSApple OSS Distributions };
146*2c2f96dcSApple OSS Distributions 
147*2c2f96dcSApple OSS Distributions typedef struct zone_magazine *zone_magazine_t;
148*2c2f96dcSApple OSS Distributions 
149*2c2f96dcSApple OSS Distributions /*!
150*2c2f96dcSApple OSS Distributions  * @struct zone_depot
151*2c2f96dcSApple OSS Distributions  *
152*2c2f96dcSApple OSS Distributions  * @abstract
153*2c2f96dcSApple OSS Distributions  * Holds a list of full and empty magazines.
154*2c2f96dcSApple OSS Distributions  *
155*2c2f96dcSApple OSS Distributions  * @discussion
156*2c2f96dcSApple OSS Distributions  * The data structure is a "STAILQ" and an "SLIST" combined with counters
157*2c2f96dcSApple OSS Distributions  * to know their lengths in O(1). Here is a graphical example:
158*2c2f96dcSApple OSS Distributions  *
159*2c2f96dcSApple OSS Distributions  *      zd_full = 3
160*2c2f96dcSApple OSS Distributions  *      zd_empty = 1
161*2c2f96dcSApple OSS Distributions  * ╭─── zd_head
162*2c2f96dcSApple OSS Distributions  * │ ╭─ zd_tail
163*2c2f96dcSApple OSS Distributions  * │ ╰────────────────────────────────────╮
164*2c2f96dcSApple OSS Distributions  * │    ╭───────╮   ╭───────╮   ╭───────╮ v ╭───────╮
165*2c2f96dcSApple OSS Distributions  * ╰───>│███████┼──>│███████┼──>│███████┼──>│       ┼─> X
166*2c2f96dcSApple OSS Distributions  *      ╰───────╯   ╰───────╯   ╰───────╯   ╰───────╯
167*2c2f96dcSApple OSS Distributions  */
168*2c2f96dcSApple OSS Distributions struct zone_depot {
169*2c2f96dcSApple OSS Distributions 	uint32_t            zd_full;
170*2c2f96dcSApple OSS Distributions 	uint32_t            zd_empty;
171*2c2f96dcSApple OSS Distributions 	zone_magazine_t     zd_head;
172*2c2f96dcSApple OSS Distributions 	zone_magazine_t    *zd_tail;
173*2c2f96dcSApple OSS Distributions };
174*2c2f96dcSApple OSS Distributions 
175*2c2f96dcSApple OSS Distributions /* see https://lemire.me/blog/2019/02/20/more-fun-with-fast-remainders-when-the-divisor-is-a-constant/ */
176*2c2f96dcSApple OSS Distributions #define Z_MAGIC_QUO(s)      (((1ull << 32) - 1) / (uint64_t)(s) + 1)
177*2c2f96dcSApple OSS Distributions #define Z_MAGIC_ALIGNED(s)  (~0u / (uint32_t)(s) + 1)
178*2c2f96dcSApple OSS Distributions 
179*2c2f96dcSApple OSS Distributions /*
180*2c2f96dcSApple OSS Distributions  * Returns (offs / size) if offs is small enough
181*2c2f96dcSApple OSS Distributions  * and magic = Z_MAGIC_QUO(size)
182*2c2f96dcSApple OSS Distributions  */
183*2c2f96dcSApple OSS Distributions static inline uint32_t
Z_FAST_QUO(uint64_t offs,uint64_t magic)184*2c2f96dcSApple OSS Distributions Z_FAST_QUO(uint64_t offs, uint64_t magic)
185*2c2f96dcSApple OSS Distributions {
186*2c2f96dcSApple OSS Distributions 	return (offs * magic) >> 32;
187*2c2f96dcSApple OSS Distributions }
188*2c2f96dcSApple OSS Distributions 
189*2c2f96dcSApple OSS Distributions /*
190*2c2f96dcSApple OSS Distributions  * Returns (offs % size) if offs is small enough
191*2c2f96dcSApple OSS Distributions  * and magic = Z_MAGIC_QUO(size)
192*2c2f96dcSApple OSS Distributions  */
193*2c2f96dcSApple OSS Distributions static inline uint32_t
Z_FAST_MOD(uint64_t offs,uint64_t magic,uint64_t size)194*2c2f96dcSApple OSS Distributions Z_FAST_MOD(uint64_t offs, uint64_t magic, uint64_t size)
195*2c2f96dcSApple OSS Distributions {
196*2c2f96dcSApple OSS Distributions 	uint32_t lowbits = (uint32_t)(offs * magic);
197*2c2f96dcSApple OSS Distributions 
198*2c2f96dcSApple OSS Distributions 	return (lowbits * size) >> 32;
199*2c2f96dcSApple OSS Distributions }
200*2c2f96dcSApple OSS Distributions 
201*2c2f96dcSApple OSS Distributions /*
202*2c2f96dcSApple OSS Distributions  * Returns whether (offs % size) == 0 if offs is small enough
203*2c2f96dcSApple OSS Distributions  * and magic = Z_MAGIC_ALIGNED(size)
204*2c2f96dcSApple OSS Distributions  */
205*2c2f96dcSApple OSS Distributions static inline bool
Z_FAST_ALIGNED(uint64_t offs,uint32_t magic)206*2c2f96dcSApple OSS Distributions Z_FAST_ALIGNED(uint64_t offs, uint32_t magic)
207*2c2f96dcSApple OSS Distributions {
208*2c2f96dcSApple OSS Distributions 	return (uint32_t)(offs * magic) < magic;
209*2c2f96dcSApple OSS Distributions }
210*2c2f96dcSApple OSS Distributions 
211*2c2f96dcSApple OSS Distributions struct zone_size_params {
212*2c2f96dcSApple OSS Distributions 	uint32_t            z_align_magic;  /* magic to use with Z_FAST_ALIGNED()  */
213*2c2f96dcSApple OSS Distributions 	uint32_t            z_elem_size;    /* size of an element                  */
214*2c2f96dcSApple OSS Distributions };
215*2c2f96dcSApple OSS Distributions 
216*2c2f96dcSApple OSS Distributions struct zone_expand {
217*2c2f96dcSApple OSS Distributions 	struct zone_expand *ze_next;
218*2c2f96dcSApple OSS Distributions 	thread_t            ze_thread;
219*2c2f96dcSApple OSS Distributions 	bool                ze_pg_wait;
220*2c2f96dcSApple OSS Distributions 	bool                ze_vm_priv;
221*2c2f96dcSApple OSS Distributions 	bool                ze_clear_priv;
222*2c2f96dcSApple OSS Distributions };
223*2c2f96dcSApple OSS Distributions 
224*2c2f96dcSApple OSS Distributions #define Z_WMA_UNIT (1u << 8)
225*2c2f96dcSApple OSS Distributions #define Z_WMA_MIX(base, e)  ((3 * (base) + (e) * Z_WMA_UNIT) / 4)
226*2c2f96dcSApple OSS Distributions 
227*2c2f96dcSApple OSS Distributions struct zone {
228*2c2f96dcSApple OSS Distributions 	/*
229*2c2f96dcSApple OSS Distributions 	 * Readonly / rarely written fields
230*2c2f96dcSApple OSS Distributions 	 */
231*2c2f96dcSApple OSS Distributions 
232*2c2f96dcSApple OSS Distributions 	/*
233*2c2f96dcSApple OSS Distributions 	 * The first 4 fields match a zone_view.
234*2c2f96dcSApple OSS Distributions 	 *
235*2c2f96dcSApple OSS Distributions 	 * z_self points back to the zone when the zone is initialized,
236*2c2f96dcSApple OSS Distributions 	 * or is NULL else.
237*2c2f96dcSApple OSS Distributions 	 */
238*2c2f96dcSApple OSS Distributions 	struct zone        *z_self;
239*2c2f96dcSApple OSS Distributions 	zone_stats_t        z_stats;
240*2c2f96dcSApple OSS Distributions 	const char         *z_name;
241*2c2f96dcSApple OSS Distributions 	struct zone_view   *z_views;
242*2c2f96dcSApple OSS Distributions 	struct zone_expand *z_expander;
243*2c2f96dcSApple OSS Distributions 
244*2c2f96dcSApple OSS Distributions 	uint64_t            z_quo_magic;
245*2c2f96dcSApple OSS Distributions 	uint32_t            z_align_magic;
246*2c2f96dcSApple OSS Distributions 	uint16_t            z_elem_size;
247*2c2f96dcSApple OSS Distributions 	uint16_t            z_elem_offs;
248*2c2f96dcSApple OSS Distributions 	uint16_t            z_chunk_pages;
249*2c2f96dcSApple OSS Distributions 	uint16_t            z_chunk_elems;
250*2c2f96dcSApple OSS Distributions 
251*2c2f96dcSApple OSS Distributions 	uint32_t /* 32 bits */
252*2c2f96dcSApple OSS Distributions 	/*
253*2c2f96dcSApple OSS Distributions 	 * Lifecycle state (Mutable after creation)
254*2c2f96dcSApple OSS Distributions 	 */
255*2c2f96dcSApple OSS Distributions 	    z_destroyed        :1,  /* zone is (being) destroyed */
256*2c2f96dcSApple OSS Distributions 	    z_async_refilling  :1,  /* asynchronous allocation pending? */
257*2c2f96dcSApple OSS Distributions 	    z_depot_cleanup    :1,  /* per cpu depots need cleaning */
258*2c2f96dcSApple OSS Distributions 	    z_expanding_wait   :1,  /* is thread waiting for expansion? */
259*2c2f96dcSApple OSS Distributions 	    z_exhausted_wait   :1,  /* are threads waiting for exhaustion end */
260*2c2f96dcSApple OSS Distributions 	    z_exhausts         :1,  /* whether the zone exhausts by design */
261*2c2f96dcSApple OSS Distributions 
262*2c2f96dcSApple OSS Distributions 	/*
263*2c2f96dcSApple OSS Distributions 	 * Behavior configuration bits
264*2c2f96dcSApple OSS Distributions 	 */
265*2c2f96dcSApple OSS Distributions 	    z_percpu           :1,  /* the zone is percpu */
266*2c2f96dcSApple OSS Distributions 	    z_smr              :1,  /* the zone uses SMR */
267*2c2f96dcSApple OSS Distributions 	    z_permanent        :1,  /* the zone allocations are permanent */
268*2c2f96dcSApple OSS Distributions 	    z_nocaching        :1,  /* disallow zone caching for this zone */
269*2c2f96dcSApple OSS Distributions 	    collectable        :1,  /* garbage collect empty pages */
270*2c2f96dcSApple OSS Distributions 	    no_callout         :1,
271*2c2f96dcSApple OSS Distributions 	    z_destructible     :1,  /* zone can be zdestroy()ed  */
272*2c2f96dcSApple OSS Distributions 
273*2c2f96dcSApple OSS Distributions 	    _reserved          :6,
274*2c2f96dcSApple OSS Distributions 
275*2c2f96dcSApple OSS Distributions 	/*
276*2c2f96dcSApple OSS Distributions 	 * Debugging features
277*2c2f96dcSApple OSS Distributions 	 */
278*2c2f96dcSApple OSS Distributions 	    z_pgz_tracked      :1,  /* this zone is tracked by pgzalloc */
279*2c2f96dcSApple OSS Distributions 	    z_pgz_use_guards   :1,  /* this zone uses guards with PGZ */
280*2c2f96dcSApple OSS Distributions 	    z_kasan_fakestacks :1,
281*2c2f96dcSApple OSS Distributions 	    z_kasan_quarantine :1,  /* whether to use the kasan quarantine */
282*2c2f96dcSApple OSS Distributions 	    z_tags_sizeclass   :6,  /* idx into zone_tags_sizeclasses to associate
283*2c2f96dcSApple OSS Distributions 	                             * sizeclass for a particualr kalloc tag */
284*2c2f96dcSApple OSS Distributions 	    z_uses_tags        :1,
285*2c2f96dcSApple OSS Distributions 	    z_log_on           :1,  /* zone logging was enabled by boot-arg */
286*2c2f96dcSApple OSS Distributions 	    z_tbi_tag          :1;  /* Zone supports tbi tagging */
287*2c2f96dcSApple OSS Distributions 
288*2c2f96dcSApple OSS Distributions 	uint8_t             z_cacheline1[0] __attribute__((aligned(64)));
289*2c2f96dcSApple OSS Distributions 
290*2c2f96dcSApple OSS Distributions 	/*
291*2c2f96dcSApple OSS Distributions 	 * Zone caching / recirculation cacheline
292*2c2f96dcSApple OSS Distributions 	 *
293*2c2f96dcSApple OSS Distributions 	 * z_recirc* fields are protected by the recirculation lock.
294*2c2f96dcSApple OSS Distributions 	 *
295*2c2f96dcSApple OSS Distributions 	 * z_recirc_cont_wma:
296*2c2f96dcSApple OSS Distributions 	 *   weighted moving average of the number of contentions per second,
297*2c2f96dcSApple OSS Distributions 	 *   in Z_WMA_UNIT units (fixed point decimal).
298*2c2f96dcSApple OSS Distributions 	 *
299*2c2f96dcSApple OSS Distributions 	 * z_recirc_cont_cur:
300*2c2f96dcSApple OSS Distributions 	 *   count of recorded contentions that will be fused
301*2c2f96dcSApple OSS Distributions 	 *   in z_recirc_cont_wma at the next period.
302*2c2f96dcSApple OSS Distributions 	 *
303*2c2f96dcSApple OSS Distributions 	 *   Note: if caching is disabled,
304*2c2f96dcSApple OSS Distributions 	 *   this field is used under the zone lock.
305*2c2f96dcSApple OSS Distributions 	 *
306*2c2f96dcSApple OSS Distributions 	 * z_elems_free_{min,wma} (overloaded on z_recirc_empty*):
307*2c2f96dcSApple OSS Distributions 	 *   tracks the history of the minimum values of z_elems_free over time
308*2c2f96dcSApple OSS Distributions 	 *   with "min" being the minimum it hit for the current period,
309*2c2f96dcSApple OSS Distributions 	 *   and "wma" the weighted moving average of those value.
310*2c2f96dcSApple OSS Distributions 	 *
311*2c2f96dcSApple OSS Distributions 	 *   This field is used if z_pcpu_cache is NULL,
312*2c2f96dcSApple OSS Distributions 	 *   otherwise it aliases with z_recirc_empty_{min,wma}
313*2c2f96dcSApple OSS Distributions 	 *
314*2c2f96dcSApple OSS Distributions 	 * z_recirc_{full,empty}_{min,wma}:
315*2c2f96dcSApple OSS Distributions 	 *   tracks the history of the the minimum number of full/empty
316*2c2f96dcSApple OSS Distributions 	 *   magazines in the depot over time, with "min" being the minimum
317*2c2f96dcSApple OSS Distributions 	 *   it hit for the current period, and "wma" the weighted moving
318*2c2f96dcSApple OSS Distributions 	 *   average of those value.
319*2c2f96dcSApple OSS Distributions 	 */
320*2c2f96dcSApple OSS Distributions 	struct zone_cache  *__zpercpu z_pcpu_cache;
321*2c2f96dcSApple OSS Distributions 	struct zone_depot   z_recirc;
322*2c2f96dcSApple OSS Distributions 
323*2c2f96dcSApple OSS Distributions 	hw_lck_ticket_t     z_recirc_lock;
324*2c2f96dcSApple OSS Distributions 	uint32_t            z_recirc_full_min;
325*2c2f96dcSApple OSS Distributions 	uint32_t            z_recirc_full_wma;
326*2c2f96dcSApple OSS Distributions 	union {
327*2c2f96dcSApple OSS Distributions 		uint32_t    z_recirc_empty_min;
328*2c2f96dcSApple OSS Distributions 		uint32_t    z_elems_free_min;
329*2c2f96dcSApple OSS Distributions 	};
330*2c2f96dcSApple OSS Distributions 	union {
331*2c2f96dcSApple OSS Distributions 		uint32_t    z_recirc_empty_wma;
332*2c2f96dcSApple OSS Distributions 		uint32_t    z_elems_free_wma;
333*2c2f96dcSApple OSS Distributions 	};
334*2c2f96dcSApple OSS Distributions 	uint32_t            z_recirc_cont_cur;
335*2c2f96dcSApple OSS Distributions 	uint32_t            z_recirc_cont_wma;
336*2c2f96dcSApple OSS Distributions 
337*2c2f96dcSApple OSS Distributions 	uint16_t            z_depot_size;
338*2c2f96dcSApple OSS Distributions 	uint16_t            z_depot_limit;
339*2c2f96dcSApple OSS Distributions 
340*2c2f96dcSApple OSS Distributions 	uint8_t             z_cacheline2[0] __attribute__((aligned(64)));
341*2c2f96dcSApple OSS Distributions 
342*2c2f96dcSApple OSS Distributions 	/*
343*2c2f96dcSApple OSS Distributions 	 * often mutated fields
344*2c2f96dcSApple OSS Distributions 	 */
345*2c2f96dcSApple OSS Distributions 
346*2c2f96dcSApple OSS Distributions 	hw_lck_ticket_t     z_lock;
347*2c2f96dcSApple OSS Distributions 
348*2c2f96dcSApple OSS Distributions 	/*
349*2c2f96dcSApple OSS Distributions 	 * Page accounting (wired / VA)
350*2c2f96dcSApple OSS Distributions 	 *
351*2c2f96dcSApple OSS Distributions 	 * Those numbers are unscaled for z_percpu zones
352*2c2f96dcSApple OSS Distributions 	 * (zone_scale_for_percpu() needs to be used to find the true value).
353*2c2f96dcSApple OSS Distributions 	 */
354*2c2f96dcSApple OSS Distributions 	uint32_t            z_wired_max;    /* how large can this zone grow        */
355*2c2f96dcSApple OSS Distributions 	uint32_t            z_wired_hwm;    /* z_wired_cur high watermark          */
356*2c2f96dcSApple OSS Distributions 	uint32_t            z_wired_cur;    /* number of pages used by this zone   */
357*2c2f96dcSApple OSS Distributions 	uint32_t            z_wired_empty;  /* pages collectable by GC             */
358*2c2f96dcSApple OSS Distributions 	uint32_t            z_va_cur;       /* amount of VA used by this zone      */
359*2c2f96dcSApple OSS Distributions 
360*2c2f96dcSApple OSS Distributions 	/*
361*2c2f96dcSApple OSS Distributions 	 * list of metadata structs, which maintain per-page free element lists
362*2c2f96dcSApple OSS Distributions 	 */
363*2c2f96dcSApple OSS Distributions 	zone_pva_t          z_pageq_empty;  /* populated, completely empty pages   */
364*2c2f96dcSApple OSS Distributions 	zone_pva_t          z_pageq_partial;/* populated, partially filled pages   */
365*2c2f96dcSApple OSS Distributions 	zone_pva_t          z_pageq_full;   /* populated, completely full pages    */
366*2c2f96dcSApple OSS Distributions 	zone_pva_t          z_pageq_va;     /* non-populated VA pages              */
367*2c2f96dcSApple OSS Distributions 
368*2c2f96dcSApple OSS Distributions 	/*
369*2c2f96dcSApple OSS Distributions 	 * Zone statistics
370*2c2f96dcSApple OSS Distributions 	 *
371*2c2f96dcSApple OSS Distributions 	 * z_elems_avail:
372*2c2f96dcSApple OSS Distributions 	 *   number of elements in the zone (at all).
373*2c2f96dcSApple OSS Distributions 	 */
374*2c2f96dcSApple OSS Distributions 	uint32_t            z_elems_free;   /* Number of free elements             */
375*2c2f96dcSApple OSS Distributions 	uint32_t            z_elems_avail;  /* Number of elements available        */
376*2c2f96dcSApple OSS Distributions 	uint32_t            z_elems_rsv;
377*2c2f96dcSApple OSS Distributions 	uint32_t            z_array_size_class;
378*2c2f96dcSApple OSS Distributions 
379*2c2f96dcSApple OSS Distributions 	struct zone        *z_kt_next;
380*2c2f96dcSApple OSS Distributions 
381*2c2f96dcSApple OSS Distributions 	uint8_t             z_cacheline3[0] __attribute__((aligned(64)));
382*2c2f96dcSApple OSS Distributions 
383*2c2f96dcSApple OSS Distributions #if KASAN_CLASSIC
384*2c2f96dcSApple OSS Distributions 	uint16_t            z_kasan_redzone;
385*2c2f96dcSApple OSS Distributions 	spl_t               z_kasan_spl;
386*2c2f96dcSApple OSS Distributions #endif
387*2c2f96dcSApple OSS Distributions 
388*2c2f96dcSApple OSS Distributions #if ZONE_ENABLE_LOGGING || CONFIG_ZLEAKS || KASAN_TBI
389*2c2f96dcSApple OSS Distributions 	/*
390*2c2f96dcSApple OSS Distributions 	 * the allocation logs are used when:
391*2c2f96dcSApple OSS Distributions 	 *
392*2c2f96dcSApple OSS Distributions 	 * - zlog<n>= boot-args are used (and then z_log_on is set)
393*2c2f96dcSApple OSS Distributions 	 *
394*2c2f96dcSApple OSS Distributions 	 * - the leak detection was triggered for the zone.
395*2c2f96dcSApple OSS Distributions 	 *   In that case, the log can't ever be freed,
396*2c2f96dcSApple OSS Distributions 	 *   but it can be enabled/disabled dynamically.
397*2c2f96dcSApple OSS Distributions 	 */
398*2c2f96dcSApple OSS Distributions 	struct btlog       *z_btlog;
399*2c2f96dcSApple OSS Distributions 	struct btlog       *z_btlog_disabled;
400*2c2f96dcSApple OSS Distributions #endif
401*2c2f96dcSApple OSS Distributions } __attribute__((aligned((64))));
402*2c2f96dcSApple OSS Distributions 
403*2c2f96dcSApple OSS Distributions /*!
404*2c2f96dcSApple OSS Distributions  * @typedef zone_security_flags_t
405*2c2f96dcSApple OSS Distributions  *
406*2c2f96dcSApple OSS Distributions  * @brief
407*2c2f96dcSApple OSS Distributions  * Type used to store the immutable security properties of a zone.
408*2c2f96dcSApple OSS Distributions  *
409*2c2f96dcSApple OSS Distributions  * @description
410*2c2f96dcSApple OSS Distributions  * These properties influence the security nature of a zone and can't be
411*2c2f96dcSApple OSS Distributions  * modified after lockdown.
412*2c2f96dcSApple OSS Distributions  */
413*2c2f96dcSApple OSS Distributions typedef struct zone_security_flags {
414*2c2f96dcSApple OSS Distributions 	uint16_t
415*2c2f96dcSApple OSS Distributions 	/*
416*2c2f96dcSApple OSS Distributions 	 * Security sensitive configuration bits
417*2c2f96dcSApple OSS Distributions 	 */
418*2c2f96dcSApple OSS Distributions 	    z_submap_idx       :8,  /* a Z_SUBMAP_IDX_* value */
419*2c2f96dcSApple OSS Distributions 	    z_kheap_id         :2,  /* zone_kheap_id_t when part of a kalloc heap */
420*2c2f96dcSApple OSS Distributions 	    z_kalloc_type      :1,  /* zones that does types based seggregation */
421*2c2f96dcSApple OSS Distributions 	    z_lifo             :1,  /* depot and recirculation layer are LIFO */
422*2c2f96dcSApple OSS Distributions 	    z_pgz_use_guards   :1,  /* this zone uses guards with PGZ */
423*2c2f96dcSApple OSS Distributions 	    z_submap_from_end  :1,  /* allocate from the left or the right ? */
424*2c2f96dcSApple OSS Distributions 	    z_noencrypt        :1,  /* do not encrypt pages when hibernating */
425*2c2f96dcSApple OSS Distributions 	    z_unused           :1;
426*2c2f96dcSApple OSS Distributions 	/*
427*2c2f96dcSApple OSS Distributions 	 * Signature equivalance zone
428*2c2f96dcSApple OSS Distributions 	 */
429*2c2f96dcSApple OSS Distributions 	zone_id_t           z_sig_eq;
430*2c2f96dcSApple OSS Distributions } zone_security_flags_t;
431*2c2f96dcSApple OSS Distributions 
432*2c2f96dcSApple OSS Distributions 
433*2c2f96dcSApple OSS Distributions /*
434*2c2f96dcSApple OSS Distributions  * Zsecurity config to enable strict free of iokit objects to zone
435*2c2f96dcSApple OSS Distributions  * or heap they were allocated from.
436*2c2f96dcSApple OSS Distributions  *
437*2c2f96dcSApple OSS Distributions  * Turn ZSECURITY_OPTIONS_STRICT_IOKIT_FREE off on x86 so as not
438*2c2f96dcSApple OSS Distributions  * not break third party kexts that haven't yet been recompiled
439*2c2f96dcSApple OSS Distributions  * to use the new iokit macros.
440*2c2f96dcSApple OSS Distributions  */
441*2c2f96dcSApple OSS Distributions #if XNU_PLATFORM_MacOSX && __x86_64__
442*2c2f96dcSApple OSS Distributions #   define ZSECURITY_CONFIG_STRICT_IOKIT_FREE           OFF
443*2c2f96dcSApple OSS Distributions #else
444*2c2f96dcSApple OSS Distributions #   define ZSECURITY_CONFIG_STRICT_IOKIT_FREE           ON
445*2c2f96dcSApple OSS Distributions #endif
446*2c2f96dcSApple OSS Distributions 
447*2c2f96dcSApple OSS Distributions /*
448*2c2f96dcSApple OSS Distributions  * Zsecurity config to enable the read-only allocator
449*2c2f96dcSApple OSS Distributions  */
450*2c2f96dcSApple OSS Distributions #if KASAN_CLASSIC
451*2c2f96dcSApple OSS Distributions #   define ZSECURITY_CONFIG_READ_ONLY                   OFF
452*2c2f96dcSApple OSS Distributions #else
453*2c2f96dcSApple OSS Distributions #   define ZSECURITY_CONFIG_READ_ONLY                   ON
454*2c2f96dcSApple OSS Distributions #endif
455*2c2f96dcSApple OSS Distributions 
456*2c2f96dcSApple OSS Distributions /*
457*2c2f96dcSApple OSS Distributions  * Zsecurity config to enable making heap feng-shui
458*2c2f96dcSApple OSS Distributions  * less reliable.
459*2c2f96dcSApple OSS Distributions  */
460*2c2f96dcSApple OSS Distributions #if KASAN_CLASSIC
461*2c2f96dcSApple OSS Distributions #   define ZSECURITY_CONFIG_SAD_FENG_SHUI               OFF
462*2c2f96dcSApple OSS Distributions #   define ZSECURITY_CONFIG_GENERAL_SUBMAPS             1
463*2c2f96dcSApple OSS Distributions #else
464*2c2f96dcSApple OSS Distributions #   define ZSECURITY_CONFIG_SAD_FENG_SHUI               ON
465*2c2f96dcSApple OSS Distributions #   define ZSECURITY_CONFIG_GENERAL_SUBMAPS             4
466*2c2f96dcSApple OSS Distributions #endif
467*2c2f96dcSApple OSS Distributions 
468*2c2f96dcSApple OSS Distributions /*
469*2c2f96dcSApple OSS Distributions  * Zsecurity config to enable adjusting of elements
470*2c2f96dcSApple OSS Distributions  * with PGZ-OOB to right-align them in their space.
471*2c2f96dcSApple OSS Distributions  */
472*2c2f96dcSApple OSS Distributions #if KASAN || defined(__x86_64__) || CONFIG_KERNEL_TAGGING
473*2c2f96dcSApple OSS Distributions #   define ZSECURITY_CONFIG_PGZ_OOB_ADJUST              OFF
474*2c2f96dcSApple OSS Distributions #else
475*2c2f96dcSApple OSS Distributions #   define ZSECURITY_CONFIG_PGZ_OOB_ADJUST              ON
476*2c2f96dcSApple OSS Distributions #endif
477*2c2f96dcSApple OSS Distributions 
478*2c2f96dcSApple OSS Distributions /*
479*2c2f96dcSApple OSS Distributions  * Zsecurity config to enable kalloc type segregation
480*2c2f96dcSApple OSS Distributions  */
481*2c2f96dcSApple OSS Distributions #if XNU_TARGET_OS_WATCH || KASAN_CLASSIC
482*2c2f96dcSApple OSS Distributions #   define ZSECURITY_CONFIG_KT_BUDGET                   120
483*2c2f96dcSApple OSS Distributions #   define ZSECURITY_CONFIG_KT_VAR_BUDGET               6
484*2c2f96dcSApple OSS Distributions #else
485*2c2f96dcSApple OSS Distributions #   define ZSECURITY_CONFIG_KT_BUDGET                   260
486*2c2f96dcSApple OSS Distributions #   define ZSECURITY_CONFIG_KT_VAR_BUDGET               6
487*2c2f96dcSApple OSS Distributions #endif
488*2c2f96dcSApple OSS Distributions 
489*2c2f96dcSApple OSS Distributions 
490*2c2f96dcSApple OSS Distributions __options_decl(kalloc_type_options_t, uint64_t, {
491*2c2f96dcSApple OSS Distributions 	/*
492*2c2f96dcSApple OSS Distributions 	 * kalloc type option to switch default accounting to private.
493*2c2f96dcSApple OSS Distributions 	 */
494*2c2f96dcSApple OSS Distributions 	KT_OPTIONS_ACCT                         = 0x00000001,
495*2c2f96dcSApple OSS Distributions 	/*
496*2c2f96dcSApple OSS Distributions 	 * kalloc type option to print additional stats regarding zone
497*2c2f96dcSApple OSS Distributions 	 * budget distribution and signatures.
498*2c2f96dcSApple OSS Distributions 	 */
499*2c2f96dcSApple OSS Distributions 	KT_OPTIONS_DEBUG                        = 0x00000002,
500*2c2f96dcSApple OSS Distributions 	/*
501*2c2f96dcSApple OSS Distributions 	 * kalloc type option to allow loose freeing between heaps
502*2c2f96dcSApple OSS Distributions 	 */
503*2c2f96dcSApple OSS Distributions 	KT_OPTIONS_LOOSE_FREE                   = 0x00000004,
504*2c2f96dcSApple OSS Distributions });
505*2c2f96dcSApple OSS Distributions 
506*2c2f96dcSApple OSS Distributions __enum_decl(kt_var_heap_id_t, uint32_t, {
507*2c2f96dcSApple OSS Distributions 	/*
508*2c2f96dcSApple OSS Distributions 	 * Fake "data" heap used to link views of data-only allocation that
509*2c2f96dcSApple OSS Distributions 	 * have been redirected to KHEAP_DATA_BUFFERS
510*2c2f96dcSApple OSS Distributions 	 */
511*2c2f96dcSApple OSS Distributions 	KT_VAR_DATA_HEAP,
512*2c2f96dcSApple OSS Distributions 	/*
513*2c2f96dcSApple OSS Distributions 	 * Heaps for pointer arrays
514*2c2f96dcSApple OSS Distributions 	 */
515*2c2f96dcSApple OSS Distributions 	KT_VAR_PTR_HEAP0,
516*2c2f96dcSApple OSS Distributions 	KT_VAR_PTR_HEAP1,
517*2c2f96dcSApple OSS Distributions 	/*
518*2c2f96dcSApple OSS Distributions 	 * Indicating first additional heap added
519*2c2f96dcSApple OSS Distributions 	 */
520*2c2f96dcSApple OSS Distributions 	KT_VAR__FIRST_FLEXIBLE_HEAP,
521*2c2f96dcSApple OSS Distributions });
522*2c2f96dcSApple OSS Distributions 
523*2c2f96dcSApple OSS Distributions /*
524*2c2f96dcSApple OSS Distributions  * Zone submap indices
525*2c2f96dcSApple OSS Distributions  *
526*2c2f96dcSApple OSS Distributions  * Z_SUBMAP_IDX_VM
527*2c2f96dcSApple OSS Distributions  * this map has the special property that its allocations
528*2c2f96dcSApple OSS Distributions  * can be done without ever locking the submap, and doesn't use
529*2c2f96dcSApple OSS Distributions  * VM entries in the map (which limits certain VM map operations on it).
530*2c2f96dcSApple OSS Distributions  *
531*2c2f96dcSApple OSS Distributions  * On ILP32 a single zone lives here (the vm_map_entry_reserved_zone).
532*2c2f96dcSApple OSS Distributions  *
533*2c2f96dcSApple OSS Distributions  * On LP64 it is also used to restrict VM allocations on LP64 lower
534*2c2f96dcSApple OSS Distributions  * in the kernel VA space, for pointer packing purposes.
535*2c2f96dcSApple OSS Distributions  *
536*2c2f96dcSApple OSS Distributions  * Z_SUBMAP_IDX_GENERAL_{0,1,2,3}
537*2c2f96dcSApple OSS Distributions  * used for unrestricted allocations
538*2c2f96dcSApple OSS Distributions  *
539*2c2f96dcSApple OSS Distributions  * Z_SUBMAP_IDX_DATA
540*2c2f96dcSApple OSS Distributions  * used to sequester bags of bytes from all other allocations and allow VA reuse
541*2c2f96dcSApple OSS Distributions  * within the map
542*2c2f96dcSApple OSS Distributions  *
543*2c2f96dcSApple OSS Distributions  * Z_SUBMAP_IDX_READ_ONLY
544*2c2f96dcSApple OSS Distributions  * used for the read-only allocator
545*2c2f96dcSApple OSS Distributions  */
546*2c2f96dcSApple OSS Distributions __enum_decl(zone_submap_idx_t, uint32_t, {
547*2c2f96dcSApple OSS Distributions 	Z_SUBMAP_IDX_VM,
548*2c2f96dcSApple OSS Distributions 	Z_SUBMAP_IDX_READ_ONLY,
549*2c2f96dcSApple OSS Distributions 	Z_SUBMAP_IDX_GENERAL_0,
550*2c2f96dcSApple OSS Distributions #if ZSECURITY_CONFIG(SAD_FENG_SHUI)
551*2c2f96dcSApple OSS Distributions 	Z_SUBMAP_IDX_GENERAL_1,
552*2c2f96dcSApple OSS Distributions 	Z_SUBMAP_IDX_GENERAL_2,
553*2c2f96dcSApple OSS Distributions 	Z_SUBMAP_IDX_GENERAL_3,
554*2c2f96dcSApple OSS Distributions #endif /* ZSECURITY_CONFIG(SAD_FENG_SHUI) */
555*2c2f96dcSApple OSS Distributions 	Z_SUBMAP_IDX_DATA,
556*2c2f96dcSApple OSS Distributions 
557*2c2f96dcSApple OSS Distributions 	Z_SUBMAP_IDX_COUNT,
558*2c2f96dcSApple OSS Distributions });
559*2c2f96dcSApple OSS Distributions 
560*2c2f96dcSApple OSS Distributions #define KALLOC_MINALIGN     (1 << KALLOC_LOG2_MINALIGN)
561*2c2f96dcSApple OSS Distributions 
562*2c2f96dcSApple OSS Distributions /*
563*2c2f96dcSApple OSS Distributions  * Variable kalloc_type heap config
564*2c2f96dcSApple OSS Distributions  */
565*2c2f96dcSApple OSS Distributions struct kheap_info {
566*2c2f96dcSApple OSS Distributions 	zone_id_t               kh_zstart;
567*2c2f96dcSApple OSS Distributions 	kalloc_heap_t           kh_views;
568*2c2f96dcSApple OSS Distributions 	kalloc_type_var_view_t  kt_views;
569*2c2f96dcSApple OSS Distributions };
570*2c2f96dcSApple OSS Distributions typedef union kalloc_type_views {
571*2c2f96dcSApple OSS Distributions 	struct kalloc_type_view     *ktv_fixed;
572*2c2f96dcSApple OSS Distributions 	struct kalloc_type_var_view *ktv_var;
573*2c2f96dcSApple OSS Distributions } kalloc_type_views_t;
574*2c2f96dcSApple OSS Distributions 
575*2c2f96dcSApple OSS Distributions #define KT_VAR_MAX_HEAPS 8
576*2c2f96dcSApple OSS Distributions #define MAX_ZONES       690
577*2c2f96dcSApple OSS Distributions extern struct kheap_info        kalloc_type_heap_array[KT_VAR_MAX_HEAPS];
578*2c2f96dcSApple OSS Distributions extern zone_id_t _Atomic        num_zones;
579*2c2f96dcSApple OSS Distributions extern uint32_t                 zone_view_count;
580*2c2f96dcSApple OSS Distributions extern struct zone              zone_array[MAX_ZONES];
581*2c2f96dcSApple OSS Distributions extern struct zone_size_params  zone_ro_size_params[ZONE_ID__LAST_RO + 1];
582*2c2f96dcSApple OSS Distributions extern zone_security_flags_t    zone_security_array[];
583*2c2f96dcSApple OSS Distributions extern const char * const       kalloc_heap_names[KHEAP_ID_COUNT];
584*2c2f96dcSApple OSS Distributions extern mach_memory_info_t      *panic_kext_memory_info;
585*2c2f96dcSApple OSS Distributions extern vm_size_t                panic_kext_memory_size;
586*2c2f96dcSApple OSS Distributions extern vm_offset_t              panic_fault_address;
587*2c2f96dcSApple OSS Distributions extern uint16_t                 _zc_mag_size;
588*2c2f96dcSApple OSS Distributions 
589*2c2f96dcSApple OSS Distributions #define zone_index_foreach(i) \
590*2c2f96dcSApple OSS Distributions 	for (zone_id_t i = 1, num_zones_##i = os_atomic_load(&num_zones, acquire); \
591*2c2f96dcSApple OSS Distributions 	    i < num_zones_##i; i++)
592*2c2f96dcSApple OSS Distributions 
593*2c2f96dcSApple OSS Distributions #define zone_foreach(z) \
594*2c2f96dcSApple OSS Distributions 	for (zone_t z = &zone_array[1], \
595*2c2f96dcSApple OSS Distributions 	    last_zone_##z = &zone_array[os_atomic_load(&num_zones, acquire)]; \
596*2c2f96dcSApple OSS Distributions 	    z < last_zone_##z; z++)
597*2c2f96dcSApple OSS Distributions 
598*2c2f96dcSApple OSS Distributions __abortlike
599*2c2f96dcSApple OSS Distributions extern void zone_invalid_panic(zone_t zone);
600*2c2f96dcSApple OSS Distributions 
601*2c2f96dcSApple OSS Distributions __pure2
602*2c2f96dcSApple OSS Distributions static inline zone_id_t
zone_index(zone_t z)603*2c2f96dcSApple OSS Distributions zone_index(zone_t z)
604*2c2f96dcSApple OSS Distributions {
605*2c2f96dcSApple OSS Distributions 	unsigned long delta;
606*2c2f96dcSApple OSS Distributions 	uint64_t quo;
607*2c2f96dcSApple OSS Distributions 
608*2c2f96dcSApple OSS Distributions 	delta = (unsigned long)z - (unsigned long)zone_array;
609*2c2f96dcSApple OSS Distributions 	if (delta >= MAX_ZONES * sizeof(*z)) {
610*2c2f96dcSApple OSS Distributions 		zone_invalid_panic(z);
611*2c2f96dcSApple OSS Distributions 	}
612*2c2f96dcSApple OSS Distributions 	quo = Z_FAST_QUO(delta, Z_MAGIC_QUO(sizeof(*z)));
613*2c2f96dcSApple OSS Distributions 	__builtin_assume(quo < MAX_ZONES);
614*2c2f96dcSApple OSS Distributions 	return (zone_id_t)quo;
615*2c2f96dcSApple OSS Distributions }
616*2c2f96dcSApple OSS Distributions 
617*2c2f96dcSApple OSS Distributions __pure2
618*2c2f96dcSApple OSS Distributions static inline bool
zone_is_ro(zone_t zone)619*2c2f96dcSApple OSS Distributions zone_is_ro(zone_t zone)
620*2c2f96dcSApple OSS Distributions {
621*2c2f96dcSApple OSS Distributions 	return zone >= &zone_array[ZONE_ID__FIRST_RO] &&
622*2c2f96dcSApple OSS Distributions 	       zone <= &zone_array[ZONE_ID__LAST_RO];
623*2c2f96dcSApple OSS Distributions }
624*2c2f96dcSApple OSS Distributions 
625*2c2f96dcSApple OSS Distributions static inline bool
zone_addr_size_crosses_page(mach_vm_address_t addr,mach_vm_size_t size)626*2c2f96dcSApple OSS Distributions zone_addr_size_crosses_page(mach_vm_address_t addr, mach_vm_size_t size)
627*2c2f96dcSApple OSS Distributions {
628*2c2f96dcSApple OSS Distributions 	return atop(addr ^ (addr + size - 1)) != 0;
629*2c2f96dcSApple OSS Distributions }
630*2c2f96dcSApple OSS Distributions 
631*2c2f96dcSApple OSS Distributions __pure2
632*2c2f96dcSApple OSS Distributions static inline uint16_t
zone_elem_redzone(zone_t zone)633*2c2f96dcSApple OSS Distributions zone_elem_redzone(zone_t zone)
634*2c2f96dcSApple OSS Distributions {
635*2c2f96dcSApple OSS Distributions #if KASAN_CLASSIC
636*2c2f96dcSApple OSS Distributions 	return zone->z_kasan_redzone;
637*2c2f96dcSApple OSS Distributions #else
638*2c2f96dcSApple OSS Distributions 	(void)zone;
639*2c2f96dcSApple OSS Distributions 	return 0;
640*2c2f96dcSApple OSS Distributions #endif
641*2c2f96dcSApple OSS Distributions }
642*2c2f96dcSApple OSS Distributions 
643*2c2f96dcSApple OSS Distributions __pure2
644*2c2f96dcSApple OSS Distributions static inline uint16_t
zone_elem_inner_offs(zone_t zone)645*2c2f96dcSApple OSS Distributions zone_elem_inner_offs(zone_t zone)
646*2c2f96dcSApple OSS Distributions {
647*2c2f96dcSApple OSS Distributions 	return zone->z_elem_offs;
648*2c2f96dcSApple OSS Distributions }
649*2c2f96dcSApple OSS Distributions 
650*2c2f96dcSApple OSS Distributions __pure2
651*2c2f96dcSApple OSS Distributions static inline uint16_t
zone_elem_outer_offs(zone_t zone)652*2c2f96dcSApple OSS Distributions zone_elem_outer_offs(zone_t zone)
653*2c2f96dcSApple OSS Distributions {
654*2c2f96dcSApple OSS Distributions 	return zone_elem_inner_offs(zone) - zone_elem_redzone(zone);
655*2c2f96dcSApple OSS Distributions }
656*2c2f96dcSApple OSS Distributions 
657*2c2f96dcSApple OSS Distributions __pure2
658*2c2f96dcSApple OSS Distributions static inline vm_offset_t
zone_elem_inner_size(zone_t zone)659*2c2f96dcSApple OSS Distributions zone_elem_inner_size(zone_t zone)
660*2c2f96dcSApple OSS Distributions {
661*2c2f96dcSApple OSS Distributions 	return zone->z_elem_size;
662*2c2f96dcSApple OSS Distributions }
663*2c2f96dcSApple OSS Distributions 
664*2c2f96dcSApple OSS Distributions __pure2
665*2c2f96dcSApple OSS Distributions static inline vm_offset_t
zone_elem_outer_size(zone_t zone)666*2c2f96dcSApple OSS Distributions zone_elem_outer_size(zone_t zone)
667*2c2f96dcSApple OSS Distributions {
668*2c2f96dcSApple OSS Distributions 	return zone_elem_inner_size(zone) + zone_elem_redzone(zone);
669*2c2f96dcSApple OSS Distributions }
670*2c2f96dcSApple OSS Distributions 
671*2c2f96dcSApple OSS Distributions __pure2
672*2c2f96dcSApple OSS Distributions static inline zone_security_flags_t
zone_security_config(zone_t z)673*2c2f96dcSApple OSS Distributions zone_security_config(zone_t z)
674*2c2f96dcSApple OSS Distributions {
675*2c2f96dcSApple OSS Distributions 	zone_id_t zid = zone_index(z);
676*2c2f96dcSApple OSS Distributions 	return zone_security_array[zid];
677*2c2f96dcSApple OSS Distributions }
678*2c2f96dcSApple OSS Distributions 
679*2c2f96dcSApple OSS Distributions static inline uint32_t
zone_count_free(zone_t zone)680*2c2f96dcSApple OSS Distributions zone_count_free(zone_t zone)
681*2c2f96dcSApple OSS Distributions {
682*2c2f96dcSApple OSS Distributions 	return zone->z_elems_free + zone->z_recirc.zd_full * _zc_mag_size;
683*2c2f96dcSApple OSS Distributions }
684*2c2f96dcSApple OSS Distributions 
685*2c2f96dcSApple OSS Distributions static inline uint32_t
zone_count_allocated(zone_t zone)686*2c2f96dcSApple OSS Distributions zone_count_allocated(zone_t zone)
687*2c2f96dcSApple OSS Distributions {
688*2c2f96dcSApple OSS Distributions 	return zone->z_elems_avail - zone_count_free(zone);
689*2c2f96dcSApple OSS Distributions }
690*2c2f96dcSApple OSS Distributions 
691*2c2f96dcSApple OSS Distributions static inline vm_size_t
zone_scale_for_percpu(zone_t zone,vm_size_t size)692*2c2f96dcSApple OSS Distributions zone_scale_for_percpu(zone_t zone, vm_size_t size)
693*2c2f96dcSApple OSS Distributions {
694*2c2f96dcSApple OSS Distributions 	if (zone->z_percpu) {
695*2c2f96dcSApple OSS Distributions 		size *= zpercpu_count();
696*2c2f96dcSApple OSS Distributions 	}
697*2c2f96dcSApple OSS Distributions 	return size;
698*2c2f96dcSApple OSS Distributions }
699*2c2f96dcSApple OSS Distributions 
700*2c2f96dcSApple OSS Distributions static inline vm_size_t
zone_size_wired(zone_t zone)701*2c2f96dcSApple OSS Distributions zone_size_wired(zone_t zone)
702*2c2f96dcSApple OSS Distributions {
703*2c2f96dcSApple OSS Distributions 	/*
704*2c2f96dcSApple OSS Distributions 	 * this either require the zone lock,
705*2c2f96dcSApple OSS Distributions 	 * or to be used for statistics purposes only.
706*2c2f96dcSApple OSS Distributions 	 */
707*2c2f96dcSApple OSS Distributions 	vm_size_t size = ptoa(os_atomic_load(&zone->z_wired_cur, relaxed));
708*2c2f96dcSApple OSS Distributions 	return zone_scale_for_percpu(zone, size);
709*2c2f96dcSApple OSS Distributions }
710*2c2f96dcSApple OSS Distributions 
711*2c2f96dcSApple OSS Distributions static inline vm_size_t
zone_size_free(zone_t zone)712*2c2f96dcSApple OSS Distributions zone_size_free(zone_t zone)
713*2c2f96dcSApple OSS Distributions {
714*2c2f96dcSApple OSS Distributions 	return zone_scale_for_percpu(zone,
715*2c2f96dcSApple OSS Distributions 	           zone_elem_inner_size(zone) * zone_count_free(zone));
716*2c2f96dcSApple OSS Distributions }
717*2c2f96dcSApple OSS Distributions 
718*2c2f96dcSApple OSS Distributions /* Under KASAN builds, this also accounts for quarantined elements. */
719*2c2f96dcSApple OSS Distributions static inline vm_size_t
zone_size_allocated(zone_t zone)720*2c2f96dcSApple OSS Distributions zone_size_allocated(zone_t zone)
721*2c2f96dcSApple OSS Distributions {
722*2c2f96dcSApple OSS Distributions 	return zone_scale_for_percpu(zone,
723*2c2f96dcSApple OSS Distributions 	           zone_elem_inner_size(zone) * zone_count_allocated(zone));
724*2c2f96dcSApple OSS Distributions }
725*2c2f96dcSApple OSS Distributions 
726*2c2f96dcSApple OSS Distributions static inline vm_size_t
zone_size_wasted(zone_t zone)727*2c2f96dcSApple OSS Distributions zone_size_wasted(zone_t zone)
728*2c2f96dcSApple OSS Distributions {
729*2c2f96dcSApple OSS Distributions 	return zone_size_wired(zone) - zone_scale_for_percpu(zone,
730*2c2f96dcSApple OSS Distributions 	           zone_elem_outer_size(zone) * zone->z_elems_avail);
731*2c2f96dcSApple OSS Distributions }
732*2c2f96dcSApple OSS Distributions 
733*2c2f96dcSApple OSS Distributions __pure2
734*2c2f96dcSApple OSS Distributions static inline bool
zone_exhaustible(zone_t zone)735*2c2f96dcSApple OSS Distributions zone_exhaustible(zone_t zone)
736*2c2f96dcSApple OSS Distributions {
737*2c2f96dcSApple OSS Distributions 	return zone->z_wired_max != ~0u;
738*2c2f96dcSApple OSS Distributions }
739*2c2f96dcSApple OSS Distributions 
740*2c2f96dcSApple OSS Distributions __pure2
741*2c2f96dcSApple OSS Distributions static inline bool
zone_exhausted(zone_t zone)742*2c2f96dcSApple OSS Distributions zone_exhausted(zone_t zone)
743*2c2f96dcSApple OSS Distributions {
744*2c2f96dcSApple OSS Distributions 	return zone->z_wired_cur >= zone->z_wired_max;
745*2c2f96dcSApple OSS Distributions }
746*2c2f96dcSApple OSS Distributions 
747*2c2f96dcSApple OSS Distributions /*
748*2c2f96dcSApple OSS Distributions  * Set and get the signature equivalance for the given zone
749*2c2f96dcSApple OSS Distributions  */
750*2c2f96dcSApple OSS Distributions extern void zone_set_sig_eq(zone_t zone, zone_id_t sig_eq);
751*2c2f96dcSApple OSS Distributions extern zone_id_t zone_get_sig_eq(zone_t zone);
752*2c2f96dcSApple OSS Distributions /*
753*2c2f96dcSApple OSS Distributions  * Return the accumulated allocated memory on the given zone stats
754*2c2f96dcSApple OSS Distributions  */
755*2c2f96dcSApple OSS Distributions static inline vm_size_t
zone_stats_get_mem_allocated(zone_stats_t stats)756*2c2f96dcSApple OSS Distributions zone_stats_get_mem_allocated(zone_stats_t stats)
757*2c2f96dcSApple OSS Distributions {
758*2c2f96dcSApple OSS Distributions 	return stats->zs_mem_allocated;
759*2c2f96dcSApple OSS Distributions }
760*2c2f96dcSApple OSS Distributions 
761*2c2f96dcSApple OSS Distributions /*
762*2c2f96dcSApple OSS Distributions  * For sysctl kern.zones_collectable_bytes used by memory_maintenance to check if a
763*2c2f96dcSApple OSS Distributions  * userspace reboot is needed. The only other way to query for this information
764*2c2f96dcSApple OSS Distributions  * is via mach_memory_info() which is unavailable on release kernels.
765*2c2f96dcSApple OSS Distributions  */
766*2c2f96dcSApple OSS Distributions extern uint64_t get_zones_collectable_bytes(void);
767*2c2f96dcSApple OSS Distributions 
768*2c2f96dcSApple OSS Distributions /*!
769*2c2f96dcSApple OSS Distributions  * @enum zone_gc_level_t
770*2c2f96dcSApple OSS Distributions  *
771*2c2f96dcSApple OSS Distributions  * @const ZONE_GC_TRIM
772*2c2f96dcSApple OSS Distributions  * Request a trimming GC: it will trim allocations in excess
773*2c2f96dcSApple OSS Distributions  * of the working set size estimate only.
774*2c2f96dcSApple OSS Distributions  *
775*2c2f96dcSApple OSS Distributions  * @const ZONE_GC_DRAIN
776*2c2f96dcSApple OSS Distributions  * Request a draining GC: this is an aggressive mode that will
777*2c2f96dcSApple OSS Distributions  * cause all caches to be drained and all free pages returned to the system.
778*2c2f96dcSApple OSS Distributions  *
779*2c2f96dcSApple OSS Distributions  * @const ZONE_GC_JETSAM
780*2c2f96dcSApple OSS Distributions  * Request to consider a jetsam, and then fallback to @c ZONE_GC_TRIM or
781*2c2f96dcSApple OSS Distributions  * @c ZONE_GC_DRAIN depending on the state of the zone map.
782*2c2f96dcSApple OSS Distributions  * To avoid deadlocks, only @c vm_pageout_garbage_collect() should ever
783*2c2f96dcSApple OSS Distributions  * request a @c ZONE_GC_JETSAM level.
784*2c2f96dcSApple OSS Distributions  */
785*2c2f96dcSApple OSS Distributions __enum_closed_decl(zone_gc_level_t, uint32_t, {
786*2c2f96dcSApple OSS Distributions 	ZONE_GC_TRIM,
787*2c2f96dcSApple OSS Distributions 	ZONE_GC_DRAIN,
788*2c2f96dcSApple OSS Distributions 	ZONE_GC_JETSAM,
789*2c2f96dcSApple OSS Distributions });
790*2c2f96dcSApple OSS Distributions 
791*2c2f96dcSApple OSS Distributions /*!
792*2c2f96dcSApple OSS Distributions  * @function zone_gc
793*2c2f96dcSApple OSS Distributions  *
794*2c2f96dcSApple OSS Distributions  * @brief
795*2c2f96dcSApple OSS Distributions  * Reduces memory used by zones by trimming caches and freelists.
796*2c2f96dcSApple OSS Distributions  *
797*2c2f96dcSApple OSS Distributions  * @discussion
798*2c2f96dcSApple OSS Distributions  * @c zone_gc() is called:
799*2c2f96dcSApple OSS Distributions  * - by the pageout daemon when the system needs more free pages.
800*2c2f96dcSApple OSS Distributions  * - by the VM when contiguous page allocation requests get stuck
801*2c2f96dcSApple OSS Distributions  *   (see vm_page_find_contiguous()).
802*2c2f96dcSApple OSS Distributions  *
803*2c2f96dcSApple OSS Distributions  * @param level         The zone GC level requested.
804*2c2f96dcSApple OSS Distributions  */
805*2c2f96dcSApple OSS Distributions extern void     zone_gc(zone_gc_level_t level);
806*2c2f96dcSApple OSS Distributions 
807*2c2f96dcSApple OSS Distributions extern void     zone_gc_trim(void);
808*2c2f96dcSApple OSS Distributions extern void     zone_gc_drain(void);
809*2c2f96dcSApple OSS Distributions 
810*2c2f96dcSApple OSS Distributions #define ZONE_WSS_UPDATE_PERIOD  15
811*2c2f96dcSApple OSS Distributions /*!
812*2c2f96dcSApple OSS Distributions  * @function compute_zone_working_set_size
813*2c2f96dcSApple OSS Distributions  *
814*2c2f96dcSApple OSS Distributions  * @brief
815*2c2f96dcSApple OSS Distributions  * Recomputes the working set size for every zone
816*2c2f96dcSApple OSS Distributions  *
817*2c2f96dcSApple OSS Distributions  * @discussion
818*2c2f96dcSApple OSS Distributions  * This runs about every @c ZONE_WSS_UPDATE_PERIOD seconds (10),
819*2c2f96dcSApple OSS Distributions  * computing an exponential moving average with a weight of 75%,
820*2c2f96dcSApple OSS Distributions  * so that the history of the last minute is the dominating factor.
821*2c2f96dcSApple OSS Distributions  */
822*2c2f96dcSApple OSS Distributions extern void     compute_zone_working_set_size(void *);
823*2c2f96dcSApple OSS Distributions 
824*2c2f96dcSApple OSS Distributions /* Debug logging for zone-map-exhaustion jetsams. */
825*2c2f96dcSApple OSS Distributions extern void     get_zone_map_size(uint64_t *current_size, uint64_t *capacity);
826*2c2f96dcSApple OSS Distributions extern void     get_largest_zone_info(char *zone_name, size_t zone_name_len, uint64_t *zone_size);
827*2c2f96dcSApple OSS Distributions 
828*2c2f96dcSApple OSS Distributions /* Bootstrap zone module (create zone zone) */
829*2c2f96dcSApple OSS Distributions extern void     zone_bootstrap(void);
830*2c2f96dcSApple OSS Distributions 
831*2c2f96dcSApple OSS Distributions /* Force-enable caching on a zone, generally unsafe to call directly */
832*2c2f96dcSApple OSS Distributions extern void     zone_enable_caching(zone_t zone);
833*2c2f96dcSApple OSS Distributions 
834*2c2f96dcSApple OSS Distributions /*!
835*2c2f96dcSApple OSS Distributions  * @function zone_early_mem_init
836*2c2f96dcSApple OSS Distributions  *
837*2c2f96dcSApple OSS Distributions  * @brief
838*2c2f96dcSApple OSS Distributions  * Steal memory from pmap (prior to initialization of zalloc)
839*2c2f96dcSApple OSS Distributions  * for the special vm zones that allow bootstrap memory and store
840*2c2f96dcSApple OSS Distributions  * the range so as to facilitate range checking in zfree.
841*2c2f96dcSApple OSS Distributions  *
842*2c2f96dcSApple OSS Distributions  * @param size              the size to steal (must be a page multiple)
843*2c2f96dcSApple OSS Distributions  */
844*2c2f96dcSApple OSS Distributions __startup_func
845*2c2f96dcSApple OSS Distributions extern vm_offset_t zone_early_mem_init(
846*2c2f96dcSApple OSS Distributions 	vm_size_t       size);
847*2c2f96dcSApple OSS Distributions 
848*2c2f96dcSApple OSS Distributions /*!
849*2c2f96dcSApple OSS Distributions  * @function zone_get_early_alloc_size
850*2c2f96dcSApple OSS Distributions  *
851*2c2f96dcSApple OSS Distributions  * @brief
852*2c2f96dcSApple OSS Distributions  * Compute the correct size (greater than @c ptoa(min_pages)) that is a multiple
853*2c2f96dcSApple OSS Distributions  * of the allocation granule for the zone with the given creation flags and
854*2c2f96dcSApple OSS Distributions  * element size.
855*2c2f96dcSApple OSS Distributions  */
856*2c2f96dcSApple OSS Distributions __startup_func
857*2c2f96dcSApple OSS Distributions extern vm_size_t zone_get_early_alloc_size(
858*2c2f96dcSApple OSS Distributions 	const char          *name __unused,
859*2c2f96dcSApple OSS Distributions 	vm_size_t            elem_size,
860*2c2f96dcSApple OSS Distributions 	zone_create_flags_t  flags,
861*2c2f96dcSApple OSS Distributions 	vm_size_t            min_elems);
862*2c2f96dcSApple OSS Distributions 
863*2c2f96dcSApple OSS Distributions /*!
864*2c2f96dcSApple OSS Distributions  * @function zone_cram_early
865*2c2f96dcSApple OSS Distributions  *
866*2c2f96dcSApple OSS Distributions  * @brief
867*2c2f96dcSApple OSS Distributions  * Cram memory allocated with @c zone_early_mem_init() into a zone.
868*2c2f96dcSApple OSS Distributions  *
869*2c2f96dcSApple OSS Distributions  * @param zone          The zone to cram memory into.
870*2c2f96dcSApple OSS Distributions  * @param newmem        The base address for the memory to cram.
871*2c2f96dcSApple OSS Distributions  * @param size          The size of the memory to cram into the zone.
872*2c2f96dcSApple OSS Distributions  */
873*2c2f96dcSApple OSS Distributions __startup_func
874*2c2f96dcSApple OSS Distributions extern void     zone_cram_early(
875*2c2f96dcSApple OSS Distributions 	zone_t          zone,
876*2c2f96dcSApple OSS Distributions 	vm_offset_t     newmem,
877*2c2f96dcSApple OSS Distributions 	vm_size_t       size);
878*2c2f96dcSApple OSS Distributions 
879*2c2f96dcSApple OSS Distributions extern bool     zone_maps_owned(
880*2c2f96dcSApple OSS Distributions 	vm_address_t    addr,
881*2c2f96dcSApple OSS Distributions 	vm_size_t       size);
882*2c2f96dcSApple OSS Distributions 
883*2c2f96dcSApple OSS Distributions #if KASAN_LIGHT
884*2c2f96dcSApple OSS Distributions extern bool     kasan_zone_maps_owned(
885*2c2f96dcSApple OSS Distributions 	vm_address_t    addr,
886*2c2f96dcSApple OSS Distributions 	vm_size_t       size);
887*2c2f96dcSApple OSS Distributions #endif /* KASAN_LIGHT */
888*2c2f96dcSApple OSS Distributions 
889*2c2f96dcSApple OSS Distributions extern void     zone_map_sizes(
890*2c2f96dcSApple OSS Distributions 	vm_map_size_t  *psize,
891*2c2f96dcSApple OSS Distributions 	vm_map_size_t  *pfree,
892*2c2f96dcSApple OSS Distributions 	vm_map_size_t  *plargest_free);
893*2c2f96dcSApple OSS Distributions 
894*2c2f96dcSApple OSS Distributions extern bool
895*2c2f96dcSApple OSS Distributions zone_map_nearing_exhaustion(void);
896*2c2f96dcSApple OSS Distributions 
897*2c2f96dcSApple OSS Distributions static inline vm_tag_t
zalloc_flags_get_tag(zalloc_flags_t flags)898*2c2f96dcSApple OSS Distributions zalloc_flags_get_tag(zalloc_flags_t flags)
899*2c2f96dcSApple OSS Distributions {
900*2c2f96dcSApple OSS Distributions 	return (vm_tag_t)((flags & Z_VM_TAG_MASK) >> Z_VM_TAG_SHIFT);
901*2c2f96dcSApple OSS Distributions }
902*2c2f96dcSApple OSS Distributions 
903*2c2f96dcSApple OSS Distributions extern struct kalloc_result zalloc_ext(
904*2c2f96dcSApple OSS Distributions 	zone_t          zone,
905*2c2f96dcSApple OSS Distributions 	zone_stats_t    zstats,
906*2c2f96dcSApple OSS Distributions 	zalloc_flags_t  flags);
907*2c2f96dcSApple OSS Distributions 
908*2c2f96dcSApple OSS Distributions #if KASAN
909*2c2f96dcSApple OSS Distributions #define ZFREE_PACK_SIZE(esize, usize)   (((uint64_t)(usize) << 32) | (esize))
910*2c2f96dcSApple OSS Distributions #define ZFREE_ELEM_SIZE(combined)       ((uint32_t)(combined))
911*2c2f96dcSApple OSS Distributions #define ZFREE_USER_SIZE(combined)       ((combined) >> 32)
912*2c2f96dcSApple OSS Distributions #else
913*2c2f96dcSApple OSS Distributions #define ZFREE_PACK_SIZE(esize, usize)   (esize)
914*2c2f96dcSApple OSS Distributions #define ZFREE_ELEM_SIZE(combined)       (combined)
915*2c2f96dcSApple OSS Distributions #endif
916*2c2f96dcSApple OSS Distributions 
917*2c2f96dcSApple OSS Distributions extern void     zfree_ext(
918*2c2f96dcSApple OSS Distributions 	zone_t          zone,
919*2c2f96dcSApple OSS Distributions 	zone_stats_t    zstats,
920*2c2f96dcSApple OSS Distributions 	void           *addr,
921*2c2f96dcSApple OSS Distributions 	uint64_t        combined_size);
922*2c2f96dcSApple OSS Distributions 
923*2c2f96dcSApple OSS Distributions extern zone_id_t zone_id_for_element(
924*2c2f96dcSApple OSS Distributions 	void           *addr,
925*2c2f96dcSApple OSS Distributions 	vm_size_t       esize);
926*2c2f96dcSApple OSS Distributions 
927*2c2f96dcSApple OSS Distributions #if ZSECURITY_CONFIG(PGZ_OOB_ADJUST)
928*2c2f96dcSApple OSS Distributions extern void *zone_element_pgz_oob_adjust(
929*2c2f96dcSApple OSS Distributions 	void           *addr,
930*2c2f96dcSApple OSS Distributions 	vm_size_t       req_size,
931*2c2f96dcSApple OSS Distributions 	vm_size_t       elem_size);
932*2c2f96dcSApple OSS Distributions #endif /* !ZSECURITY_CONFIG(PGZ_OOB_ADJUST) */
933*2c2f96dcSApple OSS Distributions 
934*2c2f96dcSApple OSS Distributions extern void zone_element_bounds_check(
935*2c2f96dcSApple OSS Distributions 	vm_address_t    addr,
936*2c2f96dcSApple OSS Distributions 	vm_size_t       len);
937*2c2f96dcSApple OSS Distributions 
938*2c2f96dcSApple OSS Distributions extern vm_size_t zone_element_size(
939*2c2f96dcSApple OSS Distributions 	void           *addr,
940*2c2f96dcSApple OSS Distributions 	zone_t         *z,
941*2c2f96dcSApple OSS Distributions 	bool            clear_oob,
942*2c2f96dcSApple OSS Distributions 	vm_offset_t    *oob_offs);
943*2c2f96dcSApple OSS Distributions 
944*2c2f96dcSApple OSS Distributions /*!
945*2c2f96dcSApple OSS Distributions  * @function zone_spans_ro_va
946*2c2f96dcSApple OSS Distributions  *
947*2c2f96dcSApple OSS Distributions  * @abstract
948*2c2f96dcSApple OSS Distributions  * This function is used to check whether the specified address range
949*2c2f96dcSApple OSS Distributions  * spans through the read-only zone range.
950*2c2f96dcSApple OSS Distributions  *
951*2c2f96dcSApple OSS Distributions  * @discussion
952*2c2f96dcSApple OSS Distributions  * This only checks for the range specified within ZONE_ADDR_READONLY.
953*2c2f96dcSApple OSS Distributions  * The parameters addr_start and addr_end are stripped off of PAC bits
954*2c2f96dcSApple OSS Distributions  * before the check is made.
955*2c2f96dcSApple OSS Distributions  */
956*2c2f96dcSApple OSS Distributions extern bool zone_spans_ro_va(
957*2c2f96dcSApple OSS Distributions 	vm_offset_t     addr_start,
958*2c2f96dcSApple OSS Distributions 	vm_offset_t     addr_end);
959*2c2f96dcSApple OSS Distributions 
960*2c2f96dcSApple OSS Distributions /*!
961*2c2f96dcSApple OSS Distributions  * @function __zalloc_ro_mut_atomic
962*2c2f96dcSApple OSS Distributions  *
963*2c2f96dcSApple OSS Distributions  * @abstract
964*2c2f96dcSApple OSS Distributions  * This function is called from the pmap to perform the specified atomic
965*2c2f96dcSApple OSS Distributions  * operation on memory from the read-only allocator.
966*2c2f96dcSApple OSS Distributions  *
967*2c2f96dcSApple OSS Distributions  * @discussion
968*2c2f96dcSApple OSS Distributions  * This function is for internal use only and should not be called directly.
969*2c2f96dcSApple OSS Distributions  */
970*2c2f96dcSApple OSS Distributions static inline uint64_t
__zalloc_ro_mut_atomic(vm_offset_t dst,zro_atomic_op_t op,uint64_t value)971*2c2f96dcSApple OSS Distributions __zalloc_ro_mut_atomic(vm_offset_t dst, zro_atomic_op_t op, uint64_t value)
972*2c2f96dcSApple OSS Distributions {
973*2c2f96dcSApple OSS Distributions #define __ZALLOC_RO_MUT_OP(op, op2) \
974*2c2f96dcSApple OSS Distributions 	case ZRO_ATOMIC_##op##_8: \
975*2c2f96dcSApple OSS Distributions 	        return os_atomic_##op2((uint8_t *)dst, (uint8_t)value, seq_cst); \
976*2c2f96dcSApple OSS Distributions 	case ZRO_ATOMIC_##op##_16: \
977*2c2f96dcSApple OSS Distributions 	        return os_atomic_##op2((uint16_t *)dst, (uint16_t)value, seq_cst); \
978*2c2f96dcSApple OSS Distributions 	case ZRO_ATOMIC_##op##_32: \
979*2c2f96dcSApple OSS Distributions 	        return os_atomic_##op2((uint32_t *)dst, (uint32_t)value, seq_cst); \
980*2c2f96dcSApple OSS Distributions 	case ZRO_ATOMIC_##op##_64: \
981*2c2f96dcSApple OSS Distributions 	        return os_atomic_##op2((uint64_t *)dst, (uint64_t)value, seq_cst)
982*2c2f96dcSApple OSS Distributions 
983*2c2f96dcSApple OSS Distributions 	switch (op) {
984*2c2f96dcSApple OSS Distributions 		__ZALLOC_RO_MUT_OP(OR, or_orig);
985*2c2f96dcSApple OSS Distributions 		__ZALLOC_RO_MUT_OP(XOR, xor_orig);
986*2c2f96dcSApple OSS Distributions 		__ZALLOC_RO_MUT_OP(AND, and_orig);
987*2c2f96dcSApple OSS Distributions 		__ZALLOC_RO_MUT_OP(ADD, add_orig);
988*2c2f96dcSApple OSS Distributions 		__ZALLOC_RO_MUT_OP(XCHG, xchg);
989*2c2f96dcSApple OSS Distributions 	default:
990*2c2f96dcSApple OSS Distributions 		panic("%s: Invalid atomic operation: %d", __func__, op);
991*2c2f96dcSApple OSS Distributions 	}
992*2c2f96dcSApple OSS Distributions 
993*2c2f96dcSApple OSS Distributions #undef __ZALLOC_RO_MUT_OP
994*2c2f96dcSApple OSS Distributions }
995*2c2f96dcSApple OSS Distributions 
996*2c2f96dcSApple OSS Distributions /*!
997*2c2f96dcSApple OSS Distributions  * @function zone_owns
998*2c2f96dcSApple OSS Distributions  *
999*2c2f96dcSApple OSS Distributions  * @abstract
1000*2c2f96dcSApple OSS Distributions  * This function is a soft version of zone_require that checks if a given
1001*2c2f96dcSApple OSS Distributions  * pointer belongs to the specified zone and should not be used outside
1002*2c2f96dcSApple OSS Distributions  * allocator code.
1003*2c2f96dcSApple OSS Distributions  *
1004*2c2f96dcSApple OSS Distributions  * @discussion
1005*2c2f96dcSApple OSS Distributions  * Note that zone_owns() can only work with:
1006*2c2f96dcSApple OSS Distributions  * - zones not allowing foreign memory
1007*2c2f96dcSApple OSS Distributions  * - zones in the general submap.
1008*2c2f96dcSApple OSS Distributions  *
1009*2c2f96dcSApple OSS Distributions  * @param zone          the zone the address needs to belong to.
1010*2c2f96dcSApple OSS Distributions  * @param addr          the element address to check.
1011*2c2f96dcSApple OSS Distributions  */
1012*2c2f96dcSApple OSS Distributions extern bool     zone_owns(
1013*2c2f96dcSApple OSS Distributions 	zone_t          zone,
1014*2c2f96dcSApple OSS Distributions 	void           *addr);
1015*2c2f96dcSApple OSS Distributions 
1016*2c2f96dcSApple OSS Distributions /**!
1017*2c2f96dcSApple OSS Distributions  * @function zone_submap
1018*2c2f96dcSApple OSS Distributions  *
1019*2c2f96dcSApple OSS Distributions  * @param zsflags       the security flags of a specified zone.
1020*2c2f96dcSApple OSS Distributions  * @returns             the zone (sub)map this zone allocates from.
1021*2c2f96dcSApple OSS Distributions  */
1022*2c2f96dcSApple OSS Distributions __pure2
1023*2c2f96dcSApple OSS Distributions extern vm_map_t zone_submap(
1024*2c2f96dcSApple OSS Distributions 	zone_security_flags_t   zsflags);
1025*2c2f96dcSApple OSS Distributions 
1026*2c2f96dcSApple OSS Distributions #ifndef VM_TAG_SIZECLASSES
1027*2c2f96dcSApple OSS Distributions #error MAX_TAG_ZONES
1028*2c2f96dcSApple OSS Distributions #endif
1029*2c2f96dcSApple OSS Distributions #if VM_TAG_SIZECLASSES
1030*2c2f96dcSApple OSS Distributions 
1031*2c2f96dcSApple OSS Distributions extern uint16_t zone_index_from_tag_index(
1032*2c2f96dcSApple OSS Distributions 	uint32_t        tag_zone_index);
1033*2c2f96dcSApple OSS Distributions 
1034*2c2f96dcSApple OSS Distributions #endif /* VM_TAG_SIZECLASSES */
1035*2c2f96dcSApple OSS Distributions 
1036*2c2f96dcSApple OSS Distributions extern lck_grp_t zone_locks_grp;
1037*2c2f96dcSApple OSS Distributions 
1038*2c2f96dcSApple OSS Distributions static inline void
zone_lock(zone_t zone)1039*2c2f96dcSApple OSS Distributions zone_lock(zone_t zone)
1040*2c2f96dcSApple OSS Distributions {
1041*2c2f96dcSApple OSS Distributions #if KASAN_FAKESTACK
1042*2c2f96dcSApple OSS Distributions 	spl_t s = 0;
1043*2c2f96dcSApple OSS Distributions 	if (zone->z_kasan_fakestacks) {
1044*2c2f96dcSApple OSS Distributions 		s = splsched();
1045*2c2f96dcSApple OSS Distributions 	}
1046*2c2f96dcSApple OSS Distributions #endif /* KASAN_FAKESTACK */
1047*2c2f96dcSApple OSS Distributions 	hw_lck_ticket_lock(&zone->z_lock, &zone_locks_grp);
1048*2c2f96dcSApple OSS Distributions #if KASAN_FAKESTACK
1049*2c2f96dcSApple OSS Distributions 	zone->z_kasan_spl = s;
1050*2c2f96dcSApple OSS Distributions #endif /* KASAN_FAKESTACK */
1051*2c2f96dcSApple OSS Distributions }
1052*2c2f96dcSApple OSS Distributions 
1053*2c2f96dcSApple OSS Distributions static inline void
zone_unlock(zone_t zone)1054*2c2f96dcSApple OSS Distributions zone_unlock(zone_t zone)
1055*2c2f96dcSApple OSS Distributions {
1056*2c2f96dcSApple OSS Distributions #if KASAN_FAKESTACK
1057*2c2f96dcSApple OSS Distributions 	spl_t s = zone->z_kasan_spl;
1058*2c2f96dcSApple OSS Distributions 	zone->z_kasan_spl = 0;
1059*2c2f96dcSApple OSS Distributions #endif /* KASAN_FAKESTACK */
1060*2c2f96dcSApple OSS Distributions 	hw_lck_ticket_unlock(&zone->z_lock);
1061*2c2f96dcSApple OSS Distributions #if KASAN_FAKESTACK
1062*2c2f96dcSApple OSS Distributions 	if (zone->z_kasan_fakestacks) {
1063*2c2f96dcSApple OSS Distributions 		splx(s);
1064*2c2f96dcSApple OSS Distributions 	}
1065*2c2f96dcSApple OSS Distributions #endif /* KASAN_FAKESTACK */
1066*2c2f96dcSApple OSS Distributions }
1067*2c2f96dcSApple OSS Distributions 
1068*2c2f96dcSApple OSS Distributions #define MAX_ZONE_NAME   32      /* max length of a zone name we can take from the boot-args */
1069*2c2f96dcSApple OSS Distributions 
1070*2c2f96dcSApple OSS Distributions int track_this_zone(const char *zonename, const char *logname);
1071*2c2f96dcSApple OSS Distributions extern bool panic_include_kalloc_types;
1072*2c2f96dcSApple OSS Distributions extern zone_t kalloc_type_src_zone;
1073*2c2f96dcSApple OSS Distributions extern zone_t kalloc_type_dst_zone;
1074*2c2f96dcSApple OSS Distributions 
1075*2c2f96dcSApple OSS Distributions #if DEBUG || DEVELOPMENT
1076*2c2f96dcSApple OSS Distributions extern vm_size_t zone_element_info(void *addr, vm_tag_t * ptag);
1077*2c2f96dcSApple OSS Distributions #endif /* DEBUG || DEVELOPMENT */
1078*2c2f96dcSApple OSS Distributions 
1079*2c2f96dcSApple OSS Distributions #pragma GCC visibility pop
1080*2c2f96dcSApple OSS Distributions 
1081*2c2f96dcSApple OSS Distributions __END_DECLS
1082*2c2f96dcSApple OSS Distributions 
1083*2c2f96dcSApple OSS Distributions #endif  /* _KERN_ZALLOC_INTERNAL_H_ */
1084