xref: /xnu-11215/iokit/Kernel/IOLib.cpp (revision d4514f0b)
1e13b1fa5SApple OSS Distributions /*
2e13b1fa5SApple OSS Distributions  * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
3e13b1fa5SApple OSS Distributions  *
4e13b1fa5SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5e13b1fa5SApple OSS Distributions  *
6e13b1fa5SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7e13b1fa5SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8e13b1fa5SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9e13b1fa5SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10e13b1fa5SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11e13b1fa5SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12e13b1fa5SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13e13b1fa5SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14e13b1fa5SApple OSS Distributions  *
15e13b1fa5SApple OSS Distributions  * Please obtain a copy of the License at
16e13b1fa5SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17e13b1fa5SApple OSS Distributions  *
18e13b1fa5SApple OSS Distributions  * The Original Code and all software distributed under the License are
19e13b1fa5SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20e13b1fa5SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21e13b1fa5SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22e13b1fa5SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23e13b1fa5SApple OSS Distributions  * Please see the License for the specific language governing rights and
24e13b1fa5SApple OSS Distributions  * limitations under the License.
25e13b1fa5SApple OSS Distributions  *
26e13b1fa5SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27e13b1fa5SApple OSS Distributions  */
28e13b1fa5SApple OSS Distributions /*
29e13b1fa5SApple OSS Distributions  * HISTORY
30e13b1fa5SApple OSS Distributions  *
31e13b1fa5SApple OSS Distributions  * 17-Apr-91   Portions from libIO.m, Doug Mitchell at NeXT.
32e13b1fa5SApple OSS Distributions  * 17-Nov-98   cpp
33e13b1fa5SApple OSS Distributions  *
34e13b1fa5SApple OSS Distributions  */
35e13b1fa5SApple OSS Distributions 
36e13b1fa5SApple OSS Distributions #include <IOKit/system.h>
37e13b1fa5SApple OSS Distributions #include <mach/sync_policy.h>
38e13b1fa5SApple OSS Distributions #include <machine/machine_routines.h>
398d741a5dSApple OSS Distributions #include <vm/vm_kern_xnu.h>
408d741a5dSApple OSS Distributions #include <vm/vm_map_xnu.h>
41e13b1fa5SApple OSS Distributions #include <libkern/c++/OSCPPDebug.h>
42e13b1fa5SApple OSS Distributions 
43e13b1fa5SApple OSS Distributions #include <IOKit/assert.h>
44e13b1fa5SApple OSS Distributions 
45e13b1fa5SApple OSS Distributions #include <IOKit/IOReturn.h>
46e13b1fa5SApple OSS Distributions #include <IOKit/IOLib.h>
47e13b1fa5SApple OSS Distributions #include <IOKit/IOLocks.h>
48e13b1fa5SApple OSS Distributions #include <IOKit/IOMapper.h>
49e13b1fa5SApple OSS Distributions #include <IOKit/IOBufferMemoryDescriptor.h>
50e13b1fa5SApple OSS Distributions #include <IOKit/IOKitDebug.h>
51e13b1fa5SApple OSS Distributions 
52e13b1fa5SApple OSS Distributions #include "IOKitKernelInternal.h"
53e13b1fa5SApple OSS Distributions 
54e13b1fa5SApple OSS Distributions #ifdef IOALLOCDEBUG
55e13b1fa5SApple OSS Distributions #include <libkern/OSDebug.h>
56e13b1fa5SApple OSS Distributions #include <sys/sysctl.h>
57e13b1fa5SApple OSS Distributions #endif
58e13b1fa5SApple OSS Distributions 
59855239e5SApple OSS Distributions #include "libkern/OSAtomic.h"
60855239e5SApple OSS Distributions #include <libkern/c++/OSKext.h>
61855239e5SApple OSS Distributions #include <IOKit/IOStatisticsPrivate.h>
6288cc0b97SApple OSS Distributions #include <os/log_private.h>
63855239e5SApple OSS Distributions #include <sys/msgbuf.h>
6476e12aa3SApple OSS Distributions #include <console/serial_protos.h>
65855239e5SApple OSS Distributions 
66855239e5SApple OSS Distributions #if IOKITSTATS
67855239e5SApple OSS Distributions 
68855239e5SApple OSS Distributions #define IOStatisticsAlloc(type, size) \
69855239e5SApple OSS Distributions do { \
70855239e5SApple OSS Distributions 	IOStatistics::countAlloc(type, size); \
71855239e5SApple OSS Distributions } while (0)
72855239e5SApple OSS Distributions 
73855239e5SApple OSS Distributions #else
74855239e5SApple OSS Distributions 
75855239e5SApple OSS Distributions #define IOStatisticsAlloc(type, size)
76855239e5SApple OSS Distributions 
77855239e5SApple OSS Distributions #endif /* IOKITSTATS */
78855239e5SApple OSS Distributions 
790f3703acSApple OSS Distributions 
800f3703acSApple OSS Distributions #define TRACK_ALLOC     (IOTRACKING && (kIOTracking & gIOKitDebug))
810f3703acSApple OSS Distributions 
820f3703acSApple OSS Distributions 
83e13b1fa5SApple OSS Distributions extern "C"
84e13b1fa5SApple OSS Distributions {
85e13b1fa5SApple OSS Distributions mach_timespec_t IOZeroTvalspec = { 0, 0 };
86e13b1fa5SApple OSS Distributions 
87e13b1fa5SApple OSS Distributions extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
88e13b1fa5SApple OSS Distributions 
89855239e5SApple OSS Distributions extern int
903ca3bd55SApple OSS Distributions __doprnt(
913ca3bd55SApple OSS Distributions 	const char              *fmt,
923ca3bd55SApple OSS Distributions 	va_list                 argp,
933ca3bd55SApple OSS Distributions 	void                    (*putc)(int, void *),
943ca3bd55SApple OSS Distributions 	void                    *arg,
950f3703acSApple OSS Distributions 	int                     radix,
960f3703acSApple OSS Distributions 	int                     is_log);
973ca3bd55SApple OSS Distributions 
98bb611c8fSApple OSS Distributions extern bool bsd_log_lock(bool);
99855239e5SApple OSS Distributions extern void bsd_log_unlock(void);
1003ca3bd55SApple OSS Distributions 
101e13b1fa5SApple OSS Distributions 
102e13b1fa5SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
103e13b1fa5SApple OSS Distributions 
104*d4514f0bSApple OSS Distributions lck_grp_t        io_lck_grp;
105e13b1fa5SApple OSS Distributions lck_grp_t       *IOLockGroup;
106e13b1fa5SApple OSS Distributions 
107e13b1fa5SApple OSS Distributions /*
108e13b1fa5SApple OSS Distributions  * Global variables for use by iLogger
109e13b1fa5SApple OSS Distributions  * These symbols are for use only by Apple diagnostic code.
110e13b1fa5SApple OSS Distributions  * Binary compatibility is not guaranteed for kexts that reference these symbols.
111e13b1fa5SApple OSS Distributions  */
112e13b1fa5SApple OSS Distributions 
113e13b1fa5SApple OSS Distributions void *_giDebugLogInternal       = NULL;
114e13b1fa5SApple OSS Distributions void *_giDebugLogDataInternal   = NULL;
115e13b1fa5SApple OSS Distributions void *_giDebugReserved1         = NULL;
116e13b1fa5SApple OSS Distributions void *_giDebugReserved2         = NULL;
117e13b1fa5SApple OSS Distributions 
118e7776783SApple OSS Distributions #if defined(__x86_64__)
119186b8fceSApple OSS Distributions iopa_t gIOBMDPageAllocator;
120e7776783SApple OSS Distributions #endif /* defined(__x86_64__) */
121e13b1fa5SApple OSS Distributions 
122e13b1fa5SApple OSS Distributions /*
123e13b1fa5SApple OSS Distributions  * Static variables for this module.
124e13b1fa5SApple OSS Distributions  */
125e13b1fa5SApple OSS Distributions 
126e13b1fa5SApple OSS Distributions static queue_head_t gIOMallocContiguousEntries;
127e13b1fa5SApple OSS Distributions static lck_mtx_t *  gIOMallocContiguousEntriesLock;
128e13b1fa5SApple OSS Distributions 
129a3bb9fccSApple OSS Distributions #if __x86_64__
130a3bb9fccSApple OSS Distributions enum { kIOMaxPageableMaps    = 8 };
1315c2921b0SApple OSS Distributions enum { kIOMaxFixedRanges     = 4 };
132a3bb9fccSApple OSS Distributions enum { kIOPageableMapSize    = 512 * 1024 * 1024 };
133a3bb9fccSApple OSS Distributions enum { kIOPageableMaxMapSize = 512 * 1024 * 1024 };
134a3bb9fccSApple OSS Distributions #else
135e13b1fa5SApple OSS Distributions enum { kIOMaxPageableMaps    = 16 };
1365c2921b0SApple OSS Distributions enum { kIOMaxFixedRanges     = 4 };
137e13b1fa5SApple OSS Distributions enum { kIOPageableMapSize    = 96 * 1024 * 1024 };
138e13b1fa5SApple OSS Distributions enum { kIOPageableMaxMapSize = 96 * 1024 * 1024 };
139a3bb9fccSApple OSS Distributions #endif
140e13b1fa5SApple OSS Distributions 
141e13b1fa5SApple OSS Distributions typedef struct {
142e13b1fa5SApple OSS Distributions 	vm_map_t            map;
143e13b1fa5SApple OSS Distributions 	vm_offset_t address;
144e13b1fa5SApple OSS Distributions 	vm_offset_t end;
145e13b1fa5SApple OSS Distributions } IOMapData;
146e13b1fa5SApple OSS Distributions 
1475c2921b0SApple OSS Distributions static SECURITY_READ_ONLY_LATE(struct mach_vm_range)
1485c2921b0SApple OSS Distributions gIOKitPageableFixedRanges[kIOMaxFixedRanges];
1495c2921b0SApple OSS Distributions 
150e13b1fa5SApple OSS Distributions static struct {
151e13b1fa5SApple OSS Distributions 	UInt32      count;
152e13b1fa5SApple OSS Distributions 	UInt32      hint;
153e13b1fa5SApple OSS Distributions 	IOMapData   maps[kIOMaxPageableMaps];
154e13b1fa5SApple OSS Distributions 	lck_mtx_t * lock;
155e13b1fa5SApple OSS Distributions } gIOKitPageableSpace;
156e13b1fa5SApple OSS Distributions 
157e7776783SApple OSS Distributions #if defined(__x86_64__)
158186b8fceSApple OSS Distributions static iopa_t gIOPageablePageAllocator;
159186b8fceSApple OSS Distributions 
160a3bb9fccSApple OSS Distributions uint32_t  gIOPageAllocChunkBytes;
161e7776783SApple OSS Distributions #endif /* defined(__x86_64__) */
162a3bb9fccSApple OSS Distributions 
1630f3703acSApple OSS Distributions #if IOTRACKING
1640f3703acSApple OSS Distributions IOTrackingQueue * gIOMallocTracking;
1650f3703acSApple OSS Distributions IOTrackingQueue * gIOWireTracking;
1660f3703acSApple OSS Distributions IOTrackingQueue * gIOMapTracking;
1670f3703acSApple OSS Distributions #endif /* IOTRACKING */
1680f3703acSApple OSS Distributions 
169e13b1fa5SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
170e13b1fa5SApple OSS Distributions 
1715c2921b0SApple OSS Distributions KMEM_RANGE_REGISTER_STATIC(gIOKitPageableFixed0,
1725c2921b0SApple OSS Distributions     &gIOKitPageableFixedRanges[0], kIOPageableMapSize);
1735c2921b0SApple OSS Distributions KMEM_RANGE_REGISTER_STATIC(gIOKitPageableFixed1,
1745c2921b0SApple OSS Distributions     &gIOKitPageableFixedRanges[1], kIOPageableMapSize);
1755c2921b0SApple OSS Distributions KMEM_RANGE_REGISTER_STATIC(gIOKitPageableFixed2,
1765c2921b0SApple OSS Distributions     &gIOKitPageableFixedRanges[2], kIOPageableMapSize);
1775c2921b0SApple OSS Distributions KMEM_RANGE_REGISTER_STATIC(gIOKitPageableFixed3,
1785c2921b0SApple OSS Distributions     &gIOKitPageableFixedRanges[3], kIOPageableMapSize);
179a5e72196SApple OSS Distributions void
IOLibInit(void)180a5e72196SApple OSS Distributions IOLibInit(void)
181e13b1fa5SApple OSS Distributions {
182e13b1fa5SApple OSS Distributions 	static bool libInitialized;
183e13b1fa5SApple OSS Distributions 
184a5e72196SApple OSS Distributions 	if (libInitialized) {
185e13b1fa5SApple OSS Distributions 		return;
186a5e72196SApple OSS Distributions 	}
187e13b1fa5SApple OSS Distributions 
188*d4514f0bSApple OSS Distributions 	lck_grp_init(&io_lck_grp, "IOKit", LCK_GRP_ATTR_NULL);
189*d4514f0bSApple OSS Distributions 	IOLockGroup = &io_lck_grp;
1900f3703acSApple OSS Distributions 
1910f3703acSApple OSS Distributions #if IOTRACKING
1920f3703acSApple OSS Distributions 	IOTrackingInit();
19388cc0b97SApple OSS Distributions 	gIOMallocTracking = IOTrackingQueueAlloc(kIOMallocTrackingName, 0, 0, 0,
19488cc0b97SApple OSS Distributions 	    kIOTrackingQueueTypeAlloc,
19588cc0b97SApple OSS Distributions 	    37);
19688cc0b97SApple OSS Distributions 	gIOWireTracking   = IOTrackingQueueAlloc(kIOWireTrackingName, 0, 0, page_size, 0, 0);
19788cc0b97SApple OSS Distributions 
19888cc0b97SApple OSS Distributions 	size_t mapCaptureSize = (kIOTracking & gIOKitDebug) ? page_size : (1024 * 1024);
19988cc0b97SApple OSS Distributions 	gIOMapTracking    = IOTrackingQueueAlloc(kIOMapTrackingName, 0, 0, mapCaptureSize,
20088cc0b97SApple OSS Distributions 	    kIOTrackingQueueTypeDefaultOn
20188cc0b97SApple OSS Distributions 	    | kIOTrackingQueueTypeMap
20288cc0b97SApple OSS Distributions 	    | kIOTrackingQueueTypeUser,
20388cc0b97SApple OSS Distributions 	    0);
2040f3703acSApple OSS Distributions #endif
2050f3703acSApple OSS Distributions 
2065c2921b0SApple OSS Distributions 	gIOKitPageableSpace.maps[0].map = kmem_suballoc(kernel_map,
2075c2921b0SApple OSS Distributions 	    &gIOKitPageableFixedRanges[0].min_address,
208e13b1fa5SApple OSS Distributions 	    kIOPageableMapSize,
209e7776783SApple OSS Distributions 	    VM_MAP_CREATE_PAGEABLE,
210aca3beaaSApple OSS Distributions 	    VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
2115c2921b0SApple OSS Distributions 	    (kms_flags_t)(KMS_PERMANENT | KMS_DATA | KMS_NOFAIL),
2125c2921b0SApple OSS Distributions 	    VM_KERN_MEMORY_IOKIT).kmr_submap;
213e13b1fa5SApple OSS Distributions 
2145c2921b0SApple OSS Distributions 	gIOKitPageableSpace.maps[0].address = gIOKitPageableFixedRanges[0].min_address;
2155c2921b0SApple OSS Distributions 	gIOKitPageableSpace.maps[0].end     = gIOKitPageableFixedRanges[0].max_address;
216e13b1fa5SApple OSS Distributions 	gIOKitPageableSpace.lock            = lck_mtx_alloc_init(IOLockGroup, LCK_ATTR_NULL);
217e13b1fa5SApple OSS Distributions 	gIOKitPageableSpace.hint            = 0;
218e13b1fa5SApple OSS Distributions 	gIOKitPageableSpace.count           = 1;
219e13b1fa5SApple OSS Distributions 
220e13b1fa5SApple OSS Distributions 	gIOMallocContiguousEntriesLock      = lck_mtx_alloc_init(IOLockGroup, LCK_ATTR_NULL);
221e13b1fa5SApple OSS Distributions 	queue_init( &gIOMallocContiguousEntries );
222e13b1fa5SApple OSS Distributions 
223e7776783SApple OSS Distributions #if defined(__x86_64__)
224a3bb9fccSApple OSS Distributions 	gIOPageAllocChunkBytes = PAGE_SIZE / 64;
225e7776783SApple OSS Distributions 
226a3bb9fccSApple OSS Distributions 	assert(sizeof(iopa_page_t) <= gIOPageAllocChunkBytes);
227186b8fceSApple OSS Distributions 	iopa_init(&gIOBMDPageAllocator);
228186b8fceSApple OSS Distributions 	iopa_init(&gIOPageablePageAllocator);
229e7776783SApple OSS Distributions #endif /* defined(__x86_64__) */
230186b8fceSApple OSS Distributions 
2310f3703acSApple OSS Distributions 
232e13b1fa5SApple OSS Distributions 	libInitialized = true;
233e13b1fa5SApple OSS Distributions }
234e13b1fa5SApple OSS Distributions 
235e13b1fa5SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
236e13b1fa5SApple OSS Distributions 
237e6231be0SApple OSS Distributions vm_size_t
log2up(vm_size_t size)238bb611c8fSApple OSS Distributions log2up(vm_size_t size)
2390f3703acSApple OSS Distributions {
240a5e72196SApple OSS Distributions 	if (size <= 1) {
241a5e72196SApple OSS Distributions 		size = 0;
242a5e72196SApple OSS Distributions 	} else {
243bb611c8fSApple OSS Distributions #if __LP64__
244bb611c8fSApple OSS Distributions 		size = 64 - __builtin_clzl(size - 1);
245bb611c8fSApple OSS Distributions #else
246bb611c8fSApple OSS Distributions 		size = 32 - __builtin_clzl(size - 1);
247bb611c8fSApple OSS Distributions #endif
248a5e72196SApple OSS Distributions 	}
249a5e72196SApple OSS Distributions 	return size;
2500f3703acSApple OSS Distributions }
2510f3703acSApple OSS Distributions 
2520f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2530f3703acSApple OSS Distributions 
254a5e72196SApple OSS Distributions IOThread
IOCreateThread(IOThreadFunc fcn,void * arg)255a5e72196SApple OSS Distributions IOCreateThread(IOThreadFunc fcn, void *arg)
256e13b1fa5SApple OSS Distributions {
257e13b1fa5SApple OSS Distributions 	kern_return_t   result;
258e13b1fa5SApple OSS Distributions 	thread_t                thread;
259e13b1fa5SApple OSS Distributions 
2605c2921b0SApple OSS Distributions 	result = kernel_thread_start((thread_continue_t)(void (*)(void))fcn, arg, &thread);
261a5e72196SApple OSS Distributions 	if (result != KERN_SUCCESS) {
262a5e72196SApple OSS Distributions 		return NULL;
263a5e72196SApple OSS Distributions 	}
264e13b1fa5SApple OSS Distributions 
265e13b1fa5SApple OSS Distributions 	thread_deallocate(thread);
266e13b1fa5SApple OSS Distributions 
267a5e72196SApple OSS Distributions 	return thread;
268e13b1fa5SApple OSS Distributions }
269e13b1fa5SApple OSS Distributions 
270e13b1fa5SApple OSS Distributions 
271a5e72196SApple OSS Distributions void
IOExitThread(void)272a5e72196SApple OSS Distributions IOExitThread(void)
273e13b1fa5SApple OSS Distributions {
274e13b1fa5SApple OSS Distributions 	(void) thread_terminate(current_thread());
275e13b1fa5SApple OSS Distributions }
276e13b1fa5SApple OSS Distributions 
277a5e72196SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
278a5e72196SApple OSS Distributions 
279a5e72196SApple OSS Distributions #if IOTRACKING
280a5e72196SApple OSS Distributions struct IOLibMallocHeader {
2810f3703acSApple OSS Distributions 	IOTrackingAddress tracking;
2820f3703acSApple OSS Distributions };
2830f3703acSApple OSS Distributions #endif
2840f3703acSApple OSS Distributions 
2850f3703acSApple OSS Distributions #if IOTRACKING
2860f3703acSApple OSS Distributions #define sizeofIOLibMallocHeader (sizeof(IOLibMallocHeader) - (TRACK_ALLOC ? 0 : sizeof(IOTrackingAddress)))
2870f3703acSApple OSS Distributions #else
2880f3703acSApple OSS Distributions #define sizeofIOLibMallocHeader (0)
2890f3703acSApple OSS Distributions #endif
2900f3703acSApple OSS Distributions 
2910f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
292e13b1fa5SApple OSS Distributions 
2935c2921b0SApple OSS Distributions __typed_allocators_ignore_push // allocator implementation
2945c2921b0SApple OSS Distributions 
295a5e72196SApple OSS Distributions void *
2965c2921b0SApple OSS Distributions (IOMalloc_internal)(struct kalloc_heap *kheap, vm_size_t size,
2975c2921b0SApple OSS Distributions zalloc_flags_t flags)
298e13b1fa5SApple OSS Distributions {
299e13b1fa5SApple OSS Distributions 	void * address;
3000f3703acSApple OSS Distributions 	vm_size_t allocSize;
301e13b1fa5SApple OSS Distributions 
3020f3703acSApple OSS Distributions 	allocSize = size + sizeofIOLibMallocHeader;
3030f3703acSApple OSS Distributions #if IOTRACKING
304a5e72196SApple OSS Distributions 	if (sizeofIOLibMallocHeader && (allocSize <= size)) {
305a5e72196SApple OSS Distributions 		return NULL;                                          // overflow
306a5e72196SApple OSS Distributions 	}
3070f3703acSApple OSS Distributions #endif
308e7776783SApple OSS Distributions 	address = kheap_alloc(kheap, allocSize,
3095c2921b0SApple OSS Distributions 	    Z_VM_TAG(Z_WAITOK | flags, VM_KERN_MEMORY_IOKIT));
3100f3703acSApple OSS Distributions 
311e13b1fa5SApple OSS Distributions 	if (address) {
3120f3703acSApple OSS Distributions #if IOTRACKING
3130f3703acSApple OSS Distributions 		if (TRACK_ALLOC) {
3140f3703acSApple OSS Distributions 			IOLibMallocHeader * hdr;
3150f3703acSApple OSS Distributions 			hdr = (typeof(hdr))address;
3160f3703acSApple OSS Distributions 			bzero(&hdr->tracking, sizeof(hdr->tracking));
3170f3703acSApple OSS Distributions 			hdr->tracking.address = ~(((uintptr_t) address) + sizeofIOLibMallocHeader);
3180f3703acSApple OSS Distributions 			hdr->tracking.size    = size;
31976e12aa3SApple OSS Distributions 			IOTrackingAdd(gIOMallocTracking, &hdr->tracking.tracking, size, true, VM_KERN_MEMORY_NONE);
3200f3703acSApple OSS Distributions 		}
3210f3703acSApple OSS Distributions #endif
3220f3703acSApple OSS Distributions 		address = (typeof(address))(((uintptr_t) address) + sizeofIOLibMallocHeader);
3230f3703acSApple OSS Distributions 
324855239e5SApple OSS Distributions #if IOALLOCDEBUG
325bb611c8fSApple OSS Distributions 		OSAddAtomicLong(size, &debug_iomalloc_size);
326e13b1fa5SApple OSS Distributions #endif
327855239e5SApple OSS Distributions 		IOStatisticsAlloc(kIOStatisticsMalloc, size);
328855239e5SApple OSS Distributions 	}
329855239e5SApple OSS Distributions 
330e13b1fa5SApple OSS Distributions 	return address;
331e13b1fa5SApple OSS Distributions }
332e13b1fa5SApple OSS Distributions 
333a5e72196SApple OSS Distributions void
IOFree_internal(struct kalloc_heap * kheap,void * inAddress,vm_size_t size)334e6231be0SApple OSS Distributions IOFree_internal(struct kalloc_heap *kheap, void * inAddress, vm_size_t size)
335e13b1fa5SApple OSS Distributions {
33676e12aa3SApple OSS Distributions 	void * address;
3370f3703acSApple OSS Distributions 
338a5e72196SApple OSS Distributions 	if ((address = inAddress)) {
3390f3703acSApple OSS Distributions 		address = (typeof(address))(((uintptr_t) address) - sizeofIOLibMallocHeader);
3400f3703acSApple OSS Distributions 
3410f3703acSApple OSS Distributions #if IOTRACKING
342a5e72196SApple OSS Distributions 		if (TRACK_ALLOC) {
3430f3703acSApple OSS Distributions 			IOLibMallocHeader * hdr;
34476e12aa3SApple OSS Distributions 			struct ptr_reference { void * ptr; };
34576e12aa3SApple OSS Distributions 			volatile struct ptr_reference ptr;
34676e12aa3SApple OSS Distributions 
34776e12aa3SApple OSS Distributions 			// we're about to block in IOTrackingRemove(), make sure the original pointer
34876e12aa3SApple OSS Distributions 			// exists in memory or a register for leak scanning to find
34976e12aa3SApple OSS Distributions 			ptr.ptr = inAddress;
35076e12aa3SApple OSS Distributions 
3510f3703acSApple OSS Distributions 			hdr = (typeof(hdr))address;
352a5e72196SApple OSS Distributions 			if (size != hdr->tracking.size) {
353e7776783SApple OSS Distributions 				OSReportWithBacktrace("bad IOFree size 0x%zx should be 0x%zx",
354e7776783SApple OSS Distributions 				    (size_t)size, (size_t)hdr->tracking.size);
3550f3703acSApple OSS Distributions 				size = hdr->tracking.size;
3560f3703acSApple OSS Distributions 			}
3575c2921b0SApple OSS Distributions 			IOTrackingRemoveAddress(gIOMallocTracking, &hdr->tracking, size);
35876e12aa3SApple OSS Distributions 			ptr.ptr = NULL;
3590f3703acSApple OSS Distributions 		}
3600f3703acSApple OSS Distributions #endif
3610f3703acSApple OSS Distributions 
362e6231be0SApple OSS Distributions 		kheap_free(kheap, address, size + sizeofIOLibMallocHeader);
363e13b1fa5SApple OSS Distributions #if IOALLOCDEBUG
364bb611c8fSApple OSS Distributions 		OSAddAtomicLong(-size, &debug_iomalloc_size);
365e13b1fa5SApple OSS Distributions #endif
366855239e5SApple OSS Distributions 		IOStatisticsAlloc(kIOStatisticsFree, size);
367e13b1fa5SApple OSS Distributions 	}
368e13b1fa5SApple OSS Distributions }
369e13b1fa5SApple OSS Distributions 
3705c2921b0SApple OSS Distributions void *
3715c2921b0SApple OSS Distributions IOMalloc_external(
3725c2921b0SApple OSS Distributions 	vm_size_t size);
3735c2921b0SApple OSS Distributions void *
IOMalloc_external(vm_size_t size)3745c2921b0SApple OSS Distributions IOMalloc_external(
3755c2921b0SApple OSS Distributions 	vm_size_t size)
3765c2921b0SApple OSS Distributions {
3775c2921b0SApple OSS Distributions 	return IOMalloc_internal(KHEAP_DEFAULT, size, Z_VM_TAG_BT_BIT);
3785c2921b0SApple OSS Distributions }
3795c2921b0SApple OSS Distributions 
380e6231be0SApple OSS Distributions void
IOFree(void * inAddress,vm_size_t size)381e6231be0SApple OSS Distributions IOFree(void * inAddress, vm_size_t size)
382e6231be0SApple OSS Distributions {
3831031c584SApple OSS Distributions 	IOFree_internal(KHEAP_DEFAULT, inAddress, size);
384e6231be0SApple OSS Distributions }
385e6231be0SApple OSS Distributions 
386e13b1fa5SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
387e13b1fa5SApple OSS Distributions 
3885c2921b0SApple OSS Distributions void *
3895c2921b0SApple OSS Distributions IOMallocZero_external(
3905c2921b0SApple OSS Distributions 	vm_size_t size);
3915c2921b0SApple OSS Distributions void *
IOMallocZero_external(vm_size_t size)3925c2921b0SApple OSS Distributions IOMallocZero_external(
3935c2921b0SApple OSS Distributions 	vm_size_t size)
3945c2921b0SApple OSS Distributions {
3955c2921b0SApple OSS Distributions 	return IOMalloc_internal(KHEAP_DEFAULT, size, Z_ZERO_VM_TAG_BT_BIT);
3965c2921b0SApple OSS Distributions }
3975c2921b0SApple OSS Distributions 
3985c2921b0SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3995c2921b0SApple OSS Distributions 
4000f3703acSApple OSS Distributions vm_tag_t
IOMemoryTag(vm_map_t map)4010f3703acSApple OSS Distributions IOMemoryTag(vm_map_t map)
4020f3703acSApple OSS Distributions {
4030f3703acSApple OSS Distributions 	vm_tag_t tag;
4040f3703acSApple OSS Distributions 
405a5e72196SApple OSS Distributions 	if (!vm_kernel_map_is_kernel(map)) {
406a5e72196SApple OSS Distributions 		return VM_MEMORY_IOKIT;
407a5e72196SApple OSS Distributions 	}
4080f3703acSApple OSS Distributions 
4090f3703acSApple OSS Distributions 	tag = vm_tag_bt();
410a5e72196SApple OSS Distributions 	if (tag == VM_KERN_MEMORY_NONE) {
411a5e72196SApple OSS Distributions 		tag = VM_KERN_MEMORY_IOKIT;
412a5e72196SApple OSS Distributions 	}
4130f3703acSApple OSS Distributions 
414a5e72196SApple OSS Distributions 	return tag;
4150f3703acSApple OSS Distributions }
4160f3703acSApple OSS Distributions 
4170f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4180f3703acSApple OSS Distributions 
419a5e72196SApple OSS Distributions struct IOLibPageMallocHeader {
4205c2921b0SApple OSS Distributions 	mach_vm_size_t    alignMask;
4215c2921b0SApple OSS Distributions 	mach_vm_offset_t  allocationOffset;
4220f3703acSApple OSS Distributions #if IOTRACKING
4230f3703acSApple OSS Distributions 	IOTrackingAddress tracking;
4240f3703acSApple OSS Distributions #endif
4250f3703acSApple OSS Distributions };
4260f3703acSApple OSS Distributions 
4270f3703acSApple OSS Distributions #if IOTRACKING
4280f3703acSApple OSS Distributions #define sizeofIOLibPageMallocHeader     (sizeof(IOLibPageMallocHeader) - (TRACK_ALLOC ? 0 : sizeof(IOTrackingAddress)))
4290f3703acSApple OSS Distributions #else
4300f3703acSApple OSS Distributions #define sizeofIOLibPageMallocHeader     (sizeof(IOLibPageMallocHeader))
4310f3703acSApple OSS Distributions #endif
4320f3703acSApple OSS Distributions 
4330f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4345c2921b0SApple OSS Distributions 
4355c2921b0SApple OSS Distributions static __header_always_inline void
IOMallocAlignedSetHdr(IOLibPageMallocHeader * hdr,mach_vm_size_t alignMask,mach_vm_address_t allocationStart,mach_vm_address_t alignedStart)4365c2921b0SApple OSS Distributions IOMallocAlignedSetHdr(
4375c2921b0SApple OSS Distributions 	IOLibPageMallocHeader  *hdr,
4385c2921b0SApple OSS Distributions 	mach_vm_size_t          alignMask,
4395c2921b0SApple OSS Distributions 	mach_vm_address_t       allocationStart,
4405c2921b0SApple OSS Distributions 	mach_vm_address_t       alignedStart)
441bb611c8fSApple OSS Distributions {
4425c2921b0SApple OSS Distributions 	mach_vm_offset_t        offset = alignedStart - allocationStart;
4435c2921b0SApple OSS Distributions #if __has_feature(ptrauth_calls)
4445c2921b0SApple OSS Distributions 	offset = (mach_vm_offset_t) ptrauth_sign_unauthenticated((void *)offset,
4455c2921b0SApple OSS Distributions 	    ptrauth_key_process_independent_data,
4465c2921b0SApple OSS Distributions 	    ptrauth_blend_discriminator((void *)(alignedStart | alignMask),
4475c2921b0SApple OSS Distributions 	    OS_PTRAUTH_DISCRIMINATOR("IOLibPageMallocHeader.allocationOffset")));
4485c2921b0SApple OSS Distributions #endif /* __has_feature(ptrauth_calls) */
4495c2921b0SApple OSS Distributions 	hdr->allocationOffset = offset;
4505c2921b0SApple OSS Distributions 	hdr->alignMask = alignMask;
4515c2921b0SApple OSS Distributions }
4525c2921b0SApple OSS Distributions 
4535c2921b0SApple OSS Distributions __abortlike
4545c2921b0SApple OSS Distributions static void
IOMallocAlignedHdrCorruptionPanic(mach_vm_offset_t offset,mach_vm_size_t alignMask,mach_vm_address_t alignedStart,vm_size_t size)4555c2921b0SApple OSS Distributions IOMallocAlignedHdrCorruptionPanic(
4565c2921b0SApple OSS Distributions 	mach_vm_offset_t        offset,
4575c2921b0SApple OSS Distributions 	mach_vm_size_t          alignMask,
4585c2921b0SApple OSS Distributions 	mach_vm_address_t       alignedStart,
4595c2921b0SApple OSS Distributions 	vm_size_t               size)
4605c2921b0SApple OSS Distributions {
4615c2921b0SApple OSS Distributions 	mach_vm_address_t       address = 0;
4625c2921b0SApple OSS Distributions 	mach_vm_address_t       recalAlignedStart = 0;
4635c2921b0SApple OSS Distributions 
4645c2921b0SApple OSS Distributions 	if (os_sub_overflow(alignedStart, offset, &address)) {
4655c2921b0SApple OSS Distributions 		panic("Invalid offset %p for aligned addr %p", (void *)offset,
4665c2921b0SApple OSS Distributions 		    (void *)alignedStart);
4675c2921b0SApple OSS Distributions 	}
4685c2921b0SApple OSS Distributions 	if (os_add3_overflow(address, sizeofIOLibPageMallocHeader, alignMask,
4695c2921b0SApple OSS Distributions 	    &recalAlignedStart)) {
4705c2921b0SApple OSS Distributions 		panic("alignMask 0x%llx overflows recalAlignedStart %p for provided addr "
4715c2921b0SApple OSS Distributions 		    "%p", alignMask, (void *)recalAlignedStart, (void *)alignedStart);
4725c2921b0SApple OSS Distributions 	}
4735c2921b0SApple OSS Distributions 	if (((recalAlignedStart &= ~alignMask) != alignedStart) &&
4745c2921b0SApple OSS Distributions 	    (round_page(recalAlignedStart) != alignedStart)) {
4755c2921b0SApple OSS Distributions 		panic("Recalculated aligned addr %p doesn't match provided addr %p",
4765c2921b0SApple OSS Distributions 		    (void *)recalAlignedStart, (void *)alignedStart);
4775c2921b0SApple OSS Distributions 	}
4785c2921b0SApple OSS Distributions 	if (offset < sizeofIOLibPageMallocHeader) {
4795c2921b0SApple OSS Distributions 		panic("Offset %zd doesn't accomodate IOLibPageMallocHeader for aligned "
4805c2921b0SApple OSS Distributions 		    "addr %p", (size_t)offset, (void *)alignedStart);
4815c2921b0SApple OSS Distributions 	}
4825c2921b0SApple OSS Distributions 	panic("alignMask 0x%llx overflows adjusted size %zd for aligned addr %p",
4835c2921b0SApple OSS Distributions 	    alignMask, (size_t)size, (void *)alignedStart);
4845c2921b0SApple OSS Distributions }
4855c2921b0SApple OSS Distributions 
4865c2921b0SApple OSS Distributions static __header_always_inline mach_vm_address_t
IOMallocAlignedGetAddress(IOLibPageMallocHeader * hdr,mach_vm_address_t alignedStart,vm_size_t * size)4875c2921b0SApple OSS Distributions IOMallocAlignedGetAddress(
4885c2921b0SApple OSS Distributions 	IOLibPageMallocHeader  *hdr,
4895c2921b0SApple OSS Distributions 	mach_vm_address_t       alignedStart,
4905c2921b0SApple OSS Distributions 	vm_size_t              *size)
4915c2921b0SApple OSS Distributions {
4925c2921b0SApple OSS Distributions 	mach_vm_address_t       address = 0;
4935c2921b0SApple OSS Distributions 	mach_vm_address_t       recalAlignedStart = 0;
4945c2921b0SApple OSS Distributions 	mach_vm_offset_t        offset = hdr->allocationOffset;
4955c2921b0SApple OSS Distributions 	mach_vm_size_t          alignMask = hdr->alignMask;
4965c2921b0SApple OSS Distributions #if __has_feature(ptrauth_calls)
4975c2921b0SApple OSS Distributions 	offset = (mach_vm_offset_t) ptrauth_auth_data((void *)offset,
4985c2921b0SApple OSS Distributions 	    ptrauth_key_process_independent_data,
4995c2921b0SApple OSS Distributions 	    ptrauth_blend_discriminator((void *)(alignedStart | alignMask),
5005c2921b0SApple OSS Distributions 	    OS_PTRAUTH_DISCRIMINATOR("IOLibPageMallocHeader.allocationOffset")));
5015c2921b0SApple OSS Distributions #endif /* __has_feature(ptrauth_calls) */
5025c2921b0SApple OSS Distributions 	if (os_sub_overflow(alignedStart, offset, &address) ||
5035c2921b0SApple OSS Distributions 	    os_add3_overflow(address, sizeofIOLibPageMallocHeader, alignMask,
5045c2921b0SApple OSS Distributions 	    &recalAlignedStart) ||
5055c2921b0SApple OSS Distributions 	    (((recalAlignedStart &= ~alignMask) != alignedStart) &&
5065c2921b0SApple OSS Distributions 	    (round_page(recalAlignedStart) != alignedStart)) ||
5075c2921b0SApple OSS Distributions 	    (offset < sizeofIOLibPageMallocHeader) ||
5085c2921b0SApple OSS Distributions 	    os_add_overflow(*size, alignMask, size)) {
5095c2921b0SApple OSS Distributions 		IOMallocAlignedHdrCorruptionPanic(offset, alignMask, alignedStart, *size);
5105c2921b0SApple OSS Distributions 	}
5115c2921b0SApple OSS Distributions 	return address;
512bb611c8fSApple OSS Distributions }
5130f3703acSApple OSS Distributions 
514a5e72196SApple OSS Distributions void *
5155c2921b0SApple OSS Distributions (IOMallocAligned_internal)(struct kalloc_heap *kheap, vm_size_t size,
5165c2921b0SApple OSS Distributions vm_size_t alignment, zalloc_flags_t flags)
517e13b1fa5SApple OSS Distributions {
518e13b1fa5SApple OSS Distributions 	kern_return_t           kr;
5193ca3bd55SApple OSS Distributions 	vm_offset_t             address;
5203ca3bd55SApple OSS Distributions 	vm_offset_t             allocationAddress;
521e13b1fa5SApple OSS Distributions 	vm_size_t               adjustedSize;
5223ca3bd55SApple OSS Distributions 	uintptr_t               alignMask;
5230f3703acSApple OSS Distributions 	IOLibPageMallocHeader * hdr;
5245c2921b0SApple OSS Distributions 	kma_flags_t kma_flags = KMA_NONE;
525e13b1fa5SApple OSS Distributions 
526a5e72196SApple OSS Distributions 	if (size == 0) {
527a5e72196SApple OSS Distributions 		return NULL;
528a5e72196SApple OSS Distributions 	}
529bb611c8fSApple OSS Distributions 	if (((uint32_t) alignment) != alignment) {
530bb611c8fSApple OSS Distributions 		return NULL;
531bb611c8fSApple OSS Distributions 	}
532e13b1fa5SApple OSS Distributions 
5335c2921b0SApple OSS Distributions 	if (flags & Z_ZERO) {
5345c2921b0SApple OSS Distributions 		kma_flags = KMA_ZERO;
5355c2921b0SApple OSS Distributions 	}
5365c2921b0SApple OSS Distributions 
5375c2921b0SApple OSS Distributions 	if (kheap == KHEAP_DATA_BUFFERS) {
5385c2921b0SApple OSS Distributions 		kma_flags = (kma_flags_t) (kma_flags | KMA_DATA);
5395c2921b0SApple OSS Distributions 	}
5405c2921b0SApple OSS Distributions 
541bb611c8fSApple OSS Distributions 	alignment = (1UL << log2up((uint32_t) alignment));
542e13b1fa5SApple OSS Distributions 	alignMask = alignment - 1;
5430f3703acSApple OSS Distributions 	adjustedSize = size + sizeofIOLibPageMallocHeader;
544e13b1fa5SApple OSS Distributions 
545d0c1fef6SApple OSS Distributions 	if (size > adjustedSize) {
546d0c1fef6SApple OSS Distributions 		address = 0; /* overflow detected */
547a5e72196SApple OSS Distributions 	} else if (adjustedSize >= page_size) {
5485c2921b0SApple OSS Distributions 		kr = kernel_memory_allocate(kernel_map, &address,
5495c2921b0SApple OSS Distributions 		    size, alignMask, kma_flags, IOMemoryTag(kernel_map));
550a5e72196SApple OSS Distributions 		if (KERN_SUCCESS != kr) {
551a5e72196SApple OSS Distributions 			address = 0;
552a5e72196SApple OSS Distributions 		}
5530f3703acSApple OSS Distributions #if IOTRACKING
554a5e72196SApple OSS Distributions 		else if (TRACK_ALLOC) {
555a5e72196SApple OSS Distributions 			IOTrackingAlloc(gIOMallocTracking, address, size);
556a5e72196SApple OSS Distributions 		}
5570f3703acSApple OSS Distributions #endif
558e13b1fa5SApple OSS Distributions 	} else {
559e13b1fa5SApple OSS Distributions 		adjustedSize += alignMask;
560e13b1fa5SApple OSS Distributions 
561e13b1fa5SApple OSS Distributions 		if (adjustedSize >= page_size) {
5625c2921b0SApple OSS Distributions 			kr = kmem_alloc(kernel_map, &allocationAddress,
5635c2921b0SApple OSS Distributions 			    adjustedSize, kma_flags, IOMemoryTag(kernel_map));
564a5e72196SApple OSS Distributions 			if (KERN_SUCCESS != kr) {
565a5e72196SApple OSS Distributions 				allocationAddress = 0;
566a5e72196SApple OSS Distributions 			}
567a5e72196SApple OSS Distributions 		} else {
568e7776783SApple OSS Distributions 			allocationAddress = (vm_address_t) kheap_alloc(kheap,
5695c2921b0SApple OSS Distributions 			    adjustedSize, Z_VM_TAG(Z_WAITOK | flags, VM_KERN_MEMORY_IOKIT));
570a5e72196SApple OSS Distributions 		}
571e13b1fa5SApple OSS Distributions 
572e13b1fa5SApple OSS Distributions 		if (allocationAddress) {
5730f3703acSApple OSS Distributions 			address = (allocationAddress + alignMask + sizeofIOLibPageMallocHeader)
574e13b1fa5SApple OSS Distributions 			    & (~alignMask);
575e13b1fa5SApple OSS Distributions 
5760f3703acSApple OSS Distributions 			hdr = (typeof(hdr))(address - sizeofIOLibPageMallocHeader);
5775c2921b0SApple OSS Distributions 			IOMallocAlignedSetHdr(hdr, alignMask, allocationAddress, address);
5780f3703acSApple OSS Distributions #if IOTRACKING
5790f3703acSApple OSS Distributions 			if (TRACK_ALLOC) {
5800f3703acSApple OSS Distributions 				bzero(&hdr->tracking, sizeof(hdr->tracking));
5810f3703acSApple OSS Distributions 				hdr->tracking.address = ~address;
5820f3703acSApple OSS Distributions 				hdr->tracking.size = size;
58376e12aa3SApple OSS Distributions 				IOTrackingAdd(gIOMallocTracking, &hdr->tracking.tracking, size, true, VM_KERN_MEMORY_NONE);
5840f3703acSApple OSS Distributions 			}
5850f3703acSApple OSS Distributions #endif
586a5e72196SApple OSS Distributions 		} else {
587e13b1fa5SApple OSS Distributions 			address = 0;
588e13b1fa5SApple OSS Distributions 		}
589a5e72196SApple OSS Distributions 	}
590e13b1fa5SApple OSS Distributions 
591e13b1fa5SApple OSS Distributions 	assert(0 == (address & alignMask));
592e13b1fa5SApple OSS Distributions 
593e13b1fa5SApple OSS Distributions 	if (address) {
594855239e5SApple OSS Distributions #if IOALLOCDEBUG
595bb611c8fSApple OSS Distributions 		OSAddAtomicLong(size, &debug_iomalloc_size);
596e13b1fa5SApple OSS Distributions #endif
597855239e5SApple OSS Distributions 		IOStatisticsAlloc(kIOStatisticsMallocAligned, size);
598855239e5SApple OSS Distributions 	}
599e13b1fa5SApple OSS Distributions 
600e13b1fa5SApple OSS Distributions 	return (void *) address;
601e13b1fa5SApple OSS Distributions }
602e13b1fa5SApple OSS Distributions 
603a5e72196SApple OSS Distributions void
IOFreeAligned_internal(kalloc_heap_t kheap,void * address,vm_size_t size)604e6231be0SApple OSS Distributions IOFreeAligned_internal(kalloc_heap_t kheap, void * address, vm_size_t size)
605e13b1fa5SApple OSS Distributions {
606e13b1fa5SApple OSS Distributions 	vm_address_t            allocationAddress;
607e13b1fa5SApple OSS Distributions 	vm_size_t               adjustedSize;
6080f3703acSApple OSS Distributions 	IOLibPageMallocHeader * hdr;
609e13b1fa5SApple OSS Distributions 
610a5e72196SApple OSS Distributions 	if (!address) {
611e13b1fa5SApple OSS Distributions 		return;
612a5e72196SApple OSS Distributions 	}
613e13b1fa5SApple OSS Distributions 
614e13b1fa5SApple OSS Distributions 	assert(size);
615e13b1fa5SApple OSS Distributions 
6160f3703acSApple OSS Distributions 	adjustedSize = size + sizeofIOLibPageMallocHeader;
617e13b1fa5SApple OSS Distributions 	if (adjustedSize >= page_size) {
6180f3703acSApple OSS Distributions #if IOTRACKING
619a5e72196SApple OSS Distributions 		if (TRACK_ALLOC) {
620a5e72196SApple OSS Distributions 			IOTrackingFree(gIOMallocTracking, (uintptr_t) address, size);
621a5e72196SApple OSS Distributions 		}
6220f3703acSApple OSS Distributions #endif
6235c2921b0SApple OSS Distributions 		kmem_free(kernel_map, (vm_offset_t) address, size);
624e13b1fa5SApple OSS Distributions 	} else {
6250f3703acSApple OSS Distributions 		hdr = (typeof(hdr))(((uintptr_t)address) - sizeofIOLibPageMallocHeader);
6265c2921b0SApple OSS Distributions 		allocationAddress = IOMallocAlignedGetAddress(hdr,
6275c2921b0SApple OSS Distributions 		    (mach_vm_address_t)address, &adjustedSize);
628e13b1fa5SApple OSS Distributions 
6290f3703acSApple OSS Distributions #if IOTRACKING
630a5e72196SApple OSS Distributions 		if (TRACK_ALLOC) {
631a5e72196SApple OSS Distributions 			if (size != hdr->tracking.size) {
632e7776783SApple OSS Distributions 				OSReportWithBacktrace("bad IOFreeAligned size 0x%zx should be 0x%zx",
633e7776783SApple OSS Distributions 				    (size_t)size, (size_t)hdr->tracking.size);
6340f3703acSApple OSS Distributions 				size = hdr->tracking.size;
6350f3703acSApple OSS Distributions 			}
6365c2921b0SApple OSS Distributions 			IOTrackingRemoveAddress(gIOMallocTracking, &hdr->tracking, size);
6370f3703acSApple OSS Distributions 		}
6380f3703acSApple OSS Distributions #endif
6390f3703acSApple OSS Distributions 		if (adjustedSize >= page_size) {
6405c2921b0SApple OSS Distributions 			kmem_free(kernel_map, allocationAddress, adjustedSize);
6410f3703acSApple OSS Distributions 		} else {
642e6231be0SApple OSS Distributions 			kheap_free(kheap, allocationAddress, adjustedSize);
643e13b1fa5SApple OSS Distributions 		}
6440f3703acSApple OSS Distributions 	}
645e13b1fa5SApple OSS Distributions 
646e13b1fa5SApple OSS Distributions #if IOALLOCDEBUG
647bb611c8fSApple OSS Distributions 	OSAddAtomicLong(-size, &debug_iomalloc_size);
648e13b1fa5SApple OSS Distributions #endif
649855239e5SApple OSS Distributions 
650855239e5SApple OSS Distributions 	IOStatisticsAlloc(kIOStatisticsFreeAligned, size);
651e13b1fa5SApple OSS Distributions }
652e13b1fa5SApple OSS Distributions 
6535c2921b0SApple OSS Distributions void *
6545c2921b0SApple OSS Distributions IOMallocAligned_external(
6555c2921b0SApple OSS Distributions 	vm_size_t size, vm_size_t alignment);
6565c2921b0SApple OSS Distributions void *
IOMallocAligned_external(vm_size_t size,vm_size_t alignment)6575c2921b0SApple OSS Distributions IOMallocAligned_external(
6585c2921b0SApple OSS Distributions 	vm_size_t size, vm_size_t alignment)
6595c2921b0SApple OSS Distributions {
6605c2921b0SApple OSS Distributions 	return IOMallocAligned_internal(KHEAP_DATA_BUFFERS, size, alignment,
6615c2921b0SApple OSS Distributions 	           Z_VM_TAG_BT_BIT);
6625c2921b0SApple OSS Distributions }
6635c2921b0SApple OSS Distributions 
6645c2921b0SApple OSS Distributions void
IOFreeAligned(void * address,vm_size_t size)6655c2921b0SApple OSS Distributions IOFreeAligned(
6665c2921b0SApple OSS Distributions 	void                  * address,
6675c2921b0SApple OSS Distributions 	vm_size_t               size)
6685c2921b0SApple OSS Distributions {
6695c2921b0SApple OSS Distributions 	IOFreeAligned_internal(KHEAP_DATA_BUFFERS, address, size);
6705c2921b0SApple OSS Distributions }
6715c2921b0SApple OSS Distributions 
6725c2921b0SApple OSS Distributions __typed_allocators_ignore_pop
6735c2921b0SApple OSS Distributions 
674e13b1fa5SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
675e13b1fa5SApple OSS Distributions 
676e13b1fa5SApple OSS Distributions void
IOKernelFreePhysical(kalloc_heap_t kheap,mach_vm_address_t address,mach_vm_size_t size)677e6231be0SApple OSS Distributions IOKernelFreePhysical(
678e6231be0SApple OSS Distributions 	kalloc_heap_t         kheap,
679e6231be0SApple OSS Distributions 	mach_vm_address_t     address,
680e6231be0SApple OSS Distributions 	mach_vm_size_t        size)
681e13b1fa5SApple OSS Distributions {
682bb611c8fSApple OSS Distributions 	vm_address_t       allocationAddress;
683bb611c8fSApple OSS Distributions 	vm_size_t          adjustedSize;
6840f3703acSApple OSS Distributions 	IOLibPageMallocHeader * hdr;
685e13b1fa5SApple OSS Distributions 
686a5e72196SApple OSS Distributions 	if (!address) {
687e13b1fa5SApple OSS Distributions 		return;
688a5e72196SApple OSS Distributions 	}
689e13b1fa5SApple OSS Distributions 
690e13b1fa5SApple OSS Distributions 	assert(size);
691e13b1fa5SApple OSS Distributions 
6920f3703acSApple OSS Distributions 	adjustedSize = (2 * size) + sizeofIOLibPageMallocHeader;
693e13b1fa5SApple OSS Distributions 	if (adjustedSize >= page_size) {
6940f3703acSApple OSS Distributions #if IOTRACKING
695a5e72196SApple OSS Distributions 		if (TRACK_ALLOC) {
696a5e72196SApple OSS Distributions 			IOTrackingFree(gIOMallocTracking, address, size);
697a5e72196SApple OSS Distributions 		}
6980f3703acSApple OSS Distributions #endif
6995c2921b0SApple OSS Distributions 		kmem_free(kernel_map, (vm_offset_t) address, size);
700e13b1fa5SApple OSS Distributions 	} else {
7010f3703acSApple OSS Distributions 		hdr = (typeof(hdr))(((uintptr_t)address) - sizeofIOLibPageMallocHeader);
7025c2921b0SApple OSS Distributions 		allocationAddress = IOMallocAlignedGetAddress(hdr, address, &adjustedSize);
7030f3703acSApple OSS Distributions #if IOTRACKING
704a5e72196SApple OSS Distributions 		if (TRACK_ALLOC) {
7055c2921b0SApple OSS Distributions 			IOTrackingRemoveAddress(gIOMallocTracking, &hdr->tracking, size);
706a5e72196SApple OSS Distributions 		}
7070f3703acSApple OSS Distributions #endif
7085c2921b0SApple OSS Distributions 		__typed_allocators_ignore(kheap_free(kheap, allocationAddress, adjustedSize));
709e13b1fa5SApple OSS Distributions 	}
710e13b1fa5SApple OSS Distributions 
711d0c1fef6SApple OSS Distributions 	IOStatisticsAlloc(kIOStatisticsFreeContiguous, size);
712e13b1fa5SApple OSS Distributions #if IOALLOCDEBUG
713bb611c8fSApple OSS Distributions 	OSAddAtomicLong(-size, &debug_iomalloc_size);
714e13b1fa5SApple OSS Distributions #endif
715e13b1fa5SApple OSS Distributions }
716e13b1fa5SApple OSS Distributions 
7175c2921b0SApple OSS Distributions #if __arm64__
71876e12aa3SApple OSS Distributions extern unsigned long gPhysBase, gPhysSize;
71976e12aa3SApple OSS Distributions #endif
720a3bb9fccSApple OSS Distributions 
721e13b1fa5SApple OSS Distributions mach_vm_address_t
IOKernelAllocateWithPhysicalRestrict(kalloc_heap_t kheap,mach_vm_size_t size,mach_vm_address_t maxPhys,mach_vm_size_t alignment,bool contiguous)722e6231be0SApple OSS Distributions IOKernelAllocateWithPhysicalRestrict(
723e6231be0SApple OSS Distributions 	kalloc_heap_t         kheap,
724e6231be0SApple OSS Distributions 	mach_vm_size_t        size,
725e6231be0SApple OSS Distributions 	mach_vm_address_t     maxPhys,
726e6231be0SApple OSS Distributions 	mach_vm_size_t        alignment,
727e6231be0SApple OSS Distributions 	bool                  contiguous)
728e13b1fa5SApple OSS Distributions {
729e13b1fa5SApple OSS Distributions 	kern_return_t           kr;
730e13b1fa5SApple OSS Distributions 	mach_vm_address_t       address;
731e13b1fa5SApple OSS Distributions 	mach_vm_address_t       allocationAddress;
732e13b1fa5SApple OSS Distributions 	mach_vm_size_t          adjustedSize;
733e13b1fa5SApple OSS Distributions 	mach_vm_address_t       alignMask;
7340f3703acSApple OSS Distributions 	IOLibPageMallocHeader * hdr;
735e13b1fa5SApple OSS Distributions 
736a5e72196SApple OSS Distributions 	if (size == 0) {
737a5e72196SApple OSS Distributions 		return 0;
738a5e72196SApple OSS Distributions 	}
739a5e72196SApple OSS Distributions 	if (alignment == 0) {
740e13b1fa5SApple OSS Distributions 		alignment = 1;
741a5e72196SApple OSS Distributions 	}
742e13b1fa5SApple OSS Distributions 
743e13b1fa5SApple OSS Distributions 	alignMask = alignment - 1;
744cc9a6355SApple OSS Distributions 
745a5e72196SApple OSS Distributions 	if (os_mul_and_add_overflow(2, size, sizeofIOLibPageMallocHeader, &adjustedSize)) {
746a5e72196SApple OSS Distributions 		return 0;
747a5e72196SApple OSS Distributions 	}
748e13b1fa5SApple OSS Distributions 
749855239e5SApple OSS Distributions 	contiguous = (contiguous && (adjustedSize > page_size))
750855239e5SApple OSS Distributions 	    || (alignment > page_size);
751855239e5SApple OSS Distributions 
752a5e72196SApple OSS Distributions 	if (contiguous || maxPhys) {
7535c2921b0SApple OSS Distributions 		kma_flags_t options = KMA_ZERO;
754e13b1fa5SApple OSS Distributions 		vm_offset_t virt;
755855239e5SApple OSS Distributions 
7565c2921b0SApple OSS Distributions 		if (kheap == KHEAP_DATA_BUFFERS) {
7575c2921b0SApple OSS Distributions 			options = (kma_flags_t) (options | KMA_DATA);
7585c2921b0SApple OSS Distributions 		}
7595c2921b0SApple OSS Distributions 
760e13b1fa5SApple OSS Distributions 		adjustedSize = size;
761855239e5SApple OSS Distributions 		contiguous = (contiguous && (adjustedSize > page_size))
762855239e5SApple OSS Distributions 		    || (alignment > page_size);
763855239e5SApple OSS Distributions 
764a5e72196SApple OSS Distributions 		if (!contiguous) {
7655c2921b0SApple OSS Distributions #if __arm64__
766a5e72196SApple OSS Distributions 			if (maxPhys >= (mach_vm_address_t)(gPhysBase + gPhysSize)) {
76776e12aa3SApple OSS Distributions 				maxPhys = 0;
768a5e72196SApple OSS Distributions 			} else
76976e12aa3SApple OSS Distributions #endif
770a5e72196SApple OSS Distributions 			if (maxPhys <= 0xFFFFFFFF) {
771855239e5SApple OSS Distributions 				maxPhys = 0;
772e6231be0SApple OSS Distributions 				options = (kma_flags_t)(options | KMA_LOMEM);
773a5e72196SApple OSS Distributions 			} else if (gIOLastPage && (atop_64(maxPhys) > gIOLastPage)) {
774d0c1fef6SApple OSS Distributions 				maxPhys = 0;
775d0c1fef6SApple OSS Distributions 			}
776d0c1fef6SApple OSS Distributions 		}
777a5e72196SApple OSS Distributions 		if (contiguous || maxPhys) {
7785c2921b0SApple OSS Distributions 			kr = kmem_alloc_contig(kernel_map, &virt, size,
779e6231be0SApple OSS Distributions 			    alignMask, (ppnum_t) atop(maxPhys), (ppnum_t) atop(alignMask),
7805c2921b0SApple OSS Distributions 			    options, IOMemoryTag(kernel_map));
781a5e72196SApple OSS Distributions 		} else {
7825c2921b0SApple OSS Distributions 			kr = kernel_memory_allocate(kernel_map, &virt,
7830f3703acSApple OSS Distributions 			    size, alignMask, options, IOMemoryTag(kernel_map));
784e13b1fa5SApple OSS Distributions 		}
785a5e72196SApple OSS Distributions 		if (KERN_SUCCESS == kr) {
786e13b1fa5SApple OSS Distributions 			address = virt;
7870f3703acSApple OSS Distributions #if IOTRACKING
788a5e72196SApple OSS Distributions 			if (TRACK_ALLOC) {
789a5e72196SApple OSS Distributions 				IOTrackingAlloc(gIOMallocTracking, address, size);
7900f3703acSApple OSS Distributions 			}
791a5e72196SApple OSS Distributions #endif
792a5e72196SApple OSS Distributions 		} else {
793e13b1fa5SApple OSS Distributions 			address = 0;
794e13b1fa5SApple OSS Distributions 		}
795a5e72196SApple OSS Distributions 	} else {
796e13b1fa5SApple OSS Distributions 		adjustedSize += alignMask;
797a5e72196SApple OSS Distributions 		if (adjustedSize < size) {
798a5e72196SApple OSS Distributions 			return 0;
799a5e72196SApple OSS Distributions 		}
8005c2921b0SApple OSS Distributions 		/* BEGIN IGNORE CODESTYLE */
8015c2921b0SApple OSS Distributions 		__typed_allocators_ignore_push // allocator implementation
802e7776783SApple OSS Distributions 		allocationAddress = (mach_vm_address_t) kheap_alloc(kheap,
803e7776783SApple OSS Distributions 		    adjustedSize, Z_VM_TAG_BT(Z_WAITOK, VM_KERN_MEMORY_IOKIT));
8045c2921b0SApple OSS Distributions 		__typed_allocators_ignore_pop
8055c2921b0SApple OSS Distributions 		/* END IGNORE CODESTYLE */
806e13b1fa5SApple OSS Distributions 
807e13b1fa5SApple OSS Distributions 		if (allocationAddress) {
8080f3703acSApple OSS Distributions 			address = (allocationAddress + alignMask + sizeofIOLibPageMallocHeader)
809e13b1fa5SApple OSS Distributions 			    & (~alignMask);
810e13b1fa5SApple OSS Distributions 
811a5e72196SApple OSS Distributions 			if (atop_32(address) != atop_32(address + size - 1)) {
8123ca3bd55SApple OSS Distributions 				address = round_page(address);
813a5e72196SApple OSS Distributions 			}
814e13b1fa5SApple OSS Distributions 
8150f3703acSApple OSS Distributions 			hdr = (typeof(hdr))(address - sizeofIOLibPageMallocHeader);
8165c2921b0SApple OSS Distributions 			IOMallocAlignedSetHdr(hdr, alignMask, allocationAddress, address);
8170f3703acSApple OSS Distributions #if IOTRACKING
8180f3703acSApple OSS Distributions 			if (TRACK_ALLOC) {
8190f3703acSApple OSS Distributions 				bzero(&hdr->tracking, sizeof(hdr->tracking));
8200f3703acSApple OSS Distributions 				hdr->tracking.address = ~address;
8210f3703acSApple OSS Distributions 				hdr->tracking.size    = size;
82276e12aa3SApple OSS Distributions 				IOTrackingAdd(gIOMallocTracking, &hdr->tracking.tracking, size, true, VM_KERN_MEMORY_NONE);
8230f3703acSApple OSS Distributions 			}
8240f3703acSApple OSS Distributions #endif
825a5e72196SApple OSS Distributions 		} else {
826e13b1fa5SApple OSS Distributions 			address = 0;
827e13b1fa5SApple OSS Distributions 		}
828a5e72196SApple OSS Distributions 	}
829e13b1fa5SApple OSS Distributions 
830e13b1fa5SApple OSS Distributions 	if (address) {
831d0c1fef6SApple OSS Distributions 		IOStatisticsAlloc(kIOStatisticsMallocContiguous, size);
832d0c1fef6SApple OSS Distributions #if IOALLOCDEBUG
833bb611c8fSApple OSS Distributions 		OSAddAtomicLong(size, &debug_iomalloc_size);
834e13b1fa5SApple OSS Distributions #endif
835d0c1fef6SApple OSS Distributions 	}
836e13b1fa5SApple OSS Distributions 
837a5e72196SApple OSS Distributions 	return address;
838e13b1fa5SApple OSS Distributions }
839e13b1fa5SApple OSS Distributions 
840855239e5SApple OSS Distributions 
841e13b1fa5SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
842e13b1fa5SApple OSS Distributions 
843a5e72196SApple OSS Distributions struct _IOMallocContiguousEntry {
844e13b1fa5SApple OSS Distributions 	mach_vm_address_t          virtualAddr;
845e13b1fa5SApple OSS Distributions 	IOBufferMemoryDescriptor * md;
846e13b1fa5SApple OSS Distributions 	queue_chain_t              link;
847e13b1fa5SApple OSS Distributions };
848e13b1fa5SApple OSS Distributions typedef struct _IOMallocContiguousEntry _IOMallocContiguousEntry;
849e13b1fa5SApple OSS Distributions 
850a5e72196SApple OSS Distributions void *
IOMallocContiguous(vm_size_t size,vm_size_t alignment,IOPhysicalAddress * physicalAddress)851a5e72196SApple OSS Distributions IOMallocContiguous(vm_size_t size, vm_size_t alignment,
852e13b1fa5SApple OSS Distributions     IOPhysicalAddress * physicalAddress)
853e13b1fa5SApple OSS Distributions {
854e13b1fa5SApple OSS Distributions 	mach_vm_address_t   address = 0;
855e13b1fa5SApple OSS Distributions 
856a5e72196SApple OSS Distributions 	if (size == 0) {
857a5e72196SApple OSS Distributions 		return NULL;
858a5e72196SApple OSS Distributions 	}
859a5e72196SApple OSS Distributions 	if (alignment == 0) {
860e13b1fa5SApple OSS Distributions 		alignment = 1;
861a5e72196SApple OSS Distributions 	}
862e13b1fa5SApple OSS Distributions 
863e13b1fa5SApple OSS Distributions 	/* Do we want a physical address? */
864a5e72196SApple OSS Distributions 	if (!physicalAddress) {
8655c2921b0SApple OSS Distributions 		address = IOKernelAllocateWithPhysicalRestrict(KHEAP_DEFAULT,
866e6231be0SApple OSS Distributions 		    size, 0 /*maxPhys*/, alignment, true);
867a5e72196SApple OSS Distributions 	} else {
868a5e72196SApple OSS Distributions 		do {
869e13b1fa5SApple OSS Distributions 			IOBufferMemoryDescriptor * bmd;
870e13b1fa5SApple OSS Distributions 			mach_vm_address_t          physicalMask;
871e13b1fa5SApple OSS Distributions 			vm_offset_t                alignMask;
872e13b1fa5SApple OSS Distributions 
873e13b1fa5SApple OSS Distributions 			alignMask = alignment - 1;
8743ca3bd55SApple OSS Distributions 			physicalMask = (0xFFFFFFFF ^ alignMask);
8753ca3bd55SApple OSS Distributions 
876e13b1fa5SApple OSS Distributions 			bmd = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
877e13b1fa5SApple OSS Distributions 				kernel_task, kIOMemoryPhysicallyContiguous, size, physicalMask);
878a5e72196SApple OSS Distributions 			if (!bmd) {
879e13b1fa5SApple OSS Distributions 				break;
880a5e72196SApple OSS Distributions 			}
881e13b1fa5SApple OSS Distributions 
882e13b1fa5SApple OSS Distributions 			_IOMallocContiguousEntry *
883e6231be0SApple OSS Distributions 			    entry = IOMallocType(_IOMallocContiguousEntry);
884a5e72196SApple OSS Distributions 			if (!entry) {
885e13b1fa5SApple OSS Distributions 				bmd->release();
886e13b1fa5SApple OSS Distributions 				break;
887e13b1fa5SApple OSS Distributions 			}
888e13b1fa5SApple OSS Distributions 			entry->virtualAddr = (mach_vm_address_t) bmd->getBytesNoCopy();
889e13b1fa5SApple OSS Distributions 			entry->md          = bmd;
890e13b1fa5SApple OSS Distributions 			lck_mtx_lock(gIOMallocContiguousEntriesLock);
891e13b1fa5SApple OSS Distributions 			queue_enter( &gIOMallocContiguousEntries, entry,
892e13b1fa5SApple OSS Distributions 			    _IOMallocContiguousEntry *, link );
893e13b1fa5SApple OSS Distributions 			lck_mtx_unlock(gIOMallocContiguousEntriesLock);
894e13b1fa5SApple OSS Distributions 
895e13b1fa5SApple OSS Distributions 			address          = (mach_vm_address_t) entry->virtualAddr;
896e13b1fa5SApple OSS Distributions 			*physicalAddress = bmd->getPhysicalAddress();
897a5e72196SApple OSS Distributions 		}while (false);
898e13b1fa5SApple OSS Distributions 	}
899e13b1fa5SApple OSS Distributions 
900e13b1fa5SApple OSS Distributions 	return (void *) address;
901e13b1fa5SApple OSS Distributions }
902e13b1fa5SApple OSS Distributions 
903a5e72196SApple OSS Distributions void
IOFreeContiguous(void * _address,vm_size_t size)904a5e72196SApple OSS Distributions IOFreeContiguous(void * _address, vm_size_t size)
905e13b1fa5SApple OSS Distributions {
906e13b1fa5SApple OSS Distributions 	_IOMallocContiguousEntry * entry;
907e13b1fa5SApple OSS Distributions 	IOMemoryDescriptor *       md = NULL;
908e13b1fa5SApple OSS Distributions 
909e13b1fa5SApple OSS Distributions 	mach_vm_address_t address = (mach_vm_address_t) _address;
910e13b1fa5SApple OSS Distributions 
911a5e72196SApple OSS Distributions 	if (!address) {
912e13b1fa5SApple OSS Distributions 		return;
913a5e72196SApple OSS Distributions 	}
914e13b1fa5SApple OSS Distributions 
915e13b1fa5SApple OSS Distributions 	assert(size);
916e13b1fa5SApple OSS Distributions 
917e13b1fa5SApple OSS Distributions 	lck_mtx_lock(gIOMallocContiguousEntriesLock);
918e13b1fa5SApple OSS Distributions 	queue_iterate( &gIOMallocContiguousEntries, entry,
919e13b1fa5SApple OSS Distributions 	    _IOMallocContiguousEntry *, link )
920e13b1fa5SApple OSS Distributions 	{
921e13b1fa5SApple OSS Distributions 		if (entry->virtualAddr == address) {
922e13b1fa5SApple OSS Distributions 			md   = entry->md;
923e13b1fa5SApple OSS Distributions 			queue_remove( &gIOMallocContiguousEntries, entry,
924e13b1fa5SApple OSS Distributions 			    _IOMallocContiguousEntry *, link );
925e13b1fa5SApple OSS Distributions 			break;
926e13b1fa5SApple OSS Distributions 		}
927e13b1fa5SApple OSS Distributions 	}
928e13b1fa5SApple OSS Distributions 	lck_mtx_unlock(gIOMallocContiguousEntriesLock);
929e13b1fa5SApple OSS Distributions 
930a5e72196SApple OSS Distributions 	if (md) {
931e13b1fa5SApple OSS Distributions 		md->release();
932e6231be0SApple OSS Distributions 		IOFreeType(entry, _IOMallocContiguousEntry);
933a5e72196SApple OSS Distributions 	} else {
9345c2921b0SApple OSS Distributions 		IOKernelFreePhysical(KHEAP_DEFAULT, (mach_vm_address_t) address, size);
935e13b1fa5SApple OSS Distributions 	}
936e13b1fa5SApple OSS Distributions }
937e13b1fa5SApple OSS Distributions 
938e13b1fa5SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
939e13b1fa5SApple OSS Distributions 
940a5e72196SApple OSS Distributions kern_return_t
IOIteratePageableMaps(vm_size_t size,IOIteratePageableMapsCallback callback,void * ref)941a5e72196SApple OSS Distributions IOIteratePageableMaps(vm_size_t size,
942e13b1fa5SApple OSS Distributions     IOIteratePageableMapsCallback callback, void * ref)
943e13b1fa5SApple OSS Distributions {
944e13b1fa5SApple OSS Distributions 	kern_return_t       kr = kIOReturnNotReady;
9455c2921b0SApple OSS Distributions 	kmem_return_t       kmr;
946e13b1fa5SApple OSS Distributions 	vm_size_t           segSize;
947e13b1fa5SApple OSS Distributions 	UInt32              attempts;
948e13b1fa5SApple OSS Distributions 	UInt32              index;
9495c2921b0SApple OSS Distributions 	mach_vm_offset_t    min;
9505c2921b0SApple OSS Distributions 	int                 flags;
951e13b1fa5SApple OSS Distributions 
952a5e72196SApple OSS Distributions 	if (size > kIOPageableMaxMapSize) {
953a5e72196SApple OSS Distributions 		return kIOReturnBadArgument;
954a5e72196SApple OSS Distributions 	}
955e13b1fa5SApple OSS Distributions 
956e13b1fa5SApple OSS Distributions 	do {
957e13b1fa5SApple OSS Distributions 		index = gIOKitPageableSpace.hint;
958e13b1fa5SApple OSS Distributions 		attempts = gIOKitPageableSpace.count;
959e13b1fa5SApple OSS Distributions 		while (attempts--) {
960e13b1fa5SApple OSS Distributions 			kr = (*callback)(gIOKitPageableSpace.maps[index].map, ref);
961e13b1fa5SApple OSS Distributions 			if (KERN_SUCCESS == kr) {
962e13b1fa5SApple OSS Distributions 				gIOKitPageableSpace.hint = index;
963e13b1fa5SApple OSS Distributions 				break;
964e13b1fa5SApple OSS Distributions 			}
965a5e72196SApple OSS Distributions 			if (index) {
966e13b1fa5SApple OSS Distributions 				index--;
967a5e72196SApple OSS Distributions 			} else {
968e13b1fa5SApple OSS Distributions 				index = gIOKitPageableSpace.count - 1;
969e13b1fa5SApple OSS Distributions 			}
970a5e72196SApple OSS Distributions 		}
971a5e72196SApple OSS Distributions 		if (KERN_NO_SPACE != kr) {
972e13b1fa5SApple OSS Distributions 			break;
973a5e72196SApple OSS Distributions 		}
974e13b1fa5SApple OSS Distributions 
975e13b1fa5SApple OSS Distributions 		lck_mtx_lock( gIOKitPageableSpace.lock );
976e13b1fa5SApple OSS Distributions 
977e13b1fa5SApple OSS Distributions 		index = gIOKitPageableSpace.count;
9788d741a5dSApple OSS Distributions 		if (index >= kIOMaxPageableMaps) {
979e13b1fa5SApple OSS Distributions 			lck_mtx_unlock( gIOKitPageableSpace.lock );
980e13b1fa5SApple OSS Distributions 			break;
981e13b1fa5SApple OSS Distributions 		}
982e13b1fa5SApple OSS Distributions 
983a5e72196SApple OSS Distributions 		if (size < kIOPageableMapSize) {
984e13b1fa5SApple OSS Distributions 			segSize = kIOPageableMapSize;
985a5e72196SApple OSS Distributions 		} else {
986e13b1fa5SApple OSS Distributions 			segSize = size;
987a5e72196SApple OSS Distributions 		}
988e13b1fa5SApple OSS Distributions 
9895c2921b0SApple OSS Distributions 		/*
9905c2921b0SApple OSS Distributions 		 * Use the predefine ranges if available, else default to data
9915c2921b0SApple OSS Distributions 		 */
9925c2921b0SApple OSS Distributions 		if (index < kIOMaxFixedRanges) {
9935c2921b0SApple OSS Distributions 			min = gIOKitPageableFixedRanges[index].min_address;
994aca3beaaSApple OSS Distributions 			flags = VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE;
9955c2921b0SApple OSS Distributions 		} else {
996e13b1fa5SApple OSS Distributions 			min = 0;
9975c2921b0SApple OSS Distributions 			flags = VM_FLAGS_ANYWHERE;
9985c2921b0SApple OSS Distributions 		}
9995c2921b0SApple OSS Distributions 		kmr = kmem_suballoc(kernel_map,
1000e13b1fa5SApple OSS Distributions 		    &min,
1001e13b1fa5SApple OSS Distributions 		    segSize,
1002e7776783SApple OSS Distributions 		    VM_MAP_CREATE_PAGEABLE,
10035c2921b0SApple OSS Distributions 		    flags,
10045c2921b0SApple OSS Distributions 		    (kms_flags_t)(KMS_PERMANENT | KMS_DATA),
10055c2921b0SApple OSS Distributions 		    VM_KERN_MEMORY_IOKIT);
10065c2921b0SApple OSS Distributions 		if (kmr.kmr_return != KERN_SUCCESS) {
10075c2921b0SApple OSS Distributions 			kr = kmr.kmr_return;
1008e13b1fa5SApple OSS Distributions 			lck_mtx_unlock( gIOKitPageableSpace.lock );
1009e13b1fa5SApple OSS Distributions 			break;
1010e13b1fa5SApple OSS Distributions 		}
1011e13b1fa5SApple OSS Distributions 
10125c2921b0SApple OSS Distributions 		gIOKitPageableSpace.maps[index].map     = kmr.kmr_submap;
1013e13b1fa5SApple OSS Distributions 		gIOKitPageableSpace.maps[index].address = min;
1014e13b1fa5SApple OSS Distributions 		gIOKitPageableSpace.maps[index].end     = min + segSize;
1015e13b1fa5SApple OSS Distributions 		gIOKitPageableSpace.hint                = index;
1016e13b1fa5SApple OSS Distributions 		gIOKitPageableSpace.count               = index + 1;
1017e13b1fa5SApple OSS Distributions 
1018e13b1fa5SApple OSS Distributions 		lck_mtx_unlock( gIOKitPageableSpace.lock );
1019e13b1fa5SApple OSS Distributions 	} while (true);
1020e13b1fa5SApple OSS Distributions 
1021e13b1fa5SApple OSS Distributions 	return kr;
1022e13b1fa5SApple OSS Distributions }
1023e13b1fa5SApple OSS Distributions 
1024a5e72196SApple OSS Distributions struct IOMallocPageableRef {
10253ca3bd55SApple OSS Distributions 	vm_offset_t address;
1026e13b1fa5SApple OSS Distributions 	vm_size_t   size;
10270f3703acSApple OSS Distributions 	vm_tag_t    tag;
1028e13b1fa5SApple OSS Distributions };
1029e13b1fa5SApple OSS Distributions 
1030a5e72196SApple OSS Distributions static kern_return_t
IOMallocPageableCallback(vm_map_t map,void * _ref)1031a5e72196SApple OSS Distributions IOMallocPageableCallback(vm_map_t map, void * _ref)
1032e13b1fa5SApple OSS Distributions {
1033e13b1fa5SApple OSS Distributions 	struct IOMallocPageableRef * ref = (struct IOMallocPageableRef *) _ref;
10345c2921b0SApple OSS Distributions 	kma_flags_t flags = (kma_flags_t)(KMA_PAGEABLE | KMA_DATA);
1035e13b1fa5SApple OSS Distributions 
10365c2921b0SApple OSS Distributions 	return kmem_alloc( map, &ref->address, ref->size, flags, ref->tag );
1037e13b1fa5SApple OSS Distributions }
1038e13b1fa5SApple OSS Distributions 
1039a5e72196SApple OSS Distributions static void *
IOMallocPageablePages(vm_size_t size,vm_size_t alignment,vm_tag_t tag)1040a5e72196SApple OSS Distributions IOMallocPageablePages(vm_size_t size, vm_size_t alignment, vm_tag_t tag)
1041e13b1fa5SApple OSS Distributions {
1042e13b1fa5SApple OSS Distributions 	kern_return_t              kr = kIOReturnNotReady;
1043e13b1fa5SApple OSS Distributions 	struct IOMallocPageableRef ref;
1044e13b1fa5SApple OSS Distributions 
1045a5e72196SApple OSS Distributions 	if (alignment > page_size) {
1046a5e72196SApple OSS Distributions 		return NULL;
1047a5e72196SApple OSS Distributions 	}
1048a5e72196SApple OSS Distributions 	if (size > kIOPageableMaxMapSize) {
1049a5e72196SApple OSS Distributions 		return NULL;
1050a5e72196SApple OSS Distributions 	}
1051e13b1fa5SApple OSS Distributions 
1052e13b1fa5SApple OSS Distributions 	ref.size = size;
10530f3703acSApple OSS Distributions 	ref.tag  = tag;
1054e13b1fa5SApple OSS Distributions 	kr = IOIteratePageableMaps( size, &IOMallocPageableCallback, &ref );
1055a5e72196SApple OSS Distributions 	if (kIOReturnSuccess != kr) {
1056e13b1fa5SApple OSS Distributions 		ref.address = 0;
1057e13b1fa5SApple OSS Distributions 	}
1058e13b1fa5SApple OSS Distributions 
1059a5e72196SApple OSS Distributions 	return (void *) ref.address;
1060a5e72196SApple OSS Distributions }
1061a5e72196SApple OSS Distributions 
1062a5e72196SApple OSS Distributions vm_map_t
IOPageableMapForAddress(uintptr_t address)1063a5e72196SApple OSS Distributions IOPageableMapForAddress( uintptr_t address )
1064e13b1fa5SApple OSS Distributions {
1065a5e72196SApple OSS Distributions 	vm_map_t    map = NULL;
1066e13b1fa5SApple OSS Distributions 	UInt32      index;
1067e13b1fa5SApple OSS Distributions 
1068e13b1fa5SApple OSS Distributions 	for (index = 0; index < gIOKitPageableSpace.count; index++) {
1069e13b1fa5SApple OSS Distributions 		if ((address >= gIOKitPageableSpace.maps[index].address)
1070e13b1fa5SApple OSS Distributions 		    && (address < gIOKitPageableSpace.maps[index].end)) {
1071e13b1fa5SApple OSS Distributions 			map = gIOKitPageableSpace.maps[index].map;
1072e13b1fa5SApple OSS Distributions 			break;
1073e13b1fa5SApple OSS Distributions 		}
1074e13b1fa5SApple OSS Distributions 	}
1075a5e72196SApple OSS Distributions 	if (!map) {
10763ca3bd55SApple OSS Distributions 		panic("IOPageableMapForAddress: null");
1077e13b1fa5SApple OSS Distributions 	}
1078e13b1fa5SApple OSS Distributions 
1079a5e72196SApple OSS Distributions 	return map;
1080a5e72196SApple OSS Distributions }
1081a5e72196SApple OSS Distributions 
1082a5e72196SApple OSS Distributions static void
IOFreePageablePages(void * address,vm_size_t size)1083a5e72196SApple OSS Distributions IOFreePageablePages(void * address, vm_size_t size)
1084e13b1fa5SApple OSS Distributions {
1085e13b1fa5SApple OSS Distributions 	vm_map_t map;
1086e13b1fa5SApple OSS Distributions 
1087e13b1fa5SApple OSS Distributions 	map = IOPageableMapForAddress((vm_address_t) address);
1088a5e72196SApple OSS Distributions 	if (map) {
1089e13b1fa5SApple OSS Distributions 		kmem_free( map, (vm_offset_t) address, size);
1090186b8fceSApple OSS Distributions 	}
1091186b8fceSApple OSS Distributions }
1092186b8fceSApple OSS Distributions 
1093e7776783SApple OSS Distributions #if defined(__x86_64__)
1094a5e72196SApple OSS Distributions static uintptr_t
IOMallocOnePageablePage(kalloc_heap_t kheap __unused,iopa_t * a)1095e6231be0SApple OSS Distributions IOMallocOnePageablePage(kalloc_heap_t kheap __unused, iopa_t * a)
1096a5e72196SApple OSS Distributions {
1097a5e72196SApple OSS Distributions 	return (uintptr_t) IOMallocPageablePages(page_size, page_size, VM_KERN_MEMORY_IOKIT);
1098a5e72196SApple OSS Distributions }
1099e7776783SApple OSS Distributions #endif /* defined(__x86_64__) */
1100a5e72196SApple OSS Distributions 
1101bb611c8fSApple OSS Distributions static void *
IOMallocPageableInternal(vm_size_t size,vm_size_t alignment,bool zeroed)1102bb611c8fSApple OSS Distributions IOMallocPageableInternal(vm_size_t size, vm_size_t alignment, bool zeroed)
1103186b8fceSApple OSS Distributions {
1104186b8fceSApple OSS Distributions 	void * addr;
1105186b8fceSApple OSS Distributions 
1106bb611c8fSApple OSS Distributions 	if (((uint32_t) alignment) != alignment) {
1107bb611c8fSApple OSS Distributions 		return NULL;
1108bb611c8fSApple OSS Distributions 	}
1109e7776783SApple OSS Distributions #if defined(__x86_64__)
1110bb611c8fSApple OSS Distributions 	if (size >= (page_size - 4 * gIOPageAllocChunkBytes) ||
1111bb611c8fSApple OSS Distributions 	    alignment > page_size) {
1112a5e72196SApple OSS Distributions 		addr = IOMallocPageablePages(size, alignment, IOMemoryTag(kernel_map));
1113bb611c8fSApple OSS Distributions 		/* Memory allocated this way will already be zeroed. */
1114a5e72196SApple OSS Distributions 	} else {
1115e6231be0SApple OSS Distributions 		addr = ((void *) iopa_alloc(&gIOPageablePageAllocator,
11165c2921b0SApple OSS Distributions 		    &IOMallocOnePageablePage, KHEAP_DEFAULT, size, (uint32_t) alignment));
1117e7776783SApple OSS Distributions 		if (addr && zeroed) {
1118bb611c8fSApple OSS Distributions 			bzero(addr, size);
1119bb611c8fSApple OSS Distributions 		}
1120a5e72196SApple OSS Distributions 	}
1121e7776783SApple OSS Distributions #else /* !defined(__x86_64__) */
1122e7776783SApple OSS Distributions 	vm_size_t allocSize = size;
1123e7776783SApple OSS Distributions 	if (allocSize == 0) {
1124e7776783SApple OSS Distributions 		allocSize = 1;
1125e7776783SApple OSS Distributions 	}
1126e7776783SApple OSS Distributions 	addr = IOMallocPageablePages(allocSize, alignment, IOMemoryTag(kernel_map));
1127e7776783SApple OSS Distributions 	/* already zeroed */
1128e7776783SApple OSS Distributions #endif /* defined(__x86_64__) */
1129186b8fceSApple OSS Distributions 
1130186b8fceSApple OSS Distributions 	if (addr) {
1131e13b1fa5SApple OSS Distributions #if IOALLOCDEBUG
11320f3703acSApple OSS Distributions 		OSAddAtomicLong(size, &debug_iomallocpageable_size);
1133186b8fceSApple OSS Distributions #endif
1134186b8fceSApple OSS Distributions 		IOStatisticsAlloc(kIOStatisticsMallocPageable, size);
1135186b8fceSApple OSS Distributions 	}
1136186b8fceSApple OSS Distributions 
1137a5e72196SApple OSS Distributions 	return addr;
1138186b8fceSApple OSS Distributions }
1139186b8fceSApple OSS Distributions 
1140bb611c8fSApple OSS Distributions void *
IOMallocPageable(vm_size_t size,vm_size_t alignment)1141bb611c8fSApple OSS Distributions IOMallocPageable(vm_size_t size, vm_size_t alignment)
1142bb611c8fSApple OSS Distributions {
1143bb611c8fSApple OSS Distributions 	return IOMallocPageableInternal(size, alignment, /*zeroed*/ false);
1144bb611c8fSApple OSS Distributions }
1145bb611c8fSApple OSS Distributions 
1146bb611c8fSApple OSS Distributions void *
IOMallocPageableZero(vm_size_t size,vm_size_t alignment)1147bb611c8fSApple OSS Distributions IOMallocPageableZero(vm_size_t size, vm_size_t alignment)
1148bb611c8fSApple OSS Distributions {
1149bb611c8fSApple OSS Distributions 	return IOMallocPageableInternal(size, alignment, /*zeroed*/ true);
1150bb611c8fSApple OSS Distributions }
1151bb611c8fSApple OSS Distributions 
1152a5e72196SApple OSS Distributions void
IOFreePageable(void * address,vm_size_t size)1153a5e72196SApple OSS Distributions IOFreePageable(void * address, vm_size_t size)
1154186b8fceSApple OSS Distributions {
1155186b8fceSApple OSS Distributions #if IOALLOCDEBUG
11560f3703acSApple OSS Distributions 	OSAddAtomicLong(-size, &debug_iomallocpageable_size);
1157186b8fceSApple OSS Distributions #endif
1158186b8fceSApple OSS Distributions 	IOStatisticsAlloc(kIOStatisticsFreePageable, size);
1159186b8fceSApple OSS Distributions 
1160e7776783SApple OSS Distributions #if defined(__x86_64__)
1161a5e72196SApple OSS Distributions 	if (size < (page_size - 4 * gIOPageAllocChunkBytes)) {
1162186b8fceSApple OSS Distributions 		address = (void *) iopa_free(&gIOPageablePageAllocator, (uintptr_t) address, size);
1163186b8fceSApple OSS Distributions 		size = page_size;
1164186b8fceSApple OSS Distributions 	}
1165a5e72196SApple OSS Distributions 	if (address) {
1166a5e72196SApple OSS Distributions 		IOFreePageablePages(address, size);
1167a5e72196SApple OSS Distributions 	}
1168e7776783SApple OSS Distributions #else /* !defined(__x86_64__) */
1169e7776783SApple OSS Distributions 	if (size == 0) {
1170e7776783SApple OSS Distributions 		size = 1;
1171e7776783SApple OSS Distributions 	}
1172e7776783SApple OSS Distributions 	if (address) {
1173e7776783SApple OSS Distributions 		IOFreePageablePages(address, size);
1174e7776783SApple OSS Distributions 	}
1175e7776783SApple OSS Distributions #endif /* defined(__x86_64__) */
1176186b8fceSApple OSS Distributions }
1177186b8fceSApple OSS Distributions 
1178186b8fceSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1179186b8fceSApple OSS Distributions 
1180e6231be0SApple OSS Distributions void *
11815c2921b0SApple OSS Distributions IOMallocData_external(
11825c2921b0SApple OSS Distributions 	vm_size_t size);
1183e6231be0SApple OSS Distributions void *
IOMallocData_external(vm_size_t size)11845c2921b0SApple OSS Distributions IOMallocData_external(vm_size_t size)
1185e6231be0SApple OSS Distributions {
11865c2921b0SApple OSS Distributions 	return IOMalloc_internal(KHEAP_DATA_BUFFERS, size, Z_VM_TAG_BT_BIT);
11875c2921b0SApple OSS Distributions }
11885c2921b0SApple OSS Distributions 
11895c2921b0SApple OSS Distributions void *
11905c2921b0SApple OSS Distributions IOMallocZeroData_external(
11915c2921b0SApple OSS Distributions 	vm_size_t size);
11925c2921b0SApple OSS Distributions void *
IOMallocZeroData_external(vm_size_t size)11935c2921b0SApple OSS Distributions IOMallocZeroData_external(vm_size_t size)
11945c2921b0SApple OSS Distributions {
11955c2921b0SApple OSS Distributions 	return IOMalloc_internal(KHEAP_DATA_BUFFERS, size, Z_ZERO_VM_TAG_BT_BIT);
1196e6231be0SApple OSS Distributions }
1197e6231be0SApple OSS Distributions 
1198e6231be0SApple OSS Distributions void
IOFreeData(void * address,vm_size_t size)1199e6231be0SApple OSS Distributions IOFreeData(void * address, vm_size_t size)
1200e6231be0SApple OSS Distributions {
1201e6231be0SApple OSS Distributions 	return IOFree_internal(KHEAP_DATA_BUFFERS, address, size);
1202e6231be0SApple OSS Distributions }
1203e6231be0SApple OSS Distributions 
1204e6231be0SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1205e6231be0SApple OSS Distributions 
12065c2921b0SApple OSS Distributions __typed_allocators_ignore_push // allocator implementation
12075c2921b0SApple OSS Distributions 
1208e6231be0SApple OSS Distributions void *
IOMallocTypeImpl(kalloc_type_view_t kt_view)1209e6231be0SApple OSS Distributions IOMallocTypeImpl(kalloc_type_view_t kt_view)
1210e6231be0SApple OSS Distributions {
1211e6231be0SApple OSS Distributions #if IOTRACKING
1212e6231be0SApple OSS Distributions 	/*
1213e6231be0SApple OSS Distributions 	 * When leak detection is on default to using IOMalloc as kalloc
1214e6231be0SApple OSS Distributions 	 * type infrastructure isn't aware of needing additional space for
1215e6231be0SApple OSS Distributions 	 * the header.
1216e6231be0SApple OSS Distributions 	 */
1217e6231be0SApple OSS Distributions 	if (TRACK_ALLOC) {
1218e7776783SApple OSS Distributions 		uint32_t kt_size = kalloc_type_get_size(kt_view->kt_size);
12195c2921b0SApple OSS Distributions 		void *mem = IOMalloc_internal(KHEAP_DEFAULT, kt_size, Z_ZERO);
1220e7776783SApple OSS Distributions 		if (!IOMallocType_from_vm(kt_view)) {
1221e6231be0SApple OSS Distributions 			assert(mem);
1222e6231be0SApple OSS Distributions 		}
1223e6231be0SApple OSS Distributions 		return mem;
1224e6231be0SApple OSS Distributions 	}
1225e6231be0SApple OSS Distributions #endif
1226e6231be0SApple OSS Distributions 	zalloc_flags_t kt_flags = (zalloc_flags_t) (Z_WAITOK | Z_ZERO);
1227e7776783SApple OSS Distributions 	if (!IOMallocType_from_vm(kt_view)) {
1228e6231be0SApple OSS Distributions 		kt_flags = (zalloc_flags_t) (kt_flags | Z_NOFAIL);
1229e6231be0SApple OSS Distributions 	}
1230e6231be0SApple OSS Distributions 	/*
1231e6231be0SApple OSS Distributions 	 * Use external symbol for kalloc_type_impl as
1232e6231be0SApple OSS Distributions 	 * kalloc_type_views generated at some external callsites
1233e6231be0SApple OSS Distributions 	 * many not have been processed during boot.
1234e6231be0SApple OSS Distributions 	 */
1235e6231be0SApple OSS Distributions 	return kalloc_type_impl_external(kt_view, kt_flags);
1236e6231be0SApple OSS Distributions }
1237e6231be0SApple OSS Distributions 
1238e6231be0SApple OSS Distributions void
IOFreeTypeImpl(kalloc_type_view_t kt_view,void * address)1239e6231be0SApple OSS Distributions IOFreeTypeImpl(kalloc_type_view_t kt_view, void * address)
1240e6231be0SApple OSS Distributions {
1241e6231be0SApple OSS Distributions #if IOTRACKING
1242e6231be0SApple OSS Distributions 	if (TRACK_ALLOC) {
1243e6231be0SApple OSS Distributions 		return IOFree_internal(KHEAP_DEFAULT, address,
1244e6231be0SApple OSS Distributions 		           kalloc_type_get_size(kt_view->kt_size));
1245e6231be0SApple OSS Distributions 	}
1246e6231be0SApple OSS Distributions #endif
1247e6231be0SApple OSS Distributions 	/*
1248e6231be0SApple OSS Distributions 	 * Use external symbol for kalloc_type_impl as
1249e6231be0SApple OSS Distributions 	 * kalloc_type_views generated at some external callsites
1250e6231be0SApple OSS Distributions 	 * many not have been processed during boot.
1251e6231be0SApple OSS Distributions 	 */
1252e6231be0SApple OSS Distributions 	return kfree_type_impl_external(kt_view, address);
1253e6231be0SApple OSS Distributions }
1254e6231be0SApple OSS Distributions 
1255e7776783SApple OSS Distributions void *
IOMallocTypeVarImpl(kalloc_type_var_view_t kt_view,vm_size_t size)1256e7776783SApple OSS Distributions IOMallocTypeVarImpl(kalloc_type_var_view_t kt_view, vm_size_t size)
1257e7776783SApple OSS Distributions {
1258e7776783SApple OSS Distributions #if IOTRACKING
1259e7776783SApple OSS Distributions 	/*
1260e7776783SApple OSS Distributions 	 * When leak detection is on default to using IOMalloc as kalloc
1261e7776783SApple OSS Distributions 	 * type infrastructure isn't aware of needing additional space for
1262e7776783SApple OSS Distributions 	 * the header.
1263e7776783SApple OSS Distributions 	 */
1264e7776783SApple OSS Distributions 	if (TRACK_ALLOC) {
12655c2921b0SApple OSS Distributions 		return IOMalloc_internal(KHEAP_DEFAULT, size, Z_ZERO);
1266e7776783SApple OSS Distributions 	}
1267e7776783SApple OSS Distributions #endif
1268e7776783SApple OSS Distributions 	zalloc_flags_t kt_flags = (zalloc_flags_t) (Z_WAITOK | Z_ZERO);
1269e7776783SApple OSS Distributions 
1270e7776783SApple OSS Distributions 	kt_flags = Z_VM_TAG_BT(kt_flags, VM_KERN_MEMORY_KALLOC_TYPE);
1271e7776783SApple OSS Distributions 	return kalloc_type_var_impl(kt_view, size, kt_flags, NULL);
1272e7776783SApple OSS Distributions }
1273e7776783SApple OSS Distributions 
1274e7776783SApple OSS Distributions void
IOFreeTypeVarImpl(kalloc_type_var_view_t kt_view,void * address,vm_size_t size)1275e7776783SApple OSS Distributions IOFreeTypeVarImpl(kalloc_type_var_view_t kt_view, void * address,
1276e7776783SApple OSS Distributions     vm_size_t size)
1277e7776783SApple OSS Distributions {
1278e7776783SApple OSS Distributions #if IOTRACKING
1279e7776783SApple OSS Distributions 	if (TRACK_ALLOC) {
1280e7776783SApple OSS Distributions 		return IOFree_internal(KHEAP_DEFAULT, address, size);
1281e7776783SApple OSS Distributions 	}
1282e7776783SApple OSS Distributions #endif
1283e7776783SApple OSS Distributions 
1284e7776783SApple OSS Distributions 	return kfree_type_var_impl(kt_view, address, size);
1285e7776783SApple OSS Distributions }
1286e7776783SApple OSS Distributions 
12875c2921b0SApple OSS Distributions __typed_allocators_ignore_pop
12885c2921b0SApple OSS Distributions 
1289e6231be0SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1290e6231be0SApple OSS Distributions 
1291e7776783SApple OSS Distributions #if defined(__x86_64__)
1292e7776783SApple OSS Distributions 
1293e7776783SApple OSS Distributions 
1294186b8fceSApple OSS Distributions extern "C" void
iopa_init(iopa_t * a)1295186b8fceSApple OSS Distributions iopa_init(iopa_t * a)
1296186b8fceSApple OSS Distributions {
1297186b8fceSApple OSS Distributions 	bzero(a, sizeof(*a));
1298186b8fceSApple OSS Distributions 	a->lock = IOLockAlloc();
1299186b8fceSApple OSS Distributions 	queue_init(&a->list);
1300186b8fceSApple OSS Distributions }
1301186b8fceSApple OSS Distributions 
1302186b8fceSApple OSS Distributions static uintptr_t
iopa_allocinpage(iopa_page_t * pa,uint32_t count,uint64_t align)1303186b8fceSApple OSS Distributions iopa_allocinpage(iopa_page_t * pa, uint32_t count, uint64_t align)
1304186b8fceSApple OSS Distributions {
1305186b8fceSApple OSS Distributions 	uint32_t n, s;
1306186b8fceSApple OSS Distributions 	uint64_t avail = pa->avail;
1307186b8fceSApple OSS Distributions 
1308186b8fceSApple OSS Distributions 	assert(avail);
1309186b8fceSApple OSS Distributions 
1310186b8fceSApple OSS Distributions 	// find strings of count 1 bits in avail
1311a5e72196SApple OSS Distributions 	for (n = count; n > 1; n -= s) {
1312186b8fceSApple OSS Distributions 		s = n >> 1;
1313186b8fceSApple OSS Distributions 		avail = avail & (avail << s);
1314186b8fceSApple OSS Distributions 	}
1315186b8fceSApple OSS Distributions 	// and aligned
1316186b8fceSApple OSS Distributions 	avail &= align;
1317186b8fceSApple OSS Distributions 
1318a5e72196SApple OSS Distributions 	if (avail) {
1319186b8fceSApple OSS Distributions 		n = __builtin_clzll(avail);
1320186b8fceSApple OSS Distributions 		pa->avail &= ~((-1ULL << (64 - count)) >> n);
1321a5e72196SApple OSS Distributions 		if (!pa->avail && pa->link.next) {
1322186b8fceSApple OSS Distributions 			remque(&pa->link);
1323a5e72196SApple OSS Distributions 			pa->link.next = NULL;
1324186b8fceSApple OSS Distributions 		}
1325a5e72196SApple OSS Distributions 		return n * gIOPageAllocChunkBytes + trunc_page((uintptr_t) pa);
1326186b8fceSApple OSS Distributions 	}
1327186b8fceSApple OSS Distributions 
1328a5e72196SApple OSS Distributions 	return 0;
1329186b8fceSApple OSS Distributions }
1330186b8fceSApple OSS Distributions 
1331186b8fceSApple OSS Distributions uintptr_t
iopa_alloc(iopa_t * a,iopa_proc_t alloc,kalloc_heap_t kheap,vm_size_t bytes,vm_size_t balign)1332e6231be0SApple OSS Distributions iopa_alloc(
1333e6231be0SApple OSS Distributions 	iopa_t          * a,
1334e6231be0SApple OSS Distributions 	iopa_proc_t       alloc,
1335e6231be0SApple OSS Distributions 	kalloc_heap_t     kheap,
1336e6231be0SApple OSS Distributions 	vm_size_t         bytes,
1337e6231be0SApple OSS Distributions 	vm_size_t         balign)
1338186b8fceSApple OSS Distributions {
1339186b8fceSApple OSS Distributions 	static const uint64_t align_masks[] = {
1340186b8fceSApple OSS Distributions 		0xFFFFFFFFFFFFFFFF,
1341186b8fceSApple OSS Distributions 		0xAAAAAAAAAAAAAAAA,
1342186b8fceSApple OSS Distributions 		0x8888888888888888,
1343186b8fceSApple OSS Distributions 		0x8080808080808080,
1344186b8fceSApple OSS Distributions 		0x8000800080008000,
1345186b8fceSApple OSS Distributions 		0x8000000080000000,
1346186b8fceSApple OSS Distributions 		0x8000000000000000,
1347186b8fceSApple OSS Distributions 	};
1348186b8fceSApple OSS Distributions 	iopa_page_t * pa;
1349186b8fceSApple OSS Distributions 	uintptr_t     addr = 0;
1350186b8fceSApple OSS Distributions 	uint32_t      count;
1351186b8fceSApple OSS Distributions 	uint64_t      align;
1352bb611c8fSApple OSS Distributions 	vm_size_t     align_masks_idx;
1353186b8fceSApple OSS Distributions 
1354bb611c8fSApple OSS Distributions 	if (((uint32_t) bytes) != bytes) {
1355bb611c8fSApple OSS Distributions 		return 0;
1356bb611c8fSApple OSS Distributions 	}
1357a5e72196SApple OSS Distributions 	if (!bytes) {
1358a5e72196SApple OSS Distributions 		bytes = 1;
1359a5e72196SApple OSS Distributions 	}
1360bb611c8fSApple OSS Distributions 	count = (((uint32_t) bytes) + gIOPageAllocChunkBytes - 1) / gIOPageAllocChunkBytes;
1361bb611c8fSApple OSS Distributions 
1362bb611c8fSApple OSS Distributions 	align_masks_idx = log2up((balign + gIOPageAllocChunkBytes - 1) / gIOPageAllocChunkBytes);
1363bb611c8fSApple OSS Distributions 	assert(align_masks_idx < sizeof(align_masks) / sizeof(*align_masks));
1364bb611c8fSApple OSS Distributions 	align = align_masks[align_masks_idx];
1365186b8fceSApple OSS Distributions 
1366186b8fceSApple OSS Distributions 	IOLockLock(a->lock);
13670f3703acSApple OSS Distributions 	__IGNORE_WCASTALIGN(pa = (typeof(pa))queue_first(&a->list));
1368a5e72196SApple OSS Distributions 	while (!queue_end(&a->list, &pa->link)) {
1369186b8fceSApple OSS Distributions 		addr = iopa_allocinpage(pa, count, align);
1370a5e72196SApple OSS Distributions 		if (addr) {
1371186b8fceSApple OSS Distributions 			a->bytecount += bytes;
1372186b8fceSApple OSS Distributions 			break;
1373186b8fceSApple OSS Distributions 		}
13740f3703acSApple OSS Distributions 		__IGNORE_WCASTALIGN(pa = (typeof(pa))queue_next(&pa->link));
1375186b8fceSApple OSS Distributions 	}
1376186b8fceSApple OSS Distributions 	IOLockUnlock(a->lock);
1377186b8fceSApple OSS Distributions 
1378a5e72196SApple OSS Distributions 	if (!addr) {
1379e6231be0SApple OSS Distributions 		addr = alloc(kheap, a);
1380a5e72196SApple OSS Distributions 		if (addr) {
1381a3bb9fccSApple OSS Distributions 			pa = (typeof(pa))(addr + page_size - gIOPageAllocChunkBytes);
1382186b8fceSApple OSS Distributions 			pa->signature = kIOPageAllocSignature;
1383186b8fceSApple OSS Distributions 			pa->avail     = -2ULL;
1384186b8fceSApple OSS Distributions 
1385186b8fceSApple OSS Distributions 			addr = iopa_allocinpage(pa, count, align);
1386186b8fceSApple OSS Distributions 			IOLockLock(a->lock);
1387a5e72196SApple OSS Distributions 			if (pa->avail) {
1388a5e72196SApple OSS Distributions 				enqueue_head(&a->list, &pa->link);
1389a5e72196SApple OSS Distributions 			}
1390186b8fceSApple OSS Distributions 			a->pagecount++;
1391a5e72196SApple OSS Distributions 			if (addr) {
1392a5e72196SApple OSS Distributions 				a->bytecount += bytes;
1393a5e72196SApple OSS Distributions 			}
1394186b8fceSApple OSS Distributions 			IOLockUnlock(a->lock);
1395186b8fceSApple OSS Distributions 		}
1396186b8fceSApple OSS Distributions 	}
1397186b8fceSApple OSS Distributions 
1398186b8fceSApple OSS Distributions 	assert((addr & ((1 << log2up(balign)) - 1)) == 0);
1399a5e72196SApple OSS Distributions 	return addr;
1400186b8fceSApple OSS Distributions }
1401186b8fceSApple OSS Distributions 
1402186b8fceSApple OSS Distributions uintptr_t
iopa_free(iopa_t * a,uintptr_t addr,vm_size_t bytes)1403186b8fceSApple OSS Distributions iopa_free(iopa_t * a, uintptr_t addr, vm_size_t bytes)
1404186b8fceSApple OSS Distributions {
1405186b8fceSApple OSS Distributions 	iopa_page_t * pa;
1406186b8fceSApple OSS Distributions 	uint32_t      count;
1407186b8fceSApple OSS Distributions 	uintptr_t     chunk;
1408186b8fceSApple OSS Distributions 
1409bb611c8fSApple OSS Distributions 	if (((uint32_t) bytes) != bytes) {
1410bb611c8fSApple OSS Distributions 		return 0;
1411bb611c8fSApple OSS Distributions 	}
1412a5e72196SApple OSS Distributions 	if (!bytes) {
1413a5e72196SApple OSS Distributions 		bytes = 1;
1414a5e72196SApple OSS Distributions 	}
1415186b8fceSApple OSS Distributions 
1416186b8fceSApple OSS Distributions 	chunk = (addr & page_mask);
1417a3bb9fccSApple OSS Distributions 	assert(0 == (chunk & (gIOPageAllocChunkBytes - 1)));
1418186b8fceSApple OSS Distributions 
1419a3bb9fccSApple OSS Distributions 	pa = (typeof(pa))(addr | (page_size - gIOPageAllocChunkBytes));
1420186b8fceSApple OSS Distributions 	assert(kIOPageAllocSignature == pa->signature);
1421186b8fceSApple OSS Distributions 
1422bb611c8fSApple OSS Distributions 	count = (((uint32_t) bytes) + gIOPageAllocChunkBytes - 1) / gIOPageAllocChunkBytes;
1423a3bb9fccSApple OSS Distributions 	chunk /= gIOPageAllocChunkBytes;
1424186b8fceSApple OSS Distributions 
1425186b8fceSApple OSS Distributions 	IOLockLock(a->lock);
1426a5e72196SApple OSS Distributions 	if (!pa->avail) {
1427186b8fceSApple OSS Distributions 		assert(!pa->link.next);
1428186b8fceSApple OSS Distributions 		enqueue_tail(&a->list, &pa->link);
1429186b8fceSApple OSS Distributions 	}
1430186b8fceSApple OSS Distributions 	pa->avail |= ((-1ULL << (64 - count)) >> chunk);
1431a5e72196SApple OSS Distributions 	if (pa->avail != -2ULL) {
1432a5e72196SApple OSS Distributions 		pa = NULL;
1433a5e72196SApple OSS Distributions 	} else {
1434186b8fceSApple OSS Distributions 		remque(&pa->link);
1435a5e72196SApple OSS Distributions 		pa->link.next = NULL;
1436186b8fceSApple OSS Distributions 		pa->signature = 0;
1437186b8fceSApple OSS Distributions 		a->pagecount--;
1438186b8fceSApple OSS Distributions 		// page to free
1439186b8fceSApple OSS Distributions 		pa = (typeof(pa))trunc_page(pa);
1440186b8fceSApple OSS Distributions 	}
1441186b8fceSApple OSS Distributions 	a->bytecount -= bytes;
1442186b8fceSApple OSS Distributions 	IOLockUnlock(a->lock);
1443186b8fceSApple OSS Distributions 
1444a5e72196SApple OSS Distributions 	return (uintptr_t) pa;
1445e13b1fa5SApple OSS Distributions }
1446e13b1fa5SApple OSS Distributions 
1447e7776783SApple OSS Distributions #endif /* defined(__x86_64__) */
1448e7776783SApple OSS Distributions 
1449e13b1fa5SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1450e13b1fa5SApple OSS Distributions 
1451a5e72196SApple OSS Distributions IOReturn
IOSetProcessorCacheMode(task_t task,IOVirtualAddress address,IOByteCount length,IOOptionBits cacheMode)1452a5e72196SApple OSS Distributions IOSetProcessorCacheMode( task_t task, IOVirtualAddress address,
1453e13b1fa5SApple OSS Distributions     IOByteCount length, IOOptionBits cacheMode )
1454e13b1fa5SApple OSS Distributions {
1455e13b1fa5SApple OSS Distributions 	IOReturn    ret = kIOReturnSuccess;
1456e13b1fa5SApple OSS Distributions 	ppnum_t     pagenum;
1457e13b1fa5SApple OSS Distributions 
1458a5e72196SApple OSS Distributions 	if (task != kernel_task) {
1459a5e72196SApple OSS Distributions 		return kIOReturnUnsupported;
1460a5e72196SApple OSS Distributions 	}
1461a5e72196SApple OSS Distributions 	if ((address | length) & PAGE_MASK) {
14623ca3bd55SApple OSS Distributions //	OSReportWithBacktrace("IOSetProcessorCacheMode(0x%x, 0x%x, 0x%x) fails\n", address, length, cacheMode);
1463a5e72196SApple OSS Distributions 		return kIOReturnUnsupported;
14643ca3bd55SApple OSS Distributions 	}
14653ca3bd55SApple OSS Distributions 	length = round_page(address + length) - trunc_page( address );
14663ca3bd55SApple OSS Distributions 	address = trunc_page( address );
1467e13b1fa5SApple OSS Distributions 
1468e13b1fa5SApple OSS Distributions 	// make map mode
1469e13b1fa5SApple OSS Distributions 	cacheMode = (cacheMode << kIOMapCacheShift) & kIOMapCacheMask;
1470e13b1fa5SApple OSS Distributions 
1471e13b1fa5SApple OSS Distributions 	while ((kIOReturnSuccess == ret) && (length > 0)) {
1472e13b1fa5SApple OSS Distributions 		// Get the physical page number
1473e13b1fa5SApple OSS Distributions 		pagenum = pmap_find_phys(kernel_pmap, (addr64_t)address);
1474e13b1fa5SApple OSS Distributions 		if (pagenum) {
1475e13b1fa5SApple OSS Distributions 			ret = IOUnmapPages( get_task_map(task), address, page_size );
1476e13b1fa5SApple OSS Distributions 			ret = IOMapPages( get_task_map(task), address, ptoa_64(pagenum), page_size, cacheMode );
1477a5e72196SApple OSS Distributions 		} else {
1478e13b1fa5SApple OSS Distributions 			ret = kIOReturnVMError;
1479a5e72196SApple OSS Distributions 		}
1480e13b1fa5SApple OSS Distributions 
1481e13b1fa5SApple OSS Distributions 		address += page_size;
1482e13b1fa5SApple OSS Distributions 		length -= page_size;
1483e13b1fa5SApple OSS Distributions 	}
1484e13b1fa5SApple OSS Distributions 
1485a5e72196SApple OSS Distributions 	return ret;
1486e13b1fa5SApple OSS Distributions }
1487e13b1fa5SApple OSS Distributions 
1488e13b1fa5SApple OSS Distributions 
1489a5e72196SApple OSS Distributions IOReturn
IOFlushProcessorCache(task_t task,IOVirtualAddress address,IOByteCount length)1490a5e72196SApple OSS Distributions IOFlushProcessorCache( task_t task, IOVirtualAddress address,
1491e13b1fa5SApple OSS Distributions     IOByteCount length )
1492e13b1fa5SApple OSS Distributions {
1493a5e72196SApple OSS Distributions 	if (task != kernel_task) {
1494a5e72196SApple OSS Distributions 		return kIOReturnUnsupported;
1495a5e72196SApple OSS Distributions 	}
1496e13b1fa5SApple OSS Distributions 
1497e13b1fa5SApple OSS Distributions 	flush_dcache64((addr64_t) address, (unsigned) length, false );
1498e13b1fa5SApple OSS Distributions 
1499a5e72196SApple OSS Distributions 	return kIOReturnSuccess;
1500e13b1fa5SApple OSS Distributions }
1501e13b1fa5SApple OSS Distributions 
1502e13b1fa5SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1503e13b1fa5SApple OSS Distributions 
1504a5e72196SApple OSS Distributions vm_offset_t
OSKernelStackRemaining(void)1505a5e72196SApple OSS Distributions OSKernelStackRemaining( void )
1506e13b1fa5SApple OSS Distributions {
1507a5e72196SApple OSS Distributions 	return ml_stack_remaining();
1508e13b1fa5SApple OSS Distributions }
1509e13b1fa5SApple OSS Distributions 
1510e13b1fa5SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1511e13b1fa5SApple OSS Distributions 
1512e13b1fa5SApple OSS Distributions /*
1513e13b1fa5SApple OSS Distributions  * Spin for indicated number of milliseconds.
1514e13b1fa5SApple OSS Distributions  */
1515a5e72196SApple OSS Distributions void
IOSleep(unsigned milliseconds)1516a5e72196SApple OSS Distributions IOSleep(unsigned milliseconds)
1517e13b1fa5SApple OSS Distributions {
1518e13b1fa5SApple OSS Distributions 	delay_for_interval(milliseconds, kMillisecondScale);
1519e13b1fa5SApple OSS Distributions }
1520e13b1fa5SApple OSS Distributions 
1521e13b1fa5SApple OSS Distributions /*
15220f3703acSApple OSS Distributions  * Spin for indicated number of milliseconds, and potentially an
15230f3703acSApple OSS Distributions  * additional number of milliseconds up to the leeway values.
15240f3703acSApple OSS Distributions  */
1525a5e72196SApple OSS Distributions void
IOSleepWithLeeway(unsigned intervalMilliseconds,unsigned leewayMilliseconds)1526a5e72196SApple OSS Distributions IOSleepWithLeeway(unsigned intervalMilliseconds, unsigned leewayMilliseconds)
15270f3703acSApple OSS Distributions {
15280f3703acSApple OSS Distributions 	delay_for_interval_with_leeway(intervalMilliseconds, leewayMilliseconds, kMillisecondScale);
15290f3703acSApple OSS Distributions }
15300f3703acSApple OSS Distributions 
15310f3703acSApple OSS Distributions /*
1532e13b1fa5SApple OSS Distributions  * Spin for indicated number of microseconds.
1533e13b1fa5SApple OSS Distributions  */
1534a5e72196SApple OSS Distributions void
IODelay(unsigned microseconds)1535a5e72196SApple OSS Distributions IODelay(unsigned microseconds)
1536e13b1fa5SApple OSS Distributions {
1537e13b1fa5SApple OSS Distributions 	delay_for_interval(microseconds, kMicrosecondScale);
1538e13b1fa5SApple OSS Distributions }
1539e13b1fa5SApple OSS Distributions 
1540e13b1fa5SApple OSS Distributions /*
1541e13b1fa5SApple OSS Distributions  * Spin for indicated number of nanoseconds.
1542e13b1fa5SApple OSS Distributions  */
1543a5e72196SApple OSS Distributions void
IOPause(unsigned nanoseconds)1544a5e72196SApple OSS Distributions IOPause(unsigned nanoseconds)
1545e13b1fa5SApple OSS Distributions {
1546e13b1fa5SApple OSS Distributions 	delay_for_interval(nanoseconds, kNanosecondScale);
1547e13b1fa5SApple OSS Distributions }
1548e13b1fa5SApple OSS Distributions 
1549e13b1fa5SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1550e13b1fa5SApple OSS Distributions 
155176e12aa3SApple OSS Distributions static void _IOLogv(const char *format, va_list ap, void *caller) __printflike(1, 0);
15523ca3bd55SApple OSS Distributions 
155388cc0b97SApple OSS Distributions __attribute__((noinline, not_tail_called))
1554a5e72196SApple OSS Distributions void
IOLog(const char * format,...)1555a5e72196SApple OSS Distributions IOLog(const char *format, ...)
1556e13b1fa5SApple OSS Distributions {
155788cc0b97SApple OSS Distributions 	void *caller = __builtin_return_address(0);
1558e13b1fa5SApple OSS Distributions 	va_list ap;
1559e13b1fa5SApple OSS Distributions 
1560e13b1fa5SApple OSS Distributions 	va_start(ap, format);
156188cc0b97SApple OSS Distributions 	_IOLogv(format, ap, caller);
1562e13b1fa5SApple OSS Distributions 	va_end(ap);
1563e13b1fa5SApple OSS Distributions }
1564e13b1fa5SApple OSS Distributions 
156588cc0b97SApple OSS Distributions __attribute__((noinline, not_tail_called))
1566a5e72196SApple OSS Distributions void
IOLogv(const char * format,va_list ap)1567a5e72196SApple OSS Distributions IOLogv(const char *format, va_list ap)
15683ca3bd55SApple OSS Distributions {
156988cc0b97SApple OSS Distributions 	void *caller = __builtin_return_address(0);
157088cc0b97SApple OSS Distributions 	_IOLogv(format, ap, caller);
157188cc0b97SApple OSS Distributions }
157288cc0b97SApple OSS Distributions 
1573a5e72196SApple OSS Distributions void
_IOLogv(const char * format,va_list ap,void * caller)1574a5e72196SApple OSS Distributions _IOLogv(const char *format, va_list ap, void *caller)
157588cc0b97SApple OSS Distributions {
1576855239e5SApple OSS Distributions 	va_list ap2;
157776e12aa3SApple OSS Distributions 	struct console_printbuf_state info_data;
157876e12aa3SApple OSS Distributions 	console_printbuf_state_init(&info_data, TRUE, TRUE);
157988cc0b97SApple OSS Distributions 
1580855239e5SApple OSS Distributions 	va_copy(ap2, ap);
1581855239e5SApple OSS Distributions 
1582e7776783SApple OSS Distributions #pragma clang diagnostic push
1583e7776783SApple OSS Distributions #pragma clang diagnostic ignored "-Wformat-nonliteral"
158488cc0b97SApple OSS Distributions 	os_log_with_args(OS_LOG_DEFAULT, OS_LOG_TYPE_DEFAULT, format, ap, caller);
1585e7776783SApple OSS Distributions #pragma clang diagnostic pop
1586855239e5SApple OSS Distributions 
1587e6231be0SApple OSS Distributions 	if (!disable_iolog_serial_output) {
158876e12aa3SApple OSS Distributions 		__doprnt(format, ap2, console_printbuf_putc, &info_data, 16, TRUE);
158976e12aa3SApple OSS Distributions 		console_printbuf_clear(&info_data);
1590e6231be0SApple OSS Distributions 	}
15910f3703acSApple OSS Distributions 	va_end(ap2);
159276e12aa3SApple OSS Distributions 
1593e6231be0SApple OSS Distributions 	assertf(ml_get_interrupts_enabled() || ml_is_quiescing() ||
1594e6231be0SApple OSS Distributions 	    debug_mode_active() || !gCPUsRunning,
1595e6231be0SApple OSS Distributions 	    "IOLog called with interrupts disabled");
15963ca3bd55SApple OSS Distributions }
15973ca3bd55SApple OSS Distributions 
15983ca3bd55SApple OSS Distributions #if !__LP64__
1599a5e72196SApple OSS Distributions void
IOPanic(const char * reason)1600a5e72196SApple OSS Distributions IOPanic(const char *reason)
1601e13b1fa5SApple OSS Distributions {
1602e13b1fa5SApple OSS Distributions 	panic("%s", reason);
1603e13b1fa5SApple OSS Distributions }
16043ca3bd55SApple OSS Distributions #endif
1605e13b1fa5SApple OSS Distributions 
1606e13b1fa5SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1607e13b1fa5SApple OSS Distributions 
1608a5e72196SApple OSS Distributions void
IOKitKernelLogBuffer(const char * title,const void * buffer,size_t size,void (* output)(const char * format,...))1609a5e72196SApple OSS Distributions IOKitKernelLogBuffer(const char * title, const void * buffer, size_t size,
1610cc9a6355SApple OSS Distributions     void (*output)(const char *format, ...))
1611cc9a6355SApple OSS Distributions {
1612a5e72196SApple OSS Distributions 	size_t idx, linestart;
1613a5e72196SApple OSS Distributions 	enum { bytelen = (sizeof("0xZZ, ") - 1) };
1614a5e72196SApple OSS Distributions 	char hex[(bytelen * 16) + 1];
1615cc9a6355SApple OSS Distributions 	uint8_t c, chars[17];
1616cc9a6355SApple OSS Distributions 
1617a5e72196SApple OSS Distributions 	output("%s(0x%lx):\n", title, size);
1618a5e72196SApple OSS Distributions 	output("              0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F\n");
1619a5e72196SApple OSS Distributions 	if (size > 4096) {
1620a5e72196SApple OSS Distributions 		size = 4096;
1621cc9a6355SApple OSS Distributions 	}
1622a5e72196SApple OSS Distributions 	chars[16] = 0;
1623a5e72196SApple OSS Distributions 	for (idx = 0, linestart = 0; idx < size;) {
1624cc9a6355SApple OSS Distributions 		c = ((char *)buffer)[idx];
1625a5e72196SApple OSS Distributions 		snprintf(&hex[bytelen * (idx & 15)], bytelen + 1, "0x%02x, ", c);
1626cc9a6355SApple OSS Distributions 		chars[idx & 15] = ((c >= 0x20) && (c <= 0x7f)) ? c : ' ';
1627cc9a6355SApple OSS Distributions 		idx++;
1628a5e72196SApple OSS Distributions 		if ((idx == size) || !(idx & 15)) {
1629a5e72196SApple OSS Distributions 			if (idx & 15) {
1630cc9a6355SApple OSS Distributions 				chars[idx & 15] = 0;
1631cc9a6355SApple OSS Distributions 			}
1632a5e72196SApple OSS Distributions 			output("/* %04lx: */ %-96s /* |%-16s| */\n", linestart, hex, chars);
1633a5e72196SApple OSS Distributions 			linestart += 16;
1634cc9a6355SApple OSS Distributions 		}
1635cc9a6355SApple OSS Distributions 	}
1636cc9a6355SApple OSS Distributions }
1637cc9a6355SApple OSS Distributions 
1638cc9a6355SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1639cc9a6355SApple OSS Distributions 
1640e13b1fa5SApple OSS Distributions /*
1641e13b1fa5SApple OSS Distributions  * Convert a integer constant (typically a #define or enum) to a string.
1642e13b1fa5SApple OSS Distributions  */
1643e13b1fa5SApple OSS Distributions static char noValue[80];        // that's pretty
1644e13b1fa5SApple OSS Distributions 
1645a5e72196SApple OSS Distributions const char *
IOFindNameForValue(int value,const IONamedValue * regValueArray)1646a5e72196SApple OSS Distributions IOFindNameForValue(int value, const IONamedValue *regValueArray)
1647e13b1fa5SApple OSS Distributions {
1648e13b1fa5SApple OSS Distributions 	for (; regValueArray->name; regValueArray++) {
1649a5e72196SApple OSS Distributions 		if (regValueArray->value == value) {
1650a5e72196SApple OSS Distributions 			return regValueArray->name;
1651a5e72196SApple OSS Distributions 		}
1652e13b1fa5SApple OSS Distributions 	}
1653e13b1fa5SApple OSS Distributions 	snprintf(noValue, sizeof(noValue), "0x%x (UNDEFINED)", value);
1654a5e72196SApple OSS Distributions 	return (const char *)noValue;
1655e13b1fa5SApple OSS Distributions }
1656e13b1fa5SApple OSS Distributions 
1657a5e72196SApple OSS Distributions IOReturn
IOFindValueForName(const char * string,const IONamedValue * regValueArray,int * value)1658a5e72196SApple OSS Distributions IOFindValueForName(const char *string,
1659e13b1fa5SApple OSS Distributions     const IONamedValue *regValueArray,
1660e13b1fa5SApple OSS Distributions     int *value)
1661e13b1fa5SApple OSS Distributions {
1662e13b1fa5SApple OSS Distributions 	for (; regValueArray->name; regValueArray++) {
1663e13b1fa5SApple OSS Distributions 		if (!strcmp(regValueArray->name, string)) {
1664e13b1fa5SApple OSS Distributions 			*value = regValueArray->value;
1665e13b1fa5SApple OSS Distributions 			return kIOReturnSuccess;
1666e13b1fa5SApple OSS Distributions 		}
1667e13b1fa5SApple OSS Distributions 	}
1668e13b1fa5SApple OSS Distributions 	return kIOReturnBadArgument;
1669e13b1fa5SApple OSS Distributions }
1670e13b1fa5SApple OSS Distributions 
1671a5e72196SApple OSS Distributions OSString *
IOCopyLogNameForPID(int pid)1672a5e72196SApple OSS Distributions IOCopyLogNameForPID(int pid)
1673e13b1fa5SApple OSS Distributions {
1674e13b1fa5SApple OSS Distributions 	char   buf[128];
1675e13b1fa5SApple OSS Distributions 	size_t len;
1676e13b1fa5SApple OSS Distributions 	snprintf(buf, sizeof(buf), "pid %d, ", pid);
1677e13b1fa5SApple OSS Distributions 	len = strlen(buf);
1678bb611c8fSApple OSS Distributions 	proc_name(pid, buf + len, (int) (sizeof(buf) - len));
1679a5e72196SApple OSS Distributions 	return OSString::withCString(buf);
1680e13b1fa5SApple OSS Distributions }
1681e13b1fa5SApple OSS Distributions 
1682e13b1fa5SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1683e13b1fa5SApple OSS Distributions 
1684a5e72196SApple OSS Distributions IOAlignment
IOSizeToAlignment(unsigned int size)1685a5e72196SApple OSS Distributions IOSizeToAlignment(unsigned int size)
1686e13b1fa5SApple OSS Distributions {
16870f3703acSApple OSS Distributions 	int shift;
1688e13b1fa5SApple OSS Distributions 	const int intsize = sizeof(unsigned int) * 8;
1689e13b1fa5SApple OSS Distributions 
1690e13b1fa5SApple OSS Distributions 	for (shift = 1; shift < intsize; shift++) {
1691a5e72196SApple OSS Distributions 		if (size & 0x80000000) {
1692e13b1fa5SApple OSS Distributions 			return (IOAlignment)(intsize - shift);
1693a5e72196SApple OSS Distributions 		}
1694e13b1fa5SApple OSS Distributions 		size <<= 1;
1695e13b1fa5SApple OSS Distributions 	}
1696e13b1fa5SApple OSS Distributions 	return 0;
1697e13b1fa5SApple OSS Distributions }
1698e13b1fa5SApple OSS Distributions 
1699a5e72196SApple OSS Distributions unsigned int
IOAlignmentToSize(IOAlignment align)1700a5e72196SApple OSS Distributions IOAlignmentToSize(IOAlignment align)
1701e13b1fa5SApple OSS Distributions {
1702e13b1fa5SApple OSS Distributions 	unsigned int size;
1703e13b1fa5SApple OSS Distributions 
1704e13b1fa5SApple OSS Distributions 	for (size = 1; align; align--) {
1705e13b1fa5SApple OSS Distributions 		size <<= 1;
1706e13b1fa5SApple OSS Distributions 	}
1707e13b1fa5SApple OSS Distributions 	return size;
1708e13b1fa5SApple OSS Distributions }
1709e13b1fa5SApple OSS Distributions } /* extern "C" */
1710