Home | History | Annotate | Line # | Download | only in arm
      1 /*	$NetBSD: linux_syscall.c,v 1.27 2015/03/07 18:52:46 christos Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2000, 2003 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Charles M. Hannum.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Copyright (c) 1994-1998 Mark Brinicombe.
     34  * Copyright (c) 1994 Brini.
     35  * All rights reserved.
     36  *
     37  * This code is derived from software written for Brini by Mark Brinicombe
     38  *
     39  * Redistribution and use in source and binary forms, with or without
     40  * modification, are permitted provided that the following conditions
     41  * are met:
     42  * 1. Redistributions of source code must retain the above copyright
     43  *    notice, this list of conditions and the following disclaimer.
     44  * 2. Redistributions in binary form must reproduce the above copyright
     45  *    notice, this list of conditions and the following disclaimer in the
     46  *    documentation and/or other materials provided with the distribution.
     47  * 3. All advertising materials mentioning features or use of this software
     48  *    must display the following acknowledgement:
     49  *	This product includes software developed by Mark Brinicombe
     50  *	for the NetBSD Project.
     51  * 4. The name of the company nor the name of the author may be used to
     52  *    endorse or promote products derived from this software without specific
     53  *    prior written permission.
     54  *
     55  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     56  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     57  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     58  * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     59  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     60  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     61  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     62  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     63  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     64  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     65  * SUCH DAMAGE.
     66  *
     67  * ARMLinux emulation: syscall entry handling
     68  */
     69 
     70 #include <sys/param.h>
     71 
     72 __KERNEL_RCSID(0, "$NetBSD: linux_syscall.c,v 1.27 2015/03/07 18:52:46 christos Exp $");
     73 
     74 #include <sys/device.h>
     75 #include <sys/errno.h>
     76 #include <sys/kernel.h>
     77 #include <sys/reboot.h>
     78 #include <sys/signalvar.h>
     79 #include <sys/systm.h>
     80 #include <sys/syscallvar.h>
     81 #include <sys/cpu.h>
     82 
     83 #include <uvm/uvm_extern.h>
     84 
     85 #include <arm/swi.h>
     86 #include <arm/locore.h>
     87 
     88 #include <compat/linux/common/linux_errno.h>
     89 #include <compat/linux/linux_syscall.h>
     90 
     91 /* ARMLinux has some system calls of its very own. */
     92 #define LINUX_ARM_NR_BASE	0x9f0000
     93 #define LINUX_EARM_NR_BASE	0x0f0000
     94 #define LINUX_SYS_ARMBASE	0x000180 /* Must agree with syscalls.master */
     95 
     96 void linux_syscall_intern(struct proc *);
     97 void linux_syscall_plain(struct trapframe *, struct lwp *, uint32_t);
     98 void linux_syscall_fancy(struct trapframe *, struct lwp *, uint32_t);
     99 
    100 void
    101 linux_syscall_intern(struct proc *p)
    102 {
    103 
    104 	if (trace_is_enabled(p))
    105 		p->p_md.md_syscall = linux_syscall_fancy;
    106 	else
    107 		p->p_md.md_syscall = linux_syscall_plain;
    108 }
    109 
    110 void
    111 linux_syscall_plain(trapframe_t *frame, struct lwp *l, uint32_t insn)
    112 {
    113 	const struct sysent *callp;
    114 	struct proc *p = l->l_proc;
    115 	int code, error;
    116 	register_t *args, rval[2];
    117 
    118 	code = insn & 0x00ffffff;
    119 	if (code == 0) {	/* EABI */
    120 		code = frame->tf_r7;
    121 		if (code > LINUX_EARM_NR_BASE)
    122 			code = code - LINUX_EARM_NR_BASE + LINUX_SYS_ARMBASE;
    123 	} else {
    124 		/* Remap ARM-specific syscalls onto the end of the standard range. */
    125 		if (code > LINUX_ARM_NR_BASE)
    126 			code = code - LINUX_ARM_NR_BASE + LINUX_SYS_ARMBASE;
    127 	}
    128 	code &= LINUX_SYS_NSYSENT - 1;
    129 
    130 	/* Linux passes all arguments in order in registers, which is nice. */
    131 	args = &frame->tf_r0;
    132 	callp = p->p_emul->e_sysent + code;
    133 
    134 	rval[0] = 0;
    135 	rval[1] = 0;
    136 	error = sy_call(callp, l, args, rval);
    137 
    138 	switch (error) {
    139 	case 0:
    140 		frame->tf_r0 = rval[0];
    141 		break;
    142 
    143 	case ERESTART:
    144 		/* Reconstruct the pc to point at the swi.  */
    145  		frame->tf_pc -= INSN_SIZE;
    146 		break;
    147 
    148 	case EJUSTRETURN:
    149 		/* nothing to do */
    150 		break;
    151 
    152 	default:
    153 		error = native_to_linux_errno[error];
    154 		frame->tf_r0 = error;
    155 		break;
    156 	}
    157 
    158 	userret(l);
    159 }
    160 
    161 void
    162 linux_syscall_fancy(trapframe_t *frame, struct lwp *l, uint32_t insn)
    163 {
    164 	const struct sysent *callp;
    165 	struct proc *p = l->l_proc;
    166 	int code, error;
    167 	register_t *args, rval[2];
    168 
    169 	code = insn & 0x00ffffff;
    170 	if (code == 0) {	/* EABI */
    171 		code = frame->tf_r7;
    172 		if (code > LINUX_EARM_NR_BASE)
    173 			code = code - LINUX_EARM_NR_BASE + LINUX_SYS_ARMBASE;
    174 	} else {
    175 		/* Remap ARM-specific syscalls onto the end of the standard range. */
    176 		if (code > LINUX_ARM_NR_BASE)
    177 			code = code - LINUX_ARM_NR_BASE + LINUX_SYS_ARMBASE;
    178 	}
    179 	code &= LINUX_SYS_NSYSENT - 1;
    180 
    181 	/* Linux passes all arguments in order in registers, which is nice. */
    182 	args = &frame->tf_r0;
    183 	callp = p->p_emul->e_sysent + code;
    184 
    185 	if ((error = trace_enter(code, callp, args)) != 0)
    186 		goto out;
    187 
    188 	rval[0] = 0;
    189 	rval[1] = 0;
    190 	error = sy_call(callp, l, args, rval);
    191 out:
    192 	switch (error) {
    193 	case 0:
    194 		frame->tf_r0 = rval[0];
    195 		break;
    196 
    197 	case ERESTART:
    198 		/* Reconstruct the pc to point at the swi.  */
    199  		frame->tf_pc -= INSN_SIZE;
    200 		break;
    201 
    202 	case EJUSTRETURN:
    203 		/* nothing to do */
    204 		break;
    205 
    206 	default:
    207 		error = native_to_linux_errno[error];
    208 		frame->tf_r0 = error;
    209 		break;
    210 	}
    211 
    212 	trace_exit(code, callp, args, rval, error);
    213 
    214 	userret(l);
    215 }
    216