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