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