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