1 | /* |
2 | * Copyright (c) 2021 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 | |
29 | #ifndef _VM_RECLAIM_H_ |
30 | #define _VM_RECLAIM_H_ |
31 | |
32 | #ifdef PRIVATE |
33 | #if defined(__LP64__) |
34 | |
35 | #include <mach/mach_types.h> |
36 | #include <mach/kern_return.h> |
37 | #include <stdbool.h> |
38 | |
39 | __BEGIN_DECLS |
40 | |
41 | typedef struct mach_vm_reclaim_indices_v1_s { |
42 | _Atomic uint64_t head; |
43 | _Atomic uint64_t tail; |
44 | _Atomic uint64_t busy; |
45 | } mach_vm_reclaim_indices_v1_t; |
46 | |
47 | // The action to be performed by the kernel on reclamation of an entry |
48 | __enum_decl(mach_vm_reclaim_behavior_v1_t, uint16_t, { |
49 | // Deallocate (unmap) the entry |
50 | MACH_VM_RECLAIM_DEALLOCATE = 0, |
51 | // Mark the entry as clean and leave mapped (VM_BEHAVIOR_REUSABLE) |
52 | MACH_VM_RECLAIM_REUSABLE = 1, |
53 | }); |
54 | |
55 | typedef struct mach_vm_reclaim_entry_v1_s { |
56 | mach_vm_address_t address; |
57 | uint32_t size; |
58 | mach_vm_reclaim_behavior_v1_t behavior; |
59 | uint16_t flags; |
60 | } mach_vm_reclaim_entry_v1_t; |
61 | |
62 | /* |
63 | * Contains the data used for synchronization with the kernel. This structure |
64 | * should be page-aligned. |
65 | */ |
66 | typedef struct mach_vm_reclaim_buffer_v1_s { |
67 | mach_vm_reclaim_indices_v1_t indices; |
68 | /* align to multiple of entry size */ |
69 | uint64_t _unused; |
70 | /* |
71 | * The ringbuffer entries themselves populate the remainder of this |
72 | * buffer's vm allocation. |
73 | */ |
74 | mach_vm_reclaim_entry_v1_t entries[0]; |
75 | } *mach_vm_reclaim_buffer_v1_t; |
76 | |
77 | #if !KERNEL |
78 | #define VM_RECLAIM_INDEX_NULL UINT64_MAX |
79 | |
80 | /* |
81 | * Userspace interface for placing items in the reclamation buffer and trying to take them back out. |
82 | * Note that these interfaces are NOT thread safe. It is the caller's responsibility to synchronize concurrent |
83 | * operations on the same buffer. |
84 | * |
85 | * These operations are implemented in libsyscall. |
86 | */ |
87 | |
88 | typedef struct mach_vm_reclaim_ringbuffer_v1_s { |
89 | mach_vm_reclaim_buffer_v1_t buffer; |
90 | mach_vm_size_t buffer_len; |
91 | uint64_t va_in_buffer; |
92 | uint64_t last_accounting_given_to_kernel; |
93 | } *mach_vm_reclaim_ringbuffer_v1_t; |
94 | |
95 | kern_return_t mach_vm_reclaim_ringbuffer_init(mach_vm_reclaim_ringbuffer_v1_t ringbuffer); |
96 | |
97 | /* |
98 | * Mark the given range as free. |
99 | * Returns a unique identifier for the range that can be used by reclaim_mark_used |
100 | * This will update the userspace reclaim buffer accounting, but will not |
101 | * inform the kernel about the new bytes in the buffer. If the kernel should be informed, |
102 | * should_update_kernel_accounting will be set to true and the caller should call |
103 | * mach_vm_reclaim_update_kernel_accounting. That syscall might reclaim the buffer, so |
104 | * this gives the caller an opportunity to first drop any locks. |
105 | */ |
106 | uint64_t mach_vm_reclaim_mark_free( |
107 | mach_vm_reclaim_ringbuffer_v1_t buffer, |
108 | mach_vm_address_t start_addr, |
109 | uint32_t size, |
110 | mach_vm_reclaim_behavior_v1_t behavior, |
111 | bool *should_update_kernel_accounting); |
112 | |
113 | /* |
114 | * Attempt to take back the range determined by id. |
115 | * Returns true iff range can now be used. |
116 | * Subsequent calls to reclaim_mark_used with the same id are not supported & may return true or false. |
117 | */ |
118 | bool mach_vm_reclaim_mark_used( |
119 | mach_vm_reclaim_ringbuffer_v1_t buffer, |
120 | uint64_t id, |
121 | mach_vm_address_t start_addr, |
122 | uint32_t size); |
123 | |
124 | /* |
125 | * Check if the range is available for re-use. |
126 | * Returns true if the range is still available. Note that this doesn't claim the range, so it may be reclaimed in parallel. |
127 | * Note that a return value of false does not guarantee that the kernel has reclaimed the range already (it may just be considering it). |
128 | */ |
129 | bool mach_vm_reclaim_is_available( |
130 | const mach_vm_reclaim_ringbuffer_v1_t buffer, |
131 | uint64_t id); |
132 | |
133 | /* |
134 | * Check if the range has been reclaimed. |
135 | * Returns true if the range is no longer available for re-use. |
136 | */ |
137 | bool mach_vm_reclaim_is_reclaimed( |
138 | const mach_vm_reclaim_ringbuffer_v1_t buffer, |
139 | uint64_t id); |
140 | |
141 | /* |
142 | * Force the kernel to reclaim at least num_entries_to_reclaim entries from the ringbuffer (if present). |
143 | * Note that mach_vm_reclaim_mark_free automatically handles the full ringbuffer case. |
144 | */ |
145 | kern_return_t mach_vm_reclaim_synchronize( |
146 | mach_vm_reclaim_ringbuffer_v1_t ringbuffer, |
147 | mach_vm_size_t num_entries_to_reclaim); |
148 | |
149 | /* |
150 | * Let the kernel know how much VA is in the ringbuffer. |
151 | * The kernel may choose to reclaim from the ringbuffer on this thread. |
152 | * This should be called whenever mach_vm_reclaim_mark_free returns true in |
153 | * should_update_kernel_accounting. It may be called at any other time |
154 | * if the caller wants to update the kernel's accounting & is |
155 | * thread safe w.r.t. all other mach_vm_reclaim calls. |
156 | */ |
157 | kern_return_t mach_vm_reclaim_update_kernel_accounting( |
158 | const mach_vm_reclaim_ringbuffer_v1_t ring_buffer); |
159 | |
160 | #endif /* !KENREL */ |
161 | |
162 | __END_DECLS |
163 | |
164 | #endif /* PRIVATE */ |
165 | |
166 | #endif /* __LP64__ */ |
167 | |
168 | #endif /* _VM_RECLAIM_H_ */ |
169 | |