1 /* The kernel call implemented in this file:
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"
21 /*===========================================================================*
23 *===========================================================================*/
24 int do_sdevio(struct proc
* caller
, message
*m_ptr
)
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
;
33 int i
, req_type
, req_dir
, size
, nr_io_range
;
35 struct io_range
*iorp
;
36 struct proc
*destproc
;
39 /* Allow safe copies and accesses to SELF */
40 if ((m_ptr
->DIO_REQUEST
& _DIO_SAFEMASK
) != _DIO_SAFE
&&
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
);
59 if(!isokendpt(proc_nr_e
, &proc_nr
))
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
,
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");
79 if(!isokendpt(newep
, &proc_nr
))
81 destproc
= proc_addr(proc_nr
);
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
);
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
);
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 */
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
)
116 if (i
>= nr_io_range
)
119 "do_sdevio: I/O port check failed for proc %d, port 0x%x\n",
120 m_ptr
->m_source
, port
);
128 printf("do_devio: unaligned port 0x%x (size %d)\n", port
, size
);
133 /* Perform device I/O for bytes and words. Longs are not supported. */
134 if (req_dir
== _DIO_INPUT
) {
136 case _DIO_BYTE
: phys_insb(port
, vir_buf
, count
); break;
137 case _DIO_WORD
: phys_insw(port
, vir_buf
, count
); break;
142 } else if (req_dir
== _DIO_OUTPUT
) {
144 case _DIO_BYTE
: phys_outsb(port
, vir_buf
, count
); break;
145 case _DIO_WORD
: phys_outsw(port
, vir_buf
, count
); break;
158 /* switch back to the address of the process which made the call */
159 switch_address_space(caller
);
163 #endif /* USE_SDEVIO */