Annotation of OSKit-Mach/oskit/ds_mem.c, revision 1.1.1.1

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: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.