1: /* This file contains the device dependent part of the drivers for the
   2:  * following special files:
   3:  *     /dev/null        - null device (data sink)
   4:  *     /dev/mem         - absolute memory
   5:  *     /dev/kmem        - kernel virtual memory
   6:  *     /dev/ram         - RAM disk
   7:  *
   8:  * The file contains one entry point:
   9:  *
  10:  *   mem_task:  main entry when system is brought up
  11:  *
  12:  *  Changes:
  13:  *      20 Apr  1992 by Kees J. Bot: device dependent/independent split
  14:  */
  15: 
  16: #include "kernel.h"
  17: #include "driver.h"
  18: #include <sys/ioc_memory.h>
  19: #if (CHIP == INTEL) && ENABLE_USERBIOS
  20: #include "protect.h"
  21: #include <ibm/int86.h>
  22: #endif
  23: 
  24: #define NR_RAMS            4    /* number of RAM-type devices */
  25: 
  26: PRIVATE struct device m_geom[NR_RAMS];  /* Base and size of each RAM disk */
  27: PRIVATE int m_device;           /* current device */
  28: 
  29: FORWARD _PROTOTYPE( struct device *m_prepare, (int device) );
  30: FORWARD _PROTOTYPE( int m_transfer, (int proc_nr, int opcode, off_t position,
  31:                                         iovec_t *iov, unsigned nr_req) );
  32: FORWARD _PROTOTYPE( int m_do_open, (struct driver *dp, message *m_ptr) );
  33: FORWARD _PROTOTYPE( void m_init, (void) );
  34: FORWARD _PROTOTYPE( int m_ioctl, (struct driver *dp, message *m_ptr) );
  35: FORWARD _PROTOTYPE( void m_geometry, (struct partition *entry) );
  36: 
  37: 
  38: /* Entry points to this driver. */
  39: PRIVATE struct driver m_dtab = {
  40:   no_name,      /* current device's name */
  41:   m_do_open,    /* open or mount */
  42:   do_nop,       /* nothing on a close */
  43:   m_ioctl,      /* specify ram disk geometry */
  44:   m_prepare,    /* prepare for I/O on a given minor device */
  45:   m_transfer,   /* do the I/O */
  46:   nop_cleanup,  /* no need to clean up */
  47:   m_geometry,   /* memory device "geometry" */
  48: };
  49: 
  50: 
  51: /*===========================================================================*
  52:  *                              mem_task                                     *
  53:  *===========================================================================*/
  54: PUBLIC void mem_task()
  55: {
  56:   m_init();
  57:   driver_task(&m_dtab);
  58: }
  59: 
  60: 
  61: /*===========================================================================*
  62:  *                              m_prepare                                    *
  63:  *===========================================================================*/
  64: PRIVATE struct device *m_prepare(device)
  65: int device;
  66: {
  67: /* Prepare for I/O on a device. */
  68: 
  69:   if (device < 0 || device >= NR_RAMS) return(NIL_DEV);
  70:   m_device = device;
  71: 
  72:   return(&m_geom[device]);
  73: }
  74: 
  75: 
  76: /*===========================================================================*
  77:  *                              m_transfer                                   *
  78:  *===========================================================================*/
  79: PRIVATE int m_transfer(proc_nr, opcode, position, iov, nr_req)
  80: int proc_nr;                    /* process doing the request */
  81: int opcode;                     /* DEV_GATHER or DEV_SCATTER */
  82: off_t position;                 /* offset on device to read or write */
  83: iovec_t *iov;                   /* pointer to read or write request vector */
  84: unsigned nr_req;                /* length of request vector */
  85: {
  86: /* Read or write /dev/null, /dev/mem, /dev/kmem, or /dev/ram. */
  87: 
  88:   int device;
  89:   phys_bytes mem_phys, user_phys;
  90:   unsigned count;
  91:   struct device *dv;
  92:   unsigned long dv_size;
  93:   phys_bytes user_base = proc_vir2phys(proc_addr(proc_nr), 0);
  94: 
  95:   /* Get minor device number and check for /dev/null. */
  96:   device = m_device;
  97:   dv = &m_geom[device];
  98:   dv_size = cv64ul(dv->dv_size);
  99: 
 100:   while (nr_req > 0) {
 101:         user_phys = user_base + iov->iov_addr;
 102:         count = iov->iov_size;
 103: 
 104:         switch (device) {
 105:         case NULL_DEV:
 106:                 if (opcode == DEV_GATHER) return(OK);   /* Always at EOF. */
 107:                 break;
 108: 
 109:         default:
 110:                 /* /dev/mem, /dev/kmem, /dev/ram: Check for EOF */
 111:                 if (position >= dv_size) return(OK);
 112:                 if (position + count > dv_size) count = dv_size - position;
 113:                 mem_phys = cv64ul(dv->dv_base) + position;
 114: 
 115:                 /* Copy the data. */
 116:                 if (opcode == DEV_GATHER) {
 117:                         phys_copy(mem_phys, user_phys, (phys_bytes) count);
 118:                 } else {
 119:                         phys_copy(user_phys, mem_phys, (phys_bytes) count);
 120:                 }
 121:         }
 122: 
 123:         /* Book the number of bytes transferred. */
 124:         position += count;
 125:         iov->iov_addr += count;
 126:         if ((iov->iov_size -= count) == 0) { iov++; nr_req--; }
 127:   }
 128:   return(OK);
 129: }
 130: 
 131: 
 132: /*============================================================================*
 133:  *                              m_do_open                                     *
 134:  *============================================================================*/
 135: PRIVATE int m_do_open(dp, m_ptr)
 136: struct driver *dp;
 137: message *m_ptr;
 138: {
 139: /* Check device number on open.  Give I/O privileges to a process opening
 140:  * /dev/mem or /dev/kmem.
 141:  */
 142: 
 143:   if (m_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
 144: 
 145: #if (CHIP == INTEL)
 146:   if (m_device == MEM_DEV || m_device == KMEM_DEV)
 147:         enable_iop(proc_addr(m_ptr->PROC_NR));
 148: #endif
 149: 
 150:   return(OK);
 151: }
 152: 
 153: 
 154: /*===========================================================================*
 155:  *                              m_init                                       *
 156:  *===========================================================================*/
 157: PRIVATE void m_init()
 158: {
 159:   /* Initialize this task. */
 160:   extern int end;
 161: 
 162:   m_geom[KMEM_DEV].dv_base = cvul64(vir2phys(0));
 163:   m_geom[KMEM_DEV].dv_size = cvul64(vir2phys(&end));
 164: 
 165: #if (CHIP == INTEL)
 166:   if (!protected_mode) {
 167:         m_geom[MEM_DEV].dv_size =   cvul64(0x100000); /* 1M for 8086 systems */
 168:   } else {
 169: #if _WORD_SIZE == 2
 170:         m_geom[MEM_DEV].dv_size =  cvul64(0x1000000); /* 16M for 286 systems */
 171: #else
 172:         m_geom[MEM_DEV].dv_size = cvul64(0xFFFFFFFF); /* 4G-1 for 386 systems */
 173: #endif
 174:   }
 175: #else /* !(CHIP == INTEL) */
 176: #if (CHIP == M68000)
 177:   m_geom[MEM_DEV].dv_size = cvul64(MEM_BYTES);
 178: #else /* !(CHIP == M68000) */
 179: #error /* memory limit not set up */
 180: #endif /* !(CHIP == M68000) */
 181: #endif /* !(CHIP == INTEL) */
 182: }
 183: 
 184: 
 185: /*===========================================================================*
 186:  *                              m_ioctl                                      *
 187:  *===========================================================================*/
 188: PRIVATE int m_ioctl(dp, m_ptr)
 189: struct driver *dp;
 190: message *m_ptr;                 /* pointer to read or write message */
 191: {
 192: /* Set parameters for one of the RAM disks. */
 193: 
 194:   static struct psinfo psinfo = { NR_TASKS, NR_PROCS, (vir_bytes) proc, 0, 0 };
 195:   struct device *dv;
 196:   struct proc *pp;
 197: 
 198:   if ((dv = m_prepare(m_ptr->DEVICE)) == NIL_DEV) return(ENXIO);
 199:   pp = proc_addr(m_ptr->PROC_NR);
 200: 
 201:   switch (m_ptr->REQUEST) {
 202:     case MIOCRAMSIZE: {
 203:         /* FS sets the RAM disk size. */
 204:         unsigned long bytesize;
 205:         unsigned base, size;
 206:         struct memory *memp;
 207: 
 208:         if (m_ptr->PROC_NR != FS_PROC_NR) return(EPERM);
 209: 
 210:         bytesize = m_ptr->POSITION * BLOCK_SIZE;
 211:         size = (bytesize + CLICK_SIZE-1) >> CLICK_SHIFT;
 212: 
 213:         /* Find a memory chunk big enough for the RAM disk. */
 214:         memp= &mem[NR_MEMS];
 215:         while ((--memp)->size < size) {
 216:                 if (memp == mem) panic("Not enough memory for RAM disk",NO_NUM);
 217:         }
 218:         memp->size -= size;
 219:         base = memp->base + memp->size;
 220: 
 221:         dv->dv_base = cvul64((u32_t) base << CLICK_SHIFT);
 222:         dv->dv_size = cvul64(bytesize);
 223:         break;
 224:     }
 225:     case MIOCSPSINFO: {
 226:         /* MM or FS set the address of their process table. */
 227:         phys_bytes psinfo_phys;
 228: 
 229:         if (m_ptr->PROC_NR == MM_PROC_NR) {
 230:                 psinfo.mproc = (vir_bytes) m_ptr->ADDRESS;
 231:         } else
 232:         if (m_ptr->PROC_NR == FS_PROC_NR) {
 233:                 psinfo.fproc = (vir_bytes) m_ptr->ADDRESS;
 234:         } else {
 235:                 return(EPERM);
 236:         }
 237:         break;
 238:     }
 239:     case MIOCGPSINFO: {
 240:         /* The ps program wants the process table addresses. */
 241:         if (vir_copy(MEM, (vir_bytes) &psinfo,
 242:                 m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS,
 243:                 sizeof(psinfo)) != OK) return(EFAULT);
 244:         break;
 245:     }
 246: #if (CHIP == INTEL) && ENABLE_USERBIOS
 247:     case MIOCINT86: {
 248:         /* Execute a BIOS call for a user process. */
 249:         phys_bytes user_phys, buf_phys;
 250:         struct mio_int86 mint86;
 251: 
 252:         if (m_device != MEM_DEV && m_device != KMEM_DEV) return(ENOTTY);
 253: 
 254:         user_phys = umap(pp, D, (vir_bytes) m_ptr->ADDRESS, sizeof(mint86));
 255:         if (user_phys == 0) return(EFAULT);
 256:         phys_copy(user_phys, vir2phys(&mint86), sizeof(mint86));
 257:         buf_phys = 0;
 258: 
 259:         if (mint86.seg == 0) {
 260:                 /* Client doesn't yet know where my buffer is... */
 261:                 mint86.off = tmp_phys % HCLICK_SIZE;
 262:                 mint86.seg = tmp_phys / HCLICK_SIZE;
 263:                 mint86.buf = NULL;
 264:                 mint86.len = DMA_BUF_SIZE;
 265:         } else {
 266:                 if (mint86.buf != NULL) {
 267:                         /* Copy user data buffer to my buffer. */
 268:                         if (mint86.len > DMA_BUF_SIZE) return(EINVAL);
 269:                         buf_phys = umap(pp, D, (vir_bytes) mint86.buf,
 270:                                                                 mint86.len);
 271:                         if (buf_phys == 0) return(EFAULT);
 272:                         phys_copy(buf_phys, tmp_phys, mint86.len);
 273:                 }
 274: 
 275:                 /* Execute the interrupt. */
 276:                 reg86 = mint86.reg86;
 277:                 level0(int86);
 278:                 mint86.reg86 = reg86;
 279:         }
 280: 
 281:         /* Copy the results back. */
 282:         phys_copy(vir2phys(&mint86), user_phys, sizeof(mint86));
 283:         if (buf_phys != 0) phys_copy(tmp_phys, buf_phys, mint86.len);
 284:         break;
 285:     }
 286:     case MIOCGLDT86:
 287:     case MIOCSLDT86: {
 288:         /* Get or set an LDT entry of this process. */
 289:         phys_bytes user_phys;
 290:         struct mio_ldt86 mldt;
 291: 
 292:         if (m_device != MEM_DEV && m_device != KMEM_DEV) return(ENOTTY);
 293: 
 294:         user_phys = umap(pp, D, (vir_bytes) m_ptr->ADDRESS, sizeof(mldt));
 295:         if (user_phys == 0) return(EFAULT);
 296:         phys_copy(user_phys, vir2phys(&mldt), sizeof(mldt));
 297: 
 298:         if (!protected_mode || mldt.idx >= LDT_SIZE) return(ESRCH);
 299: 
 300:         if (m_ptr->REQUEST == MIOCGLDT86) {
 301:                 * (struct segdesc_s *) mldt.entry = pp->p_ldt[mldt.idx];
 302:                 phys_copy(vir2phys(&mldt), user_phys, sizeof(mldt));
 303:         } else {
 304:                 pp->p_ldt[mldt.idx] = * (struct segdesc_s *) mldt.entry;
 305:         }
 306:         break;
 307:     }
 308: #endif /* CHIP == INTEL && ENABLE_USERBIOS */
 309: 
 310:     default:
 311:         return(do_diocntl(&m_dtab, m_ptr));
 312:   }
 313:   return(OK);
 314: }
 315: 
 316: 
 317: /*============================================================================*
 318:  *                              m_geometry                                    *
 319:  *============================================================================*/
 320: PRIVATE void m_geometry(entry)
 321: struct partition *entry;
 322: {
 323:   /* Memory devices don't have a geometry, but the outside world insists. */
 324:   entry->cylinders = div64u(m_geom[m_device].dv_size, SECTOR_SIZE) / (64 * 32);
 325:   entry->heads = 64;
 326:   entry->sectors = 32;
 327: }