Annotation of OSKit-Mach/oskit/ds_mem.c, revision 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.