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