xref: /minix/minix/kernel/system/do_copy.c (revision 2a404668)
1 /* The kernel call implemented in this file:
2  *   m_type:	SYS_VIRCOPY, SYS_PHYSCOPY
3  *
4  * The parameters for this kernel call are:
5  *   m_lsys_krn_sys_copy.src_addr		source offset within segment
6  *   m_lsys_krn_sys_copy.src_endpt		source process number
7  *   m_lsys_krn_sys_copy.dst_addr		destination offset within segment
8  *   m_lsys_krn_sys_copy.dst_endpt		destination process number
9  *   m_lsys_krn_sys_copy.nr_bytes		number of bytes to copy
10  *   m_lsys_krn_sys_copy.flags
11  */
12 
13 #include "kernel/system.h"
14 #include "kernel/vm.h"
15 #include <assert.h>
16 
17 #if (USE_VIRCOPY || USE_PHYSCOPY)
18 
19 /*===========================================================================*
20  *				do_copy					     *
21  *===========================================================================*/
22 int do_copy(struct proc * caller, message * m_ptr)
23 {
24 /* Handle sys_vircopy() and sys_physcopy().  Copy data using virtual or
25  * physical addressing. Although a single handler function is used, there
26  * are two different kernel calls so that permissions can be checked.
27  */
28   struct vir_addr vir_addr[2];	/* virtual source and destination address */
29   phys_bytes bytes;		/* number of bytes to copy */
30   int i;
31 
32 #if 0
33   if (caller->p_endpoint != PM_PROC_NR && caller->p_endpoint != VFS_PROC_NR &&
34 	caller->p_endpoint != RS_PROC_NR && caller->p_endpoint != MEM_PROC_NR &&
35 	caller->p_endpoint != VM_PROC_NR)
36   {
37 	static int first=1;
38 	if (first)
39 	{
40 		first= 0;
41 		printf(
42 "do_copy: got request from %d (source %d, destination %d)\n",
43 			caller->p_endpoint,
44 			m_ptr->m_lsys_krn_sys_copy.src_endpt,
45 			m_ptr->m_lsys_krn_sys_copy.dst_endpt);
46 	}
47   }
48 #endif
49 
50   /* Dismember the command message. */
51   vir_addr[_SRC_].proc_nr_e = m_ptr->m_lsys_krn_sys_copy.src_endpt;
52   vir_addr[_DST_].proc_nr_e = m_ptr->m_lsys_krn_sys_copy.dst_endpt;
53 
54   vir_addr[_SRC_].offset = m_ptr->m_lsys_krn_sys_copy.src_addr;
55   vir_addr[_DST_].offset = m_ptr->m_lsys_krn_sys_copy.dst_addr;
56   bytes = m_ptr->m_lsys_krn_sys_copy.nr_bytes;
57 
58   /* Now do some checks for both the source and destination virtual address.
59    * This is done once for _SRC_, then once for _DST_.
60    */
61   for (i=_SRC_; i<=_DST_; i++) {
62 	int p;
63       /* Check if process number was given implicitly with SELF and is valid. */
64       if (vir_addr[i].proc_nr_e == SELF)
65 	vir_addr[i].proc_nr_e = caller->p_endpoint;
66       if (vir_addr[i].proc_nr_e != NONE) {
67 	if(! isokendpt(vir_addr[i].proc_nr_e, &p)) {
68 	  printf("do_copy: %d: %d not ok endpoint\n", i, vir_addr[i].proc_nr_e);
69           return(EINVAL);
70         }
71       }
72   }
73 
74   /* Check for overflow. This would happen for 64K segments and 16-bit
75    * vir_bytes. Especially copying by the PM on do_fork() is affected.
76    */
77   if (bytes != (phys_bytes) (vir_bytes) bytes) return(E2BIG);
78 
79   /* Now try to make the actual virtual copy. */
80   if(m_ptr->m_lsys_krn_sys_copy.flags & CP_FLAG_TRY) {
81 	int r;
82 	assert(caller->p_endpoint == VFS_PROC_NR);
83 	r = virtual_copy(&vir_addr[_SRC_], &vir_addr[_DST_], bytes);
84 	if(r == EFAULT_SRC || r == EFAULT_DST) return r = EFAULT;
85 	return r;
86   } else {
87 	return( virtual_copy_vmcheck(caller, &vir_addr[_SRC_],
88 			  	&vir_addr[_DST_], bytes) );
89   }
90 }
91 #endif /* (USE_VIRCOPY || USE_PHYSCOPY) */
92