1*433d6423SLionel Sambuc /* The kernel call implemented in this file: 2*433d6423SLionel Sambuc * m_type: SYS_VDEVIO 3*433d6423SLionel Sambuc * 4*433d6423SLionel Sambuc * The parameters for this kernel call are: 5*433d6423SLionel Sambuc * m_lsys_krn_sys_vdevio.request (request input or output) 6*433d6423SLionel Sambuc * m_lsys_krn_sys_vdevio.vec_addr (pointer to port/ value pairs) 7*433d6423SLionel Sambuc * m_lsys_krn_sys_vdevio.vec_size (number of ports to read or write) 8*433d6423SLionel Sambuc */ 9*433d6423SLionel Sambuc 10*433d6423SLionel Sambuc #include "kernel/system.h" 11*433d6423SLionel Sambuc #include <minix/devio.h> 12*433d6423SLionel Sambuc #include <minix/endpoint.h> 13*433d6423SLionel Sambuc #include <minix/portio.h> 14*433d6423SLionel Sambuc 15*433d6423SLionel Sambuc #if USE_VDEVIO 16*433d6423SLionel Sambuc 17*433d6423SLionel Sambuc /* Buffer for SYS_VDEVIO to copy (port,value)-pairs from/ to user. */ 18*433d6423SLionel Sambuc static char vdevio_buf[VDEVIO_BUF_SIZE]; 19*433d6423SLionel Sambuc static pvb_pair_t * const pvb = (pvb_pair_t *) vdevio_buf; 20*433d6423SLionel Sambuc static pvw_pair_t * const pvw = (pvw_pair_t *) vdevio_buf; 21*433d6423SLionel Sambuc static pvl_pair_t * const pvl = (pvl_pair_t *) vdevio_buf; 22*433d6423SLionel Sambuc 23*433d6423SLionel Sambuc /*===========================================================================* 24*433d6423SLionel Sambuc * do_vdevio * 25*433d6423SLionel Sambuc *===========================================================================*/ 26*433d6423SLionel Sambuc int do_vdevio(struct proc * caller, message * m_ptr) 27*433d6423SLionel Sambuc { 28*433d6423SLionel Sambuc /* Perform a series of device I/O on behalf of a non-kernel process. The 29*433d6423SLionel Sambuc * I/O addresses and I/O values are fetched from and returned to some buffer 30*433d6423SLionel Sambuc * in user space. The actual I/O is wrapped by lock() and unlock() to prevent 31*433d6423SLionel Sambuc * that I/O batch from being interrupted. 32*433d6423SLionel Sambuc * This is the counterpart of do_devio, which performs a single device I/O. 33*433d6423SLionel Sambuc */ 34*433d6423SLionel Sambuc int vec_size; /* size of vector */ 35*433d6423SLionel Sambuc int io_in; /* true if input */ 36*433d6423SLionel Sambuc size_t bytes; /* # bytes to be copied */ 37*433d6423SLionel Sambuc port_t port; 38*433d6423SLionel Sambuc int i, j, io_size, nr_io_range; 39*433d6423SLionel Sambuc int io_dir, io_type; 40*433d6423SLionel Sambuc struct priv *privp; 41*433d6423SLionel Sambuc struct io_range *iorp; 42*433d6423SLionel Sambuc int r; 43*433d6423SLionel Sambuc 44*433d6423SLionel Sambuc /* Get the request, size of the request vector, and check the values. */ 45*433d6423SLionel Sambuc io_dir = m_ptr->m_lsys_krn_sys_vdevio.request & _DIO_DIRMASK; 46*433d6423SLionel Sambuc io_type = m_ptr->m_lsys_krn_sys_vdevio.request & _DIO_TYPEMASK; 47*433d6423SLionel Sambuc if (io_dir == _DIO_INPUT) io_in = TRUE; 48*433d6423SLionel Sambuc else if (io_dir == _DIO_OUTPUT) io_in = FALSE; 49*433d6423SLionel Sambuc else return(EINVAL); 50*433d6423SLionel Sambuc if ((vec_size = m_ptr->m_lsys_krn_sys_vdevio.vec_size) <= 0) return(EINVAL); 51*433d6423SLionel Sambuc switch (io_type) { 52*433d6423SLionel Sambuc case _DIO_BYTE: 53*433d6423SLionel Sambuc bytes = vec_size * sizeof(pvb_pair_t); 54*433d6423SLionel Sambuc io_size= sizeof(u8_t); 55*433d6423SLionel Sambuc break; 56*433d6423SLionel Sambuc case _DIO_WORD: 57*433d6423SLionel Sambuc bytes = vec_size * sizeof(pvw_pair_t); 58*433d6423SLionel Sambuc io_size= sizeof(u16_t); 59*433d6423SLionel Sambuc break; 60*433d6423SLionel Sambuc case _DIO_LONG: 61*433d6423SLionel Sambuc bytes = vec_size * sizeof(pvl_pair_t); 62*433d6423SLionel Sambuc io_size= sizeof(u32_t); 63*433d6423SLionel Sambuc break; 64*433d6423SLionel Sambuc default: return(EINVAL); /* check type once and for all */ 65*433d6423SLionel Sambuc } 66*433d6423SLionel Sambuc if (bytes > sizeof(vdevio_buf)) return(E2BIG); 67*433d6423SLionel Sambuc 68*433d6423SLionel Sambuc /* Copy (port,value)-pairs from user. */ 69*433d6423SLionel Sambuc if((r=data_copy(caller->p_endpoint, m_ptr->m_lsys_krn_sys_vdevio.vec_addr, 70*433d6423SLionel Sambuc KERNEL, (vir_bytes) vdevio_buf, bytes)) != OK) 71*433d6423SLionel Sambuc return r; 72*433d6423SLionel Sambuc 73*433d6423SLionel Sambuc privp= priv(caller); 74*433d6423SLionel Sambuc if (privp && (privp->s_flags & CHECK_IO_PORT)) 75*433d6423SLionel Sambuc { 76*433d6423SLionel Sambuc /* Check whether the I/O is allowed */ 77*433d6423SLionel Sambuc nr_io_range= privp->s_nr_io_range; 78*433d6423SLionel Sambuc for (i=0; i<vec_size; i++) 79*433d6423SLionel Sambuc { 80*433d6423SLionel Sambuc switch (io_type) { 81*433d6423SLionel Sambuc case _DIO_BYTE: port= pvb[i].port; break; 82*433d6423SLionel Sambuc case _DIO_WORD: port= pvw[i].port; break; 83*433d6423SLionel Sambuc default: port= pvl[i].port; break; 84*433d6423SLionel Sambuc } 85*433d6423SLionel Sambuc for (j= 0, iorp= privp->s_io_tab; j<nr_io_range; j++, iorp++) 86*433d6423SLionel Sambuc { 87*433d6423SLionel Sambuc if (port >= iorp->ior_base && 88*433d6423SLionel Sambuc port+io_size-1 <= iorp->ior_limit) 89*433d6423SLionel Sambuc { 90*433d6423SLionel Sambuc break; 91*433d6423SLionel Sambuc } 92*433d6423SLionel Sambuc } 93*433d6423SLionel Sambuc if (j >= nr_io_range) 94*433d6423SLionel Sambuc { 95*433d6423SLionel Sambuc printf( 96*433d6423SLionel Sambuc "do_vdevio: I/O port check failed for proc %d, port 0x%x\n", 97*433d6423SLionel Sambuc caller->p_endpoint, port); 98*433d6423SLionel Sambuc return EPERM; 99*433d6423SLionel Sambuc } 100*433d6423SLionel Sambuc } 101*433d6423SLionel Sambuc } 102*433d6423SLionel Sambuc 103*433d6423SLionel Sambuc /* Perform actual device I/O for byte, word, and long values */ 104*433d6423SLionel Sambuc switch (io_type) { 105*433d6423SLionel Sambuc case _DIO_BYTE: /* byte values */ 106*433d6423SLionel Sambuc if (io_in) for (i=0; i<vec_size; i++) 107*433d6423SLionel Sambuc pvb[i].value = inb( pvb[i].port); 108*433d6423SLionel Sambuc else for (i=0; i<vec_size; i++) 109*433d6423SLionel Sambuc outb( pvb[i].port, pvb[i].value); 110*433d6423SLionel Sambuc break; 111*433d6423SLionel Sambuc case _DIO_WORD: /* word values */ 112*433d6423SLionel Sambuc if (io_in) 113*433d6423SLionel Sambuc { 114*433d6423SLionel Sambuc for (i=0; i<vec_size; i++) 115*433d6423SLionel Sambuc { 116*433d6423SLionel Sambuc port= pvw[i].port; 117*433d6423SLionel Sambuc if (port & 1) goto bad; 118*433d6423SLionel Sambuc pvw[i].value = inw( pvw[i].port); 119*433d6423SLionel Sambuc } 120*433d6423SLionel Sambuc } 121*433d6423SLionel Sambuc else 122*433d6423SLionel Sambuc { 123*433d6423SLionel Sambuc for (i=0; i<vec_size; i++) 124*433d6423SLionel Sambuc { 125*433d6423SLionel Sambuc port= pvw[i].port; 126*433d6423SLionel Sambuc if (port & 1) goto bad; 127*433d6423SLionel Sambuc outw( pvw[i].port, pvw[i].value); 128*433d6423SLionel Sambuc } 129*433d6423SLionel Sambuc } 130*433d6423SLionel Sambuc break; 131*433d6423SLionel Sambuc default: /* long values */ 132*433d6423SLionel Sambuc if (io_in) 133*433d6423SLionel Sambuc { 134*433d6423SLionel Sambuc for (i=0; i<vec_size; i++) 135*433d6423SLionel Sambuc { 136*433d6423SLionel Sambuc port= pvl[i].port; 137*433d6423SLionel Sambuc if (port & 3) goto bad; 138*433d6423SLionel Sambuc pvl[i].value = inl(pvl[i].port); 139*433d6423SLionel Sambuc } 140*433d6423SLionel Sambuc } 141*433d6423SLionel Sambuc else 142*433d6423SLionel Sambuc { 143*433d6423SLionel Sambuc for (i=0; i<vec_size; i++) 144*433d6423SLionel Sambuc { 145*433d6423SLionel Sambuc port= pvl[i].port; 146*433d6423SLionel Sambuc if (port & 3) goto bad; 147*433d6423SLionel Sambuc outl( pvb[i].port, pvl[i].value); 148*433d6423SLionel Sambuc } 149*433d6423SLionel Sambuc } 150*433d6423SLionel Sambuc } 151*433d6423SLionel Sambuc 152*433d6423SLionel Sambuc /* Almost done, copy back results for input requests. */ 153*433d6423SLionel Sambuc if (io_in) 154*433d6423SLionel Sambuc if((r=data_copy(KERNEL, (vir_bytes) vdevio_buf, 155*433d6423SLionel Sambuc caller->p_endpoint, m_ptr->m_lsys_krn_sys_vdevio.vec_addr, 156*433d6423SLionel Sambuc (phys_bytes) bytes)) != OK) 157*433d6423SLionel Sambuc return r; 158*433d6423SLionel Sambuc return(OK); 159*433d6423SLionel Sambuc 160*433d6423SLionel Sambuc bad: 161*433d6423SLionel Sambuc panic("do_vdevio: unaligned port: %d", port); 162*433d6423SLionel Sambuc return EPERM; 163*433d6423SLionel Sambuc } 164*433d6423SLionel Sambuc 165*433d6423SLionel Sambuc #endif /* USE_VDEVIO */ 166*433d6423SLionel Sambuc 167