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