xref: /xnu-12377.81.4/osfmk/mach/vm_reclaim_private.h (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
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