]> git.saurik.com Git - apple/xnu.git/blob - osfmk/default_pager/default_pager.c
xnu-1504.15.3.tar.gz
[apple/xnu.git] / osfmk / default_pager / default_pager.c
1 /*
2 * Copyright (c) 2000-2006 Apple Computer, 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 * @OSF_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56
57 /*
58 * Default pager.
59 * Threads management.
60 * Requests handling.
61 */
62
63 #include "default_pager_internal.h"
64 #include <default_pager/default_pager_object_server.h>
65 #include <kern/host.h>
66 #include <kern/ledger.h>
67 #include <mach/host_info.h>
68 #include <mach/host_priv.h>
69 #include <mach/vm_map.h>
70 #include <ipc/ipc_space.h>
71 #include <vm/vm_kern.h>
72 #include <vm/vm_map.h>
73 #include <vm/vm_protos.h>
74
75 char my_name[] = "(default pager): ";
76
77 #if DEFAULT_PAGER_DEBUG
78 int debug_mask = 0;
79 #endif /* DEFAULT_PAGER_DEBUG */
80
81 /*
82 * Use 16 Kbyte stacks instead of the default 64K.
83 * Use 4 Kbyte waiting stacks instead of the default 8K.
84 */
85
86 vm_size_t cthread_stack_size = 16 *1024;
87 extern vm_size_t cthread_wait_stack_size;
88
89 #ifndef MACH_KERNEL
90 unsigned long long vm_page_mask;
91 int vm_page_shift;
92 #endif
93
94 int norma_mk;
95
96 boolean_t verbose;
97
98 /* task_t default_pager_self; */ /* Our task port. */
99 lck_mtx_t dpt_lock; /* lock for the dpt array struct */
100 default_pager_thread_t **dpt_array;
101
102 memory_object_default_t default_pager_object; /* for memory_object_create. */
103
104 MACH_PORT_FACE default_pager_default_set; /* Port set for "default" thread. */
105 MACH_PORT_FACE default_pager_internal_set; /* Port set for internal objects. */
106 MACH_PORT_FACE default_pager_external_set; /* Port set for external objects. */
107
108 #define DEFAULT_PAGER_INTERNAL_COUNT (4)
109
110
111 /* Memory created by default_pager_object_create should mostly be resident. */
112 #define DEFAULT_PAGER_EXTERNAL_COUNT (2)
113
114 int default_pager_internal_count = DEFAULT_PAGER_INTERNAL_COUNT;
115 /* Number of "internal" threads. */
116 int default_pager_external_count = DEFAULT_PAGER_EXTERNAL_COUNT;
117 /* Number of "external" threads. */
118
119 /*
120 * Forward declarations.
121 */
122 boolean_t default_pager_notify_server(mach_msg_header_t *,
123 mach_msg_header_t *);
124 boolean_t default_pager_demux_object(mach_msg_header_t *,
125 mach_msg_header_t *);
126 boolean_t default_pager_demux_default(mach_msg_header_t *,
127 mach_msg_header_t *);
128 default_pager_thread_t *start_default_pager_thread(int, boolean_t);
129 void default_pager(void);
130 void default_pager_thread(void *);
131 void default_pager_initialize(void);
132 boolean_t dp_parse_argument(char *); /* forward; */
133 unsigned int d_to_i(char *); /* forward; */
134
135 extern int vstruct_def_clshift;
136
137 struct global_stats global_stats;
138
139 /*
140 * Initialize and Run the default pager
141 */
142 void
143 default_pager(void)
144 {
145 int i, id;
146 __unused static char here[] = "default_pager";
147 default_pager_thread_t dpt;
148 kern_return_t kr;
149
150
151
152 /*
153 * Give me space for the thread array and zero it.
154 */
155 i = default_pager_internal_count + default_pager_external_count + 1;
156 dpt_array = (default_pager_thread_t **)
157 kalloc(i * sizeof(default_pager_thread_t *));
158 memset(dpt_array, 0, i * sizeof(default_pager_thread_t *));
159
160 /* Setup my thread structure. */
161 id = 0;
162 dpt.dpt_buffer = 0;
163 dpt.dpt_internal = FALSE;
164 dpt.dpt_initialized_p = TRUE;
165 dpt_array[0] = &dpt;
166
167 /*
168 * Now we create the threads that will actually
169 * manage objects.
170 */
171
172 for (i = 0; i < default_pager_internal_count; i++) {
173 dpt_array[id] = (default_pager_thread_t *)
174 kalloc(sizeof (default_pager_thread_t));
175 if (dpt_array[id] == NULL)
176 Panic("alloc pager thread");
177 kr = vm_allocate(kernel_map, &((dpt_array[id])->dpt_buffer),
178 vm_page_size << vstruct_def_clshift, VM_FLAGS_ANYWHERE);
179 if (kr != KERN_SUCCESS)
180 Panic("alloc thread buffer");
181 kr = vm_map_wire(kernel_map, (dpt_array[id])->dpt_buffer,
182 ((dpt_array[id])->dpt_buffer)
183 +(vm_page_size << vstruct_def_clshift),
184 VM_PROT_DEFAULT,
185 FALSE);
186 if (kr != KERN_SUCCESS)
187 Panic("wire thread buffer");
188 (dpt_array[id])->dpt_internal = TRUE;
189 (dpt_array[id])->dpt_initialized_p = TRUE;
190 (dpt_array[id])->checked_out = FALSE;
191 id++;
192 }
193 DPT_LOCK_INIT(dpt_lock);
194 }
195
196
197
198
199
200
201 /* simple utility: only works for 2^n */
202 int
203 local_log2(
204 unsigned int n)
205 {
206 register int i = 0;
207
208 if(n == 0) return 0;
209
210 while ((n & 1) == 0) {
211 i++;
212 n >>= 1;
213 }
214 return i;
215 }
216
217
218
219
220 /* another simple utility, d_to_i(char*) supporting only decimal
221 * and devoid of range checking; obscure name chosen deliberately
222 * to avoid confusion with semantic-rich POSIX routines */
223 unsigned int
224 d_to_i(char * arg)
225 {
226 unsigned int rval = 0;
227 char ch;
228
229 while ((ch = *arg++) && ch >= '0' && ch <= '9') {
230 rval *= 10;
231 rval += ch - '0';
232 }
233 return(rval);
234 }
235
236
237
238
239 /*
240 * Check for non-disk-partition arguments of the form
241 * attribute=argument
242 * returning TRUE if one if found
243 */
244 boolean_t dp_parse_argument(char *av)
245 {
246 char *rhs = av;
247 __unused static char here[] = "dp_parse_argument";
248
249 /* Check for '-v' flag */
250
251 if (av[0] == '-' && av[1] == 'v' && av[2] == 0) {
252 verbose = TRUE ;
253 return TRUE;
254 }
255
256 /*
257 * If we find a '=' followed by an argument in the string,
258 * check for known arguments
259 */
260 while (*rhs && *rhs != '=')
261 rhs++;
262 if (*rhs && *++rhs) {
263 /* clsize=N pages */
264 if (strprefix(av,"cl")) {
265 if (!bs_set_default_clsize(d_to_i(rhs)))
266 dprintf(("Bad argument (%s) - ignored\n", av));
267 return(TRUE);
268 }
269 /* else if strprefix(av,"another_argument")) {
270 handle_another_argument(av);
271 return(TRUE);
272 } */
273 }
274 return(FALSE);
275 }
276
277 int
278 start_def_pager( __unused char *bs_device )
279 {
280 /*
281 MACH_PORT_FACE master_device_port;
282 */
283 /*
284 MACH_PORT_FACE security_port;
285 MACH_PORT_FACE root_ledger_wired;
286 MACH_PORT_FACE root_ledger_paged;
287 */
288 __unused static char here[] = "main";
289
290
291
292 /*
293 default_pager_host_port = ipc_port_make_send(realhost.host_priv_self);
294 master_device_port = ipc_port_make_send(master_device_port);
295 root_ledger_wired = ipc_port_make_send(root_wired_ledger_port);
296 root_ledger_paged = ipc_port_make_send(root_paged_ledger_port);
297 security_port = ipc_port_make_send(realhost.host_security_self);
298 */
299
300
301 #if NORMA_VM
302 norma_mk = 1;
303 #else
304 norma_mk = 0;
305 #endif
306
307
308 /* setup read buffers, etc */
309 default_pager_initialize();
310
311 #ifndef MACH_KERNEL
312 default_pager();
313 #endif
314
315 /* start the backing store monitor, it runs on a callout thread */
316 default_pager_backing_store_monitor_callout =
317 thread_call_allocate(default_pager_backing_store_monitor, NULL);
318 if (!default_pager_backing_store_monitor_callout)
319 panic("can't start backing store monitor thread");
320 thread_call_enter(default_pager_backing_store_monitor_callout);
321
322 return (0);
323 }
324
325 kern_return_t
326 default_pager_info(
327 memory_object_default_t pager,
328 default_pager_info_t *infop)
329 {
330 uint64_t pages_total, pages_free;
331
332 if (pager != default_pager_object)
333 return KERN_INVALID_ARGUMENT;
334
335 bs_global_info(&pages_total, &pages_free);
336
337 infop->dpi_total_space = (vm_size_t) ptoa_64(pages_total);
338 infop->dpi_free_space = (vm_size_t) ptoa_64(pages_free);
339 infop->dpi_page_size = vm_page_size;
340
341 return KERN_SUCCESS;
342 }
343
344
345 kern_return_t
346 default_pager_info_64(
347 memory_object_default_t pager,
348 default_pager_info_64_t *infop)
349 {
350 uint64_t pages_total, pages_free;
351
352 if (pager != default_pager_object)
353 return KERN_INVALID_ARGUMENT;
354
355 bs_global_info(&pages_total, &pages_free);
356
357 infop->dpi_total_space = ptoa_64(pages_total);
358 infop->dpi_free_space = ptoa_64(pages_free);
359 infop->dpi_page_size = vm_page_size;
360 infop->dpi_flags = 0;
361 if (dp_encryption_inited && dp_encryption == TRUE) {
362 infop->dpi_flags |= DPI_ENCRYPTED;
363 }
364
365 return KERN_SUCCESS;
366 }
367
368 lck_grp_t default_pager_lck_grp;
369 lck_grp_attr_t default_pager_lck_grp_attr;
370 lck_attr_t default_pager_lck_attr;
371
372
373
374 void
375 default_pager_initialize(void)
376 {
377 kern_return_t kr;
378 __unused static char here[] = "default_pager_initialize";
379
380 lck_grp_attr_setdefault(&default_pager_lck_grp_attr);
381 lck_grp_init(&default_pager_lck_grp, "default_pager", &default_pager_lck_grp_attr);
382 lck_attr_setdefault(&default_pager_lck_attr);
383
384 /*
385 * Vm variables.
386 */
387 #ifndef MACH_KERNEL
388 vm_page_mask = vm_page_size - 1;
389 assert((unsigned int) vm_page_size == vm_page_size);
390 vm_page_shift = local_log2((unsigned int) vm_page_size);
391 #endif
392
393 /*
394 * List of all vstructs.
395 */
396 vstruct_zone = zinit(sizeof(struct vstruct),
397 10000 * sizeof(struct vstruct),
398 8192, "vstruct zone");
399 zone_change(vstruct_zone, Z_NOENCRYPT, TRUE);
400
401 VSL_LOCK_INIT();
402 queue_init(&vstruct_list.vsl_queue);
403 vstruct_list.vsl_count = 0;
404
405 VSTATS_LOCK_INIT(&global_stats.gs_lock);
406
407 bs_initialize();
408
409 /*
410 * Exported DMM port.
411 */
412 default_pager_object = ipc_port_alloc_kernel();
413
414
415 /*
416 * Export pager interfaces.
417 */
418 #ifdef USER_PAGER
419 if ((kr = netname_check_in(name_server_port, "UserPager",
420 default_pager_self,
421 default_pager_object))
422 != KERN_SUCCESS) {
423 dprintf(("netname_check_in returned 0x%x\n", kr));
424 exit(1);
425 }
426 #else /* USER_PAGER */
427 {
428 unsigned int clsize;
429 memory_object_default_t dmm;
430
431 dmm = default_pager_object;
432 assert((unsigned int) vm_page_size == vm_page_size);
433 clsize = ((unsigned int) vm_page_size << vstruct_def_clshift);
434 kr = host_default_memory_manager(host_priv_self(), &dmm, clsize);
435 if ((kr != KERN_SUCCESS) ||
436 (dmm != MEMORY_OBJECT_DEFAULT_NULL))
437 Panic("default memory manager");
438
439 }
440 #endif /* USER_PAGER */
441
442
443 }
444