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