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