- page_size, 0, options);
- if (KERN_SUCCESS != kr) return (0);
-
- bzero((void *) vmaddr, page_size);
- pa = (typeof(pa)) (vmaddr + page_size - kIOPageAllocChunkBytes);
-
- pa->signature = kIOPageAllocSignature;
- pa->avail = -2ULL;
-
- return (pa);
-}
-
-static void
-iopa_freepage(io_pagealloc_t * pa)
-{
- kmem_free( kernel_map, trunc_page((uintptr_t) pa), page_size);
-}
-
-static uintptr_t
-iopa_allocinpage(io_pagealloc_t * pa, uint32_t count, uint64_t align)
-{
- uint32_t n, s;
- uint64_t avail = pa->avail;
-
- assert(avail);
-
- // find strings of count 1 bits in avail
- for (n = count; n > 1; n -= s)
- {
- s = n >> 1;
- avail = avail & (avail << s);
- }
- // and aligned
- avail &= align;
-
- if (avail)
- {
- n = __builtin_clzll(avail);
- pa->avail &= ~((-1ULL << (64 - count)) >> n);
- if (!pa->avail && pa->link.next)
- {
- remque(&pa->link);
- pa->link.next = 0;
- }
- return (n * kIOPageAllocChunkBytes + trunc_page((uintptr_t) pa));
- }
-
- return (0);
-}
-
-static uint32_t
-log2up(uint32_t size)
-{
- if (size <= 1) size = 0;
- else size = 32 - __builtin_clz(size - 1);
- return (size);
-}
-
-static uintptr_t
-iopa_alloc(vm_size_t bytes, uint32_t balign)
-{
- static const uint64_t align_masks[] = {
- 0xFFFFFFFFFFFFFFFF,
- 0xAAAAAAAAAAAAAAAA,
- 0x8888888888888888,
- 0x8080808080808080,
- 0x8000800080008000,
- 0x8000000080000000,
- 0x8000000000000000,
- };
- io_pagealloc_t * pa;
- uintptr_t addr = 0;
- uint32_t count;
- uint64_t align;
-
- if (!bytes) bytes = 1;
- count = (bytes + kIOPageAllocChunkBytes - 1) / kIOPageAllocChunkBytes;
- align = align_masks[log2up((balign + kIOPageAllocChunkBytes - 1) / kIOPageAllocChunkBytes)];
-
- IOSimpleLockLock(gIOPageAllocLock);
- pa = (typeof(pa)) queue_first(&gIOPageAllocList);
- while (!queue_end(&gIOPageAllocList, &pa->link))
- {
- addr = iopa_allocinpage(pa, count, align);
- if (addr)
- {
- gIOPageAllocBytes += bytes;
- break;
- }
- pa = (typeof(pa)) queue_next(&pa->link);
- }
- IOSimpleLockUnlock(gIOPageAllocLock);
- if (!addr)
- {
- pa = iopa_allocpage();
- if (pa)
- {
- addr = iopa_allocinpage(pa, count, align);
- IOSimpleLockLock(gIOPageAllocLock);
- if (pa->avail) enqueue_head(&gIOPageAllocList, &pa->link);
- gIOPageAllocCount++;
- if (addr) gIOPageAllocBytes += bytes;
- IOSimpleLockUnlock(gIOPageAllocLock);
- }
- }
-
- if (addr)
- {
- assert((addr & ((1 << log2up(balign)) - 1)) == 0);
- IOStatisticsAlloc(kIOStatisticsMallocAligned, bytes);
-#if IOALLOCDEBUG
- debug_iomalloc_size += bytes;
-#endif
- }
-
- return (addr);
-}
-
-static void
-iopa_free(uintptr_t addr, vm_size_t bytes)
-{
- io_pagealloc_t * pa;
- uint32_t count;
- uintptr_t chunk;