Home | History | Annotate | Line # | Download | only in x86
      1 /*	$NetBSD: linux_trap.c,v 1.12 2021/10/07 12:52:27 msaitoh Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Christos Zoulas.
      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  * x86 Trap and System call handling
     34  */
     35 
     36 #include <sys/cdefs.h>
     37 __KERNEL_RCSID(0, "$NetBSD: linux_trap.c,v 1.12 2021/10/07 12:52:27 msaitoh Exp $");
     38 
     39 #include <sys/param.h>
     40 #include <sys/systm.h>
     41 #include <sys/proc.h>
     42 #include <sys/acct.h>
     43 #include <sys/kernel.h>
     44 #include <sys/signal.h>
     45 #include <sys/signalvar.h>
     46 #include <sys/syscall.h>
     47 
     48 #include <uvm/uvm_extern.h>
     49 
     50 #include <machine/cpu.h>
     51 #include <machine/cpufunc.h>
     52 #include <machine/psl.h>
     53 #include <machine/reg.h>
     54 #include <machine/trap.h>
     55 #include <machine/userret.h>
     56 
     57 #include <compat/linux/common/linux_exec.h>
     58 
     59 #ifndef DEBUG_LINUX
     60 #define DPRINTF(a)
     61 #else
     62 #define DPRINTF(a)	uprintf a
     63 #endif
     64 
     65 struct linux_user_desc {
     66 	unsigned int		entry_number;
     67 	unsigned int		base_addr;
     68 	unsigned int		limit;
     69 	unsigned int		seg_32bit:1;
     70 	unsigned int		contents:2;
     71 	unsigned int		read_exec_only:1;
     72 	unsigned int		limit_in_pages:1;
     73 	unsigned int		seg_not_present:1;
     74 	unsigned int		useable:1;
     75 };
     76 
     77 #define LINUX_T_DIVIDE			0
     78 #define LINUX_T_DEBUG			1
     79 #define LINUX_T_NMI			2
     80 #define LINUX_T_INT3			3
     81 #define LINUX_T_OVERFLOW		4
     82 #define LINUX_T_BOUNDS			5
     83 #define LINUX_T_INVALID_OP		6
     84 #define LINUX_T_DEVICE_NOT_AVAIL	7
     85 #define LINUX_T_DOUBLE_FAULT		8
     86 #define LINUX_T_COPROC_SEG_OVERRUN	9
     87 #define LINUX_T_INVALID_TSS		10
     88 #define LINUX_T_SEG_NOT_PRESENT		11
     89 #define LINUX_T_STACK_SEG_FAULT		12
     90 #define LINUX_T_GENERAL_PROT_FAULT	13
     91 #define LINUX_T_PAGE_FAULT		14
     92 #define LINUX_T_SPURIOUS_INTERRUPT	15
     93 #define LINUX_T_COPROC_ERROR		16
     94 #define LINUX_T_ALIGN_CHECK		17
     95 #define LINUX_T_MACHINE_CHECK		18	/* XXX */
     96 #define LINUX_T_SIMD_COPROC_ERROR	19	/* XXX */
     97 
     98 /* Note 255 is bogus */
     99 static const int trapno_to_x86_vec[] = {
    100 	LINUX_T_INVALID_OP,		/*  0 T_PRIVINFLT */
    101 	LINUX_T_INT3,			/*  1 T_BPTFLT */
    102 	LINUX_T_COPROC_ERROR,		/*  2 T_ARITHTRAP */
    103 	LINUX_T_SPURIOUS_INTERRUPT,	/*  3 T_ASTFLT XXX: ??? */
    104 	LINUX_T_GENERAL_PROT_FAULT,	/*  4 T_PROTFLT */
    105 	LINUX_T_DEBUG,			/*  5 T_TRCTRAP */
    106 	LINUX_T_PAGE_FAULT,		/*  6 T_PAGEFLT */
    107 	LINUX_T_ALIGN_CHECK,		/*  7 T_ALIGNFLT */
    108 	LINUX_T_DIVIDE,			/*  8 T_DIVIDE */
    109 	LINUX_T_NMI,			/*  9 T_NMI */
    110 	LINUX_T_OVERFLOW,		/* 10 T_OFLOW */
    111 	LINUX_T_BOUNDS,			/* 11 T_BOUND */
    112 	LINUX_T_DEVICE_NOT_AVAIL,	/* 12 T_DNA */
    113 	LINUX_T_DOUBLE_FAULT,		/* 13 T_DOUBLEFLT */
    114 	LINUX_T_COPROC_SEG_OVERRUN,	/* 14 T_FPOPFLT */
    115 	LINUX_T_INVALID_TSS,		/* 15 T_TSSFLT */
    116 	LINUX_T_SEG_NOT_PRESENT,	/* 16 T_SEGNPFLT */
    117 	LINUX_T_STACK_SEG_FAULT,	/* 17 T_STKFLT */
    118 	LINUX_T_MACHINE_CHECK		/* 18 T_RESERVED XXX: ??? */
    119 };
    120 
    121 /* For the nmi and reserved below linux does not post a signal. */
    122 static const int linux_x86_vec_to_sig[] = {
    123 	SIGFPE,				/*  0 LINUX_T_DIVIDE */
    124 	SIGTRAP,			/*  1 LINUX_T_DEBUG */
    125 /*nmi*/	SIGSEGV,			/*  2 LINUX_T_NMI */
    126 	SIGTRAP,			/*  3 LINUX_T_INT3 */
    127 	SIGSEGV,			/*  4 LINUX_T_OVERFLOW */
    128 	SIGSEGV,			/*  5 LINUX_T_BOUNDS */
    129 	SIGILL,				/*  6 LINUX_T_INVALIDOP */
    130 	SIGSEGV,			/*  7 LINUX_T_DEVICE_NOT_AVAIL */
    131 	SIGSEGV,			/*  8 LINUX_T_DOUBLE_FAULT */
    132 	SIGFPE,				/*  9 LINUX_T_COPROC_SEG_OVERRUN */
    133 	SIGSEGV,			/* 10 LINUX_T_INVALID_TSS */
    134 	SIGBUS,				/* 11 LINUX_T_SEG_NOT_PRESENT */
    135 	SIGBUS,				/* 12 LINUX_T_STACK_SEG_FAULT */
    136 	SIGSEGV,			/* 13 LINUX_T_GENERAL_PROT_FAULT */
    137 	SIGSEGV,			/* 14 LINUX_T_PAGE_FAULT */
    138 /*resv*/SIGSEGV,			/* 15 LINUX_T_SPURIOUS_INTERRUPT */
    139 	SIGFPE,				/* 16 LINUX_T_COPROC_ERROR */
    140 	SIGSEGV,			/* 17 LINUX_T_ALIGN_CHECK */
    141 	SIGSEGV				/* 18 LINUX_T_MACHINE_CHECK */
    142 };
    143 
    144 void
    145 linux_trapsignal(struct lwp *l, ksiginfo_t *ksi)
    146 {
    147 	ksiginfo_t nksi;
    148 
    149 	switch (ksi->ksi_signo) {
    150 	case SIGILL:
    151 	case SIGTRAP:
    152 	case SIGIOT:
    153 	case SIGBUS:
    154 	case SIGFPE:
    155 	case SIGSEGV:
    156 		KASSERT(KSI_TRAP_P(ksi));
    157 		if (ksi->ksi_trap < __arraycount(trapno_to_x86_vec)) {
    158 			nksi = *ksi;
    159 			nksi.ksi_trap = trapno_to_x86_vec[ksi->ksi_trap];
    160 			if (nksi.ksi_trap < __arraycount(linux_x86_vec_to_sig)) {
    161 				nksi.ksi_signo
    162 				    = linux_x86_vec_to_sig[nksi.ksi_trap];
    163 			} else {
    164 				uprintf("Unhandled sig type %d\n",
    165 				    ksi->ksi_trap);
    166 			}
    167 			ksi = &nksi;
    168 		} else {
    169 			uprintf("Unhandled trap type %d\n", ksi->ksi_trap);
    170 		}
    171 		/*FALLTHROUGH*/
    172 
    173 	default:
    174 		trapsignal(l, ksi);
    175 		return;
    176 	}
    177 }
    178 
    179 int
    180 linux_lwp_setprivate(struct lwp *l, void *ptr)
    181 {
    182 	struct linux_user_desc info;
    183 	int error;
    184 
    185 #ifdef __x86_64__
    186 	if ((l->l_proc->p_flag & PK_32) == 0) {
    187 		return lwp_setprivate(l, ptr);
    188 	}
    189 #endif
    190 	error = copyin(ptr, &info, sizeof(info));
    191 	if (error)
    192 		return error;
    193 
    194 	DPRINTF(("linux_lwp_setprivate: %i, %x, %x, %i, %i, %i, %i, %i, %i\n",
    195 	    info.entry_number, info.base_addr, info.limit, info.seg_32bit,
    196 	    info.contents, info.read_exec_only, info.limit_in_pages,
    197 	    info.seg_not_present, info.useable));
    198 
    199 	if (info.entry_number != GUGS_SEL) {
    200 		info.entry_number = GUGS_SEL;
    201 		error = copyout(&info, ptr, sizeof(info));
    202 		if (error)
    203 			return error;
    204 	}
    205 	return lwp_setprivate(l, (void *)(uintptr_t)info.base_addr);
    206 }
    207