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