mkfs: move directory entry manipulation
[minix.git] / kernel / arch / i386 / do_sdevio.c
blob23ea4fa240a926a3f73830fb91e5f34a234d2644
1 /* The kernel call implemented in this file:
2 * m_type: SYS_SDEVIO
4 * The parameters for this kernel call are:
5 * m2_i3: DIO_REQUEST (request input or output)
6 * m2_l1: DIO_PORT (port to read/ write)
7 * m2_p1: DIO_VEC_ADDR (virtual address of buffer, or grant ID)
8 * m2_l2: DIO_VEC_SIZE (number of elements)
9 * m2_i2: DIO_VEC_PROC (process where buffer is)
10 * m2_i1: DIO_OFFSET (offset into the grant)
13 #include "kernel/system.h"
14 #include <minix/devio.h>
15 #include <minix/endpoint.h>
17 #include "arch_proto.h"
19 #if USE_SDEVIO
21 /*===========================================================================*
22 * do_sdevio *
23 *===========================================================================*/
24 int do_sdevio(struct proc * caller, message *m_ptr)
26 vir_bytes newoffset;
27 endpoint_t newep;
28 int proc_nr;
29 endpoint_t proc_nr_e = m_ptr->DIO_VEC_ENDPT;
30 vir_bytes count = m_ptr->DIO_VEC_SIZE;
31 long port = m_ptr->DIO_PORT;
32 phys_bytes vir_buf;
33 int i, req_type, req_dir, size, nr_io_range;
34 struct priv *privp;
35 struct io_range *iorp;
36 struct proc *destproc;
37 int retval;
39 /* Allow safe copies and accesses to SELF */
40 if ((m_ptr->DIO_REQUEST & _DIO_SAFEMASK) != _DIO_SAFE &&
41 proc_nr_e != SELF)
43 static int first= 1;
44 if (first)
46 first= 0;
47 printf("do_sdevio: for %d, req %d\n",
48 m_ptr->m_source, m_ptr->DIO_REQUEST);
52 /* Check if process endpoint is OK.
53 * A driver may directly provide a pointer to a buffer at the user-process
54 * that initiated the device I/O. Kernel processes, of course, are denied.
56 if (proc_nr_e == SELF)
57 okendpt(caller->p_endpoint, &proc_nr);
58 else
59 if(!isokendpt(proc_nr_e, &proc_nr))
60 return(EINVAL);
61 if (iskerneln(proc_nr)) return(EPERM);
63 /* Extract direction (in or out) and type (size). */
64 req_dir = m_ptr->DIO_REQUEST & _DIO_DIRMASK;
65 req_type = m_ptr->DIO_REQUEST & _DIO_TYPEMASK;
67 /* Check for 'safe' variants. */
68 if((m_ptr->DIO_REQUEST & _DIO_SAFEMASK) == _DIO_SAFE) {
69 /* Map grant address to physical address. */
70 if(verify_grant(proc_nr_e, caller->p_endpoint,
71 (cp_grant_id_t) m_ptr->DIO_VEC_ADDR,
72 count,
73 req_dir == _DIO_INPUT ? CPF_WRITE : CPF_READ,
74 (vir_bytes) m_ptr->DIO_OFFSET,
75 &newoffset, &newep) != OK) {
76 printf("do_sdevio: verify_grant failed\n");
77 return EPERM;
79 if(!isokendpt(newep, &proc_nr))
80 return(EINVAL);
81 destproc = proc_addr(proc_nr);
82 vir_buf = newoffset;
83 } else {
84 if(proc_nr != _ENDPOINT_P(caller->p_endpoint))
86 printf("do_sdevio: unsafe sdevio by %d in %d denied\n",
87 caller->p_endpoint, proc_nr_e);
88 return EPERM;
90 /* Get and check physical address. */
91 vir_buf = (phys_bytes) m_ptr->DIO_VEC_ADDR;
92 destproc = proc_addr(proc_nr);
94 /* current process must be target for phys_* to be OK */
96 switch_address_space(destproc);
98 switch (req_type)
100 case _DIO_BYTE: size= 1; break;
101 case _DIO_WORD: size= 2; break;
102 case _DIO_LONG: size= 4; break;
103 default: size= 4; break; /* Be conservative */
106 privp= priv(caller);
107 if (privp && privp->s_flags & CHECK_IO_PORT)
109 port= m_ptr->DIO_PORT;
110 nr_io_range= privp->s_nr_io_range;
111 for (i= 0, iorp= privp->s_io_tab; i<nr_io_range; i++, iorp++)
113 if (port >= iorp->ior_base && port+size-1 <= iorp->ior_limit)
114 break;
116 if (i >= nr_io_range)
118 printf(
119 "do_sdevio: I/O port check failed for proc %d, port 0x%x\n",
120 m_ptr->m_source, port);
121 retval = EPERM;
122 goto return_error;
126 if (port & (size-1))
128 printf("do_devio: unaligned port 0x%x (size %d)\n", port, size);
129 retval = EPERM;
130 goto return_error;
133 /* Perform device I/O for bytes and words. Longs are not supported. */
134 if (req_dir == _DIO_INPUT) {
135 switch (req_type) {
136 case _DIO_BYTE: phys_insb(port, vir_buf, count); break;
137 case _DIO_WORD: phys_insw(port, vir_buf, count); break;
138 default:
139 retval = EINVAL;
140 goto return_error;
142 } else if (req_dir == _DIO_OUTPUT) {
143 switch (req_type) {
144 case _DIO_BYTE: phys_outsb(port, vir_buf, count); break;
145 case _DIO_WORD: phys_outsw(port, vir_buf, count); break;
146 default:
147 retval = EINVAL;
148 goto return_error;
151 else {
152 retval = EINVAL;
153 goto return_error;
155 retval = OK;
157 return_error:
158 /* switch back to the address of the process which made the call */
159 switch_address_space(caller);
160 return retval;
163 #endif /* USE_SDEVIO */