1 /* The kernel call implemented in this file:
2 * m_type: SYS_SAFECOPYFROM or SYS_SAFECOPYTO or SYS_VSAFECOPY
4 * The parameters for this kernel call are:
5 * SCP_FROM_TO other endpoint
7 * SCP_OFFSET offset within granted space
8 * SCP_ADDRESS address in own address space
9 * SCP_BYTES bytes to be copied
11 * For the vectored variant (do_vsafecopy):
12 * VSCP_VEC_ADDR address of vector
13 * VSCP_VEC_SIZE number of significant elements in vector
18 #include "kernel/system.h"
19 #include "kernel/kernel.h"
20 #include "kernel/vm.h"
22 #define MAX_INDIRECT_DEPTH 5 /* up to how many indirect grants to follow? */
24 #define MEM_TOP 0xFFFFFFFFUL
26 static int safecopy(struct proc
*, endpoint_t
, endpoint_t
,
27 cp_grant_id_t
, size_t, vir_bytes
, vir_bytes
, int);
29 #define HASGRANTTABLE(gr) \
30 (priv(gr) && priv(gr)->s_grant_table)
32 /*===========================================================================*
34 *===========================================================================*/
35 int verify_grant(granter
, grantee
, grant
, bytes
, access
,
36 offset_in
, offset_result
, e_granter
, flags
)
37 endpoint_t granter
, grantee
; /* copyee, copyer */
38 cp_grant_id_t grant
; /* grant id */
39 vir_bytes bytes
; /* copy size */
40 int access
; /* direction (read/write) */
41 vir_bytes offset_in
; /* copy offset within grant */
42 vir_bytes
*offset_result
; /* copy offset within virtual address space */
43 endpoint_t
*e_granter
; /* new granter (magic grants) */
44 u32_t
*flags
; /* CPF_* */
48 static const struct proc
*granter_proc
;
52 /* Get granter process slot (if valid), and check range of
55 if(!isokendpt(granter
, &proc_nr
) ) {
57 "grant verify failed: invalid granter %d\n", (int) granter
);
60 if(!GRANT_VALID(grant
)) {
62 "grant verify failed: invalid grant %d\n", (int) grant
);
65 granter_proc
= proc_addr(proc_nr
);
67 /* If there is no priv. structure, or no grant table in the
68 * priv. structure, or the grant table in the priv. structure
69 * is too small for the grant, return EPERM.
71 if(!HASGRANTTABLE(granter_proc
)) {
73 "grant verify failed: granter %d has no grant table\n",
78 if(priv(granter_proc
)->s_grant_entries
<= grant
) {
80 "verify_grant: grant verify failed in ep %d "
81 "proc %d: grant %d out of range "
82 "for table size %d\n",
83 granter
, proc_nr
, grant
,
84 priv(granter_proc
)->s_grant_entries
);
88 /* Copy the grant entry corresponding to this id to see what it
89 * looks like. If it fails, hide the fact that granter has
90 * (presumably) set an invalid grant table entry by returning
91 * EPERM, just like with an invalid grant id.
94 priv(granter_proc
)->s_grant_table
+ sizeof(g
)*grant
,
95 KERNEL
, (vir_bytes
) &g
, sizeof(g
)) != OK
) {
97 "verify_grant: grant verify: data_copy failed\n");
101 if(flags
) *flags
= g
.cp_flags
;
103 /* Check validity. */
104 if((g
.cp_flags
& (CPF_USED
| CPF_VALID
)) !=
105 (CPF_USED
| CPF_VALID
)) {
107 "verify_grant: grant failed: invalid (%d flags 0x%lx)\n",
112 /* The given grant may be an indirect grant, that is, a grant
113 * that provides permission to use a grant given to the
114 * granter (i.e., for which it is the grantee). This can lead
115 * to a chain of indirect grants which must be followed back.
117 if((g
.cp_flags
& CPF_INDIRECT
)) {
118 /* Stop after a few iterations. There may be a loop. */
119 if (depth
== MAX_INDIRECT_DEPTH
) {
121 "verify grant: indirect grant verify "
122 "failed: exceeded maximum depth\n");
127 /* Verify actual grantee. */
128 if(g
.cp_u
.cp_indirect
.cp_who_to
!= grantee
&&
130 g
.cp_u
.cp_indirect
.cp_who_to
!= ANY
) {
132 "verify_grant: indirect grant verify "
133 "failed: bad grantee\n");
137 /* Start over with new granter, grant, and grantee. */
139 granter
= g
.cp_u
.cp_indirect
.cp_who_from
;
140 grant
= g
.cp_u
.cp_indirect
.cp_grant
;
142 } while(g
.cp_flags
& CPF_INDIRECT
);
144 /* Check access of grant. */
145 if(((g
.cp_flags
& access
) != access
)) {
147 "verify_grant: grant verify failed: access invalid; want 0x%x, have 0x%x\n",
152 if((g
.cp_flags
& CPF_DIRECT
)) {
153 /* Don't fiddle around with grants that wrap, arithmetic
154 * below may be confused.
156 if(MEM_TOP
- g
.cp_u
.cp_direct
.cp_len
+ 1 <
157 g
.cp_u
.cp_direct
.cp_start
) {
159 "verify_grant: direct grant verify failed: len too long\n");
163 /* Verify actual grantee. */
164 if(g
.cp_u
.cp_direct
.cp_who_to
!= grantee
&& grantee
!= ANY
165 && g
.cp_u
.cp_direct
.cp_who_to
!= ANY
) {
167 "verify_grant: direct grant verify failed: bad grantee\n");
171 /* Verify actual copy range. */
172 if((offset_in
+bytes
< offset_in
) ||
173 offset_in
+bytes
> g
.cp_u
.cp_direct
.cp_len
) {
175 "verify_grant: direct grant verify failed: bad size or range. "
176 "granted %d bytes @ 0x%lx; wanted %d bytes @ 0x%lx\n",
177 g
.cp_u
.cp_direct
.cp_len
,
178 g
.cp_u
.cp_direct
.cp_start
,
183 /* Verify successful - tell caller what address it is. */
184 *offset_result
= g
.cp_u
.cp_direct
.cp_start
+ offset_in
;
185 *e_granter
= granter
;
186 } else if(g
.cp_flags
& CPF_MAGIC
) {
187 /* Currently, it is hardcoded that only FS may do
190 if(granter
!= VFS_PROC_NR
) {
192 "verify_grant: magic grant verify failed: granter (%d) "
193 "is not FS (%d)\n", granter
, VFS_PROC_NR
);
197 /* Verify actual grantee. */
198 if(g
.cp_u
.cp_magic
.cp_who_to
!= grantee
&& grantee
!= ANY
199 && g
.cp_u
.cp_direct
.cp_who_to
!= ANY
) {
201 "verify_grant: magic grant verify failed: bad grantee\n");
205 /* Verify actual copy range. */
206 if((offset_in
+bytes
< offset_in
) ||
207 offset_in
+bytes
> g
.cp_u
.cp_magic
.cp_len
) {
209 "verify_grant: magic grant verify failed: bad size or range. "
210 "granted %d bytes @ 0x%lx; wanted %d bytes @ 0x%lx\n",
211 g
.cp_u
.cp_magic
.cp_len
,
212 g
.cp_u
.cp_magic
.cp_start
,
217 /* Verify successful - tell caller what address it is. */
218 *offset_result
= g
.cp_u
.cp_magic
.cp_start
+ offset_in
;
219 *e_granter
= g
.cp_u
.cp_magic
.cp_who_from
;
222 "verify_grant: grant verify failed: unknown grant type\n");
229 /*===========================================================================*
231 *===========================================================================*/
232 static int safecopy(caller
, granter
, grantee
, grantid
, bytes
,
233 g_offset
, addr
, access
)
234 struct proc
* caller
;
235 endpoint_t granter
, grantee
;
236 cp_grant_id_t grantid
;
238 vir_bytes g_offset
, addr
;
239 int access
; /* CPF_READ for a copy from granter to grantee, CPF_WRITE
240 * for a copy from grantee to granter.
243 static struct vir_addr v_src
, v_dst
;
244 static vir_bytes v_offset
;
245 endpoint_t new_granter
, *src
, *dst
;
246 struct proc
*granter_p
;
249 #if PERF_USE_COW_SAFECOPY
253 if(granter
== NONE
|| grantee
== NONE
) {
254 printf("safecopy: nonsense processes\n");
258 /* See if there is a reasonable grant table. */
259 if(!(granter_p
= endpoint_lookup(granter
))) return EINVAL
;
260 if(!HASGRANTTABLE(granter_p
)) {
262 "safecopy failed: granter %d has no grant table\n", granter
);
266 /* Decide who is src and who is dst. */
267 if(access
& CPF_READ
) {
275 /* Verify permission exists. */
276 if((r
=verify_grant(granter
, grantee
, grantid
, bytes
, access
,
277 g_offset
, &v_offset
, &new_granter
, &flags
)) != OK
) {
279 "grant %d verify to copy %d->%d by %d failed: err %d\n",
280 grantid
, *src
, *dst
, grantee
, r
);
284 /* verify_grant() can redirect the grantee to someone else,
285 * meaning the source or destination changes.
287 granter
= new_granter
;
289 /* Now it's a regular copy. */
290 v_src
.proc_nr_e
= *src
;
291 v_dst
.proc_nr_e
= *dst
;
293 /* Now the offset in virtual addressing is known in 'offset'.
294 * Depending on the access, this is the source or destination
297 if(access
& CPF_READ
) {
298 v_src
.offset
= v_offset
;
299 v_dst
.offset
= (vir_bytes
) addr
;
301 v_src
.offset
= (vir_bytes
) addr
;
302 v_dst
.offset
= v_offset
;
305 /* Do the regular copy. */
306 if(flags
& CPF_TRY
) {
308 /* Try copy without transparently faulting in pages. */
309 r
= virtual_copy(&v_src
, &v_dst
, bytes
);
310 if(r
== EFAULT_SRC
|| r
== EFAULT_DST
) return EFAULT
;
313 return virtual_copy_vmcheck(caller
, &v_src
, &v_dst
, bytes
);
316 /*===========================================================================*
318 *===========================================================================*/
319 int do_safecopy_to(struct proc
* caller
, message
* m_ptr
)
321 return safecopy(caller
, m_ptr
->SCP_FROM_TO
, caller
->p_endpoint
,
322 (cp_grant_id_t
) m_ptr
->SCP_GID
,
323 m_ptr
->SCP_BYTES
, m_ptr
->SCP_OFFSET
,
324 (vir_bytes
) m_ptr
->SCP_ADDRESS
, CPF_WRITE
);
327 /*===========================================================================*
329 *===========================================================================*/
330 int do_safecopy_from(struct proc
* caller
, message
* m_ptr
)
332 return safecopy(caller
, m_ptr
->SCP_FROM_TO
, caller
->p_endpoint
,
333 (cp_grant_id_t
) m_ptr
->SCP_GID
,
334 m_ptr
->SCP_BYTES
, m_ptr
->SCP_OFFSET
,
335 (vir_bytes
) m_ptr
->SCP_ADDRESS
, CPF_READ
);
338 /*===========================================================================*
340 *===========================================================================*/
341 int do_vsafecopy(struct proc
* caller
, message
* m_ptr
)
343 static struct vscp_vec vec
[SCPVEC_NR
];
344 static struct vir_addr src
, dst
;
348 /* Set vector copy parameters. */
349 src
.proc_nr_e
= caller
->p_endpoint
;
350 assert(src
.proc_nr_e
!= NONE
);
351 src
.offset
= (vir_bytes
) m_ptr
->VSCP_VEC_ADDR
;
352 dst
.proc_nr_e
= KERNEL
;
353 dst
.offset
= (vir_bytes
) vec
;
355 /* No. of vector elements. */
356 els
= m_ptr
->VSCP_VEC_SIZE
;
357 bytes
= els
* sizeof(struct vscp_vec
);
359 /* Obtain vector of copies. */
360 if((r
=virtual_copy_vmcheck(caller
, &src
, &dst
, bytes
)) != OK
)
363 /* Perform safecopies. */
364 for(i
= 0; i
< els
; i
++) {
367 if(vec
[i
].v_from
== SELF
) {
369 granter
= vec
[i
].v_to
;
370 } else if(vec
[i
].v_to
== SELF
) {
372 granter
= vec
[i
].v_from
;
374 printf("vsafecopy: %d: element %d/%d: no SELF found\n",
375 caller
->p_endpoint
, i
, els
);
379 /* Do safecopy for this element. */
380 if((r
=safecopy(caller
, granter
, caller
->p_endpoint
,
382 vec
[i
].v_bytes
, vec
[i
].v_offset
,
383 vec
[i
].v_addr
, access
)) != OK
) {