|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1993-1989 Carnegie Mellon University
4: * All Rights Reserved.
5: *
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.
11: *
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.
15: *
16: * Carnegie Mellon requests users of this software to return to
17: *
18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
22: *
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: */
32: #include <norma_vm.h>
33:
34: #include <mach/boolean.h>
35: #include <mach/port.h>
36: #include <mach/message.h>
37: #include <mach/std_types.h>
38: #include <mach/mach_types.h>
39:
40: #include <ipc/ipc_port.h>
41: #include <ipc/ipc_space.h>
42:
43: #include <kern/queue.h>
44: #include <kern/zalloc.h>
45: #include <kern/kalloc.h>
46:
47: #include <vm/vm_page.h>
48: #include <vm/vm_kern.h>
49:
50: #include <device/device_types.h>
51: #include <device/ds_routines.h>
52: #include <device/dev_hdr.h>
53:
54: #include "../oskit/ds_oskit.h"
55:
56: extern vm_offset_t block_io_mmap(); /* dummy routine to allow
57: mmap for block devices */
58:
59: /*
60: * The device pager routines are called directly from the message
61: * system (via mach_msg), and thus run in the kernel-internal
62: * environment. All ports are in internal form (ipc_port_t),
63: * and must be correctly reference-counted in order to be saved
64: * in other data structures. Kernel routines may be called
65: * directly. Kernel types are used for data objects (tasks,
66: * memory objects, ports). The only IPC routines that may be
67: * called are ones that masquerade as the kernel task (via
68: * msg_send_from_kernel).
69: *
70: * Port rights and references are maintained as follows:
71: * Memory object port:
72: * The device_pager task has all rights.
73: * Memory object control port:
74: * The device_pager task has only send rights.
75: * Memory object name port:
76: * The device_pager task has only send rights.
77: * The name port is not even recorded.
78: * Regardless how the object is created, the control and name
79: * ports are created by the kernel and passed through the memory
80: * management interface.
81: *
82: * The device_pager assumes that access to its memory objects
83: * will not be propagated to more that one host, and therefore
84: * provides no consistency guarantees beyond those made by the
85: * kernel.
86: *
87: * In the event that more than one host attempts to use a device
88: * memory object, the device_pager will only record the last set
89: * of port names. [This can happen with only one host if a new
90: * mapping is being established while termination of all previous
91: * mappings is taking place.] Currently, the device_pager assumes
92: * that its clients adhere to the initialization and termination
93: * protocols in the memory management interface; otherwise, port
94: * rights or out-of-line memory from erroneous messages may be
95: * allowed to accumulate.
96: *
97: * [The phrase "currently" has been used above to denote aspects of
98: * the implementation that could be altered without changing the rest
99: * of the basic documentation.]
100: */
101:
102: /*
103: * Basic device pager structure.
104: */
105: struct dev_pager {
106: decl_simple_lock_data(, lock) /* lock for reference count */
107: int ref_count; /* reference count */
108: int client_count; /* How many memory_object_create
109: * calls have we received */
110: ipc_port_t pager; /* pager port */
111: ipc_port_t pager_request; /* Known request port */
112: ipc_port_t pager_name; /* Known name port */
113: device_t device; /* Device handle */
114: vm_prot_t prot;
115: };
116: typedef struct dev_pager *dev_pager_t;
117: #define DEV_PAGER_NULL ((dev_pager_t)0)
118:
119:
120: zone_t dev_pager_zone;
121:
122: void dev_pager_reference(register dev_pager_t ds)
123: {
124: simple_lock(&ds->lock);
125: ds->ref_count++;
126: simple_unlock(&ds->lock);
127: }
128:
129: void dev_pager_deallocate(register dev_pager_t ds)
130: {
131: simple_lock(&ds->lock);
132: if (--ds->ref_count > 0) {
133: simple_unlock(&ds->lock);
134: return;
135: }
136:
137: simple_unlock(&ds->lock);
138: zfree(dev_pager_zone, (vm_offset_t)ds);
139: }
140:
141: /*
142: * A hash table of ports for device_pager backed objects.
143: */
144:
145: #define DEV_PAGER_HASH_COUNT 127
146:
147: struct dev_pager_entry {
148: queue_chain_t links;
149: ipc_port_t name;
150: dev_pager_t pager_rec;
151: };
152: typedef struct dev_pager_entry *dev_pager_entry_t;
153:
154: queue_head_t dev_pager_hashtable[DEV_PAGER_HASH_COUNT];
155: zone_t dev_pager_hash_zone;
156: decl_simple_lock_data(,
157: dev_pager_hash_lock)
158:
159: #define dev_pager_hash(name_port) \
160: (((natural_t)(name_port) & 0xffffff) % DEV_PAGER_HASH_COUNT)
161:
162: void dev_pager_hash_init(void)
163: {
164: register int i;
165: register vm_size_t size;
166:
167: size = sizeof(struct dev_pager_entry);
168: dev_pager_hash_zone = zinit(
169: size,
170: size * 1000,
171: PAGE_SIZE,
172: FALSE,
173: "dev_pager port hash");
174: for (i = 0; i < DEV_PAGER_HASH_COUNT; i++)
175: queue_init(&dev_pager_hashtable[i]);
176: simple_lock_init(&dev_pager_hash_lock);
177: }
178:
179: void dev_pager_hash_insert(
180: ipc_port_t name_port,
181: dev_pager_t rec)
182: {
183: register dev_pager_entry_t new_entry;
184:
185: new_entry = (dev_pager_entry_t) zalloc(dev_pager_hash_zone);
186: new_entry->name = name_port;
187: new_entry->pager_rec = rec;
188:
189: simple_lock(&dev_pager_hash_lock);
190: queue_enter(&dev_pager_hashtable[dev_pager_hash(name_port)],
191: new_entry, dev_pager_entry_t, links);
192: simple_unlock(&dev_pager_hash_lock);
193: }
194:
195: void dev_pager_hash_delete(ipc_port_t name_port)
196: {
197: register queue_t bucket;
198: register dev_pager_entry_t entry;
199:
200: bucket = &dev_pager_hashtable[dev_pager_hash(name_port)];
201:
202: simple_lock(&dev_pager_hash_lock);
203: for (entry = (dev_pager_entry_t)queue_first(bucket);
204: !queue_end(bucket, &entry->links);
205: entry = (dev_pager_entry_t)queue_next(&entry->links)) {
206: if (entry->name == name_port) {
207: queue_remove(bucket, entry, dev_pager_entry_t, links);
208: break;
209: }
210: }
211: simple_unlock(&dev_pager_hash_lock);
212: if (entry)
213: zfree(dev_pager_hash_zone, (vm_offset_t)entry);
214: }
215:
216: dev_pager_t dev_pager_hash_lookup(ipc_port_t name_port)
217: {
218: register queue_t bucket;
219: register dev_pager_entry_t entry;
220: register dev_pager_t pager;
221:
222: bucket = &dev_pager_hashtable[dev_pager_hash(name_port)];
223:
224: simple_lock(&dev_pager_hash_lock);
225: for (entry = (dev_pager_entry_t)queue_first(bucket);
226: !queue_end(bucket, &entry->links);
227: entry = (dev_pager_entry_t)queue_next(&entry->links)) {
228: if (entry->name == name_port) {
229: pager = entry->pager_rec;
230: dev_pager_reference(pager);
231: simple_unlock(&dev_pager_hash_lock);
232: return (pager);
233: }
234: }
235: simple_unlock(&dev_pager_hash_lock);
236: return (DEV_PAGER_NULL);
237: }
238:
239: kern_return_t device_pager_setup(
240: device_t device,
241: int prot,
242: vm_offset_t offset,
243: vm_size_t size,
244: mach_port_t *pager)
245: {
246: register dev_pager_t d;
247:
248: /*
249: * Allocate a structure to hold the arguments
250: * and port to represent this object.
251: */
252:
253: d = dev_pager_hash_lookup((ipc_port_t)device); /* HACK */
254: if (d != DEV_PAGER_NULL) {
255: *pager = (mach_port_t) ipc_port_make_send(d->pager);
256: dev_pager_deallocate(d);
257: return (D_SUCCESS);
258: }
259:
260: d = (dev_pager_t) zalloc(dev_pager_zone);
261: if (d == DEV_PAGER_NULL)
262: return (KERN_RESOURCE_SHORTAGE);
263:
264: simple_lock_init(&d->lock);
265: d->ref_count = 1;
266:
267: /*
268: * Allocate the pager port.
269: */
270: d->pager = ipc_port_alloc_kernel();
271: if (d->pager == IP_NULL) {
272: dev_pager_deallocate(d);
273: return (KERN_RESOURCE_SHORTAGE);
274: }
275:
276: d->client_count = 0;
277: d->pager_request = IP_NULL;
278: d->pager_name = IP_NULL;
279: d->device = device;
280: device_reference(device);
281: d->prot = prot;
282:
283: dev_pager_hash_insert(d->pager, d);
284: dev_pager_hash_insert((ipc_port_t)device, d); /* HACK */
285:
286: *pager = (mach_port_t) ipc_port_make_send(d->pager);
287: return (KERN_SUCCESS);
288: }
289:
290: /*
291: * Routine: device_pager_release
292: * Purpose:
293: * Relinquish any references or rights that were
294: * associated with the result of a call to
295: * device_pager_setup.
296: */
297: void device_pager_release(memory_object_t object)
298: {
299: if (MACH_PORT_VALID(object))
300: ipc_port_release_send((ipc_port_t) object);
301: }
302:
303: boolean_t device_pager_debug = FALSE;
304:
305: boolean_t device_pager_data_request_done(); /* forward */
306: boolean_t device_pager_data_write_done(); /* forward */
307:
308:
309: kern_return_t device_pager_data_request(
310: ipc_port_t pager,
311: ipc_port_t pager_request,
312: vm_offset_t offset,
313: vm_size_t length,
314: vm_prot_t protection_required)
315: {
316: register dev_pager_t ds;
317: register vm_object_t object;
318: vm_offset_t device_map_page(void *,vm_offset_t);
319:
320: #ifdef lint
321: protection_required++;
322: #endif /* lint */
323:
324: if (device_pager_debug)
325: printf("(device_pager)data_request: pager=%d, offset=0x%x, length=0x%x\n",
326: pager, offset, length);
327:
328: ds = dev_pager_hash_lookup((ipc_port_t)pager);
329: if (ds == DEV_PAGER_NULL)
330: panic("(device_pager)data_request: lookup failed");
331:
332: if (ds->pager_request != pager_request)
333: panic("(device_pager)data_request: bad pager_request");
334:
335: #if NORMA_VM
336: object = vm_object_lookup(pager);
337: #else /* NORMA_VM */
338: object = vm_object_lookup(pager_request);
339: #endif /* NORMA_VM */
340: if (object == VM_OBJECT_NULL) {
341: (void) r_memory_object_data_error(pager_request,
342: offset, length,
343: KERN_FAILURE);
344: dev_pager_deallocate(ds);
345: return (KERN_SUCCESS);
346: }
347:
348: vm_object_page_map(object,
349: offset, length,
350: device_map_page, (char *)ds);
351:
352: vm_object_deallocate(object);
353:
354: dev_pager_deallocate(ds);
355:
356: return (KERN_SUCCESS);
357: }
358:
359: #if 0
360: /*
361: * Always called by io_done thread.
362: */
363: boolean_t device_pager_data_request_done(register io_req_t ior)
364: {
365: vm_offset_t start_alloc, end_alloc;
366: vm_size_t size_read;
367:
368: if (ior->io_error == D_SUCCESS) {
369: size_read = ior->io_count;
370: if (ior->io_residual) {
371: if (device_pager_debug)
372: printf("(device_pager)data_request_done: r: 0x%x\n",ior->io_residual);
373: bzero( (char *) (&ior->io_data[ior->io_count -
374: ior->io_residual]),
375: (unsigned) ior->io_residual);
376: }
377: } else {
378: size_read = ior->io_count - ior->io_residual;
379: }
380:
381: start_alloc = trunc_page((vm_offset_t)ior->io_data);
382: end_alloc = start_alloc + round_page(ior->io_alloc_size);
383:
384: if (ior->io_error == D_SUCCESS) {
385: vm_map_copy_t copy;
386: kern_return_t kr;
387:
388: kr = vm_map_copyin(kernel_map, (vm_offset_t)ior->io_data,
389: size_read, TRUE, ©);
390: if (kr != KERN_SUCCESS)
391: panic("device_pager_data_request_done");
392:
393: (void) r_memory_object_data_provided(
394: ior->io_reply_port,
395: ior->io_recnum * ior->io_device->bsize,
396: (vm_offset_t)copy,
397: size_read,
398: VM_PROT_NONE);
399: }
400: else {
401: (void) r_memory_object_data_error(
402: ior->io_reply_port,
403: ior->io_recnum * ior->io_device->bsize,
404: (vm_size_t)ior->io_count,
405: ior->io_error);
406: }
407:
408: (void)vm_deallocate(kernel_map,
409: start_alloc,
410: end_alloc - start_alloc);
411: device_deallocate(ior->io_device);
412: return (TRUE);
413: }
414: #endif
415:
416: kern_return_t device_pager_data_write(
417: ipc_port_t pager,
418: ipc_port_t pager_request,
419: register vm_offset_t offset,
420: register pointer_t addr,
421: vm_size_t data_count)
422: {
423: register dev_pager_t ds;
424: register device_t device;
425: kern_return_t result;
426:
427: panic("(device_pager)data_write: called");
428: #if 0
429: ds = dev_pager_hash_lookup((ipc_port_t)pager);
430: if (ds == DEV_PAGER_NULL)
431: panic("(device_pager)data_write: lookup failed");
432:
433: if (ds->pager_request != pager_request)
434: panic("(device_pager)data_write: bad pager_request");
435:
436: if (ds->type == CHAR_PAGER_TYPE)
437: panic("(device_pager)data_write: char pager");
438:
439: device = ds->device;
440: device_reference(device);
441: dev_pager_deallocate(ds);
442:
443: /*
444: * Package the write request for the device driver.
445: */
446: io_req_alloc(ior, data_count);
447:
448: ior->io_device = device;
449: ior->io_unit = device->dev_number;
450: ior->io_op = IO_WRITE | IO_CALL;
451: ior->io_mode = 0;
452: ior->io_recnum = offset / device->bsize;
453: ior->io_data = (io_buf_ptr_t)addr;
454: ior->io_count = data_count;
455: ior->io_alloc_size = data_count; /* amount to deallocate */
456: ior->io_residual = 0;
457: ior->io_error = 0;
458: ior->io_done = device_pager_data_write_done;
459: ior->io_reply_port = IP_NULL;
460:
461: result = (*device->dev_ops->d_write)(device->dev_number, ior);
462:
463: if (result != D_IO_QUEUED) {
464: device_write_dealloc(ior);
465: io_req_free((vm_offset_t)ior);
466: device_deallocate(device);
467: }
468: #endif
469:
470: return (KERN_SUCCESS);
471: }
472:
473: #if 0
474: boolean_t device_pager_data_write_done(ior)
475: register io_req_t ior;
476: {
477: device_write_dealloc(ior);
478: device_deallocate(ior->io_device);
479:
480: return (TRUE);
481: }
482: #endif
483:
484: kern_return_t device_pager_copy(
485: ipc_port_t pager,
486: ipc_port_t pager_request,
487: register vm_offset_t offset,
488: register vm_size_t length,
489: ipc_port_t new_pager)
490: {
491: panic("(device_pager)copy: called");
492: }
493:
494: kern_return_t
495: device_pager_supply_completed(
496: ipc_port_t pager,
497: ipc_port_t pager_request,
498: vm_offset_t offset,
499: vm_size_t length,
500: kern_return_t result,
501: vm_offset_t error_offset)
502: {
503: panic("(device_pager)supply_completed: called");
504: }
505:
506: kern_return_t
507: device_pager_data_return(
508: ipc_port_t pager,
509: ipc_port_t pager_request,
510: vm_offset_t offset,
511: register pointer_t addr,
512: vm_size_t data_cnt,
513: boolean_t dirty,
514: boolean_t kernel_copy)
515: {
516: panic("(device_pager)data_return: called");
517: }
518:
519: kern_return_t
520: device_pager_change_completed(
521: ipc_port_t pager,
522: boolean_t may_cache,
523: memory_object_copy_strategy_t copy_strategy)
524: {
525: panic("(device_pager)change_completed: called");
526: }
527:
528: /*
529: * The mapping function takes a byte offset, but returns
530: * a machine-dependent page frame number. We convert
531: * that into something that the pmap module will
532: * accept later.
533: */
534: vm_offset_t device_map_page(
535: void *dsp,
536: vm_offset_t offset)
537: {
538: register dev_pager_t ds = (dev_pager_t) dsp;
539: oskit_addr_t pa;
540: kern_return_t err;
541:
542: err = (*ds->device->ops->map) (ds->device, ds->prot,
543: offset, PAGE_SIZE, &pa);
544: if (err)
545: panic ("device_map_page: map failure: %x", err);
546:
547: return pa;
548: }
549:
550: kern_return_t device_pager_init_pager(
551: ipc_port_t pager,
552: ipc_port_t pager_request,
553: ipc_port_t pager_name,
554: vm_size_t pager_page_size)
555: {
556: register dev_pager_t ds;
557:
558: if (device_pager_debug)
559: printf("(device_pager)init: pager=%d, request=%d, name=%d\n",
560: pager, pager_request, pager_name);
561:
562: assert(pager_page_size == PAGE_SIZE);
563: assert(IP_VALID(pager_request));
564: assert(IP_VALID(pager_name));
565:
566: ds = dev_pager_hash_lookup(pager);
567: assert(ds != DEV_PAGER_NULL);
568:
569: assert(ds->client_count == 0);
570: assert(ds->pager_request == IP_NULL);
571: assert(ds->pager_name == IP_NULL);
572:
573: ds->client_count = 1;
574:
575: /*
576: * We save the send rights for the request and name ports.
577: */
578:
579: ds->pager_request = pager_request;
580: ds->pager_name = pager_name;
581:
582: /*
583: * Reply that the object is ready
584: */
585: (void) r_memory_object_set_attributes(pager_request,
586: TRUE, /* ready */
587: FALSE, /* do not cache */
588: MEMORY_OBJECT_COPY_NONE);
589: #if 0
590: /* for block devices, not supported now */
591: (void) r_memory_object_set_attributes(pager_request,
592: TRUE, /* ready */
593: TRUE, /* cache */
594: MEMORY_OBJECT_COPY_DELAY);
595: #endif
596:
597: dev_pager_deallocate(ds);
598: return (KERN_SUCCESS);
599: }
600:
601: kern_return_t device_pager_terminate(
602: ipc_port_t pager,
603: ipc_port_t pager_request,
604: ipc_port_t pager_name)
605: {
606: register dev_pager_t ds;
607:
608: assert(IP_VALID(pager_request));
609: assert(IP_VALID(pager_name));
610:
611: ds = dev_pager_hash_lookup(pager);
612: assert(ds != DEV_PAGER_NULL);
613:
614: assert(ds->client_count == 1);
615: assert(ds->pager_request == pager_request);
616: assert(ds->pager_name == pager_name);
617:
618: dev_pager_hash_delete(ds->pager);
619: dev_pager_hash_delete((ipc_port_t)ds->device); /* HACK */
620: device_deallocate(ds->device);
621:
622: /* release the send rights we have saved from the init call */
623:
624: ipc_port_release_send(pager_request);
625: ipc_port_release_send(pager_name);
626:
627: /* release the naked receive rights we just acquired */
628:
629: ipc_port_release_receive(pager_request);
630: ipc_port_release_receive(pager_name);
631:
632: /* release the kernel's receive right for the pager port */
633:
634: ipc_port_dealloc_kernel(pager);
635:
636: /* once for ref from lookup, once to make it go away */
637: dev_pager_deallocate(ds);
638: dev_pager_deallocate(ds);
639:
640: return (KERN_SUCCESS);
641: }
642:
643: kern_return_t device_pager_data_unlock(
644: ipc_port_t memory_object,
645: ipc_port_t memory_control_port,
646: vm_offset_t offset,
647: vm_size_t length,
648: vm_prot_t desired_access)
649: {
650: #ifdef lint
651: memory_object++; memory_control_port++; offset++; length++; desired_access++;
652: #endif /* lint */
653:
654: panic("(device_pager)data_unlock: called");
655: return (KERN_FAILURE);
656: }
657:
658: kern_return_t device_pager_lock_completed(
659: ipc_port_t memory_object,
660: ipc_port_t pager_request_port,
661: vm_offset_t offset,
662: vm_size_t length)
663: {
664: #ifdef lint
665: memory_object++; pager_request_port++; offset++; length++;
666: #endif /* lint */
667:
668: panic("(device_pager)lock_completed: called");
669: return (KERN_FAILURE);
670: }
671:
672: void device_pager_init(void)
673: {
674: register vm_size_t size;
675:
676: /*
677: * Initialize zone of paging structures.
678: */
679: size = sizeof(struct dev_pager);
680: dev_pager_zone = zinit(size,
681: (vm_size_t) size * 1000,
682: PAGE_SIZE,
683: FALSE,
684: "device pager structures");
685:
686: /*
687: * Initialize the name port hashing stuff.
688: */
689: dev_pager_hash_init();
690: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.