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 * m_lsys_kern_safecopy.from_to other endpoint
6 * m_lsys_kern_safecopy.gid grant id
7 * m_lsys_kern_safecopy.offset offset within granted space
8 * m_lsys_kern_safecopy.address address in own address space
9 * m_lsys_kern_safecopy.bytes bytes to be copied
11 * For the vectored variant (do_vsafecopy):
12 * m_lsys_kern_vsafecopy.vec_addr address of vector
13 * m_lsys_kern_vsafecopy.vec_size number of significant elements in vector
18 #include "kernel/system.h"
19 #include "kernel/vm.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 struct cp_sfinfo
{ /* information for handling soft faults */
32 int try; /* if nonzero, try copy only, stop on fault */
33 endpoint_t endpt
; /* endpoint owning grant with CPF_TRY flag */
34 vir_bytes addr
; /* address to write mark upon soft fault */
35 cp_grant_id_t value
; /* grant ID to use as mark value to write */
38 /*===========================================================================*
40 *===========================================================================*/
42 endpoint_t granter
, /* copyee */
43 endpoint_t grantee
, /* copyer */
44 cp_grant_id_t grant
, /* grant id */
45 vir_bytes bytes
, /* copy size */
46 int access
, /* direction (read/write) */
47 vir_bytes offset_in
, /* copy offset within grant */
48 vir_bytes
*offset_result
, /* copy offset within virtual address space */
49 endpoint_t
*e_granter
, /* new granter (magic grants) */
50 struct cp_sfinfo
*sfinfo
/* storage for soft fault information */
55 const struct proc
*granter_proc
;
56 int grant_idx
, grant_seq
;
60 /* Get granter process slot (if valid), and check range of
63 if(!isokendpt(granter
, &proc_nr
) ) {
65 "grant verify failed: invalid granter %d\n", (int) granter
);
68 if(!GRANT_VALID(grant
)) {
70 "grant verify failed: invalid grant %d\n", (int) grant
);
73 granter_proc
= proc_addr(proc_nr
);
75 /* If the granter has a temporary grant table, always allow
76 * requests with unspecified access and return ENOTREADY if
77 * no grant table is present or if the grantee's endpoint is not
78 * the endpoint the table belongs to. When ENOTREADY is returned
79 * the same verify_grant() request will be replayed again in a
80 * while until the grant table is final. This is necessary to
81 * avoid races at live update time.
83 if(priv(granter_proc
)->s_grant_endpoint
!= granter_proc
->p_endpoint
) {
87 else if(!HASGRANTTABLE(granter_proc
) || grantee
!= priv(granter_proc
)->s_grant_endpoint
) {
92 /* If there is no priv. structure, or no grant table in the
93 * priv. structure, or the grant table in the priv. structure
94 * is too small for the grant, return EPERM.
96 if(!HASGRANTTABLE(granter_proc
)) {
98 "grant verify failed: granter %d has no grant table\n",
103 grant_idx
= GRANT_IDX(grant
);
104 grant_seq
= GRANT_SEQ(grant
);
106 if(priv(granter_proc
)->s_grant_entries
<= grant_idx
) {
108 "verify_grant: grant verify failed in ep %d "
109 "proc %d: grant 0x%x (#%d) out of range "
110 "for table size %d\n",
111 granter
, proc_nr
, grant
, grant_idx
,
112 priv(granter_proc
)->s_grant_entries
);
116 /* Copy the grant entry corresponding to this ID's index to see
117 * what it looks like. If it fails, hide the fact that granter
118 * has (presumably) set an invalid grant table entry by
119 * returning EPERM, just like with an invalid grant id.
121 if(data_copy(granter
, priv(granter_proc
)->s_grant_table
+
122 sizeof(g
) * grant_idx
,
123 KERNEL
, (vir_bytes
) &g
, sizeof(g
)) != OK
) {
125 "verify_grant: grant verify: data_copy failed\n");
129 /* Check validity: flags and sequence number. */
130 if((g
.cp_flags
& (CPF_USED
| CPF_VALID
)) !=
131 (CPF_USED
| CPF_VALID
)) {
132 printf("verify_grant: grant failed: invalid flags "
133 "(0x%x, 0x%lx)\n", grant
, g
.cp_flags
);
137 if (g
.cp_seq
!= grant_seq
) {
138 printf("verify_grant: grant failed: invalid sequence "
139 "(0x%x, %d vs %d)\n", grant
, grant_seq
, g
.cp_seq
);
143 /* The given grant may be an indirect grant, that is, a grant
144 * that provides permission to use a grant given to the
145 * granter (i.e., for which it is the grantee). This can lead
146 * to a chain of indirect grants which must be followed back.
148 if((g
.cp_flags
& CPF_INDIRECT
)) {
149 /* Stop after a few iterations. There may be a loop. */
150 if (depth
== MAX_INDIRECT_DEPTH
) {
152 "verify grant: indirect grant verify "
153 "failed: exceeded maximum depth\n");
158 /* Verify actual grantee. */
159 if(g
.cp_u
.cp_indirect
.cp_who_to
!= grantee
&&
161 g
.cp_u
.cp_indirect
.cp_who_to
!= ANY
) {
163 "verify_grant: indirect grant verify "
164 "failed: bad grantee\n");
168 /* Start over with new granter, grant, and grantee. */
170 granter
= g
.cp_u
.cp_indirect
.cp_who_from
;
171 grant
= g
.cp_u
.cp_indirect
.cp_grant
;
173 } while(g
.cp_flags
& CPF_INDIRECT
);
175 /* Check access of grant. */
176 if(((g
.cp_flags
& access
) != access
)) {
178 "verify_grant: grant verify failed: access invalid; want 0x%x, have 0x%x\n",
183 if((g
.cp_flags
& CPF_DIRECT
)) {
184 /* Don't fiddle around with grants that wrap, arithmetic
185 * below may be confused.
187 if(MEM_TOP
- g
.cp_u
.cp_direct
.cp_len
+ 1 <
188 g
.cp_u
.cp_direct
.cp_start
) {
190 "verify_grant: direct grant verify failed: len too long\n");
194 /* Verify actual grantee. */
195 if(g
.cp_u
.cp_direct
.cp_who_to
!= grantee
&& grantee
!= ANY
196 && g
.cp_u
.cp_direct
.cp_who_to
!= ANY
) {
198 "verify_grant: direct grant verify failed: bad grantee\n");
202 /* Verify actual copy range. */
203 if((offset_in
+bytes
< offset_in
) ||
204 offset_in
+bytes
> g
.cp_u
.cp_direct
.cp_len
) {
206 "verify_grant: direct grant verify failed: bad size or range. "
207 "granted %d bytes @ 0x%lx; wanted %d bytes @ 0x%lx\n",
208 g
.cp_u
.cp_direct
.cp_len
,
209 g
.cp_u
.cp_direct
.cp_start
,
214 /* Verify successful - tell caller what address it is. */
215 *offset_result
= g
.cp_u
.cp_direct
.cp_start
+ offset_in
;
216 *e_granter
= granter
;
217 } else if(g
.cp_flags
& CPF_MAGIC
) {
218 /* Currently, it is hardcoded that only VFS and MIB may do
219 * magic grants. TODO: this should be a system.conf flag.
221 if(granter
!= VFS_PROC_NR
&& granter
!= MIB_PROC_NR
) {
223 "verify_grant: magic grant verify failed: granter (%d) "
224 "not allowed\n", granter
);
228 /* Verify actual grantee. */
229 if(g
.cp_u
.cp_magic
.cp_who_to
!= grantee
&& grantee
!= ANY
230 && g
.cp_u
.cp_direct
.cp_who_to
!= ANY
) {
232 "verify_grant: magic grant verify failed: bad grantee\n");
236 /* Verify actual copy range. */
237 if((offset_in
+bytes
< offset_in
) ||
238 offset_in
+bytes
> g
.cp_u
.cp_magic
.cp_len
) {
240 "verify_grant: magic grant verify failed: bad size or range. "
241 "granted %d bytes @ 0x%lx; wanted %d bytes @ 0x%lx\n",
242 g
.cp_u
.cp_magic
.cp_len
,
243 g
.cp_u
.cp_magic
.cp_start
,
248 /* Verify successful - tell caller what address it is. */
249 *offset_result
= g
.cp_u
.cp_magic
.cp_start
+ offset_in
;
250 *e_granter
= g
.cp_u
.cp_magic
.cp_who_from
;
253 "verify_grant: grant verify failed: unknown grant type\n");
257 /* If requested, store information regarding soft faults. */
258 if (sfinfo
!= NULL
&& (sfinfo
->try = !!(g
.cp_flags
& CPF_TRY
))) {
259 sfinfo
->endpt
= granter
;
260 sfinfo
->addr
= priv(granter_proc
)->s_grant_table
+
261 sizeof(g
) * grant_idx
+ offsetof(cp_grant_t
, cp_faulted
);
262 sfinfo
->value
= grant
;
268 /*===========================================================================*
270 *===========================================================================*/
272 struct proc
* caller
,
275 cp_grant_id_t grantid
,
279 int access
/* CPF_READ for a copy from granter to grantee, CPF_WRITE
280 * for a copy from grantee to granter.
284 static struct vir_addr v_src
, v_dst
;
285 static vir_bytes v_offset
;
286 endpoint_t new_granter
, *src
, *dst
;
288 struct cp_sfinfo sfinfo
;
290 if(granter
== NONE
|| grantee
== NONE
) {
291 printf("safecopy: nonsense processes\n");
295 /* Decide who is src and who is dst. */
296 if(access
& CPF_READ
) {
304 /* Verify permission exists. */
305 if((r
=verify_grant(granter
, grantee
, grantid
, bytes
, access
,
306 g_offset
, &v_offset
, &new_granter
, &sfinfo
)) != OK
) {
307 if(r
== ENOTREADY
) return r
;
309 "grant %d verify to copy %d->%d by %d failed: err %d\n",
310 grantid
, *src
, *dst
, grantee
, r
);
314 /* verify_grant() can redirect the grantee to someone else,
315 * meaning the source or destination changes.
317 granter
= new_granter
;
319 /* Now it's a regular copy. */
320 v_src
.proc_nr_e
= *src
;
321 v_dst
.proc_nr_e
= *dst
;
323 /* Now the offset in virtual addressing is known in 'offset'.
324 * Depending on the access, this is the source or destination
327 if(access
& CPF_READ
) {
328 v_src
.offset
= v_offset
;
329 v_dst
.offset
= (vir_bytes
) addr
;
331 v_src
.offset
= (vir_bytes
) addr
;
332 v_dst
.offset
= v_offset
;
335 /* Do the regular copy. */
338 * Try copying without transparently faulting in pages.
339 * TODO: while CPF_TRY is meant to protect against deadlocks on
340 * memory-mapped files in file systems, it seems that this case
341 * triggers faults a whole lot more often, resulting in extra
342 * overhead due to retried file system operations. It might be
343 * a good idea to go through VM even in this case, and have VM
344 * fail (only) if the affected page belongs to a file mapping.
346 r
= virtual_copy(&v_src
, &v_dst
, bytes
);
347 if (r
== EFAULT_SRC
|| r
== EFAULT_DST
) {
349 * Mark the magic grant as having experienced a soft
350 * fault during its lifetime. The exact value does not
351 * matter, but we use the grant ID (including its
352 * sequence number) as a form of protection in the
353 * light of CPU concurrency.
355 r
= data_copy(KERNEL
, (vir_bytes
)&sfinfo
.value
,
356 sfinfo
.endpt
, sfinfo
.addr
, sizeof(sfinfo
.value
));
358 * Failure means the creator of the magic grant messed
359 * up, which can only be unintentional, so report..
362 printf("Kernel: writing soft fault marker %d "
363 "into %d at 0x%lx failed (%d)\n",
364 sfinfo
.value
, sfinfo
.endpt
, sfinfo
.addr
,
371 return virtual_copy_vmcheck(caller
, &v_src
, &v_dst
, bytes
);
374 /*===========================================================================*
376 *===========================================================================*/
377 int do_safecopy_to(struct proc
* caller
, message
* m_ptr
)
379 return safecopy(caller
, m_ptr
->m_lsys_kern_safecopy
.from_to
, caller
->p_endpoint
,
380 (cp_grant_id_t
) m_ptr
->m_lsys_kern_safecopy
.gid
,
381 m_ptr
->m_lsys_kern_safecopy
.bytes
, m_ptr
->m_lsys_kern_safecopy
.offset
,
382 (vir_bytes
) m_ptr
->m_lsys_kern_safecopy
.address
, CPF_WRITE
);
385 /*===========================================================================*
387 *===========================================================================*/
388 int do_safecopy_from(struct proc
* caller
, message
* m_ptr
)
390 return safecopy(caller
, m_ptr
->m_lsys_kern_safecopy
.from_to
, caller
->p_endpoint
,
391 (cp_grant_id_t
) m_ptr
->m_lsys_kern_safecopy
.gid
,
392 m_ptr
->m_lsys_kern_safecopy
.bytes
, m_ptr
->m_lsys_kern_safecopy
.offset
,
393 (vir_bytes
) m_ptr
->m_lsys_kern_safecopy
.address
, CPF_READ
);
396 /*===========================================================================*
398 *===========================================================================*/
399 int do_vsafecopy(struct proc
* caller
, message
* m_ptr
)
401 static struct vscp_vec vec
[SCPVEC_NR
];
402 static struct vir_addr src
, dst
;
406 /* Set vector copy parameters. */
407 src
.proc_nr_e
= caller
->p_endpoint
;
408 assert(src
.proc_nr_e
!= NONE
);
409 src
.offset
= (vir_bytes
) m_ptr
->m_lsys_kern_vsafecopy
.vec_addr
;
410 dst
.proc_nr_e
= KERNEL
;
411 dst
.offset
= (vir_bytes
) vec
;
413 /* No. of vector elements. */
414 els
= m_ptr
->m_lsys_kern_vsafecopy
.vec_size
;
415 bytes
= els
* sizeof(struct vscp_vec
);
417 /* Obtain vector of copies. */
418 if((r
=virtual_copy_vmcheck(caller
, &src
, &dst
, bytes
)) != OK
)
421 /* Perform safecopies. */
422 for(i
= 0; i
< els
; i
++) {
425 if(vec
[i
].v_from
== SELF
) {
427 granter
= vec
[i
].v_to
;
428 } else if(vec
[i
].v_to
== SELF
) {
430 granter
= vec
[i
].v_from
;
432 printf("vsafecopy: %d: element %d/%d: no SELF found\n",
433 caller
->p_endpoint
, i
, els
);
437 /* Do safecopy for this element. */
438 if((r
=safecopy(caller
, granter
, caller
->p_endpoint
,
440 vec
[i
].v_bytes
, vec
[i
].v_offset
,
441 vec
[i
].v_addr
, access
)) != OK
) {