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