1 /* 2 * Copyright (c) 2024 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 #pragma once 29 #if defined(__LP64__) 30 #include <mach/mach_types.h> 31 #include <mach/vm_reclaim.h> 32 #include <ptrcheck.h> 33 34 #define VM_RECLAIM_MAX_BUFFER_SIZE (128ull << 20) 35 #define VM_RECLAIM_MAX_CAPACITY ((VM_RECLAIM_MAX_BUFFER_SIZE - \ 36 offsetof(struct mach_vm_reclaim_ring_s, entries)) / \ 37 sizeof(struct mach_vm_reclaim_entry_s)) 38 39 __BEGIN_DECLS 40 41 typedef struct mach_vm_reclaim_entry_s { 42 mach_vm_address_t address; 43 uint32_t size; 44 mach_vm_reclaim_action_t behavior; 45 uint8_t _unused[3]; 46 } *mach_vm_reclaim_entry_t; 47 48 /* This struct is no longer used () */ 49 typedef struct mach_vm_reclaim_indices_s { 50 _Atomic mach_vm_reclaim_id_t head; 51 _Atomic mach_vm_reclaim_id_t tail; 52 _Atomic mach_vm_reclaim_id_t busy; 53 } *mach_vm_reclaim_indices_t; 54 55 /* 56 * Contains the data used for synchronization with the kernel 57 */ 58 struct mach_vm_reclaim_ring_s { 59 /* no longer used () */ 60 mach_vm_size_t va_in_buffer; 61 /* no longer used () */ 62 mach_vm_size_t last_accounting_given_to_kernel; 63 /* The current length of the ringbuffer */ 64 mach_vm_reclaim_count_t len; 65 /* The maximum length of the ringbuffer */ 66 mach_vm_reclaim_count_t max_len; 67 /* no longer used () */ 68 struct mach_vm_reclaim_indices_s indices; 69 /* The minimum period of time between kernel accounting updates */ 70 uint64_t sampling_period_abs; 71 /* timestamp (MAS) of the last kernel accounting update */ 72 uint64_t last_sample_abs; 73 /* 74 * An estimate for the number of reclaimable bytes currently in the ring. This 75 * is updating atomically after entering a new reclaimable region, after 76 * successfully cancelling a region, and after reclaiming regions. 77 */ 78 _Atomic uint64_t reclaimable_bytes; 79 /* 80 * The minimum amount of reclaimable memory in this buffer for the current 81 * sampling interval. 82 */ 83 _Atomic uint64_t reclaimable_bytes_min; 84 /* Marks IDs which have been reclaimed */ 85 _Atomic mach_vm_reclaim_id_t head; 86 /* Marks IDs which are in the process of being reclaimed */ 87 _Atomic mach_vm_reclaim_id_t busy; 88 /* The ID of the most recent entry */ 89 _Atomic mach_vm_reclaim_id_t tail; 90 /* Pad to a multiple of the entry size */ 91 uint64_t _unused; 92 /* 93 * The ringbuffer entries themselves populate the remainder of this 94 * buffer's vm allocation. 95 * NB: the fields preceding `entries` should be aligned to a multiple of 96 * the entry size. 97 */ 98 struct mach_vm_reclaim_entry_s entries[] __counted_by(len); 99 }; 100 101 /* 102 * The above definitions exist for the internal implementation in libsyscall / 103 * xnu and for observability with debugging tools. They should _NOT_ be used by 104 * clients. 105 */ 106 107 #if !KERNEL 108 109 /* 110 * The below interfaces are intended for observing a task's reclaim ring(s) and 111 * querying which regions are reclaimable. General usage would look something 112 * like the following: 113 * 114 * - Use `mach_vm_reclaim_get_rings_for_task` to get a list of reclaim rings 115 * for a task. 116 * - Use `mach_vm_reclaim_ring_copy` for each ring to map a copy of the 117 * reclaim ring into your address space. 118 * - Use `mach_vm_reclaim_copied_ring_query` to query a list of reclaimable 119 * regions in the ring. 120 * - Use `mach_vm_reclaim_copied_ring_free` to free the copied reclaim ring. 121 */ 122 123 /// A descriptor for a reclaimable region 124 typedef struct mach_vm_reclaim_region_s { 125 mach_vm_address_t vmrr_addr; 126 mach_vm_size_t vmrr_size; 127 mach_vm_reclaim_action_t vmrr_behavior; 128 uint8_t _vmrr_unused[3]; 129 } *mach_vm_reclaim_region_t; 130 131 /// A reference to a task's reclaim ring 132 typedef struct mach_vm_reclaim_ring_ref_s { 133 mach_vm_address_t addr; 134 mach_vm_size_t size; 135 } *mach_vm_reclaim_ring_ref_t; 136 137 /// A reclaim ring copied from another task 138 typedef void *mach_vm_reclaim_ring_copy_t; 139 140 /// Get references to another task's reclaim rings. 141 /// 142 /// - Parameters: 143 /// - task: The target task 144 /// - refs_out: A buffer to store the references in. If NULL, only the number 145 /// of rings will be queried. 146 /// - count_inout: A pointer to the count of the buffer, which will be 147 /// overwritten with the number of rings in the target task. 148 /// 149 /// - Returns: `VM_RECLAIM_SUCCESS` upon success. 150 __SPI_AVAILABLE(macos(16.0), ios(19.0), tvos(19.0), visionos(3.0)) 151 mach_vm_reclaim_error_t mach_vm_reclaim_get_rings_for_task( 152 task_read_t task, 153 mach_vm_reclaim_ring_ref_t refs_out, 154 mach_vm_reclaim_count_t *count_inout); 155 156 /// Copy another task's reclaim ring into this task's VA. 157 /// 158 /// - Parameters: 159 /// - task: The task to copy the ring from 160 /// - ref: The reference to the ring to copy 161 /// (obtained via mach_vm_reclaim_get_rings_for_task). 162 /// - ring_out: The pointer to the copied ring to be written out upon success 163 /// 164 /// - Returns: `VM_RECLAIM_SUCCESS` upon success. 165 __SPI_AVAILABLE(macos(16.0), ios(19.0), tvos(19.0), visionos(3.0)) 166 mach_vm_reclaim_error_t mach_vm_reclaim_ring_copy( 167 task_read_t task, 168 mach_vm_reclaim_ring_ref_t ref, 169 mach_vm_reclaim_ring_copy_t *ring_out); 170 171 /// Free a reclaim ring copied from another task. 172 /// 173 /// - Parameters: 174 /// - ring: The copied ring to free. 175 /// 176 /// - Returns: `VM_RECLAIM_SUCCESS` upon success. 177 __SPI_AVAILABLE(macos(16.0), ios(19.0), tvos(19.0), visionos(3.0)) 178 mach_vm_reclaim_error_t mach_vm_reclaim_copied_ring_free( 179 mach_vm_reclaim_ring_copy_t *ring); 180 181 /// Query the reclaimable regions in a copied reclaim ring. 182 /// 183 /// - Parameters: 184 /// - ring: The ring to query 185 /// - regions_out: A buffer of `mach_vm_reclaim_region_s` to copy the query 186 /// results into. If NULL, only the size of the ring will be queried. 187 /// - count_inout: A pointer to the size, in regions, of the buffer. Will 188 /// be overwritten with the count of regions in the ring upon success. 189 /// 190 /// - Returns: `VM_RECLAIM_SUCCESS` on success. 191 /// `KERN_NO_SPACE` if there is insufficient space in the buffer to store 192 /// the queried ring's regions. 193 /// `VM_RECLAIM_INVALID_CAPACITY` if the ringbuffer structure was malformed 194 /// and had a buffer too small for its reported size. The entries that were 195 /// able to be queried and the count will still be written out. 196 __SPI_AVAILABLE(macos(16.0), ios(19.0), tvos(19.0), visionos(3.0)) 197 mach_vm_reclaim_error_t mach_vm_reclaim_copied_ring_query( 198 mach_vm_reclaim_ring_copy_t *ring, 199 mach_vm_reclaim_region_t regions_out, 200 mach_vm_reclaim_count_t *count_inout); 201 202 #endif /* !KERNEL */ 203 204 __END_DECLS 205 #endif /* __LP64__ */ 206