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#include <vm/vm_pageout.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 89#ifndef MACH_KERNEL 90unsigned long long vm_page_mask; 91int vm_page_shift; 92#endif 93 94boolean_t verbose; 95 96/* task_t default_pager_self; */ /* Our task port. */ 97lck_mtx_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 135struct global_stats global_stats; 136 137/* 138 * Initialize and Run the default pager 139 */ 140void 141default_pager(void) 142{ 143 int i, id; 144 __unused static char here[] = "default_pager"; 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), 176 vm_page_size << vstruct_def_clshift, VM_FLAGS_ANYWHERE); 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), 182 VM_PROT_DEFAULT, 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; 245 __unused static char here[] = "dp_parse_argument"; 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 276start_def_pager( __unused char *bs_device ) 277{ 278/* 279 MACH_PORT_FACE master_device_port; 280*/ 281/* 282 MACH_PORT_FACE security_port; 283*/ 284 __unused static char here[] = "main"; 285 286 287 288 289 /* setup read buffers, etc */ 290 default_pager_initialize(); 291 292#ifndef MACH_KERNEL 293 default_pager(); 294#endif 295 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 305 return (0); 306} 307 308kern_return_t 309default_pager_info( 310 memory_object_default_t pager, 311 default_pager_info_t *infop) 312{ 313 uint64_t pages_total, pages_free; 314 315 if (pager != default_pager_object) 316 return KERN_INVALID_ARGUMENT; 317 318 bs_global_info(&pages_total, &pages_free); 319 320 infop->dpi_total_space = (vm_size_t) ptoa_64(pages_total); 321 infop->dpi_free_space = (vm_size_t) ptoa_64(pages_free); 322 infop->dpi_page_size = vm_page_size; 323 324 return KERN_SUCCESS; 325} 326 327 328kern_return_t 329default_pager_info_64( 330 memory_object_default_t pager, 331 default_pager_info_64_t *infop) 332{ 333 uint64_t pages_total, pages_free; 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 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 356 357void 358default_pager_initialize(void) 359{ 360 kern_return_t kr; 361 __unused static char here[] = "default_pager_initialize"; 362 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); 366 367 /* 368 * Vm variables. 369 */ 370#ifndef MACH_KERNEL 371 vm_page_mask = vm_page_size - 1; 372 assert((unsigned int) vm_page_size == vm_page_size); 373 vm_page_shift = local_log2((unsigned int) vm_page_size); 374#endif 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 zone_change(vstruct_zone, Z_CALLERACCT, FALSE); 383 zone_change(vstruct_zone, Z_NOENCRYPT, TRUE); 384 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 393 /* 394 * Exported DMM port. 395 */ 396 default_pager_object = ipc_port_alloc_kernel(); 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, 405 default_pager_object)) 406 != KERN_SUCCESS) { 407 dprintf(("netname_check_in returned 0x%x\n", kr)); 408 exit(1); 409 } 410#else /* USER_PAGER */ 411 { 412 unsigned int clsize; 413 memory_object_default_t dmm; 414 415 dmm = default_pager_object; 416 assert((unsigned int) vm_page_size == vm_page_size); 417 clsize = ((unsigned int) vm_page_size << vstruct_def_clshift); 418 kr = host_default_memory_manager(host_priv_self(), &dmm, clsize); 419 if ((kr != KERN_SUCCESS) || 420 (dmm != MEMORY_OBJECT_DEFAULT_NULL)) 421 Panic("default memory manager"); 422 423 } 424#endif /* USER_PAGER */ 425 426 427} 428 429