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