xref: /minix3/minix/kernel/system/do_copy.c (revision 2a4046681ace62ad0c38bcc11c47f796c74ca4c6)
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