1*433d6423SLionel Sambuc /* This file contains the device dependent part of the drivers for the 2*433d6423SLionel Sambuc * following special files: 3*433d6423SLionel Sambuc * /dev/ram - RAM disk 4*433d6423SLionel Sambuc * /dev/mem - absolute memory 5*433d6423SLionel Sambuc * /dev/kmem - kernel virtual memory 6*433d6423SLionel Sambuc * /dev/null - null device (data sink) 7*433d6423SLionel Sambuc * /dev/boot - boot device loaded from boot image 8*433d6423SLionel Sambuc * /dev/zero - null byte stream generator 9*433d6423SLionel Sambuc * /dev/imgrd - boot image RAM disk 10*433d6423SLionel Sambuc * 11*433d6423SLionel Sambuc * Changes: 12*433d6423SLionel Sambuc * Apr 29, 2005 added null byte generator (Jorrit N. Herder) 13*433d6423SLionel Sambuc * Apr 09, 2005 added support for boot device (Jorrit N. Herder) 14*433d6423SLionel Sambuc * Jul 26, 2004 moved RAM driver to user-space (Jorrit N. Herder) 15*433d6423SLionel Sambuc * Apr 20, 1992 device dependent/independent split (Kees J. Bot) 16*433d6423SLionel Sambuc */ 17*433d6423SLionel Sambuc 18*433d6423SLionel Sambuc #include <assert.h> 19*433d6423SLionel Sambuc #include <minix/drivers.h> 20*433d6423SLionel Sambuc #include <minix/chardriver.h> 21*433d6423SLionel Sambuc #include <minix/blockdriver.h> 22*433d6423SLionel Sambuc #include <sys/ioc_memory.h> 23*433d6423SLionel Sambuc #include <minix/ds.h> 24*433d6423SLionel Sambuc #include <minix/vm.h> 25*433d6423SLionel Sambuc #include <machine/param.h> 26*433d6423SLionel Sambuc #include <machine/vmparam.h> 27*433d6423SLionel Sambuc #include <sys/mman.h> 28*433d6423SLionel Sambuc #include "kernel/const.h" 29*433d6423SLionel Sambuc #include "kernel/config.h" 30*433d6423SLionel Sambuc #include "kernel/type.h" 31*433d6423SLionel Sambuc 32*433d6423SLionel Sambuc #include <machine/vm.h> 33*433d6423SLionel Sambuc 34*433d6423SLionel Sambuc #include "local.h" 35*433d6423SLionel Sambuc 36*433d6423SLionel Sambuc /* ramdisks (/dev/ram*) */ 37*433d6423SLionel Sambuc #define RAMDISKS 6 38*433d6423SLionel Sambuc 39*433d6423SLionel Sambuc #define RAM_DEV_LAST (RAM_DEV_FIRST+RAMDISKS-1) 40*433d6423SLionel Sambuc 41*433d6423SLionel Sambuc #define NR_DEVS (7+RAMDISKS) /* number of minor devices */ 42*433d6423SLionel Sambuc 43*433d6423SLionel Sambuc static struct device m_geom[NR_DEVS]; /* base and size of each device */ 44*433d6423SLionel Sambuc static vir_bytes m_vaddrs[NR_DEVS]; 45*433d6423SLionel Sambuc 46*433d6423SLionel Sambuc static int openct[NR_DEVS]; 47*433d6423SLionel Sambuc 48*433d6423SLionel Sambuc static ssize_t m_char_read(devminor_t minor, u64_t position, endpoint_t endpt, 49*433d6423SLionel Sambuc cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); 50*433d6423SLionel Sambuc static ssize_t m_char_write(devminor_t minor, u64_t position, endpoint_t endpt, 51*433d6423SLionel Sambuc cp_grant_id_t grant, size_t size, int flags, cdev_id_t id); 52*433d6423SLionel Sambuc static int m_char_open(devminor_t minor, int access, endpoint_t user_endpt); 53*433d6423SLionel Sambuc static int m_char_close(devminor_t minor); 54*433d6423SLionel Sambuc 55*433d6423SLionel Sambuc static struct device *m_block_part(devminor_t minor); 56*433d6423SLionel Sambuc static ssize_t m_block_transfer(devminor_t minor, int do_write, u64_t position, 57*433d6423SLionel Sambuc endpoint_t endpt, iovec_t *iov, unsigned int nr_req, int flags); 58*433d6423SLionel Sambuc static int m_block_open(devminor_t minor, int access); 59*433d6423SLionel Sambuc static int m_block_close(devminor_t minor); 60*433d6423SLionel Sambuc static int m_block_ioctl(devminor_t minor, unsigned long request, endpoint_t 61*433d6423SLionel Sambuc endpt, cp_grant_id_t grant, endpoint_t user_endpt); 62*433d6423SLionel Sambuc 63*433d6423SLionel Sambuc /* Entry points to the CHARACTER part of this driver. */ 64*433d6423SLionel Sambuc static struct chardriver m_cdtab = { 65*433d6423SLionel Sambuc .cdr_open = m_char_open, /* open device */ 66*433d6423SLionel Sambuc .cdr_close = m_char_close, /* close device */ 67*433d6423SLionel Sambuc .cdr_read = m_char_read, /* read from device */ 68*433d6423SLionel Sambuc .cdr_write = m_char_write /* write to device */ 69*433d6423SLionel Sambuc }; 70*433d6423SLionel Sambuc 71*433d6423SLionel Sambuc /* Entry points to the BLOCK part of this driver. */ 72*433d6423SLionel Sambuc static struct blockdriver m_bdtab = { 73*433d6423SLionel Sambuc .bdr_type = BLOCKDRIVER_TYPE_DISK,/* handle partition requests */ 74*433d6423SLionel Sambuc .bdr_open = m_block_open, /* open device */ 75*433d6423SLionel Sambuc .bdr_close = m_block_close, /* nothing on a close */ 76*433d6423SLionel Sambuc .bdr_transfer = m_block_transfer, /* do the I/O */ 77*433d6423SLionel Sambuc .bdr_ioctl = m_block_ioctl, /* ram disk I/O control */ 78*433d6423SLionel Sambuc .bdr_part = m_block_part /* return partition information */ 79*433d6423SLionel Sambuc }; 80*433d6423SLionel Sambuc 81*433d6423SLionel Sambuc /* SEF functions and variables. */ 82*433d6423SLionel Sambuc static void sef_local_startup(void); 83*433d6423SLionel Sambuc static int sef_cb_init_fresh(int type, sef_init_info_t *info); 84*433d6423SLionel Sambuc 85*433d6423SLionel Sambuc /*===========================================================================* 86*433d6423SLionel Sambuc * main * 87*433d6423SLionel Sambuc *===========================================================================*/ 88*433d6423SLionel Sambuc int main(void) 89*433d6423SLionel Sambuc { 90*433d6423SLionel Sambuc message msg; 91*433d6423SLionel Sambuc int r, ipc_status; 92*433d6423SLionel Sambuc 93*433d6423SLionel Sambuc /* SEF local startup. */ 94*433d6423SLionel Sambuc sef_local_startup(); 95*433d6423SLionel Sambuc 96*433d6423SLionel Sambuc /* The receive loop. */ 97*433d6423SLionel Sambuc for (;;) { 98*433d6423SLionel Sambuc if ((r = driver_receive(ANY, &msg, &ipc_status)) != OK) 99*433d6423SLionel Sambuc panic("memory: driver_receive failed (%d)", r); 100*433d6423SLionel Sambuc 101*433d6423SLionel Sambuc if (IS_BDEV_RQ(msg.m_type)) 102*433d6423SLionel Sambuc blockdriver_process(&m_bdtab, &msg, ipc_status); 103*433d6423SLionel Sambuc else 104*433d6423SLionel Sambuc chardriver_process(&m_cdtab, &msg, ipc_status); 105*433d6423SLionel Sambuc } 106*433d6423SLionel Sambuc 107*433d6423SLionel Sambuc return(OK); 108*433d6423SLionel Sambuc } 109*433d6423SLionel Sambuc 110*433d6423SLionel Sambuc /*===========================================================================* 111*433d6423SLionel Sambuc * sef_local_startup * 112*433d6423SLionel Sambuc *===========================================================================*/ 113*433d6423SLionel Sambuc static void sef_local_startup() 114*433d6423SLionel Sambuc { 115*433d6423SLionel Sambuc /* Register init callbacks. */ 116*433d6423SLionel Sambuc sef_setcb_init_fresh(sef_cb_init_fresh); 117*433d6423SLionel Sambuc sef_setcb_init_lu(sef_cb_init_fresh); 118*433d6423SLionel Sambuc sef_setcb_init_restart(sef_cb_init_fresh); 119*433d6423SLionel Sambuc 120*433d6423SLionel Sambuc /* Register live update callbacks. */ 121*433d6423SLionel Sambuc sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); 122*433d6423SLionel Sambuc sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard); 123*433d6423SLionel Sambuc 124*433d6423SLionel Sambuc /* Let SEF perform startup. */ 125*433d6423SLionel Sambuc sef_startup(); 126*433d6423SLionel Sambuc } 127*433d6423SLionel Sambuc 128*433d6423SLionel Sambuc /*===========================================================================* 129*433d6423SLionel Sambuc * sef_cb_init_fresh * 130*433d6423SLionel Sambuc *===========================================================================*/ 131*433d6423SLionel Sambuc static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info)) 132*433d6423SLionel Sambuc { 133*433d6423SLionel Sambuc /* Initialize the memory driver. */ 134*433d6423SLionel Sambuc int i; 135*433d6423SLionel Sambuc #if 0 136*433d6423SLionel Sambuc struct kinfo kinfo; /* kernel information */ 137*433d6423SLionel Sambuc int s; 138*433d6423SLionel Sambuc 139*433d6423SLionel Sambuc if (OK != (s=sys_getkinfo(&kinfo))) { 140*433d6423SLionel Sambuc panic("Couldn't get kernel information: %d", s); 141*433d6423SLionel Sambuc } 142*433d6423SLionel Sambuc 143*433d6423SLionel Sambuc /* Map in kernel memory for /dev/kmem. */ 144*433d6423SLionel Sambuc m_geom[KMEM_DEV].dv_base = kinfo.kmem_base; 145*433d6423SLionel Sambuc m_geom[KMEM_DEV].dv_size = kinfo.kmem_size; 146*433d6423SLionel Sambuc if((m_vaddrs[KMEM_DEV] = vm_map_phys(SELF, (void *) kinfo.kmem_base, 147*433d6423SLionel Sambuc kinfo.kmem_size)) == MAP_FAILED) { 148*433d6423SLionel Sambuc printf("MEM: Couldn't map in /dev/kmem."); 149*433d6423SLionel Sambuc } 150*433d6423SLionel Sambuc #endif 151*433d6423SLionel Sambuc 152*433d6423SLionel Sambuc /* Ramdisk image built into the memory driver */ 153*433d6423SLionel Sambuc m_geom[IMGRD_DEV].dv_base= 0; 154*433d6423SLionel Sambuc m_geom[IMGRD_DEV].dv_size= imgrd_size; 155*433d6423SLionel Sambuc m_vaddrs[IMGRD_DEV] = (vir_bytes) imgrd; 156*433d6423SLionel Sambuc 157*433d6423SLionel Sambuc for(i = 0; i < NR_DEVS; i++) 158*433d6423SLionel Sambuc openct[i] = 0; 159*433d6423SLionel Sambuc 160*433d6423SLionel Sambuc /* Set up memory range for /dev/mem. */ 161*433d6423SLionel Sambuc m_geom[MEM_DEV].dv_base = 0; 162*433d6423SLionel Sambuc m_geom[MEM_DEV].dv_size = 0xffffffffULL; 163*433d6423SLionel Sambuc 164*433d6423SLionel Sambuc m_vaddrs[MEM_DEV] = (vir_bytes) MAP_FAILED; /* we are not mapping this in. */ 165*433d6423SLionel Sambuc 166*433d6423SLionel Sambuc return(OK); 167*433d6423SLionel Sambuc } 168*433d6423SLionel Sambuc 169*433d6423SLionel Sambuc /*===========================================================================* 170*433d6423SLionel Sambuc * m_is_block * 171*433d6423SLionel Sambuc *===========================================================================*/ 172*433d6423SLionel Sambuc static int m_is_block(devminor_t minor) 173*433d6423SLionel Sambuc { 174*433d6423SLionel Sambuc /* Return TRUE iff the given minor device number is for a block device. */ 175*433d6423SLionel Sambuc 176*433d6423SLionel Sambuc switch (minor) { 177*433d6423SLionel Sambuc case MEM_DEV: 178*433d6423SLionel Sambuc case KMEM_DEV: 179*433d6423SLionel Sambuc case NULL_DEV: 180*433d6423SLionel Sambuc case ZERO_DEV: 181*433d6423SLionel Sambuc return FALSE; 182*433d6423SLionel Sambuc 183*433d6423SLionel Sambuc default: 184*433d6423SLionel Sambuc return TRUE; 185*433d6423SLionel Sambuc } 186*433d6423SLionel Sambuc } 187*433d6423SLionel Sambuc 188*433d6423SLionel Sambuc /*===========================================================================* 189*433d6423SLionel Sambuc * m_transfer_kmem * 190*433d6423SLionel Sambuc *===========================================================================*/ 191*433d6423SLionel Sambuc static ssize_t m_transfer_kmem(devminor_t minor, int do_write, u64_t position, 192*433d6423SLionel Sambuc endpoint_t endpt, cp_grant_id_t grant, size_t size) 193*433d6423SLionel Sambuc { 194*433d6423SLionel Sambuc /* Transfer from or to the KMEM device. */ 195*433d6423SLionel Sambuc u64_t dv_size, dev_vaddr; 196*433d6423SLionel Sambuc int r; 197*433d6423SLionel Sambuc 198*433d6423SLionel Sambuc dv_size = m_geom[minor].dv_size; 199*433d6423SLionel Sambuc dev_vaddr = m_vaddrs[minor]; 200*433d6423SLionel Sambuc 201*433d6423SLionel Sambuc if (!dev_vaddr || dev_vaddr == (vir_bytes) MAP_FAILED) { 202*433d6423SLionel Sambuc printf("MEM: dev %d not initialized\n", minor); 203*433d6423SLionel Sambuc return EIO; 204*433d6423SLionel Sambuc } 205*433d6423SLionel Sambuc 206*433d6423SLionel Sambuc if (position >= dv_size) return 0; /* check for EOF */ 207*433d6423SLionel Sambuc if (position + size > dv_size) size = dv_size - position; 208*433d6423SLionel Sambuc 209*433d6423SLionel Sambuc if (!do_write) /* copy actual data */ 210*433d6423SLionel Sambuc r = sys_safecopyto(endpt, grant, 0, dev_vaddr + position, size); 211*433d6423SLionel Sambuc else 212*433d6423SLionel Sambuc r = sys_safecopyfrom(endpt, grant, 0, dev_vaddr + position, size); 213*433d6423SLionel Sambuc 214*433d6423SLionel Sambuc return (r != OK) ? r : size; 215*433d6423SLionel Sambuc } 216*433d6423SLionel Sambuc 217*433d6423SLionel Sambuc /*===========================================================================* 218*433d6423SLionel Sambuc * m_transfer_mem * 219*433d6423SLionel Sambuc *===========================================================================*/ 220*433d6423SLionel Sambuc static ssize_t m_transfer_mem(devminor_t minor, int do_write, u64_t position, 221*433d6423SLionel Sambuc endpoint_t endpt, cp_grant_id_t grant, size_t size) 222*433d6423SLionel Sambuc { 223*433d6423SLionel Sambuc /* Transfer from or to the MEM device. */ 224*433d6423SLionel Sambuc static int any_mapped = 0; 225*433d6423SLionel Sambuc static phys_bytes pagestart_mapped; 226*433d6423SLionel Sambuc static char *vaddr; 227*433d6423SLionel Sambuc phys_bytes mem_phys, pagestart; 228*433d6423SLionel Sambuc size_t off, page_off, subcount; 229*433d6423SLionel Sambuc u64_t dv_size; 230*433d6423SLionel Sambuc int r; 231*433d6423SLionel Sambuc 232*433d6423SLionel Sambuc dv_size = m_geom[minor].dv_size; 233*433d6423SLionel Sambuc if (position >= dv_size) return 0; /* check for EOF */ 234*433d6423SLionel Sambuc if (position + size > dv_size) size = dv_size - position; 235*433d6423SLionel Sambuc 236*433d6423SLionel Sambuc /* Physical copying. Only used to access entire memory. 237*433d6423SLionel Sambuc * Transfer one 'page window' at a time. 238*433d6423SLionel Sambuc */ 239*433d6423SLionel Sambuc off = 0; 240*433d6423SLionel Sambuc while (off < size) { 241*433d6423SLionel Sambuc mem_phys = (phys_bytes) position; 242*433d6423SLionel Sambuc 243*433d6423SLionel Sambuc page_off = (size_t) (mem_phys % PAGE_SIZE); 244*433d6423SLionel Sambuc pagestart = mem_phys - page_off; 245*433d6423SLionel Sambuc 246*433d6423SLionel Sambuc /* All memory to the map call has to be page-aligned. 247*433d6423SLionel Sambuc * Don't have to map same page over and over. 248*433d6423SLionel Sambuc */ 249*433d6423SLionel Sambuc if (!any_mapped || pagestart_mapped != pagestart) { 250*433d6423SLionel Sambuc if (any_mapped) { 251*433d6423SLionel Sambuc if (vm_unmap_phys(SELF, vaddr, PAGE_SIZE) != OK) 252*433d6423SLionel Sambuc panic("vm_unmap_phys failed"); 253*433d6423SLionel Sambuc any_mapped = 0; 254*433d6423SLionel Sambuc } 255*433d6423SLionel Sambuc 256*433d6423SLionel Sambuc vaddr = vm_map_phys(SELF, (void *) pagestart, PAGE_SIZE); 257*433d6423SLionel Sambuc if (vaddr == MAP_FAILED) { 258*433d6423SLionel Sambuc printf("memory: vm_map_phys failed\n"); 259*433d6423SLionel Sambuc return ENOMEM; 260*433d6423SLionel Sambuc } 261*433d6423SLionel Sambuc any_mapped = 1; 262*433d6423SLionel Sambuc pagestart_mapped = pagestart; 263*433d6423SLionel Sambuc } 264*433d6423SLionel Sambuc 265*433d6423SLionel Sambuc /* how much to be done within this page. */ 266*433d6423SLionel Sambuc subcount = PAGE_SIZE - page_off; 267*433d6423SLionel Sambuc if (subcount > size) 268*433d6423SLionel Sambuc subcount = size; 269*433d6423SLionel Sambuc 270*433d6423SLionel Sambuc if (!do_write) /* copy data */ 271*433d6423SLionel Sambuc r = sys_safecopyto(endpt, grant, off, 272*433d6423SLionel Sambuc (vir_bytes) vaddr + page_off, subcount); 273*433d6423SLionel Sambuc else 274*433d6423SLionel Sambuc r = sys_safecopyfrom(endpt, grant, off, 275*433d6423SLionel Sambuc (vir_bytes) vaddr + page_off, subcount); 276*433d6423SLionel Sambuc if (r != OK) 277*433d6423SLionel Sambuc return r; 278*433d6423SLionel Sambuc 279*433d6423SLionel Sambuc position += subcount; 280*433d6423SLionel Sambuc off += subcount; 281*433d6423SLionel Sambuc } 282*433d6423SLionel Sambuc 283*433d6423SLionel Sambuc return off; 284*433d6423SLionel Sambuc } 285*433d6423SLionel Sambuc 286*433d6423SLionel Sambuc /*===========================================================================* 287*433d6423SLionel Sambuc * m_char_read * 288*433d6423SLionel Sambuc *===========================================================================*/ 289*433d6423SLionel Sambuc static ssize_t m_char_read(devminor_t minor, u64_t position, endpoint_t endpt, 290*433d6423SLionel Sambuc cp_grant_id_t grant, size_t size, int UNUSED(flags), 291*433d6423SLionel Sambuc cdev_id_t UNUSED(id)) 292*433d6423SLionel Sambuc { 293*433d6423SLionel Sambuc /* Read from one of the driver's character devices. */ 294*433d6423SLionel Sambuc ssize_t r; 295*433d6423SLionel Sambuc 296*433d6423SLionel Sambuc /* Check if the minor device number is ok. */ 297*433d6423SLionel Sambuc if (minor < 0 || minor >= NR_DEVS || m_is_block(minor)) return ENXIO; 298*433d6423SLionel Sambuc 299*433d6423SLionel Sambuc switch (minor) { 300*433d6423SLionel Sambuc case NULL_DEV: 301*433d6423SLionel Sambuc r = 0; /* always at EOF */ 302*433d6423SLionel Sambuc break; 303*433d6423SLionel Sambuc 304*433d6423SLionel Sambuc case ZERO_DEV: 305*433d6423SLionel Sambuc /* Fill the target area with zeroes. In fact, let the kernel do it! */ 306*433d6423SLionel Sambuc if ((r = sys_safememset(endpt, grant, 0, '\0', size)) == OK) 307*433d6423SLionel Sambuc r = size; 308*433d6423SLionel Sambuc break; 309*433d6423SLionel Sambuc 310*433d6423SLionel Sambuc case KMEM_DEV: 311*433d6423SLionel Sambuc r = m_transfer_kmem(minor, FALSE, position, endpt, grant, size); 312*433d6423SLionel Sambuc break; 313*433d6423SLionel Sambuc 314*433d6423SLionel Sambuc case MEM_DEV: 315*433d6423SLionel Sambuc r = m_transfer_mem(minor, FALSE, position, endpt, grant, size); 316*433d6423SLionel Sambuc break; 317*433d6423SLionel Sambuc 318*433d6423SLionel Sambuc default: 319*433d6423SLionel Sambuc panic("unknown character device %d", minor); 320*433d6423SLionel Sambuc } 321*433d6423SLionel Sambuc 322*433d6423SLionel Sambuc return r; 323*433d6423SLionel Sambuc } 324*433d6423SLionel Sambuc 325*433d6423SLionel Sambuc /*===========================================================================* 326*433d6423SLionel Sambuc * m_char_write * 327*433d6423SLionel Sambuc *===========================================================================*/ 328*433d6423SLionel Sambuc static ssize_t m_char_write(devminor_t minor, u64_t position, endpoint_t endpt, 329*433d6423SLionel Sambuc cp_grant_id_t grant, size_t size, int UNUSED(flags), 330*433d6423SLionel Sambuc cdev_id_t UNUSED(id)) 331*433d6423SLionel Sambuc { 332*433d6423SLionel Sambuc /* Write to one of the driver's character devices. */ 333*433d6423SLionel Sambuc ssize_t r; 334*433d6423SLionel Sambuc 335*433d6423SLionel Sambuc /* Check if the minor device number is ok. */ 336*433d6423SLionel Sambuc if (minor < 0 || minor >= NR_DEVS || m_is_block(minor)) return ENXIO; 337*433d6423SLionel Sambuc 338*433d6423SLionel Sambuc switch (minor) { 339*433d6423SLionel Sambuc case NULL_DEV: 340*433d6423SLionel Sambuc case ZERO_DEV: 341*433d6423SLionel Sambuc r = size; /* just eat everything */ 342*433d6423SLionel Sambuc break; 343*433d6423SLionel Sambuc 344*433d6423SLionel Sambuc case KMEM_DEV: 345*433d6423SLionel Sambuc r = m_transfer_kmem(minor, TRUE, position, endpt, grant, size); 346*433d6423SLionel Sambuc break; 347*433d6423SLionel Sambuc 348*433d6423SLionel Sambuc case MEM_DEV: 349*433d6423SLionel Sambuc r = m_transfer_mem(minor, TRUE, position, endpt, grant, size); 350*433d6423SLionel Sambuc break; 351*433d6423SLionel Sambuc 352*433d6423SLionel Sambuc default: 353*433d6423SLionel Sambuc panic("unknown character device %d", minor); 354*433d6423SLionel Sambuc } 355*433d6423SLionel Sambuc 356*433d6423SLionel Sambuc return r; 357*433d6423SLionel Sambuc } 358*433d6423SLionel Sambuc 359*433d6423SLionel Sambuc /*===========================================================================* 360*433d6423SLionel Sambuc * m_char_open * 361*433d6423SLionel Sambuc *===========================================================================*/ 362*433d6423SLionel Sambuc static int m_char_open(devminor_t minor, int access, endpoint_t user_endpt) 363*433d6423SLionel Sambuc { 364*433d6423SLionel Sambuc /* Open a memory character device. */ 365*433d6423SLionel Sambuc 366*433d6423SLionel Sambuc /* Check if the minor device number is ok. */ 367*433d6423SLionel Sambuc if (minor < 0 || minor >= NR_DEVS || m_is_block(minor)) return ENXIO; 368*433d6423SLionel Sambuc 369*433d6423SLionel Sambuc #if defined(__i386__) 370*433d6423SLionel Sambuc if (minor == MEM_DEV) 371*433d6423SLionel Sambuc { 372*433d6423SLionel Sambuc int r = sys_enable_iop(user_endpt); 373*433d6423SLionel Sambuc if (r != OK) 374*433d6423SLionel Sambuc { 375*433d6423SLionel Sambuc printf("m_char_open: sys_enable_iop failed for %d: %d\n", 376*433d6423SLionel Sambuc user_endpt, r); 377*433d6423SLionel Sambuc return r; 378*433d6423SLionel Sambuc } 379*433d6423SLionel Sambuc } 380*433d6423SLionel Sambuc #endif 381*433d6423SLionel Sambuc 382*433d6423SLionel Sambuc openct[minor]++; 383*433d6423SLionel Sambuc 384*433d6423SLionel Sambuc return(OK); 385*433d6423SLionel Sambuc } 386*433d6423SLionel Sambuc 387*433d6423SLionel Sambuc /*===========================================================================* 388*433d6423SLionel Sambuc * m_char_close * 389*433d6423SLionel Sambuc *===========================================================================*/ 390*433d6423SLionel Sambuc static int m_char_close(devminor_t minor) 391*433d6423SLionel Sambuc { 392*433d6423SLionel Sambuc /* Close a memory character device. */ 393*433d6423SLionel Sambuc 394*433d6423SLionel Sambuc if (minor < 0 || minor >= NR_DEVS || m_is_block(minor)) return ENXIO; 395*433d6423SLionel Sambuc 396*433d6423SLionel Sambuc if(openct[minor] < 1) { 397*433d6423SLionel Sambuc printf("MEMORY: closing unopened device %d\n", minor); 398*433d6423SLionel Sambuc return(EINVAL); 399*433d6423SLionel Sambuc } 400*433d6423SLionel Sambuc openct[minor]--; 401*433d6423SLionel Sambuc 402*433d6423SLionel Sambuc return(OK); 403*433d6423SLionel Sambuc } 404*433d6423SLionel Sambuc 405*433d6423SLionel Sambuc /*===========================================================================* 406*433d6423SLionel Sambuc * m_block_part * 407*433d6423SLionel Sambuc *===========================================================================*/ 408*433d6423SLionel Sambuc static struct device *m_block_part(devminor_t minor) 409*433d6423SLionel Sambuc { 410*433d6423SLionel Sambuc /* Prepare for I/O on a device: check if the minor device number is ok. */ 411*433d6423SLionel Sambuc if (minor < 0 || minor >= NR_DEVS || !m_is_block(minor)) return(NULL); 412*433d6423SLionel Sambuc 413*433d6423SLionel Sambuc return(&m_geom[minor]); 414*433d6423SLionel Sambuc } 415*433d6423SLionel Sambuc 416*433d6423SLionel Sambuc /*===========================================================================* 417*433d6423SLionel Sambuc * m_block_transfer * 418*433d6423SLionel Sambuc *===========================================================================*/ 419*433d6423SLionel Sambuc static int m_block_transfer( 420*433d6423SLionel Sambuc devminor_t minor, /* minor device number */ 421*433d6423SLionel Sambuc int do_write, /* read or write? */ 422*433d6423SLionel Sambuc u64_t position, /* offset on device to read or write */ 423*433d6423SLionel Sambuc endpoint_t endpt, /* process doing the request */ 424*433d6423SLionel Sambuc iovec_t *iov, /* pointer to read or write request vector */ 425*433d6423SLionel Sambuc unsigned int nr_req, /* length of request vector */ 426*433d6423SLionel Sambuc int UNUSED(flags) /* transfer flags */ 427*433d6423SLionel Sambuc ) 428*433d6423SLionel Sambuc { 429*433d6423SLionel Sambuc /* Read or write one the driver's block devices. */ 430*433d6423SLionel Sambuc unsigned count; 431*433d6423SLionel Sambuc vir_bytes vir_offset = 0; 432*433d6423SLionel Sambuc struct device *dv; 433*433d6423SLionel Sambuc u64_t dv_size; 434*433d6423SLionel Sambuc int r; 435*433d6423SLionel Sambuc vir_bytes dev_vaddr; 436*433d6423SLionel Sambuc cp_grant_id_t grant; 437*433d6423SLionel Sambuc ssize_t total = 0; 438*433d6423SLionel Sambuc 439*433d6423SLionel Sambuc /* Get minor device information. */ 440*433d6423SLionel Sambuc if ((dv = m_block_part(minor)) == NULL) return(ENXIO); 441*433d6423SLionel Sambuc dv_size = dv->dv_size; 442*433d6423SLionel Sambuc dev_vaddr = m_vaddrs[minor]; 443*433d6423SLionel Sambuc 444*433d6423SLionel Sambuc if (ex64hi(position) != 0) 445*433d6423SLionel Sambuc return OK; /* Beyond EOF */ 446*433d6423SLionel Sambuc 447*433d6423SLionel Sambuc while (nr_req > 0) { 448*433d6423SLionel Sambuc 449*433d6423SLionel Sambuc /* How much to transfer and where to / from. */ 450*433d6423SLionel Sambuc count = iov->iov_size; 451*433d6423SLionel Sambuc grant = (cp_grant_id_t) iov->iov_addr; 452*433d6423SLionel Sambuc 453*433d6423SLionel Sambuc /* Virtual copying. For RAM disks and internal FS. */ 454*433d6423SLionel Sambuc if(!dev_vaddr || dev_vaddr == (vir_bytes) MAP_FAILED) { 455*433d6423SLionel Sambuc printf("MEM: dev %d not initialized\n", minor); 456*433d6423SLionel Sambuc return EIO; 457*433d6423SLionel Sambuc } 458*433d6423SLionel Sambuc if (position >= dv_size) return(total); /* check for EOF */ 459*433d6423SLionel Sambuc if (position + count > dv_size) count = dv_size - position; 460*433d6423SLionel Sambuc if (!do_write) { /* copy actual data */ 461*433d6423SLionel Sambuc r=sys_safecopyto(endpt, grant, vir_offset, 462*433d6423SLionel Sambuc dev_vaddr + position, count); 463*433d6423SLionel Sambuc } else { 464*433d6423SLionel Sambuc r=sys_safecopyfrom(endpt, grant, vir_offset, 465*433d6423SLionel Sambuc dev_vaddr + position, count); 466*433d6423SLionel Sambuc } 467*433d6423SLionel Sambuc if(r != OK) { 468*433d6423SLionel Sambuc panic("I/O copy failed: %d", r); 469*433d6423SLionel Sambuc } 470*433d6423SLionel Sambuc 471*433d6423SLionel Sambuc /* Book the number of bytes transferred. */ 472*433d6423SLionel Sambuc position += count; 473*433d6423SLionel Sambuc vir_offset += count; 474*433d6423SLionel Sambuc total += count; 475*433d6423SLionel Sambuc if ((iov->iov_size -= count) == 0) { iov++; nr_req--; vir_offset = 0; } 476*433d6423SLionel Sambuc 477*433d6423SLionel Sambuc } 478*433d6423SLionel Sambuc return(total); 479*433d6423SLionel Sambuc } 480*433d6423SLionel Sambuc 481*433d6423SLionel Sambuc /*===========================================================================* 482*433d6423SLionel Sambuc * m_block_open * 483*433d6423SLionel Sambuc *===========================================================================*/ 484*433d6423SLionel Sambuc static int m_block_open(devminor_t minor, int UNUSED(access)) 485*433d6423SLionel Sambuc { 486*433d6423SLionel Sambuc /* Open a memory block device. */ 487*433d6423SLionel Sambuc if (m_block_part(minor) == NULL) return(ENXIO); 488*433d6423SLionel Sambuc 489*433d6423SLionel Sambuc openct[minor]++; 490*433d6423SLionel Sambuc 491*433d6423SLionel Sambuc return(OK); 492*433d6423SLionel Sambuc } 493*433d6423SLionel Sambuc 494*433d6423SLionel Sambuc /*===========================================================================* 495*433d6423SLionel Sambuc * m_block_close * 496*433d6423SLionel Sambuc *===========================================================================*/ 497*433d6423SLionel Sambuc static int m_block_close(devminor_t minor) 498*433d6423SLionel Sambuc { 499*433d6423SLionel Sambuc /* Close a memory block device. */ 500*433d6423SLionel Sambuc if (m_block_part(minor) == NULL) return(ENXIO); 501*433d6423SLionel Sambuc 502*433d6423SLionel Sambuc if(openct[minor] < 1) { 503*433d6423SLionel Sambuc printf("MEMORY: closing unopened device %d\n", minor); 504*433d6423SLionel Sambuc return(EINVAL); 505*433d6423SLionel Sambuc } 506*433d6423SLionel Sambuc openct[minor]--; 507*433d6423SLionel Sambuc 508*433d6423SLionel Sambuc return(OK); 509*433d6423SLionel Sambuc } 510*433d6423SLionel Sambuc 511*433d6423SLionel Sambuc /*===========================================================================* 512*433d6423SLionel Sambuc * m_block_ioctl * 513*433d6423SLionel Sambuc *===========================================================================*/ 514*433d6423SLionel Sambuc static int m_block_ioctl(devminor_t minor, unsigned long request, 515*433d6423SLionel Sambuc endpoint_t endpt, cp_grant_id_t grant, endpoint_t UNUSED(user_endpt)) 516*433d6423SLionel Sambuc { 517*433d6423SLionel Sambuc /* I/O controls for the block devices of the memory driver. Currently there is 518*433d6423SLionel Sambuc * one I/O control specific to the memory driver: 519*433d6423SLionel Sambuc * - MIOCRAMSIZE: to set the size of the RAM disk. 520*433d6423SLionel Sambuc */ 521*433d6423SLionel Sambuc struct device *dv; 522*433d6423SLionel Sambuc u32_t ramdev_size; 523*433d6423SLionel Sambuc int s; 524*433d6423SLionel Sambuc void *mem; 525*433d6423SLionel Sambuc int is_imgrd = 0; 526*433d6423SLionel Sambuc 527*433d6423SLionel Sambuc if (request != MIOCRAMSIZE) 528*433d6423SLionel Sambuc return EINVAL; 529*433d6423SLionel Sambuc 530*433d6423SLionel Sambuc if(minor == IMGRD_DEV) 531*433d6423SLionel Sambuc is_imgrd = 1; 532*433d6423SLionel Sambuc 533*433d6423SLionel Sambuc /* Someone wants to create a new RAM disk with the given size. 534*433d6423SLionel Sambuc * A ramdisk can be created only once, and only on RAM disk device. 535*433d6423SLionel Sambuc */ 536*433d6423SLionel Sambuc if ((dv = m_block_part(minor)) == NULL) return ENXIO; 537*433d6423SLionel Sambuc if((minor < RAM_DEV_FIRST || minor > RAM_DEV_LAST) && 538*433d6423SLionel Sambuc minor != RAM_DEV_OLD && !is_imgrd) { 539*433d6423SLionel Sambuc printf("MEM: MIOCRAMSIZE: %d not a ramdisk\n", minor); 540*433d6423SLionel Sambuc return EINVAL; 541*433d6423SLionel Sambuc } 542*433d6423SLionel Sambuc 543*433d6423SLionel Sambuc /* Get request structure */ 544*433d6423SLionel Sambuc s= sys_safecopyfrom(endpt, grant, 0, (vir_bytes)&ramdev_size, 545*433d6423SLionel Sambuc sizeof(ramdev_size)); 546*433d6423SLionel Sambuc if (s != OK) 547*433d6423SLionel Sambuc return s; 548*433d6423SLionel Sambuc if(is_imgrd) 549*433d6423SLionel Sambuc ramdev_size = 0; 550*433d6423SLionel Sambuc if(m_vaddrs[minor] && dv->dv_size == (u64_t) ramdev_size) { 551*433d6423SLionel Sambuc return(OK); 552*433d6423SLionel Sambuc } 553*433d6423SLionel Sambuc /* openct is 1 for the ioctl(). */ 554*433d6423SLionel Sambuc if(openct[minor] != 1) { 555*433d6423SLionel Sambuc printf("MEM: MIOCRAMSIZE: %d in use (count %d)\n", 556*433d6423SLionel Sambuc minor, openct[minor]); 557*433d6423SLionel Sambuc return(EBUSY); 558*433d6423SLionel Sambuc } 559*433d6423SLionel Sambuc if(m_vaddrs[minor]) { 560*433d6423SLionel Sambuc u32_t a, o; 561*433d6423SLionel Sambuc u64_t size; 562*433d6423SLionel Sambuc int r; 563*433d6423SLionel Sambuc if(ex64hi(dv->dv_size)) { 564*433d6423SLionel Sambuc panic("huge old ramdisk"); 565*433d6423SLionel Sambuc } 566*433d6423SLionel Sambuc size = dv->dv_size; 567*433d6423SLionel Sambuc a = m_vaddrs[minor]; 568*433d6423SLionel Sambuc if((o = a % PAGE_SIZE)) { 569*433d6423SLionel Sambuc vir_bytes l = PAGE_SIZE - o; 570*433d6423SLionel Sambuc a += l; 571*433d6423SLionel Sambuc size -= l; 572*433d6423SLionel Sambuc } 573*433d6423SLionel Sambuc size = rounddown(size, PAGE_SIZE); 574*433d6423SLionel Sambuc r = munmap((void *) a, size); 575*433d6423SLionel Sambuc if(r != OK) { 576*433d6423SLionel Sambuc printf("memory: WARNING: munmap failed: %d\n", r); 577*433d6423SLionel Sambuc } 578*433d6423SLionel Sambuc m_vaddrs[minor] = (vir_bytes) NULL; 579*433d6423SLionel Sambuc dv->dv_size = 0; 580*433d6423SLionel Sambuc } 581*433d6423SLionel Sambuc 582*433d6423SLionel Sambuc #if DEBUG 583*433d6423SLionel Sambuc printf("MEM:%d: allocating ramdisk of size 0x%x\n", minor, ramdev_size); 584*433d6423SLionel Sambuc #endif 585*433d6423SLionel Sambuc 586*433d6423SLionel Sambuc mem = NULL; 587*433d6423SLionel Sambuc 588*433d6423SLionel Sambuc /* Try to allocate a piece of memory for the RAM disk. */ 589*433d6423SLionel Sambuc if(ramdev_size > 0 && 590*433d6423SLionel Sambuc (mem = mmap(NULL, ramdev_size, PROT_READ|PROT_WRITE, 591*433d6423SLionel Sambuc MAP_PREALLOC|MAP_ANON, -1, 0)) == MAP_FAILED) { 592*433d6423SLionel Sambuc printf("MEM: failed to get memory for ramdisk\n"); 593*433d6423SLionel Sambuc return(ENOMEM); 594*433d6423SLionel Sambuc } 595*433d6423SLionel Sambuc 596*433d6423SLionel Sambuc m_vaddrs[minor] = (vir_bytes) mem; 597*433d6423SLionel Sambuc 598*433d6423SLionel Sambuc dv->dv_size = ramdev_size; 599*433d6423SLionel Sambuc 600*433d6423SLionel Sambuc return(OK); 601*433d6423SLionel Sambuc } 602