|
|
1.1.1.2 root 1: /*
1.1 root 2: * Mach Operating System
3: * Copyright (c) 1993-1989 Carnegie Mellon University
4: * All Rights Reserved.
1.1.1.2 root 5: *
1.1 root 6: * Permission to use, copy, modify and distribute this software and its
7: * documentation is hereby granted, provided that both the copyright
8: * notice and this permission notice appear in all copies of the
9: * software, derivative works or modified versions, and any portions
10: * thereof, and that both notices appear in supporting documentation.
1.1.1.2 root 11: *
1.1 root 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
1.1.1.2 root 15: *
1.1 root 16: * Carnegie Mellon requests users of this software to return to
1.1.1.2 root 17: *
1.1 root 18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
1.1.1.2 root 22: *
1.1 root 23: * any improvements or extensions that they make and grant Carnegie Mellon
24: * the rights to redistribute these changes.
25: */
26: /*
27: * Author: David B. Golub, Carnegie Mellon University
28: * Date: 3/89
29: *
30: * Device pager.
31: */
1.1.1.3 root 32:
33: #include <string.h>
1.1 root 34:
35: #include <mach/boolean.h>
36: #include <mach/port.h>
37: #include <mach/message.h>
38: #include <mach/std_types.h>
39: #include <mach/mach_types.h>
40:
41: #include <ipc/ipc_port.h>
42: #include <ipc/ipc_space.h>
43:
1.1.1.3 root 44: #include <kern/debug.h>
45: #include <kern/printf.h>
1.1 root 46: #include <kern/queue.h>
1.1.1.3 root 47: #include <kern/slab.h>
1.1 root 48:
49: #include <vm/vm_page.h>
50: #include <vm/vm_kern.h>
1.1.1.3 root 51: #include <vm/vm_user.h>
1.1 root 52:
53: #include <device/device_types.h>
54: #include <device/ds_routines.h>
55: #include <device/dev_hdr.h>
56: #include <device/io_req.h>
1.1.1.3 root 57: #include <device/memory_object_reply.user.h>
1.1.1.4 root 58: #include <device/dev_pager.h>
59: #include <device/blkio.h>
1.1 root 60:
61: /*
62: * The device pager routines are called directly from the message
63: * system (via mach_msg), and thus run in the kernel-internal
64: * environment. All ports are in internal form (ipc_port_t),
65: * and must be correctly reference-counted in order to be saved
66: * in other data structures. Kernel routines may be called
67: * directly. Kernel types are used for data objects (tasks,
68: * memory objects, ports). The only IPC routines that may be
69: * called are ones that masquerade as the kernel task (via
70: * msg_send_from_kernel).
71: *
72: * Port rights and references are maintained as follows:
73: * Memory object port:
74: * The device_pager task has all rights.
75: * Memory object control port:
76: * The device_pager task has only send rights.
77: * Memory object name port:
78: * The device_pager task has only send rights.
79: * The name port is not even recorded.
80: * Regardless how the object is created, the control and name
81: * ports are created by the kernel and passed through the memory
82: * management interface.
83: *
84: * The device_pager assumes that access to its memory objects
85: * will not be propagated to more that one host, and therefore
86: * provides no consistency guarantees beyond those made by the
87: * kernel.
88: *
89: * In the event that more than one host attempts to use a device
90: * memory object, the device_pager will only record the last set
91: * of port names. [This can happen with only one host if a new
92: * mapping is being established while termination of all previous
93: * mappings is taking place.] Currently, the device_pager assumes
94: * that its clients adhere to the initialization and termination
95: * protocols in the memory management interface; otherwise, port
96: * rights or out-of-line memory from erroneous messages may be
97: * allowed to accumulate.
98: *
99: * [The phrase "currently" has been used above to denote aspects of
100: * the implementation that could be altered without changing the rest
101: * of the basic documentation.]
102: */
103:
104: /*
105: * Basic device pager structure.
106: */
107: struct dev_pager {
108: decl_simple_lock_data(, lock) /* lock for reference count */
109: int ref_count; /* reference count */
110: int client_count; /* How many memory_object_create
111: * calls have we received */
112: ipc_port_t pager; /* pager port */
113: ipc_port_t pager_request; /* Known request port */
114: ipc_port_t pager_name; /* Known name port */
115: mach_device_t device; /* Device handle */
116: int type; /* to distinguish */
117: #define DEV_PAGER_TYPE 0
118: #define CHAR_PAGER_TYPE 1
119: /* char pager specifics */
120: int prot;
121: vm_size_t size;
122: };
123: typedef struct dev_pager *dev_pager_t;
124: #define DEV_PAGER_NULL ((dev_pager_t)0)
125:
126:
1.1.1.3 root 127: struct kmem_cache dev_pager_cache;
1.1 root 128:
1.1.1.3 root 129: void dev_pager_reference(dev_pager_t ds)
1.1 root 130: {
131: simple_lock(&ds->lock);
132: ds->ref_count++;
133: simple_unlock(&ds->lock);
134: }
135:
1.1.1.3 root 136: void dev_pager_deallocate(dev_pager_t ds)
1.1 root 137: {
138: simple_lock(&ds->lock);
139: if (--ds->ref_count > 0) {
140: simple_unlock(&ds->lock);
141: return;
142: }
143:
144: simple_unlock(&ds->lock);
1.1.1.3 root 145: kmem_cache_free(&dev_pager_cache, (vm_offset_t)ds);
1.1 root 146: }
147:
148: /*
149: * A hash table of ports for device_pager backed objects.
150: */
151:
152: #define DEV_PAGER_HASH_COUNT 127
153:
154: struct dev_pager_entry {
155: queue_chain_t links;
156: ipc_port_t name;
157: dev_pager_t pager_rec;
158: };
159: typedef struct dev_pager_entry *dev_pager_entry_t;
160:
161: queue_head_t dev_pager_hashtable[DEV_PAGER_HASH_COUNT];
1.1.1.3 root 162: struct kmem_cache dev_pager_hash_cache;
1.1 root 163: decl_simple_lock_data(,
164: dev_pager_hash_lock)
165:
166: #define dev_pager_hash(name_port) \
1.1.1.3 root 167: (((vm_offset_t)(name_port) & 0xffffff) % DEV_PAGER_HASH_COUNT)
1.1 root 168:
169: void dev_pager_hash_init(void)
170: {
1.1.1.3 root 171: int i;
172: vm_size_t size;
1.1 root 173:
174: size = sizeof(struct dev_pager_entry);
1.1.1.3 root 175: kmem_cache_init(&dev_pager_hash_cache, "dev_pager_entry", size, 0,
1.1.1.5 root 176: NULL, 0);
1.1 root 177: for (i = 0; i < DEV_PAGER_HASH_COUNT; i++)
178: queue_init(&dev_pager_hashtable[i]);
179: simple_lock_init(&dev_pager_hash_lock);
180: }
181:
182: void dev_pager_hash_insert(
1.1.1.4 root 183: const ipc_port_t name_port,
184: const dev_pager_t rec)
1.1 root 185: {
1.1.1.3 root 186: dev_pager_entry_t new_entry;
1.1 root 187:
1.1.1.3 root 188: new_entry = (dev_pager_entry_t) kmem_cache_alloc(&dev_pager_hash_cache);
1.1 root 189: new_entry->name = name_port;
190: new_entry->pager_rec = rec;
191:
192: simple_lock(&dev_pager_hash_lock);
193: queue_enter(&dev_pager_hashtable[dev_pager_hash(name_port)],
194: new_entry, dev_pager_entry_t, links);
195: simple_unlock(&dev_pager_hash_lock);
196: }
197:
1.1.1.4 root 198: void dev_pager_hash_delete(const ipc_port_t name_port)
1.1 root 199: {
1.1.1.3 root 200: queue_t bucket;
201: dev_pager_entry_t entry;
1.1 root 202:
203: bucket = &dev_pager_hashtable[dev_pager_hash(name_port)];
204:
205: simple_lock(&dev_pager_hash_lock);
206: for (entry = (dev_pager_entry_t)queue_first(bucket);
207: !queue_end(bucket, &entry->links);
208: entry = (dev_pager_entry_t)queue_next(&entry->links)) {
209: if (entry->name == name_port) {
210: queue_remove(bucket, entry, dev_pager_entry_t, links);
211: break;
212: }
213: }
214: simple_unlock(&dev_pager_hash_lock);
215: if (entry)
1.1.1.3 root 216: kmem_cache_free(&dev_pager_hash_cache, (vm_offset_t)entry);
1.1 root 217: }
218:
1.1.1.4 root 219: dev_pager_t dev_pager_hash_lookup(const ipc_port_t name_port)
1.1 root 220: {
1.1.1.3 root 221: queue_t bucket;
222: dev_pager_entry_t entry;
223: dev_pager_t pager;
1.1 root 224:
225: bucket = &dev_pager_hashtable[dev_pager_hash(name_port)];
226:
227: simple_lock(&dev_pager_hash_lock);
228: for (entry = (dev_pager_entry_t)queue_first(bucket);
229: !queue_end(bucket, &entry->links);
230: entry = (dev_pager_entry_t)queue_next(&entry->links)) {
231: if (entry->name == name_port) {
232: pager = entry->pager_rec;
233: dev_pager_reference(pager);
234: simple_unlock(&dev_pager_hash_lock);
235: return (pager);
236: }
237: }
238: simple_unlock(&dev_pager_hash_lock);
239: return (DEV_PAGER_NULL);
240: }
241:
242: kern_return_t device_pager_setup(
1.1.1.4 root 243: const mach_device_t device,
244: int prot,
245: vm_offset_t offset,
246: vm_size_t size,
247: mach_port_t *pager)
1.1 root 248: {
1.1.1.3 root 249: dev_pager_t d;
1.1 root 250:
251: /*
252: * Verify the device is indeed mappable
253: */
254: if (!device->dev_ops->d_mmap || (device->dev_ops->d_mmap == nomap))
255: return (D_INVALID_OPERATION);
256:
257: /*
258: * Allocate a structure to hold the arguments
259: * and port to represent this object.
260: */
261:
262: d = dev_pager_hash_lookup((ipc_port_t)device); /* HACK */
263: if (d != DEV_PAGER_NULL) {
264: *pager = (mach_port_t) ipc_port_make_send(d->pager);
265: dev_pager_deallocate(d);
266: return (D_SUCCESS);
267: }
268:
1.1.1.3 root 269: d = (dev_pager_t) kmem_cache_alloc(&dev_pager_cache);
1.1 root 270: if (d == DEV_PAGER_NULL)
271: return (KERN_RESOURCE_SHORTAGE);
272:
273: simple_lock_init(&d->lock);
274: d->ref_count = 1;
275:
276: /*
277: * Allocate the pager port.
278: */
279: d->pager = ipc_port_alloc_kernel();
280: if (d->pager == IP_NULL) {
281: dev_pager_deallocate(d);
282: return (KERN_RESOURCE_SHORTAGE);
283: }
284:
285: d->client_count = 0;
286: d->pager_request = IP_NULL;
287: d->pager_name = IP_NULL;
288: d->device = device;
289: mach_device_reference(device);
290: d->prot = prot;
291: d->size = round_page(size);
292: if (device->dev_ops->d_mmap == block_io_mmap) {
293: d->type = DEV_PAGER_TYPE;
294: } else {
295: d->type = CHAR_PAGER_TYPE;
296: }
297:
298: dev_pager_hash_insert(d->pager, d);
299: dev_pager_hash_insert((ipc_port_t)device, d); /* HACK */
300:
301: *pager = (mach_port_t) ipc_port_make_send(d->pager);
302: return (KERN_SUCCESS);
303: }
304:
305: /*
306: * Routine: device_pager_release
307: * Purpose:
308: * Relinquish any references or rights that were
309: * associated with the result of a call to
310: * device_pager_setup.
311: */
312: void device_pager_release(memory_object_t object)
313: {
314: if (MACH_PORT_VALID(object))
315: ipc_port_release_send((ipc_port_t) object);
316: }
317:
318: boolean_t device_pager_debug = FALSE;
319:
320: kern_return_t device_pager_data_request(
1.1.1.4 root 321: const ipc_port_t pager,
322: const ipc_port_t pager_request,
323: vm_offset_t offset,
324: vm_size_t length,
325: vm_prot_t protection_required)
1.1 root 326: {
1.1.1.3 root 327: dev_pager_t ds;
1.1 root 328:
329: if (device_pager_debug)
1.1.1.3 root 330: printf("(device_pager)data_request: pager=%p, offset=0x%lx, length=0x%x\n",
1.1 root 331: pager, offset, length);
332:
1.1.1.4 root 333: ds = dev_pager_hash_lookup(pager);
1.1 root 334: if (ds == DEV_PAGER_NULL)
335: panic("(device_pager)data_request: lookup failed");
336:
337: if (ds->pager_request != pager_request)
338: panic("(device_pager)data_request: bad pager_request");
339:
340: if (ds->type == CHAR_PAGER_TYPE) {
1.1.1.3 root 341: vm_object_t object;
1.1 root 342:
343: object = vm_object_lookup(pager_request);
344: if (object == VM_OBJECT_NULL) {
345: (void) r_memory_object_data_error(pager_request,
346: offset, length,
347: KERN_FAILURE);
348: dev_pager_deallocate(ds);
349: return (KERN_SUCCESS);
350: }
351:
352: vm_object_page_map(object,
353: offset, length,
1.1.1.4 root 354: device_map_page, (void *)ds);
1.1 root 355:
356: vm_object_deallocate(object);
357: }
358: else {
359: panic("(device_pager)data_request: dev pager");
360: }
361:
362: dev_pager_deallocate(ds);
363:
364: return (KERN_SUCCESS);
365: }
366:
367: kern_return_t device_pager_copy(
1.1.1.4 root 368: const ipc_port_t pager,
369: const ipc_port_t pager_request,
1.1.1.3 root 370: vm_offset_t offset,
371: vm_size_t length,
1.1.1.4 root 372: const ipc_port_t new_pager)
1.1 root 373: {
374: panic("(device_pager)copy: called");
375: }
376:
377: kern_return_t
378: device_pager_supply_completed(
1.1.1.4 root 379: const ipc_port_t pager,
380: const ipc_port_t pager_request,
1.1 root 381: vm_offset_t offset,
382: vm_size_t length,
383: kern_return_t result,
384: vm_offset_t error_offset)
385: {
386: panic("(device_pager)supply_completed: called");
387: }
388:
389: kern_return_t
390: device_pager_data_return(
1.1.1.4 root 391: const ipc_port_t pager,
392: const ipc_port_t pager_request,
1.1 root 393: vm_offset_t offset,
1.1.1.3 root 394: pointer_t addr,
1.1 root 395: vm_size_t data_cnt,
396: boolean_t dirty,
397: boolean_t kernel_copy)
398: {
399: panic("(device_pager)data_return: called");
400: }
401:
402: kern_return_t
403: device_pager_change_completed(
1.1.1.4 root 404: const ipc_port_t pager,
1.1 root 405: boolean_t may_cache,
406: memory_object_copy_strategy_t copy_strategy)
407: {
408: panic("(device_pager)change_completed: called");
409: }
410:
411: /*
412: * The mapping function takes a byte offset, but returns
413: * a machine-dependent page frame number. We convert
414: * that into something that the pmap module will
415: * accept later.
416: */
417: vm_offset_t device_map_page(
418: void *dsp,
419: vm_offset_t offset)
420: {
1.1.1.3 root 421: dev_pager_t ds = (dev_pager_t) dsp;
1.1 root 422:
423: return pmap_phys_address(
424: (*(ds->device->dev_ops->d_mmap))
425: (ds->device->dev_number, offset, ds->prot));
426: }
427:
428: kern_return_t device_pager_init_pager(
1.1.1.4 root 429: const ipc_port_t pager,
430: const ipc_port_t pager_request,
431: const ipc_port_t pager_name,
432: vm_size_t pager_page_size)
1.1 root 433: {
1.1.1.3 root 434: dev_pager_t ds;
1.1 root 435:
436: if (device_pager_debug)
1.1.1.3 root 437: printf("(device_pager)init: pager=%p, request=%p, name=%p\n",
1.1 root 438: pager, pager_request, pager_name);
439:
440: assert(pager_page_size == PAGE_SIZE);
441: assert(IP_VALID(pager_request));
442: assert(IP_VALID(pager_name));
443:
444: ds = dev_pager_hash_lookup(pager);
445: assert(ds != DEV_PAGER_NULL);
446:
447: assert(ds->client_count == 0);
448: assert(ds->pager_request == IP_NULL);
449: assert(ds->pager_name == IP_NULL);
450:
451: ds->client_count = 1;
452:
453: /*
454: * We save the send rights for the request and name ports.
455: */
456:
457: ds->pager_request = pager_request;
458: ds->pager_name = pager_name;
459:
460: if (ds->type == CHAR_PAGER_TYPE) {
461: /*
462: * Reply that the object is ready
463: */
1.1.1.6 ! root 464: (void) r_memory_object_ready(pager_request,
! 465: FALSE, /* do not cache */
! 466: MEMORY_OBJECT_COPY_NONE);
1.1 root 467: } else {
1.1.1.6 ! root 468: (void) r_memory_object_ready(pager_request,
! 469: TRUE, /* cache */
! 470: MEMORY_OBJECT_COPY_DELAY);
1.1 root 471: }
472:
473: dev_pager_deallocate(ds);
474: return (KERN_SUCCESS);
475: }
476:
477: kern_return_t device_pager_terminate(
1.1.1.4 root 478: const ipc_port_t pager,
479: const ipc_port_t pager_request,
480: const ipc_port_t pager_name)
1.1 root 481: {
1.1.1.3 root 482: dev_pager_t ds;
1.1 root 483:
484: assert(IP_VALID(pager_request));
485: assert(IP_VALID(pager_name));
486:
487: ds = dev_pager_hash_lookup(pager);
488: assert(ds != DEV_PAGER_NULL);
489:
490: assert(ds->client_count == 1);
491: assert(ds->pager_request == pager_request);
492: assert(ds->pager_name == pager_name);
493:
494: dev_pager_hash_delete(ds->pager);
495: dev_pager_hash_delete((ipc_port_t)ds->device); /* HACK */
496: mach_device_deallocate(ds->device);
497:
498: /* release the send rights we have saved from the init call */
499:
500: ipc_port_release_send(pager_request);
501: ipc_port_release_send(pager_name);
502:
503: /* release the naked receive rights we just acquired */
504:
505: ipc_port_release_receive(pager_request);
506: ipc_port_release_receive(pager_name);
507:
508: /* release the kernel's receive right for the pager port */
509:
510: ipc_port_dealloc_kernel(pager);
511:
512: /* once for ref from lookup, once to make it go away */
513: dev_pager_deallocate(ds);
514: dev_pager_deallocate(ds);
515:
516: return (KERN_SUCCESS);
517: }
518:
519: kern_return_t device_pager_data_unlock(
1.1.1.4 root 520: const ipc_port_t memory_object,
521: const ipc_port_t memory_control_port,
1.1 root 522: vm_offset_t offset,
523: vm_size_t length,
524: vm_prot_t desired_access)
525: {
526: panic("(device_pager)data_unlock: called");
527: return (KERN_FAILURE);
528: }
529:
530: kern_return_t device_pager_lock_completed(
1.1.1.4 root 531: const ipc_port_t memory_object,
532: const ipc_port_t pager_request_port,
533: vm_offset_t offset,
534: vm_size_t length)
1.1 root 535: {
536: panic("(device_pager)lock_completed: called");
537: return (KERN_FAILURE);
538: }
539:
540: void device_pager_init(void)
541: {
1.1.1.3 root 542: vm_size_t size;
1.1 root 543:
544: /*
1.1.1.3 root 545: * Initialize cache of paging structures.
1.1 root 546: */
547: size = sizeof(struct dev_pager);
1.1.1.3 root 548: kmem_cache_init(&dev_pager_cache, "dev_pager", size, 0,
1.1.1.5 root 549: NULL, 0);
1.1 root 550:
551: /*
552: * Initialize the name port hashing stuff.
553: */
554: dev_pager_hash_init();
555: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.