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
41typedef 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
55typedef 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 */
66typedef 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
88typedef 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
95kern_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 */
106uint64_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 */
118bool 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 */
129bool 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 */
137bool 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 */
145kern_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 */
157kern_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