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 "../../system.h"
14 #include <minix/devio.h>
15 #include <minix/endpoint.h>
21 /*===========================================================================*
23 *===========================================================================*/
24 PUBLIC
int do_sdevio(struct proc
* caller
, message
*m_ptr
)
28 int proc_nr
, proc_nr_e
= m_ptr
->DIO_VEC_ENDPT
;
29 int count
= m_ptr
->DIO_VEC_SIZE
;
30 long port
= m_ptr
->DIO_PORT
;
32 int i
, req_type
, req_dir
, size
, nr_io_range
;
34 struct io_range
*iorp
;
35 struct proc
*destproc
;
37 /* Allow safe copies and accesses to SELF */
38 if ((m_ptr
->DIO_REQUEST
& _DIO_SAFEMASK
) != _DIO_SAFE
&&
45 kprintf("do_sdevio: for %d, req %d\n",
46 m_ptr
->m_source
, m_ptr
->DIO_REQUEST
);
50 /* Check if process endpoint is OK.
51 * A driver may directly provide a pointer to a buffer at the user-process
52 * that initiated the device I/O. Kernel processes, of course, are denied.
54 if (proc_nr_e
== SELF
)
55 proc_nr
= _ENDPOINT_P(caller
->p_endpoint
);
57 if(!isokendpt(proc_nr_e
, &proc_nr
))
59 if (iskerneln(proc_nr
)) return(EPERM
);
61 /* Extract direction (in or out) and type (size). */
62 req_dir
= m_ptr
->DIO_REQUEST
& _DIO_DIRMASK
;
63 req_type
= m_ptr
->DIO_REQUEST
& _DIO_TYPEMASK
;
65 /* Check for 'safe' variants. */
66 if((m_ptr
->DIO_REQUEST
& _DIO_SAFEMASK
) == _DIO_SAFE
) {
67 /* Map grant address to physical address. */
68 if(verify_grant(proc_nr_e
, caller
->p_endpoint
,
69 (vir_bytes
) m_ptr
->DIO_VEC_ADDR
,
71 req_dir
== _DIO_INPUT
? CPF_WRITE
: CPF_READ
,
72 (vir_bytes
) m_ptr
->DIO_OFFSET
,
73 &newoffset
, &newep
) != OK
) {
74 printf("do_sdevio: verify_grant failed\n");
77 if(!isokendpt(newep
, &proc_nr
))
79 destproc
= proc_addr(proc_nr
);
80 if ((phys_buf
= umap_local(destproc
, D
,
81 (vir_bytes
) newoffset
, count
)) == 0) {
82 printf("do_sdevio: umap_local failed\n");
86 if(proc_nr
!= _ENDPOINT_P(caller
->p_endpoint
))
88 kprintf("do_sdevio: unsafe sdevio by %d in %d denied\n",
89 caller
->p_endpoint
, proc_nr_e
);
92 /* Get and check physical address. */
93 if ((phys_buf
= umap_local(proc_addr(proc_nr
), D
,
94 (vir_bytes
) m_ptr
->DIO_VEC_ADDR
, count
)) == 0)
96 destproc
= proc_addr(proc_nr
);
98 /* current process must be target for phys_* to be OK */
100 vm_set_cr3(destproc
);
104 case _DIO_BYTE
: size
= 1; break;
105 case _DIO_WORD
: size
= 2; break;
106 case _DIO_LONG
: size
= 4; break;
107 default: size
= 4; break; /* Be conservative */
111 if (privp
&& privp
->s_flags
& CHECK_IO_PORT
)
113 port
= m_ptr
->DIO_PORT
;
114 nr_io_range
= privp
->s_nr_io_range
;
115 for (i
= 0, iorp
= privp
->s_io_tab
; i
<nr_io_range
; i
++, iorp
++)
117 if (port
>= iorp
->ior_base
&& port
+size
-1 <= iorp
->ior_limit
)
120 if (i
>= nr_io_range
)
123 "do_sdevio: I/O port check failed for proc %d, port 0x%x\n",
124 m_ptr
->m_source
, port
);
131 kprintf("do_devio: unaligned port 0x%x (size %d)\n", port
, size
);
135 /* Perform device I/O for bytes and words. Longs are not supported. */
136 if (req_dir
== _DIO_INPUT
) {
138 case _DIO_BYTE
: phys_insb(port
, phys_buf
, count
); break;
139 case _DIO_WORD
: phys_insw(port
, phys_buf
, count
); break;
140 default: return(EINVAL
);
142 } else if (req_dir
== _DIO_OUTPUT
) {
144 case _DIO_BYTE
: phys_outsb(port
, phys_buf
, count
); break;
145 case _DIO_WORD
: phys_outsw(port
, phys_buf
, count
); break;
146 default: return(EINVAL
);
155 #endif /* USE_SDEVIO */