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