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