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