For /dev/mem, map in memory to be copied to memory's own address space
[minix3.git] / kernel / system / do_vdevio.c
blob0d6e3c718b51a1b96b417afab9c5f1cc27a1039a
1 /* The kernel call implemented in this file:
2 * m_type: SYS_VDEVIO
4 * The parameters for this kernel call are:
5 * m2_i3: DIO_REQUEST (request input or output)
6 * m2_i1: DIO_TYPE (flag indicating byte, word, or long)
7 * m2_p1: DIO_VEC_ADDR (pointer to port/ value pairs)
8 * m2_i2: DIO_VEC_SIZE (number of ports to read or write)
9 */
11 #include "../system.h"
12 #include <minix/devio.h>
13 #include <minix/endpoint.h>
14 #include <minix/portio.h>
16 #if USE_VDEVIO
18 /* Buffer for SYS_VDEVIO to copy (port,value)-pairs from/ to user. */
19 PRIVATE char vdevio_buf[VDEVIO_BUF_SIZE];
20 PRIVATE pvb_pair_t *pvb = (pvb_pair_t *) vdevio_buf;
21 PRIVATE pvw_pair_t *pvw = (pvw_pair_t *) vdevio_buf;
22 PRIVATE pvl_pair_t *pvl = (pvl_pair_t *) vdevio_buf;
24 /*===========================================================================*
25 * do_vdevio *
26 *===========================================================================*/
27 PUBLIC int do_vdevio(m_ptr)
28 register message *m_ptr; /* pointer to request message */
30 /* Perform a series of device I/O on behalf of a non-kernel process. The
31 * I/O addresses and I/O values are fetched from and returned to some buffer
32 * in user space. The actual I/O is wrapped by lock() and unlock() to prevent
33 * that I/O batch from being interrrupted.
34 * This is the counterpart of do_devio, which performs a single device I/O.
35 */
36 int vec_size; /* size of vector */
37 int io_in; /* true if input */
38 size_t bytes; /* # bytes to be copied */
39 vir_bytes caller_vir; /* virtual address at caller */
40 phys_bytes caller_phys; /* physical address at caller */
41 port_t port;
42 int i, j, io_size, nr_io_range;
43 int io_dir, io_type;
44 struct proc *rp;
45 struct priv *privp;
46 struct io_range *iorp;
48 /* Get the request, size of the request vector, and check the values. */
49 io_dir = m_ptr->DIO_REQUEST & _DIO_DIRMASK;
50 io_type = m_ptr->DIO_REQUEST & _DIO_TYPEMASK;
51 if (io_dir == _DIO_INPUT) io_in = TRUE;
52 else if (io_dir == _DIO_OUTPUT) io_in = FALSE;
53 else return(EINVAL);
54 if ((vec_size = m_ptr->DIO_VEC_SIZE) <= 0) return(EINVAL);
55 switch (io_type) {
56 case _DIO_BYTE:
57 bytes = vec_size * sizeof(pvb_pair_t);
58 io_size= sizeof(u8_t);
59 break;
60 case _DIO_WORD:
61 bytes = vec_size * sizeof(pvw_pair_t);
62 io_size= sizeof(u16_t);
63 break;
64 case _DIO_LONG:
65 bytes = vec_size * sizeof(pvl_pair_t);
66 io_size= sizeof(u32_t);
67 break;
68 default: return(EINVAL); /* check type once and for all */
70 if (bytes > sizeof(vdevio_buf)) return(E2BIG);
72 /* Calculate physical addresses and copy (port,value)-pairs from user. */
73 caller_vir = (vir_bytes) m_ptr->DIO_VEC_ADDR;
74 caller_phys = umap_local(proc_addr(who_p), D, caller_vir, bytes);
75 if (0 == caller_phys) return(EFAULT);
76 phys_copy(caller_phys, vir2phys(vdevio_buf), (phys_bytes) bytes);
78 rp= proc_addr(who_p);
79 privp= priv(rp);
80 if (privp && (privp->s_flags & CHECK_IO_PORT))
82 /* Check whether the I/O is allowed */
83 nr_io_range= privp->s_nr_io_range;
84 for (i=0; i<vec_size; i++)
86 switch (io_type) {
87 case _DIO_BYTE: port= pvb[i].port; break;
88 case _DIO_WORD: port= pvw[i].port; break;
89 default: port= pvl[i].port; break;
91 for (j= 0, iorp= privp->s_io_tab; j<nr_io_range; j++, iorp++)
93 if (port >= iorp->ior_base &&
94 port+io_size-1 <= iorp->ior_limit)
96 break;
99 if (j >= nr_io_range)
101 kprintf(
102 "do_vdevio: I/O port check failed for proc %d, port 0x%x\n",
103 m_ptr->m_source, port);
104 return EPERM;
109 /* Perform actual device I/O for byte, word, and long values. Note that
110 * the entire switch is wrapped in lock() and unlock() to prevent the I/O
111 * batch from being interrupted.
113 lock(13, "do_vdevio");
114 switch (io_type) {
115 case _DIO_BYTE: /* byte values */
116 if (io_in) for (i=0; i<vec_size; i++)
117 pvb[i].value = inb( pvb[i].port);
118 else for (i=0; i<vec_size; i++)
119 outb( pvb[i].port, pvb[i].value);
120 break;
121 case _DIO_WORD: /* word values */
122 if (io_in) for (i=0; i<vec_size; i++)
123 pvw[i].value = inw( pvw[i].port);
124 else for (i=0; i<vec_size; i++)
125 outw( pvw[i].port, pvw[i].value);
126 break;
127 default: /* long values */
128 if (io_in) for (i=0; i<vec_size; i++)
129 pvl[i].value = inl(pvl[i].port);
130 else for (i=0; i<vec_size; i++)
131 outl( pvb[i].port, pvl[i].value);
133 unlock(13);
135 /* Almost done, copy back results for input requests. */
136 if (io_in) phys_copy(vir2phys(vdevio_buf), caller_phys, (phys_bytes) bytes);
137 return(OK);
140 #endif /* USE_VDEVIO */