kernel, libc: signals fixes
[minix.git] / kernel / system / do_vumap.c
blob56bd635f490e9640bde74dda5774af322833739a
1 /* The kernel call implemented in this file:
2 * m_type: SYS_VUMAP
4 * The parameters for this kernel call are:
5 * m10_i1: VUMAP_ENDPT (grant owner, or SELF for local addresses)
6 * m10_l1: VUMAP_VADDR (address of virtual (input) vector)
7 * m10_i2: VUMAP_VCOUNT (number of elements in virtual vector)
8 * m10_l2: VUMAP_OFFSET (offset into first entry of input vector)
9 * m10_i3: VUMAP_ACCESS (safecopy access requested for input)
10 * m10_l3: VUMAP_PADDR (address of physical (output) vector)
11 * m10_i4: VUMAP_PMAX (maximum number of physical vector elements)
12 * m10_i1: VUMAP_PCOUNT (upon return: number of elements filled)
15 #include "kernel/system.h"
17 #include <assert.h>
19 /*===========================================================================*
20 * do_vumap *
21 *===========================================================================*/
22 int do_vumap(struct proc *caller, message *m_ptr)
24 /* Map a vector of grants or local virtual addresses to physical addresses.
25 * Designed to be used by drivers to perform an efficient lookup of physical
26 * addresses for the purpose of direct DMA from/to a remote process.
28 endpoint_t endpt, source, granter;
29 struct proc *procp;
30 struct vumap_vir vvec[MAPVEC_NR];
31 struct vumap_phys pvec[MAPVEC_NR];
32 vir_bytes vaddr, paddr, vir_addr;
33 phys_bytes phys_addr;
34 int i, r, proc_nr, vcount, pcount, pmax, access;
35 size_t size, chunk, offset;
37 endpt = caller->p_endpoint;
39 /* Retrieve and check input parameters. */
40 source = m_ptr->VUMAP_ENDPT;
41 vaddr = (vir_bytes) m_ptr->VUMAP_VADDR;
42 vcount = m_ptr->VUMAP_VCOUNT;
43 offset = m_ptr->VUMAP_OFFSET;
44 access = m_ptr->VUMAP_ACCESS;
45 paddr = (vir_bytes) m_ptr->VUMAP_PADDR;
46 pmax = m_ptr->VUMAP_PMAX;
48 if (vcount <= 0 || pmax <= 0)
49 return EINVAL;
51 if (vcount > MAPVEC_NR) vcount = MAPVEC_NR;
52 if (pmax > MAPVEC_NR) pmax = MAPVEC_NR;
54 /* Convert access to safecopy access flags. */
55 switch (access) {
56 case VUA_READ: access = CPF_READ; break;
57 case VUA_WRITE: access = CPF_WRITE; break;
58 case VUA_READ|VUA_WRITE: access = CPF_READ|CPF_WRITE; break;
59 default: return EINVAL;
62 /* Copy in the vector of virtual addresses. */
63 size = vcount * sizeof(vvec[0]);
65 if (data_copy(endpt, vaddr, KERNEL, (vir_bytes) vvec, size) != OK)
66 return EFAULT;
68 pcount = 0;
70 /* Go through the input entries, one at a time. Stop early in case the output
71 * vector has filled up.
73 for (i = 0; i < vcount && pcount < pmax; i++) {
74 size = vvec[i].vv_size;
75 if (size <= offset)
76 return EINVAL;
77 size -= offset;
79 if (source != SELF) {
80 r = verify_grant(source, endpt, vvec[i].vv_grant, size, access,
81 offset, &vir_addr, &granter);
82 if (r != OK)
83 return r;
84 } else {
85 vir_addr = vvec[i].vv_addr + offset;
86 granter = endpt;
89 okendpt(granter, &proc_nr);
90 procp = proc_addr(proc_nr);
92 /* Each virtual range is made up of one or more physical ranges. */
93 while (size > 0 && pcount < pmax) {
94 chunk = vm_lookup_range(procp, vir_addr, &phys_addr, size);
96 if (!chunk) {
97 /* Try to get the memory allocated, unless the memory
98 * is supposed to be there to be read from.
100 if (access & CPF_READ)
101 return EFAULT;
103 /* This call may suspend the current call, or return an
104 * error for a previous invocation.
106 return vm_check_range(caller, procp, vir_addr, size);
109 pvec[pcount].vp_addr = phys_addr;
110 pvec[pcount].vp_size = chunk;
111 pcount++;
113 vir_addr += chunk;
114 size -= chunk;
117 offset = 0;
120 /* Copy out the resulting vector of physical addresses. */
121 assert(pcount > 0);
123 size = pcount * sizeof(pvec[0]);
125 r = data_copy_vmcheck(caller, KERNEL, (vir_bytes) pvec, endpt, paddr, size);
127 if (r == OK)
128 m_ptr->VUMAP_PCOUNT = pcount;
130 return r;