xref: /minix3/minix/kernel/system/do_safecopy.c (revision 6f3e0bcd3d3c17c74429db9d63eb808350d9a344)
1433d6423SLionel Sambuc /* The kernel call implemented in this file:
2433d6423SLionel Sambuc  *   m_type:	SYS_SAFECOPYFROM or SYS_SAFECOPYTO or SYS_VSAFECOPY
3433d6423SLionel Sambuc  *
4433d6423SLionel Sambuc  * The parameters for this kernel call are:
5433d6423SLionel Sambuc  *    	m_lsys_kern_safecopy.from_to	other endpoint
6433d6423SLionel Sambuc  *    	m_lsys_kern_safecopy.gid	grant id
7433d6423SLionel Sambuc  *    	m_lsys_kern_safecopy.offset	offset within granted space
8433d6423SLionel Sambuc  *	m_lsys_kern_safecopy.address	address in own address space
9433d6423SLionel Sambuc  *    	m_lsys_kern_safecopy.bytes	bytes to be copied
10433d6423SLionel Sambuc  *
11433d6423SLionel Sambuc  * For the vectored variant (do_vsafecopy):
12433d6423SLionel Sambuc  *      m_lsys_kern_vsafecopy.vec_addr   address of vector
13433d6423SLionel Sambuc  *      m_lsys_kern_vsafecopy.vec_size   number of significant elements in vector
14433d6423SLionel Sambuc  */
15433d6423SLionel Sambuc 
16433d6423SLionel Sambuc #include <assert.h>
17433d6423SLionel Sambuc 
18433d6423SLionel Sambuc #include "kernel/system.h"
19433d6423SLionel Sambuc #include "kernel/kernel.h"
20433d6423SLionel Sambuc #include "kernel/vm.h"
21433d6423SLionel Sambuc 
22433d6423SLionel Sambuc #define MAX_INDIRECT_DEPTH 5	/* up to how many indirect grants to follow? */
23433d6423SLionel Sambuc 
24433d6423SLionel Sambuc #define MEM_TOP 0xFFFFFFFFUL
25433d6423SLionel Sambuc 
26433d6423SLionel Sambuc static int safecopy(struct proc *, endpoint_t, endpoint_t,
27433d6423SLionel Sambuc 	cp_grant_id_t, size_t, vir_bytes, vir_bytes, int);
28433d6423SLionel Sambuc 
29433d6423SLionel Sambuc #define HASGRANTTABLE(gr) \
30433d6423SLionel Sambuc 	(priv(gr) && priv(gr)->s_grant_table)
31433d6423SLionel Sambuc 
3210b7016bSDavid van Moolenbroek struct cp_sfinfo {		/* information for handling soft faults */
3310b7016bSDavid van Moolenbroek 	int try;		/* if nonzero, try copy only, stop on fault */
3410b7016bSDavid van Moolenbroek 	endpoint_t endpt;	/* endpoint owning grant with CPF_TRY flag */
3510b7016bSDavid van Moolenbroek 	vir_bytes addr;		/* address to write mark upon soft fault */
3610b7016bSDavid van Moolenbroek 	cp_grant_id_t value;	/* grant ID to use as mark value to write */
3710b7016bSDavid van Moolenbroek };
3810b7016bSDavid van Moolenbroek 
39433d6423SLionel Sambuc /*===========================================================================*
40433d6423SLionel Sambuc  *				verify_grant				     *
41433d6423SLionel Sambuc  *===========================================================================*/
426077d1adSDr. Florian Grätz int verify_grant(
436077d1adSDr. Florian Grätz   endpoint_t granter,		/* copyee */
446077d1adSDr. Florian Grätz   endpoint_t grantee,		/* copyer */
456077d1adSDr. Florian Grätz   cp_grant_id_t grant,		/* grant id */
466077d1adSDr. Florian Grätz   vir_bytes bytes,		/* copy size */
476077d1adSDr. Florian Grätz   int access,			/* direction (read/write) */
486077d1adSDr. Florian Grätz   vir_bytes offset_in,		/* copy offset within grant */
496077d1adSDr. Florian Grätz   vir_bytes *offset_result,	/* copy offset within virtual address space */
506077d1adSDr. Florian Grätz   endpoint_t *e_granter,	/* new granter (magic grants) */
5110b7016bSDavid van Moolenbroek   struct cp_sfinfo *sfinfo	/* storage for soft fault information */
526077d1adSDr. Florian Grätz )
53433d6423SLionel Sambuc {
54ca779acdSDavid van Moolenbroek 	cp_grant_t g;
55ca779acdSDavid van Moolenbroek 	int proc_nr;
56ca779acdSDavid van Moolenbroek 	const struct proc *granter_proc;
57ca779acdSDavid van Moolenbroek 	int grant_idx, grant_seq;
58433d6423SLionel Sambuc 	int depth = 0;
59433d6423SLionel Sambuc 
60433d6423SLionel Sambuc 	do {
61433d6423SLionel Sambuc 		/* Get granter process slot (if valid), and check range of
62433d6423SLionel Sambuc 		 * grant id.
63433d6423SLionel Sambuc 		 */
64433d6423SLionel Sambuc 		if(!isokendpt(granter, &proc_nr) ) {
65433d6423SLionel Sambuc 			printf(
66433d6423SLionel Sambuc 			"grant verify failed: invalid granter %d\n", (int) granter);
67433d6423SLionel Sambuc 			return(EINVAL);
68433d6423SLionel Sambuc 		}
69433d6423SLionel Sambuc 		if(!GRANT_VALID(grant)) {
70433d6423SLionel Sambuc 			printf(
71433d6423SLionel Sambuc 			"grant verify failed: invalid grant %d\n", (int) grant);
72433d6423SLionel Sambuc 			return(EINVAL);
73433d6423SLionel Sambuc 		}
74433d6423SLionel Sambuc 		granter_proc = proc_addr(proc_nr);
75433d6423SLionel Sambuc 
769e6b1315SCristiano Giuffrida 		/* If the granter has a temporary grant table, always allow
779e6b1315SCristiano Giuffrida 		 * requests with unspecified access and return ENOTREADY if
789e6b1315SCristiano Giuffrida 		 * no grant table is present or if the grantee's endpoint is not
799e6b1315SCristiano Giuffrida 		 * the endpoint the table belongs to. When ENOTREADY is returned
809e6b1315SCristiano Giuffrida 		 * the same verify_grant() request will be replayed again in a
819e6b1315SCristiano Giuffrida 		 * while until the grant table is final. This is necessary to
829e6b1315SCristiano Giuffrida 		 * avoid races at live update time.
839e6b1315SCristiano Giuffrida 		 */
849e6b1315SCristiano Giuffrida 		if(priv(granter_proc)->s_grant_endpoint != granter_proc->p_endpoint) {
859e6b1315SCristiano Giuffrida 			if(!access) {
869e6b1315SCristiano Giuffrida 				return OK;
879e6b1315SCristiano Giuffrida 			}
889e6b1315SCristiano Giuffrida 			else if(!HASGRANTTABLE(granter_proc) || grantee != priv(granter_proc)->s_grant_endpoint) {
899e6b1315SCristiano Giuffrida 				return ENOTREADY;
909e6b1315SCristiano Giuffrida 			}
919e6b1315SCristiano Giuffrida 		}
929e6b1315SCristiano Giuffrida 
93433d6423SLionel Sambuc 		/* If there is no priv. structure, or no grant table in the
94433d6423SLionel Sambuc 		 * priv. structure, or the grant table in the priv. structure
95433d6423SLionel Sambuc 		 * is too small for the grant, return EPERM.
96433d6423SLionel Sambuc 		 */
97433d6423SLionel Sambuc 		if(!HASGRANTTABLE(granter_proc)) {
98433d6423SLionel Sambuc 			printf(
99433d6423SLionel Sambuc 			"grant verify failed: granter %d has no grant table\n",
100433d6423SLionel Sambuc 			granter);
101433d6423SLionel Sambuc 			return(EPERM);
102433d6423SLionel Sambuc 		}
103433d6423SLionel Sambuc 
104ca779acdSDavid van Moolenbroek 		grant_idx = GRANT_IDX(grant);
105ca779acdSDavid van Moolenbroek 		grant_seq = GRANT_SEQ(grant);
106ca779acdSDavid van Moolenbroek 
107ca779acdSDavid van Moolenbroek 		if(priv(granter_proc)->s_grant_entries <= grant_idx) {
108433d6423SLionel Sambuc 				printf(
109433d6423SLionel Sambuc 				"verify_grant: grant verify failed in ep %d "
110ca779acdSDavid van Moolenbroek 				"proc %d: grant 0x%x (#%d) out of range "
111433d6423SLionel Sambuc 				"for table size %d\n",
112ca779acdSDavid van Moolenbroek 					granter, proc_nr, grant, grant_idx,
113433d6423SLionel Sambuc 					priv(granter_proc)->s_grant_entries);
114433d6423SLionel Sambuc 			return(EPERM);
115433d6423SLionel Sambuc 		}
116433d6423SLionel Sambuc 
117ca779acdSDavid van Moolenbroek 		/* Copy the grant entry corresponding to this ID's index to see
118ca779acdSDavid van Moolenbroek 		 * what it looks like. If it fails, hide the fact that granter
119ca779acdSDavid van Moolenbroek 		 * has (presumably) set an invalid grant table entry by
120ca779acdSDavid van Moolenbroek 		 * returning EPERM, just like with an invalid grant id.
121433d6423SLionel Sambuc 		 */
122ca779acdSDavid van Moolenbroek 		if(data_copy(granter, priv(granter_proc)->s_grant_table +
123ca779acdSDavid van Moolenbroek 			sizeof(g) * grant_idx,
124433d6423SLionel Sambuc 			KERNEL, (vir_bytes) &g, sizeof(g)) != OK) {
125433d6423SLionel Sambuc 			printf(
126433d6423SLionel Sambuc 			"verify_grant: grant verify: data_copy failed\n");
127433d6423SLionel Sambuc 			return EPERM;
128433d6423SLionel Sambuc 		}
129433d6423SLionel Sambuc 
130ca779acdSDavid van Moolenbroek 		/* Check validity: flags and sequence number. */
131433d6423SLionel Sambuc 		if((g.cp_flags & (CPF_USED | CPF_VALID)) !=
132433d6423SLionel Sambuc 			(CPF_USED | CPF_VALID)) {
133ca779acdSDavid van Moolenbroek 			printf("verify_grant: grant failed: invalid flags "
134ca779acdSDavid van Moolenbroek 			    "(0x%x, 0x%lx)\n", grant, g.cp_flags);
135ca779acdSDavid van Moolenbroek 			return EPERM;
136ca779acdSDavid van Moolenbroek 		}
137ca779acdSDavid van Moolenbroek 
138ca779acdSDavid van Moolenbroek 		if (g.cp_seq != grant_seq) {
139ca779acdSDavid van Moolenbroek 			printf("verify_grant: grant failed: invalid sequence "
140ca779acdSDavid van Moolenbroek 			    "(0x%x, %d vs %d)\n", grant, grant_seq, g.cp_seq);
141433d6423SLionel Sambuc 			return EPERM;
142433d6423SLionel Sambuc 		}
143433d6423SLionel Sambuc 
144433d6423SLionel Sambuc 		/* The given grant may be an indirect grant, that is, a grant
145433d6423SLionel Sambuc 		 * that provides permission to use a grant given to the
146433d6423SLionel Sambuc 		 * granter (i.e., for which it is the grantee). This can lead
147433d6423SLionel Sambuc 		 * to a chain of indirect grants which must be followed back.
148433d6423SLionel Sambuc 		 */
149433d6423SLionel Sambuc 		if((g.cp_flags & CPF_INDIRECT)) {
150433d6423SLionel Sambuc 			/* Stop after a few iterations. There may be a loop. */
151433d6423SLionel Sambuc 			if (depth == MAX_INDIRECT_DEPTH) {
152433d6423SLionel Sambuc 				printf(
153433d6423SLionel Sambuc 					"verify grant: indirect grant verify "
154433d6423SLionel Sambuc 					"failed: exceeded maximum depth\n");
155433d6423SLionel Sambuc 				return ELOOP;
156433d6423SLionel Sambuc 			}
157433d6423SLionel Sambuc 			depth++;
158433d6423SLionel Sambuc 
159433d6423SLionel Sambuc 			/* Verify actual grantee. */
160433d6423SLionel Sambuc 			if(g.cp_u.cp_indirect.cp_who_to != grantee &&
161433d6423SLionel Sambuc 				grantee != ANY &&
162433d6423SLionel Sambuc 				g.cp_u.cp_indirect.cp_who_to != ANY) {
163433d6423SLionel Sambuc 				printf(
164433d6423SLionel Sambuc 					"verify_grant: indirect grant verify "
165433d6423SLionel Sambuc 					"failed: bad grantee\n");
166433d6423SLionel Sambuc 				return EPERM;
167433d6423SLionel Sambuc 			}
168433d6423SLionel Sambuc 
169433d6423SLionel Sambuc 			/* Start over with new granter, grant, and grantee. */
170433d6423SLionel Sambuc 			grantee = granter;
171433d6423SLionel Sambuc 			granter = g.cp_u.cp_indirect.cp_who_from;
172433d6423SLionel Sambuc 			grant = g.cp_u.cp_indirect.cp_grant;
173433d6423SLionel Sambuc 		}
174433d6423SLionel Sambuc 	} while(g.cp_flags & CPF_INDIRECT);
175433d6423SLionel Sambuc 
176433d6423SLionel Sambuc 	/* Check access of grant. */
177433d6423SLionel Sambuc 	if(((g.cp_flags & access) != access)) {
178433d6423SLionel Sambuc 		printf(
179433d6423SLionel Sambuc 	"verify_grant: grant verify failed: access invalid; want 0x%x, have 0x%x\n",
180433d6423SLionel Sambuc 			access, g.cp_flags);
181433d6423SLionel Sambuc 		return EPERM;
182433d6423SLionel Sambuc 	}
183433d6423SLionel Sambuc 
184433d6423SLionel Sambuc 	if((g.cp_flags & CPF_DIRECT)) {
185433d6423SLionel Sambuc 		/* Don't fiddle around with grants that wrap, arithmetic
186433d6423SLionel Sambuc 		 * below may be confused.
187433d6423SLionel Sambuc 		 */
188433d6423SLionel Sambuc 		if(MEM_TOP - g.cp_u.cp_direct.cp_len + 1 <
189433d6423SLionel Sambuc 			g.cp_u.cp_direct.cp_start) {
190433d6423SLionel Sambuc 			printf(
191433d6423SLionel Sambuc 		"verify_grant: direct grant verify failed: len too long\n");
192433d6423SLionel Sambuc 			return EPERM;
193433d6423SLionel Sambuc 		}
194433d6423SLionel Sambuc 
195433d6423SLionel Sambuc 		/* Verify actual grantee. */
196433d6423SLionel Sambuc 		if(g.cp_u.cp_direct.cp_who_to != grantee && grantee != ANY
197433d6423SLionel Sambuc 			&& g.cp_u.cp_direct.cp_who_to != ANY) {
198433d6423SLionel Sambuc 			printf(
199433d6423SLionel Sambuc 		"verify_grant: direct grant verify failed: bad grantee\n");
200433d6423SLionel Sambuc 			return EPERM;
201433d6423SLionel Sambuc 		}
202433d6423SLionel Sambuc 
203433d6423SLionel Sambuc 		/* Verify actual copy range. */
204433d6423SLionel Sambuc 		if((offset_in+bytes < offset_in) ||
205433d6423SLionel Sambuc 		    offset_in+bytes > g.cp_u.cp_direct.cp_len) {
206433d6423SLionel Sambuc 			printf(
207433d6423SLionel Sambuc 		"verify_grant: direct grant verify failed: bad size or range. "
208433d6423SLionel Sambuc 		"granted %d bytes @ 0x%lx; wanted %d bytes @ 0x%lx\n",
209433d6423SLionel Sambuc 				g.cp_u.cp_direct.cp_len,
210433d6423SLionel Sambuc 				g.cp_u.cp_direct.cp_start,
211433d6423SLionel Sambuc 				bytes, offset_in);
212433d6423SLionel Sambuc 			return EPERM;
213433d6423SLionel Sambuc 		}
214433d6423SLionel Sambuc 
215433d6423SLionel Sambuc 		/* Verify successful - tell caller what address it is. */
216433d6423SLionel Sambuc 		*offset_result = g.cp_u.cp_direct.cp_start + offset_in;
217433d6423SLionel Sambuc 		*e_granter = granter;
218433d6423SLionel Sambuc 	} else if(g.cp_flags & CPF_MAGIC) {
219*6f3e0bcdSDavid van Moolenbroek 		/* Currently, it is hardcoded that only VFS and MIB may do
220*6f3e0bcdSDavid van Moolenbroek 		 * magic grants.  TODO: this should be a system.conf flag.
221433d6423SLionel Sambuc 		 */
222*6f3e0bcdSDavid van Moolenbroek 		if(granter != VFS_PROC_NR && granter != MIB_PROC_NR) {
223433d6423SLionel Sambuc 			printf(
224433d6423SLionel Sambuc 		"verify_grant: magic grant verify failed: granter (%d) "
225*6f3e0bcdSDavid van Moolenbroek 		"not allowed\n", granter);
226433d6423SLionel Sambuc 			return EPERM;
227433d6423SLionel Sambuc 		}
228433d6423SLionel Sambuc 
229433d6423SLionel Sambuc 		/* Verify actual grantee. */
230433d6423SLionel Sambuc 		if(g.cp_u.cp_magic.cp_who_to != grantee && grantee != ANY
231433d6423SLionel Sambuc 			&& g.cp_u.cp_direct.cp_who_to != ANY) {
232433d6423SLionel Sambuc 			printf(
233433d6423SLionel Sambuc 		"verify_grant: magic grant verify failed: bad grantee\n");
234433d6423SLionel Sambuc 			return EPERM;
235433d6423SLionel Sambuc 		}
236433d6423SLionel Sambuc 
237433d6423SLionel Sambuc 		/* Verify actual copy range. */
238433d6423SLionel Sambuc 		if((offset_in+bytes < offset_in) ||
239433d6423SLionel Sambuc 		    offset_in+bytes > g.cp_u.cp_magic.cp_len) {
240433d6423SLionel Sambuc 			printf(
241433d6423SLionel Sambuc 		"verify_grant: magic grant verify failed: bad size or range. "
242433d6423SLionel Sambuc 		"granted %d bytes @ 0x%lx; wanted %d bytes @ 0x%lx\n",
243433d6423SLionel Sambuc 				g.cp_u.cp_magic.cp_len,
244433d6423SLionel Sambuc 				g.cp_u.cp_magic.cp_start,
245433d6423SLionel Sambuc 				bytes, offset_in);
246433d6423SLionel Sambuc 			return EPERM;
247433d6423SLionel Sambuc 		}
248433d6423SLionel Sambuc 
249433d6423SLionel Sambuc 		/* Verify successful - tell caller what address it is. */
250433d6423SLionel Sambuc 		*offset_result = g.cp_u.cp_magic.cp_start + offset_in;
251433d6423SLionel Sambuc 		*e_granter = g.cp_u.cp_magic.cp_who_from;
252433d6423SLionel Sambuc 	} else {
253433d6423SLionel Sambuc 		printf(
254433d6423SLionel Sambuc 		"verify_grant: grant verify failed: unknown grant type\n");
255433d6423SLionel Sambuc 		return EPERM;
256433d6423SLionel Sambuc 	}
257433d6423SLionel Sambuc 
25810b7016bSDavid van Moolenbroek 	/* If requested, store information regarding soft faults. */
25910b7016bSDavid van Moolenbroek 	if (sfinfo != NULL && (sfinfo->try = !!(g.cp_flags & CPF_TRY))) {
26010b7016bSDavid van Moolenbroek 		sfinfo->endpt = granter;
26110b7016bSDavid van Moolenbroek 		sfinfo->addr = priv(granter_proc)->s_grant_table +
26210b7016bSDavid van Moolenbroek 		    sizeof(g) * grant_idx + offsetof(cp_grant_t, cp_faulted);
26310b7016bSDavid van Moolenbroek 		sfinfo->value = grant;
26410b7016bSDavid van Moolenbroek 	}
26510b7016bSDavid van Moolenbroek 
266433d6423SLionel Sambuc 	return OK;
267433d6423SLionel Sambuc }
268433d6423SLionel Sambuc 
269433d6423SLionel Sambuc /*===========================================================================*
270433d6423SLionel Sambuc  *				safecopy				     *
271433d6423SLionel Sambuc  *===========================================================================*/
2726077d1adSDr. Florian Grätz static int safecopy(
2736077d1adSDr. Florian Grätz   struct proc * caller,
2746077d1adSDr. Florian Grätz   endpoint_t granter,
2756077d1adSDr. Florian Grätz   endpoint_t grantee,
2766077d1adSDr. Florian Grätz   cp_grant_id_t grantid,
2776077d1adSDr. Florian Grätz   size_t bytes,
2786077d1adSDr. Florian Grätz   vir_bytes g_offset,
2796077d1adSDr. Florian Grätz   vir_bytes addr,
2806077d1adSDr. Florian Grätz   int access			/* CPF_READ for a copy from granter to grantee, CPF_WRITE
281433d6423SLionel Sambuc 				 * for a copy from grantee to granter.
282433d6423SLionel Sambuc 				 */
2836077d1adSDr. Florian Grätz )
284433d6423SLionel Sambuc {
285433d6423SLionel Sambuc 	static struct vir_addr v_src, v_dst;
286433d6423SLionel Sambuc 	static vir_bytes v_offset;
287433d6423SLionel Sambuc 	endpoint_t new_granter, *src, *dst;
288433d6423SLionel Sambuc 	struct proc *granter_p;
289433d6423SLionel Sambuc 	int r;
29010b7016bSDavid van Moolenbroek 	struct cp_sfinfo sfinfo;
291433d6423SLionel Sambuc #if PERF_USE_COW_SAFECOPY
292433d6423SLionel Sambuc 	vir_bytes size;
293433d6423SLionel Sambuc #endif
294433d6423SLionel Sambuc 
295433d6423SLionel Sambuc 	if(granter == NONE || grantee == NONE) {
296433d6423SLionel Sambuc 		printf("safecopy: nonsense processes\n");
297433d6423SLionel Sambuc 		return EFAULT;
298433d6423SLionel Sambuc 	}
299433d6423SLionel Sambuc 
300433d6423SLionel Sambuc 	/* Decide who is src and who is dst. */
301433d6423SLionel Sambuc 	if(access & CPF_READ) {
302433d6423SLionel Sambuc 		src = &granter;
303433d6423SLionel Sambuc 		dst = &grantee;
304433d6423SLionel Sambuc 	} else {
305433d6423SLionel Sambuc 		src = &grantee;
306433d6423SLionel Sambuc 		dst = &granter;
307433d6423SLionel Sambuc 	}
308433d6423SLionel Sambuc 
309433d6423SLionel Sambuc 	/* Verify permission exists. */
310433d6423SLionel Sambuc 	if((r=verify_grant(granter, grantee, grantid, bytes, access,
31110b7016bSDavid van Moolenbroek 	    g_offset, &v_offset, &new_granter, &sfinfo)) != OK) {
3129e6b1315SCristiano Giuffrida 		if(r == ENOTREADY) return r;
313433d6423SLionel Sambuc 			printf(
314433d6423SLionel Sambuc 		"grant %d verify to copy %d->%d by %d failed: err %d\n",
315433d6423SLionel Sambuc 				grantid, *src, *dst, grantee, r);
316433d6423SLionel Sambuc 		return r;
317433d6423SLionel Sambuc 	}
318433d6423SLionel Sambuc 
319433d6423SLionel Sambuc 	/* verify_grant() can redirect the grantee to someone else,
320433d6423SLionel Sambuc 	 * meaning the source or destination changes.
321433d6423SLionel Sambuc 	 */
322433d6423SLionel Sambuc 	granter = new_granter;
323433d6423SLionel Sambuc 
324433d6423SLionel Sambuc 	/* Now it's a regular copy. */
325433d6423SLionel Sambuc 	v_src.proc_nr_e = *src;
326433d6423SLionel Sambuc 	v_dst.proc_nr_e = *dst;
327433d6423SLionel Sambuc 
328433d6423SLionel Sambuc 	/* Now the offset in virtual addressing is known in 'offset'.
329433d6423SLionel Sambuc 	 * Depending on the access, this is the source or destination
330433d6423SLionel Sambuc 	 * address.
331433d6423SLionel Sambuc 	 */
332433d6423SLionel Sambuc 	if(access & CPF_READ) {
333433d6423SLionel Sambuc 		v_src.offset = v_offset;
334433d6423SLionel Sambuc 		v_dst.offset = (vir_bytes) addr;
335433d6423SLionel Sambuc 	} else {
336433d6423SLionel Sambuc 		v_src.offset = (vir_bytes) addr;
337433d6423SLionel Sambuc 		v_dst.offset = v_offset;
338433d6423SLionel Sambuc 	}
339433d6423SLionel Sambuc 
340433d6423SLionel Sambuc 	/* Do the regular copy. */
34110b7016bSDavid van Moolenbroek 	if (sfinfo.try) {
34210b7016bSDavid van Moolenbroek 		/*
34310b7016bSDavid van Moolenbroek 		 * Try copying without transparently faulting in pages.
34410b7016bSDavid van Moolenbroek 		 * TODO: while CPF_TRY is meant to protect against deadlocks on
34510b7016bSDavid van Moolenbroek 		 * memory-mapped files in file systems, it seems that this case
34610b7016bSDavid van Moolenbroek 		 * triggers faults a whole lot more often, resulting in extra
34710b7016bSDavid van Moolenbroek 		 * overhead due to retried file system operations.  It might be
34810b7016bSDavid van Moolenbroek 		 * a good idea to go through VM even in this case, and have VM
34910b7016bSDavid van Moolenbroek 		 * fail (only) if the affected page belongs to a file mapping.
35010b7016bSDavid van Moolenbroek 		 */
351433d6423SLionel Sambuc 		r = virtual_copy(&v_src, &v_dst, bytes);
35210b7016bSDavid van Moolenbroek 		if (r == EFAULT_SRC || r == EFAULT_DST) {
35310b7016bSDavid van Moolenbroek 			/*
35410b7016bSDavid van Moolenbroek 			 * Mark the magic grant as having experienced a soft
35510b7016bSDavid van Moolenbroek 			 * fault during its lifetime.  The exact value does not
35610b7016bSDavid van Moolenbroek 			 * matter, but we use the grant ID (including its
35710b7016bSDavid van Moolenbroek 			 * sequence number) as a form of protection in the
35810b7016bSDavid van Moolenbroek 			 * light of CPU concurrency.
35910b7016bSDavid van Moolenbroek 			 */
36010b7016bSDavid van Moolenbroek 			r = data_copy(KERNEL, (vir_bytes)&sfinfo.value,
36110b7016bSDavid van Moolenbroek 			    sfinfo.endpt, sfinfo.addr, sizeof(sfinfo.value));
36210b7016bSDavid van Moolenbroek 			/*
36310b7016bSDavid van Moolenbroek 			 * Failure means the creator of the magic grant messed
36410b7016bSDavid van Moolenbroek 			 * up, which can only be unintentional, so report..
36510b7016bSDavid van Moolenbroek 			 */
36610b7016bSDavid van Moolenbroek 			if (r != OK)
36710b7016bSDavid van Moolenbroek 				printf("Kernel: writing soft fault marker %d "
36810b7016bSDavid van Moolenbroek 				    "into %d at 0x%lx failed (%d)\n",
36910b7016bSDavid van Moolenbroek 				    sfinfo.value, sfinfo.endpt, sfinfo.addr,
37010b7016bSDavid van Moolenbroek 				    r);
37110b7016bSDavid van Moolenbroek 
37210b7016bSDavid van Moolenbroek 			return EFAULT;
37310b7016bSDavid van Moolenbroek 		}
374433d6423SLionel Sambuc 		return r;
375433d6423SLionel Sambuc 	}
376433d6423SLionel Sambuc 	return virtual_copy_vmcheck(caller, &v_src, &v_dst, bytes);
377433d6423SLionel Sambuc }
378433d6423SLionel Sambuc 
379433d6423SLionel Sambuc /*===========================================================================*
380433d6423SLionel Sambuc  *				do_safecopy_to				     *
381433d6423SLionel Sambuc  *===========================================================================*/
382433d6423SLionel Sambuc int do_safecopy_to(struct proc * caller, message * m_ptr)
383433d6423SLionel Sambuc {
384433d6423SLionel Sambuc 	return safecopy(caller, m_ptr->m_lsys_kern_safecopy.from_to, caller->p_endpoint,
385433d6423SLionel Sambuc 		(cp_grant_id_t) m_ptr->m_lsys_kern_safecopy.gid,
386433d6423SLionel Sambuc 		m_ptr->m_lsys_kern_safecopy.bytes, m_ptr->m_lsys_kern_safecopy.offset,
387433d6423SLionel Sambuc 		(vir_bytes) m_ptr->m_lsys_kern_safecopy.address, CPF_WRITE);
388433d6423SLionel Sambuc }
389433d6423SLionel Sambuc 
390433d6423SLionel Sambuc /*===========================================================================*
391433d6423SLionel Sambuc  *				do_safecopy_from			     *
392433d6423SLionel Sambuc  *===========================================================================*/
393433d6423SLionel Sambuc int do_safecopy_from(struct proc * caller, message * m_ptr)
394433d6423SLionel Sambuc {
395433d6423SLionel Sambuc 	return safecopy(caller, m_ptr->m_lsys_kern_safecopy.from_to, caller->p_endpoint,
396433d6423SLionel Sambuc 		(cp_grant_id_t) m_ptr->m_lsys_kern_safecopy.gid,
397433d6423SLionel Sambuc 		m_ptr->m_lsys_kern_safecopy.bytes, m_ptr->m_lsys_kern_safecopy.offset,
398433d6423SLionel Sambuc 		(vir_bytes) m_ptr->m_lsys_kern_safecopy.address, CPF_READ);
399433d6423SLionel Sambuc }
400433d6423SLionel Sambuc 
401433d6423SLionel Sambuc /*===========================================================================*
402433d6423SLionel Sambuc  *				do_vsafecopy				     *
403433d6423SLionel Sambuc  *===========================================================================*/
404433d6423SLionel Sambuc int do_vsafecopy(struct proc * caller, message * m_ptr)
405433d6423SLionel Sambuc {
406433d6423SLionel Sambuc 	static struct vscp_vec vec[SCPVEC_NR];
407433d6423SLionel Sambuc 	static struct vir_addr src, dst;
408433d6423SLionel Sambuc 	int r, i, els;
409433d6423SLionel Sambuc 	size_t bytes;
410433d6423SLionel Sambuc 
411433d6423SLionel Sambuc 	/* Set vector copy parameters. */
412433d6423SLionel Sambuc 	src.proc_nr_e = caller->p_endpoint;
413433d6423SLionel Sambuc 	assert(src.proc_nr_e != NONE);
414433d6423SLionel Sambuc 	src.offset = (vir_bytes) m_ptr->m_lsys_kern_vsafecopy.vec_addr;
415433d6423SLionel Sambuc 	dst.proc_nr_e = KERNEL;
416433d6423SLionel Sambuc 	dst.offset = (vir_bytes) vec;
417433d6423SLionel Sambuc 
418433d6423SLionel Sambuc 	/* No. of vector elements. */
419433d6423SLionel Sambuc 	els = m_ptr->m_lsys_kern_vsafecopy.vec_size;
420433d6423SLionel Sambuc 	bytes = els * sizeof(struct vscp_vec);
421433d6423SLionel Sambuc 
422433d6423SLionel Sambuc 	/* Obtain vector of copies. */
423433d6423SLionel Sambuc 	if((r=virtual_copy_vmcheck(caller, &src, &dst, bytes)) != OK)
424433d6423SLionel Sambuc 		return r;
425433d6423SLionel Sambuc 
426433d6423SLionel Sambuc 	/* Perform safecopies. */
427433d6423SLionel Sambuc 	for(i = 0; i < els; i++) {
428433d6423SLionel Sambuc 		int access;
429433d6423SLionel Sambuc 		endpoint_t granter;
430433d6423SLionel Sambuc 		if(vec[i].v_from == SELF) {
431433d6423SLionel Sambuc 			access = CPF_WRITE;
432433d6423SLionel Sambuc 			granter = vec[i].v_to;
433433d6423SLionel Sambuc 		} else if(vec[i].v_to == SELF) {
434433d6423SLionel Sambuc 			access = CPF_READ;
435433d6423SLionel Sambuc 			granter = vec[i].v_from;
436433d6423SLionel Sambuc 		} else {
437433d6423SLionel Sambuc 			printf("vsafecopy: %d: element %d/%d: no SELF found\n",
438433d6423SLionel Sambuc 				caller->p_endpoint, i, els);
439433d6423SLionel Sambuc 			return EINVAL;
440433d6423SLionel Sambuc 		}
441433d6423SLionel Sambuc 
442433d6423SLionel Sambuc 		/* Do safecopy for this element. */
443433d6423SLionel Sambuc 		if((r=safecopy(caller, granter, caller->p_endpoint,
444433d6423SLionel Sambuc 			vec[i].v_gid,
445433d6423SLionel Sambuc 			vec[i].v_bytes, vec[i].v_offset,
446433d6423SLionel Sambuc 			vec[i].v_addr, access)) != OK) {
447433d6423SLionel Sambuc 			return r;
448433d6423SLionel Sambuc 		}
449433d6423SLionel Sambuc 	}
450433d6423SLionel Sambuc 
451433d6423SLionel Sambuc 	return OK;
452433d6423SLionel Sambuc }
453433d6423SLionel Sambuc 
454