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