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"
21 #define MAX_INDIRECT_DEPTH 5 /* up to how many indirect grants to follow? */
23 #define MEM_TOP 0xFFFFFFFFUL
25 static int safecopy(struct proc
*, endpoint_t
, endpoint_t
,
26 cp_grant_id_t
, size_t, vir_bytes
, vir_bytes
, int);
28 #define HASGRANTTABLE(gr) \
29 (priv(gr) && priv(gr)->s_grant_table)
31 /*===========================================================================*
33 *===========================================================================*/
34 int verify_grant(granter
, grantee
, grant
, bytes
, access
,
35 offset_in
, offset_result
, e_granter
)
36 endpoint_t granter
, grantee
; /* copyee, copyer */
37 cp_grant_id_t grant
; /* grant id */
38 vir_bytes bytes
; /* copy size */
39 int access
; /* direction (read/write) */
40 vir_bytes offset_in
; /* copy offset within grant */
41 vir_bytes
*offset_result
; /* copy offset within virtual address space */
42 endpoint_t
*e_granter
; /* new granter (magic grants) */
46 static const struct proc
*granter_proc
;
50 /* Get granter process slot (if valid), and check range of
53 if(!isokendpt(granter
, &proc_nr
) ) {
55 "grant verify failed: invalid granter %d\n", (int) granter
);
58 if(!GRANT_VALID(grant
)) {
60 "grant verify failed: invalid grant %d\n", (int) grant
);
63 granter_proc
= proc_addr(proc_nr
);
65 /* If there is no priv. structure, or no grant table in the
66 * priv. structure, or the grant table in the priv. structure
67 * is too small for the grant, return EPERM.
69 if(!HASGRANTTABLE(granter_proc
)) {
71 "grant verify failed: granter %d has no grant table\n",
76 if(priv(granter_proc
)->s_grant_entries
<= grant
) {
78 "verify_grant: grant verify failed in ep %d "
79 "proc %d: grant %d out of range "
80 "for table size %d\n",
81 granter
, proc_nr
, grant
,
82 priv(granter_proc
)->s_grant_entries
);
86 /* Copy the grant entry corresponding to this id to see what it
87 * looks like. If it fails, hide the fact that granter has
88 * (presumably) set an invalid grant table entry by returning
89 * EPERM, just like with an invalid grant id.
92 priv(granter_proc
)->s_grant_table
+ sizeof(g
)*grant
,
93 KERNEL
, (vir_bytes
) &g
, sizeof(g
)) != OK
) {
95 "verify_grant: grant verify: data_copy failed\n");
100 if((g
.cp_flags
& (CPF_USED
| CPF_VALID
)) !=
101 (CPF_USED
| CPF_VALID
)) {
103 "verify_grant: grant failed: invalid (%d flags 0x%lx)\n",
108 /* The given grant may be an indirect grant, that is, a grant
109 * that provides permission to use a grant given to the
110 * granter (i.e., for which it is the grantee). This can lead
111 * to a chain of indirect grants which must be followed back.
113 if((g
.cp_flags
& CPF_INDIRECT
)) {
114 /* Stop after a few iterations. There may be a loop. */
115 if (depth
== MAX_INDIRECT_DEPTH
) {
117 "verify grant: indirect grant verify "
118 "failed: exceeded maximum depth\n");
123 /* Verify actual grantee. */
124 if(g
.cp_u
.cp_indirect
.cp_who_to
!= grantee
&&
126 g
.cp_u
.cp_indirect
.cp_who_to
!= ANY
) {
128 "verify_grant: indirect grant verify "
129 "failed: bad grantee\n");
133 /* Start over with new granter, grant, and grantee. */
135 granter
= g
.cp_u
.cp_indirect
.cp_who_from
;
136 grant
= g
.cp_u
.cp_indirect
.cp_grant
;
138 } while(g
.cp_flags
& CPF_INDIRECT
);
140 /* Check access of grant. */
141 if(((g
.cp_flags
& access
) != access
)) {
143 "verify_grant: grant verify failed: access invalid; want 0x%x, have 0x%x\n",
148 if((g
.cp_flags
& CPF_DIRECT
)) {
149 /* Don't fiddle around with grants that wrap, arithmetic
150 * below may be confused.
152 if(MEM_TOP
- g
.cp_u
.cp_direct
.cp_len
+ 1 <
153 g
.cp_u
.cp_direct
.cp_start
) {
155 "verify_grant: direct grant verify failed: len too long\n");
159 /* Verify actual grantee. */
160 if(g
.cp_u
.cp_direct
.cp_who_to
!= grantee
&& grantee
!= ANY
161 && g
.cp_u
.cp_direct
.cp_who_to
!= ANY
) {
163 "verify_grant: direct grant verify failed: bad grantee\n");
167 /* Verify actual copy range. */
168 if((offset_in
+bytes
< offset_in
) ||
169 offset_in
+bytes
> g
.cp_u
.cp_direct
.cp_len
) {
171 "verify_grant: direct grant verify failed: bad size or range. "
172 "granted %d bytes @ 0x%lx; wanted %d bytes @ 0x%lx\n",
173 g
.cp_u
.cp_direct
.cp_len
,
174 g
.cp_u
.cp_direct
.cp_start
,
179 /* Verify successful - tell caller what address it is. */
180 *offset_result
= g
.cp_u
.cp_direct
.cp_start
+ offset_in
;
181 *e_granter
= granter
;
182 } else if(g
.cp_flags
& CPF_MAGIC
) {
183 /* Currently, it is hardcoded that only FS may do
186 if(granter
!= VFS_PROC_NR
) {
188 "verify_grant: magic grant verify failed: granter (%d) "
189 "is not FS (%d)\n", granter
, VFS_PROC_NR
);
193 /* Verify actual grantee. */
194 if(g
.cp_u
.cp_magic
.cp_who_to
!= grantee
&& grantee
!= ANY
195 && g
.cp_u
.cp_direct
.cp_who_to
!= ANY
) {
197 "verify_grant: magic grant verify failed: bad grantee\n");
201 /* Verify actual copy range. */
202 if((offset_in
+bytes
< offset_in
) ||
203 offset_in
+bytes
> g
.cp_u
.cp_magic
.cp_len
) {
205 "verify_grant: magic grant verify failed: bad size or range. "
206 "granted %d bytes @ 0x%lx; wanted %d bytes @ 0x%lx\n",
207 g
.cp_u
.cp_magic
.cp_len
,
208 g
.cp_u
.cp_magic
.cp_start
,
213 /* Verify successful - tell caller what address it is. */
214 *offset_result
= g
.cp_u
.cp_magic
.cp_start
+ offset_in
;
215 *e_granter
= g
.cp_u
.cp_magic
.cp_who_from
;
218 "verify_grant: grant verify failed: unknown grant type\n");
225 /*===========================================================================*
227 *===========================================================================*/
228 static int safecopy(caller
, granter
, grantee
, grantid
, bytes
,
229 g_offset
, addr
, access
)
230 struct proc
* caller
;
231 endpoint_t granter
, grantee
;
232 cp_grant_id_t grantid
;
234 vir_bytes g_offset
, addr
;
235 int access
; /* CPF_READ for a copy from granter to grantee, CPF_WRITE
236 * for a copy from grantee to granter.
239 static struct vir_addr v_src
, v_dst
;
240 static vir_bytes v_offset
;
241 endpoint_t new_granter
, *src
, *dst
;
242 struct proc
*granter_p
;
244 #if PERF_USE_COW_SAFECOPY
248 if(granter
== NONE
|| grantee
== NONE
) {
249 printf("safecopy: nonsense processes\n");
253 /* See if there is a reasonable grant table. */
254 if(!(granter_p
= endpoint_lookup(granter
))) return EINVAL
;
255 if(!HASGRANTTABLE(granter_p
)) {
257 "safecopy failed: granter %d has no grant table\n", granter
);
261 /* Decide who is src and who is dst. */
262 if(access
& CPF_READ
) {
270 /* Verify permission exists. */
271 if((r
=verify_grant(granter
, grantee
, grantid
, bytes
, access
,
272 g_offset
, &v_offset
, &new_granter
)) != OK
) {
274 "grant %d verify to copy %d->%d by %d failed: err %d\n",
275 grantid
, *src
, *dst
, grantee
, r
);
279 /* verify_grant() can redirect the grantee to someone else,
280 * meaning the source or destination changes.
282 granter
= new_granter
;
284 /* Now it's a regular copy. */
285 v_src
.proc_nr_e
= *src
;
286 v_dst
.proc_nr_e
= *dst
;
288 /* Now the offset in virtual addressing is known in 'offset'.
289 * Depending on the access, this is the source or destination
292 if(access
& CPF_READ
) {
293 v_src
.offset
= v_offset
;
294 v_dst
.offset
= (vir_bytes
) addr
;
296 v_src
.offset
= (vir_bytes
) addr
;
297 v_dst
.offset
= v_offset
;
300 /* Do the regular copy. */
301 #if PERF_USE_COW_SAFECOPY
302 if(v_offset
% CLICK_SIZE
!= addr
% CLICK_SIZE
|| bytes
< CLICK_SIZE
) {
303 /* Give up on COW immediately when offsets are not aligned
304 * or we are copying less than a page.
306 return virtual_copy_vmcheck(caller
, &v_src
, &v_dst
, bytes
);
309 if((size
= v_offset
% CLICK_SIZE
) != 0) {
310 /* Normal copy for everything before the first page boundary. */
311 size
= CLICK_SIZE
- size
;
312 r
= virtual_copy_vmcheck(caller
, &v_src
, &v_dst
, size
);
315 v_src
.offset
+= size
;
316 v_dst
.offset
+= size
;
319 if((size
= bytes
/ CLICK_SIZE
) != 0) {
320 /* Use COW optimization when copying entire pages. */
322 r
= map_invoke_vm(VMPTYPE_COWMAP
,
323 v_dst
.proc_nr_e
, v_dst
.segment
, v_dst
.offset
,
324 v_src
.proc_nr_e
, v_src
.segment
, v_src
.offset
,
328 v_src
.offset
+= size
;
329 v_dst
.offset
+= size
;
333 /* Normal copy for everything after the last page boundary. */
334 r
= virtual_copy_vmcheck(caller
, &v_src
, &v_dst
, bytes
);
341 return virtual_copy_vmcheck(caller
, &v_src
, &v_dst
, bytes
);
345 /*===========================================================================*
347 *===========================================================================*/
348 int do_safecopy_to(struct proc
* caller
, message
* m_ptr
)
350 return safecopy(caller
, m_ptr
->SCP_FROM_TO
, caller
->p_endpoint
,
351 (cp_grant_id_t
) m_ptr
->SCP_GID
,
352 m_ptr
->SCP_BYTES
, m_ptr
->SCP_OFFSET
,
353 (vir_bytes
) m_ptr
->SCP_ADDRESS
, CPF_WRITE
);
356 /*===========================================================================*
358 *===========================================================================*/
359 int do_safecopy_from(struct proc
* caller
, message
* m_ptr
)
361 return safecopy(caller
, m_ptr
->SCP_FROM_TO
, caller
->p_endpoint
,
362 (cp_grant_id_t
) m_ptr
->SCP_GID
,
363 m_ptr
->SCP_BYTES
, m_ptr
->SCP_OFFSET
,
364 (vir_bytes
) m_ptr
->SCP_ADDRESS
, CPF_READ
);
367 /*===========================================================================*
369 *===========================================================================*/
370 int do_vsafecopy(struct proc
* caller
, message
* m_ptr
)
372 static struct vscp_vec vec
[SCPVEC_NR
];
373 static struct vir_addr src
, dst
;
377 /* Set vector copy parameters. */
378 src
.proc_nr_e
= caller
->p_endpoint
;
379 assert(src
.proc_nr_e
!= NONE
);
380 src
.offset
= (vir_bytes
) m_ptr
->VSCP_VEC_ADDR
;
381 dst
.proc_nr_e
= KERNEL
;
382 dst
.offset
= (vir_bytes
) vec
;
384 /* No. of vector elements. */
385 els
= m_ptr
->VSCP_VEC_SIZE
;
386 bytes
= els
* sizeof(struct vscp_vec
);
388 /* Obtain vector of copies. */
389 if((r
=virtual_copy_vmcheck(caller
, &src
, &dst
, bytes
)) != OK
)
392 /* Perform safecopies. */
393 for(i
= 0; i
< els
; i
++) {
396 if(vec
[i
].v_from
== SELF
) {
398 granter
= vec
[i
].v_to
;
399 } else if(vec
[i
].v_to
== SELF
) {
401 granter
= vec
[i
].v_from
;
403 printf("vsafecopy: %d: element %d/%d: no SELF found\n",
404 caller
->p_endpoint
, i
, els
);
408 /* Do safecopy for this element. */
409 if((r
=safecopy(caller
, granter
, caller
->p_endpoint
,
411 vec
[i
].v_bytes
, vec
[i
].v_offset
,
412 vec
[i
].v_addr
, access
)) != OK
) {