|
|
1.1 ! root 1: #include "ds_oskit.h" ! 2: ! 3: #include <oskit/machine/physmem.h> ! 4: #include <vm/vm_map.h> ! 5: #include <string.h> ! 6: ! 7: ! 8: /* For device_get_status, we look like a block device. */ ! 9: io_return_t ! 10: ds_mem_get_status (device_t dev, dev_flavor_t flavor, dev_status_t status, ! 11: mach_msg_type_number_t *status_count) ! 12: { ! 13: switch (flavor) ! 14: { ! 15: case DEV_GET_SIZE: ! 16: status[DEV_GET_SIZE_RECORD_SIZE] = dev->com.mem.recsize; ! 17: status[DEV_GET_SIZE_DEVICE_SIZE] = dev->com.mem.size; ! 18: *status_count = 2; ! 19: return D_SUCCESS; ! 20: } ! 21: INVALOP; ! 22: } ! 23: ! 24: /* This is the main use for these pseudo-devices, to map physical pages ! 25: into user tasks. This is called from the device pager to get a physical ! 26: page address that will be inserted into a task's page tables. So we can ! 27: safely use any physical address at all, regardless of whether it is ! 28: mapped into the kernel address space. */ ! 29: io_return_t ! 30: ds_mem_map (device_t dev, vm_prot_t prot, ! 31: vm_offset_t offset, vm_size_t size, oskit_addr_t *pa) ! 32: { ! 33: if (offset == 0 && size == 0) ! 34: /* Special case for compatibility with the old Mach driver behavior. */ ! 35: size = dev->com.mem.size; ! 36: ! 37: if (offset % dev->com.mem.recsize || !page_aligned (offset)) ! 38: INVALREC; ! 39: if (trunc_page (offset) > trunc_page (dev->com.mem.size)) ! 40: INVALREC; ! 41: if (trunc_page (offset + size - 1) > trunc_page (dev->com.mem.size - 1)) ! 42: INVALSZ; ! 43: if (round_page (size) % dev->com.mem.recsize) ! 44: INVALSZ; ! 45: ! 46: if (pa) ! 47: *pa = dev->com.mem.pa + offset; ! 48: return 0; ! 49: } ! 50: ! 51: ! 52: /* Real physical memory is already direct-mapped into the kernel address ! 53: space, but i/o memory may not be. To copy into or out of i/o memory ! 54: addresses, we need to map pages into the kernel address space ! 55: temporarily. */ ! 56: static int ! 57: direct_mapped (vm_offset_t pa) ! 58: { ! 59: return (trunc_page (pa) >= PAGE_SIZE && ! 60: trunc_page (pa) >= round_page (phys_mem_min) && ! 61: round_page (pa) <= trunc_page (phys_mem_max)); ! 62: } ! 63: ! 64: static int ! 65: map_phys (vm_offset_t pa, unsigned *count, vm_prot_t prot, ! 66: vm_offset_t *kva, vm_size_t *mapsz, vm_offset_t *ofs) ! 67: { ! 68: vm_offset_t start = trunc_page (pa), end = round_page (pa + *count); ! 69: kern_return_t kr; ! 70: vm_offset_t addr; ! 71: ! 72: /* Find some address space to use. ! 73: If we can't get it all, get a smaller amount. */ ! 74: addr = vm_map_min (device_io_map); ! 75: while ((kr = vm_map_enter (device_io_map, &addr, end - start, 0, TRUE, ! 76: 0, 0, FALSE, prot, prot, VM_INHERIT_NONE)) ! 77: == KERN_NO_SPACE) ! 78: end = start + (end - start) / 2; ! 79: if (kr != KERN_SUCCESS) ! 80: return kr; ! 81: ! 82: *kva = addr; ! 83: *ofs = pa - start; ! 84: if (end < pa + *count) ! 85: *count = end - pa; ! 86: *mapsz = end - start; ! 87: ! 88: /* Now map those physical pages in. */ ! 89: do ! 90: { ! 91: pmap_enter (vm_map_pmap (device_io_map), addr, start, prot, TRUE); ! 92: start += PAGE_SIZE; ! 93: addr += PAGE_SIZE; ! 94: } while (start < end); ! 95: ! 96: return 0; ! 97: } ! 98: ! 99: static void ! 100: unmap_phys (vm_offset_t addr, vm_size_t size) ! 101: { ! 102: vm_map_remove (device_io_map, addr, addr + size); ! 103: } ! 104: ! 105: ! 106: io_return_t ! 107: ds_mem_read_inband (device_t dev, ipc_port_t reply_port, ! 108: mach_msg_type_name_t reply_port_type, dev_mode_t mode, ! 109: recnum_t recnum, int count, char *data, ! 110: unsigned *bytes_read) ! 111: { ! 112: vm_offset_t pa; ! 113: ! 114: if (count == 0) ! 115: { ! 116: *bytes_read = 0; ! 117: return 0; ! 118: } ! 119: recnum *= dev->com.mem.recsize; ! 120: if ((oskit_size_t) recnum > dev->com.mem.size) ! 121: INVALREC; ! 122: if ((oskit_size_t) recnum + count > dev->com.mem.size) ! 123: INVALSZ; ! 124: ! 125: pa = dev->com.mem.pa + recnum; ! 126: *bytes_read = count; ! 127: if (direct_mapped (pa) && direct_mapped (pa + recnum - 1)) ! 128: memcpy (data, (char *) phystokv (pa), count); ! 129: else ! 130: { ! 131: vm_offset_t kva, ofs; ! 132: vm_size_t mapsz; ! 133: if (! map_phys (pa, bytes_read, VM_PROT_READ, ! 134: &kva, &mapsz, &ofs)) ! 135: return D_NO_MEMORY; ! 136: memcpy (data, (char *) kva + ofs, *bytes_read); ! 137: unmap_phys (kva, mapsz); ! 138: } ! 139: ! 140: return 0; ! 141: } ! 142: ! 143: io_return_t ! 144: ds_mem_write_inband (device_t dev, ipc_port_t reply_port, ! 145: mach_msg_type_name_t reply_port_type, dev_mode_t mode, ! 146: recnum_t recnum, ! 147: io_buf_ptr_t data, unsigned int count, ! 148: int *bytes_written) ! 149: { ! 150: vm_offset_t pa; ! 151: ! 152: if (count == 0) ! 153: { ! 154: *bytes_written = 0; ! 155: return 0; ! 156: } ! 157: recnum *= dev->com.mem.recsize; ! 158: if ((oskit_size_t) recnum > dev->com.mem.size) ! 159: INVALREC; ! 160: if ((oskit_size_t) recnum + count > dev->com.mem.size) ! 161: INVALSZ; ! 162: ! 163: pa = dev->com.mem.pa + recnum; ! 164: *bytes_written = count; ! 165: if (direct_mapped (pa) && direct_mapped (pa + recnum - 1)) ! 166: memcpy ((char *) phystokv (pa), data, count); ! 167: else ! 168: { ! 169: vm_offset_t kva, ofs; ! 170: vm_size_t mapsz; ! 171: if (! map_phys (pa, (unsigned *) bytes_written, ! 172: VM_PROT_READ | VM_PROT_WRITE, ! 173: &kva, &mapsz, &ofs)) ! 174: return D_NO_MEMORY; ! 175: memcpy ((char *) kva + ofs, data, *bytes_written); ! 176: unmap_phys (kva, mapsz); ! 177: } ! 178: ! 179: return 0; ! 180: } ! 181: ! 182: ! 183: const struct device_ops mem_device_ops = ! 184: { ! 185: read_inband: ds_mem_read_inband, ! 186: write_inband: ds_mem_write_inband, ! 187: get_status: ds_mem_get_status, ! 188: map: ds_mem_map, ! 189: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.