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 *===========================================================================*/
do_vdevio(struct proc * caller,message * m_ptr)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