]> git.saurik.com Git - apple/xnu.git/blame - osfmk/vm/vm_external.c
xnu-517.12.7.tar.gz
[apple/xnu.git] / osfmk / vm / vm_external.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
e5568f75
A
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
1c79356b 11 *
e5568f75
A
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
e5568f75
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
1c79356b
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * @OSF_COPYRIGHT@
24 */
25/*
26 * Mach Operating System
27 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
28 * All Rights Reserved.
29 *
30 * Permission to use, copy, modify and distribute this software and its
31 * documentation is hereby granted, provided that both the copyright
32 * notice and this permission notice appear in all copies of the
33 * software, derivative works or modified versions, and any portions
34 * thereof, and that both notices appear in supporting documentation.
35 *
36 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39 *
40 * Carnegie Mellon requests users of this software to return to
41 *
42 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
43 * School of Computer Science
44 * Carnegie Mellon University
45 * Pittsburgh PA 15213-3890
46 *
47 * any improvements or extensions that they make and grant Carnegie Mellon
48 * the rights to redistribute these changes.
49 */
50/*
51 */
52
53/*
54 * This module maintains information about the presence of
55 * pages not in memory. Since an external memory object
56 * must maintain a complete knowledge of its contents, this
57 * information takes the form of hints.
58 */
59#include <string.h> /* for memcpy()/memset() */
60
61#include <mach/boolean.h>
62#include <vm/vm_external.h>
63#include <kern/kalloc.h>
64#include <mach/vm_param.h>
65#include <kern/assert.h>
66
67/*
68 * The implementation uses bit arrays to record whether
69 * a page has been written to external storage. For
70 * convenience, these bit arrays come in various sizes.
71 * For example, a map N bytes long can record:
72 *
73 * 16 bytes = 128 pages = (@ 4KB/page) 512KB
74 * 1024 bytes = 8192 pages = (@ 4KB/page) 32MB
75 * 4096 bytes = 32768 pages = (@ 4KB/page) 128MB
76 *
77 * For a 32-bit machine with 4KB pages, the largest size
78 * would be 128KB = 32 pages. Machines with a larger page
79 * size are more efficient.
80 *
81 * This subsystem must be very careful about memory allocation,
82 * since vm_external_create() is almost always called with
83 * vm_privilege set. The largest map to be allocated must be less
84 * than or equal to a single page, and the kalloc subsystem must
85 * never allocate more than a single page in response to a kalloc()
86 * request. Also, vm_external_destroy() must not take any blocking
87 * locks, since it is called with a vm_object lock held. This
88 * implies that kfree() MUST be implemented in terms of zfree()
89 * NOT kmem_free() for all request sizes that this subsystem uses.
90 *
91 * For efficiency, this subsystem knows that the kalloc() subsystem
92 * is implemented in terms of power-of-2 allocation, and that the
93 * minimum allocation unit is KALLOC_MINSIZE
94 *
95 * XXXO
96 * Should consider using existence_map to hold bits directly
97 * when existence_size <= 4 bytes (i.e., 32 pages).
98 */
99
100#define SMALL_SIZE KALLOC_MINSIZE
101#define LARGE_SIZE PAGE_SIZE
102
103static vm_size_t power_of_2(vm_size_t size);
104
105static vm_size_t
106power_of_2(vm_size_t size)
107{
108 vm_size_t power;
109
110 power = 2 * SMALL_SIZE;
111 while (power < size) {
112 power <<= 1;
113 }
114 return(power);
115}
116
117vm_external_map_t
118vm_external_create(
119 vm_offset_t size)
120{
121 vm_size_t bytes;
122 vm_external_map_t result = VM_EXTERNAL_NULL;
123
124 bytes = stob(size);
125 if (bytes <= SMALL_SIZE) {
126 if ((result = (vm_external_map_t)kalloc(SMALL_SIZE)) != NULL) {
127 memset(result, 0, SMALL_SIZE);
128 }
129 } else if (bytes <= LARGE_SIZE) {
130 bytes = power_of_2(bytes);
131
132 if ((result = (vm_external_map_t)kalloc(bytes)) != NULL) {
133 memset(result, 0, bytes);
134 }
135 }
136 return(result);
137}
138
139void
140vm_external_destroy(
141 vm_external_map_t map,
142 vm_size_t size)
143{
144 vm_size_t bytes;
145
146 if (map == VM_EXTERNAL_NULL)
147 return;
148
149 bytes = stob(size);
150 if (bytes <= SMALL_SIZE) {
151 bytes = SMALL_SIZE;
152 } else {
153 bytes = power_of_2(bytes);
154 }
155 kfree((vm_offset_t)map, bytes);
156}
157
158/*
159 * Return the number of bytes needed for a vm_external_map given the
160 * size of the object to be mapped, i.e. the size of the map that was
161 * created by vm_external_create.
162 */
163vm_size_t
164vm_external_map_size(
165 vm_offset_t size)
166{
167 vm_size_t bytes;
168
169 bytes = stob(size);
170 if (bytes != 0)
171 if (bytes <= SMALL_SIZE) {
172 bytes = SMALL_SIZE;
173 } else {
174 bytes = power_of_2(bytes);
175 }
176 return bytes;
177}
178
179void
180vm_external_copy(
181 vm_external_map_t old_map,
182 vm_size_t old_size,
183 vm_external_map_t new_map)
184{
185 /*
186 * Cannot copy non-existent maps
187 */
188 if ((old_map == VM_EXTERNAL_NULL) || (new_map == VM_EXTERNAL_NULL))
189 return;
190
191 /*
192 * Copy old map to new
193 */
194 memcpy(new_map, old_map, stob(old_size));
195}
196
197boolean_t
198vm_external_within(
199 vm_size_t new_size,
200 vm_size_t old_size)
201{
202 vm_size_t new_bytes;
203 vm_size_t old_bytes;
204
205 assert(new_size >= old_size);
206
207 /*
208 * "old_bytes" is calculated to be the actual amount of space
209 * allocated for a map of size "old_size".
210 */
211 old_bytes = stob(old_size);
212 if (old_bytes <= SMALL_SIZE) old_bytes = SMALL_SIZE;
213 else if (old_bytes <= LARGE_SIZE) old_bytes = power_of_2(old_bytes);
214
215 /*
216 * "new_bytes" is the map size required to map the "new_size" object.
217 * Since the rounding algorithms are the same, we needn't actually
218 * round up new_bytes to get the correct answer
219 */
220 new_bytes = stob(new_size);
221
222 return(new_bytes <= old_bytes);
223}
224
225vm_external_state_t
226_vm_external_state_get(
227 vm_external_map_t map,
228 vm_offset_t offset)
229{
230 unsigned
231 int bit, byte;
232
233 assert (map != VM_EXTERNAL_NULL);
234
55e303ae 235 bit = atop_32(offset);
1c79356b
A
236 byte = bit >> 3;
237 if (map[byte] & (1 << (bit & 07))) {
238 return VM_EXTERNAL_STATE_EXISTS;
239 } else {
240 return VM_EXTERNAL_STATE_ABSENT;
241 }
242}
243
244void
245vm_external_state_set(
246 vm_external_map_t map,
247 vm_offset_t offset)
248{
249 unsigned
250 int bit, byte;
251
252 if (map == VM_EXTERNAL_NULL)
253 return;
254
55e303ae 255 bit = atop_32(offset);
1c79356b
A
256 byte = bit >> 3;
257 map[byte] |= (1 << (bit & 07));
258}
259
260void
261vm_external_state_clr(
262 vm_external_map_t map,
263 vm_offset_t offset)
264{
265 unsigned
266 int bit, byte;
267
268 if (map == VM_EXTERNAL_NULL)
269 return;
270
55e303ae 271 bit = atop_32(offset);
1c79356b
A
272 byte = bit >> 3;
273 map[byte] &= ~(1 << (bit & 07));
274}
275
276void
277vm_external_module_initialize(void)
278{
279}