]> git.saurik.com Git - apple/xnu.git/blame - osfmk/vm/device_vm.c
xnu-792.6.61.tar.gz
[apple/xnu.git] / osfmk / vm / device_vm.c
CommitLineData
0b4e3aa0 1/*
91447636 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
0b4e3aa0
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
37839358
A
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.
0b4e3aa0 11 *
37839358
A
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
0b4e3aa0
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
37839358
A
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.
0b4e3aa0
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23#include <sys/errno.h>
91447636 24
0b4e3aa0 25#include <mach/mach_types.h>
0b4e3aa0 26#include <mach/kern_return.h>
91447636 27#include <mach/memory_object_control.h>
0b4e3aa0
A
28#include <mach/memory_object_types.h>
29#include <mach/port.h>
30#include <mach/policy.h>
91447636
A
31#include <mach/upl.h>
32#include <kern/kern_types.h>
33#include <kern/ipc_kobject.h>
34#include <kern/host.h>
35#include <kern/thread.h>
0b4e3aa0
A
36#include <ipc/ipc_port.h>
37#include <ipc/ipc_space.h>
0b4e3aa0 38#include <device/device_port.h>
91447636 39#include <vm/memory_object.h>
0b4e3aa0 40#include <vm/vm_pageout.h>
91447636
A
41#include <vm/vm_map.h>
42#include <vm/vm_kern.h>
43#include <vm/vm_pageout.h>
44#include <vm/vm_protos.h>
45
0b4e3aa0 46
0b4e3aa0
A
47/* Device VM COMPONENT INTERFACES */
48
49
50/*
51 * Device PAGER
52 */
53
54
55/* until component support available */
56
57
58
59/* until component support available */
60int device_pager_workaround;
61
62typedef int device_port_t;
63
64typedef struct device_pager {
65 int *pager; /* pager workaround pointer */
66 unsigned int pager_ikot; /* fake ip_kotype() */
67 unsigned int ref_count; /* reference count */
68 memory_object_control_t control_handle; /* mem object's cntrl handle */
69 device_port_t device_handle; /* device_handle */
70 vm_size_t size;
71 int flags;
72} *device_pager_t;
73
74
75
0b4e3aa0
A
76
77device_pager_t
91447636 78device_pager_lookup( /* forward */
0b4e3aa0
A
79 memory_object_t);
80
81device_pager_t
91447636 82device_object_create(void); /* forward */
0b4e3aa0
A
83
84zone_t device_pager_zone;
85
86
87#define DEVICE_PAGER_NULL ((device_pager_t) 0)
88
89
90#define MAX_DNODE 10000
91
92
93
94
95
96/*
97 *
98 */
99void
100device_pager_bootstrap(void)
101{
102 register vm_size_t size;
103
104 size = (vm_size_t) sizeof(struct device_pager);
105 device_pager_zone = zinit(size, (vm_size_t) MAX_DNODE*size,
106 PAGE_SIZE, "device node pager structures");
107
108 return;
109}
110
111/*
112 *
113 */
114memory_object_t
115device_pager_setup(
91447636 116 __unused memory_object_t device,
0b4e3aa0
A
117 int device_handle,
118 vm_size_t size,
119 int flags)
120{
121 device_pager_t device_object;
122
123 device_object = device_object_create();
124 if (device_object == DEVICE_PAGER_NULL)
125 panic("device_pager_setup: device_object_create() failed");
126
127 device_object->device_handle = device_handle;
128 device_object->size = size;
9bccf70c 129 device_object->flags = flags;
0b4e3aa0
A
130
131 return((memory_object_t)device_object);
132}
133
134/*
135 *
136 */
137kern_return_t
138device_pager_populate_object(
139 memory_object_t device,
140 memory_object_offset_t offset,
55e303ae 141 ppnum_t page_num,
0b4e3aa0
A
142 vm_size_t size)
143{
144 device_pager_t device_object;
145 vm_object_t vm_object;
146 kern_return_t kr;
147 upl_t upl;
0b4e3aa0
A
148
149 device_object = device_pager_lookup(device);
150 if(device_object == DEVICE_PAGER_NULL)
151 return KERN_FAILURE;
152
153 vm_object = (vm_object_t)memory_object_control_to_vm_object(
154 device_object->control_handle);
155 if(vm_object == NULL)
156 return KERN_FAILURE;
157
158 kr = vm_object_populate_with_private(
55e303ae 159 vm_object, offset, page_num, size);
0b4e3aa0
A
160 if(kr != KERN_SUCCESS)
161 return kr;
162
163 if(!vm_object->phys_contiguous) {
164 int null_size = 0;
165 kr = vm_object_upl_request(vm_object,
166 (vm_object_offset_t)offset, size, &upl, NULL,
167 &null_size, (UPL_NO_SYNC | UPL_CLEAN_IN_PLACE));
168
169 if(kr != KERN_SUCCESS)
170 panic("device_pager_populate_object: list_req failed");
171
91447636 172 upl_commit(upl, NULL, 0);
0b4e3aa0
A
173 upl_deallocate(upl);
174 }
175
176
177 return kr;
178}
179
180/*
181 *
182 */
183device_pager_t
184device_pager_lookup(
185 memory_object_t name)
186{
187 device_pager_t device_object;
188
189 device_object = (device_pager_t)name;
190 assert(device_object->pager == &device_pager_workaround);
191 return (device_object);
192}
193
194/*
195 *
196 */
197kern_return_t
91447636
A
198device_pager_init(
199 memory_object_t mem_obj,
200 memory_object_control_t control,
201 __unused vm_size_t pg_size)
0b4e3aa0
A
202{
203 device_pager_t device_object;
204 kern_return_t kr;
205 memory_object_attr_info_data_t attributes;
206
207 vm_object_t vm_object;
208
209
210 if (control == MEMORY_OBJECT_CONTROL_NULL)
211 return KERN_INVALID_ARGUMENT;
212
213 device_object = device_pager_lookup(mem_obj);
214
215 memory_object_control_reference(control);
216 device_object->control_handle = control;
217
218
219/* The following settings should be done through an expanded change */
220/* attributes call */
221
222 vm_object = (vm_object_t)memory_object_control_to_vm_object(control);
223 vm_object_lock(vm_object);
224 vm_object->private = TRUE;
225 if(device_object->flags & DEVICE_PAGER_CONTIGUOUS)
226 vm_object->phys_contiguous = TRUE;
227 if(device_object->flags & DEVICE_PAGER_NOPHYSCACHE)
228 vm_object->nophyscache = TRUE;
9bccf70c
A
229
230 vm_object->wimg_bits = device_object->flags & VM_WIMG_MASK;
0b4e3aa0
A
231 vm_object_unlock(vm_object);
232
233
234 attributes.copy_strategy = MEMORY_OBJECT_COPY_DELAY;
235 /* attributes.cluster_size = (1 << (CLUSTER_SHIFT + PAGE_SHIFT));*/
236 attributes.cluster_size = (1 << (PAGE_SHIFT));
237 attributes.may_cache_object = FALSE;
238 attributes.temporary = TRUE;
239
240 kr = memory_object_change_attributes(
241 control,
242 MEMORY_OBJECT_ATTRIBUTE_INFO,
243 (memory_object_info_t) &attributes,
244 MEMORY_OBJECT_ATTR_INFO_COUNT);
245 if (kr != KERN_SUCCESS)
246 panic("device_pager_init: memory_object_change_attributes() failed");
247
248 return(KERN_SUCCESS);
249}
250
251/*
252 *
253 */
91447636 254/*ARGSUSED6*/
0b4e3aa0
A
255kern_return_t
256device_pager_data_return(
91447636
A
257 memory_object_t mem_obj,
258 memory_object_offset_t offset,
259 vm_size_t data_cnt,
260 __unused boolean_t dirty,
261 __unused boolean_t kernel_copy,
262 __unused int upl_flags)
0b4e3aa0
A
263{
264 device_pager_t device_object;
265
266 device_object = device_pager_lookup(mem_obj);
267 if (device_object == DEVICE_PAGER_NULL)
268 panic("device_pager_data_return: lookup failed");
269
91447636
A
270 return device_data_action(device_object->device_handle,
271 (ipc_port_t) device_object,
272 VM_PROT_READ | VM_PROT_WRITE,
273 offset, data_cnt);
0b4e3aa0
A
274}
275
276/*
277 *
278 */
279kern_return_t
280device_pager_data_request(
281 memory_object_t mem_obj,
282 memory_object_offset_t offset,
283 vm_size_t length,
91447636 284 __unused vm_prot_t protection_required)
0b4e3aa0
A
285{
286 device_pager_t device_object;
287
288 device_object = device_pager_lookup(mem_obj);
289
290 if (device_object == DEVICE_PAGER_NULL)
291 panic("device_pager_data_request: lookup failed");
292
91447636
A
293 device_data_action(device_object->device_handle,
294 (ipc_port_t) device_object,
295 VM_PROT_READ, offset, length);
0b4e3aa0
A
296 return KERN_SUCCESS;
297}
298
299/*
300 *
301 */
302void
303device_pager_reference(
304 memory_object_t mem_obj)
305{
306 device_pager_t device_object;
9bccf70c 307 unsigned int new_ref_count;
0b4e3aa0
A
308
309 device_object = device_pager_lookup(mem_obj);
9bccf70c
A
310 new_ref_count = hw_atomic_add(&device_object->ref_count, 1);
311 assert(new_ref_count > 1);
0b4e3aa0
A
312}
313
314/*
315 *
316 */
317void
318device_pager_deallocate(
319 memory_object_t mem_obj)
320{
91447636
A
321 device_pager_t device_object;
322 memory_object_control_t device_control;
0b4e3aa0
A
323
324 device_object = device_pager_lookup(mem_obj);
325
9bccf70c 326 if (hw_atomic_sub(&device_object->ref_count, 1) == 0) {
0b4e3aa0
A
327 if (device_object->device_handle != (device_port_t) NULL) {
328 device_close(device_object->device_handle);
91447636 329 device_object->device_handle = (device_port_t) NULL;
0b4e3aa0 330 }
91447636
A
331 device_control = device_object->control_handle;
332 if (device_control != MEMORY_OBJECT_CONTROL_NULL) {
333 /*
334 * The VM object should already have been disconnected
335 * from the pager at this point.
336 * We still have to release the "memory object control"
337 * handle.
338 */
339 assert(device_control->object == VM_OBJECT_NULL);
340 memory_object_control_deallocate(device_control);
341 device_object->control_handle =
342 MEMORY_OBJECT_CONTROL_NULL;
343 }
344
345 zfree(device_pager_zone, device_object);
0b4e3aa0
A
346 }
347 return;
348}
349
350kern_return_t
351device_pager_data_initialize(
91447636
A
352 __unused memory_object_t mem_obj,
353 __unused memory_object_offset_t offset,
354 __unused vm_size_t data_cnt)
0b4e3aa0 355{
91447636 356 panic("device_pager_data_initialize");
0b4e3aa0
A
357 return KERN_FAILURE;
358}
359
360kern_return_t
361device_pager_data_unlock(
91447636
A
362 __unused memory_object_t mem_obj,
363 __unused memory_object_offset_t offset,
364 __unused vm_size_t size,
365 __unused vm_prot_t desired_access)
0b4e3aa0
A
366{
367 return KERN_FAILURE;
368}
369
91447636 370kern_return_t
0b4e3aa0 371device_pager_terminate(
91447636 372 __unused memory_object_t mem_obj)
0b4e3aa0
A
373{
374 return KERN_SUCCESS;
375}
376
377
378
379/*
380 *
381 */
382kern_return_t
383device_pager_synchronize(
384 memory_object_t mem_obj,
385 memory_object_offset_t offset,
386 vm_offset_t length,
91447636 387 __unused vm_sync_t sync_flags)
0b4e3aa0
A
388{
389 device_pager_t device_object;
390
391 device_object = device_pager_lookup(mem_obj);
392
393 memory_object_synchronize_completed(
394 device_object->control_handle, offset, length);
395
396 return KERN_SUCCESS;
397}
398
399/*
400 *
401 */
402kern_return_t
403device_pager_unmap(
91447636 404 __unused memory_object_t mem_obj)
0b4e3aa0
A
405{
406 return KERN_SUCCESS;
407}
408
409
410
411/*
412 *
413 */
414device_pager_t
415device_object_create()
416{
417 register device_pager_t device_object;
418
419 device_object = (struct device_pager *) zalloc(device_pager_zone);
420 if (device_object == DEVICE_PAGER_NULL)
421 return(DEVICE_PAGER_NULL);
422 device_object->pager = &device_pager_workaround;
423 device_object->pager_ikot = IKOT_MEMORY_OBJECT;
424 device_object->ref_count = 1;
425 device_object->control_handle = MEMORY_OBJECT_CONTROL_NULL;
426
427
428 return(device_object);
429}
430