Home | History | Annotate | Line # | Download | only in x86_64
cpu_x86_64.c revision 1.6.2.1
      1 /* $NetBSD: cpu_x86_64.c,v 1.6.2.1 2019/06/10 22:06:50 christos Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2011 Reinoud Zandijk <reinoud (at) netbsd.org>
      5  * Copyright (c) 2007 Jared D. McNeill <jmcneill (at) invisible.ca>
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     27  * POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 
     31 #include <sys/cdefs.h>
     32 __KERNEL_RCSID(0, "$NetBSD: cpu_x86_64.c,v 1.6.2.1 2019/06/10 22:06:50 christos Exp $");
     33 
     34 #include <sys/types.h>
     35 #include <sys/systm.h>
     36 #include <sys/param.h>
     37 #include <sys/time.h>
     38 #include <sys/exec.h>
     39 #include <sys/buf.h>
     40 #include <sys/boot_flag.h>
     41 #include <sys/ucontext.h>
     42 #include <sys/utsname.h>
     43 #include <machine/pcb.h>
     44 #include <machine/psl.h>
     45 
     46 #include <uvm/uvm_extern.h>
     47 #include <uvm/uvm_page.h>
     48 
     49 #include <dev/mm.h>
     50 #include <machine/machdep.h>
     51 #include <machine/thunk.h>
     52 #include <machine/mcontext.h>
     53 
     54 #if 0
     55 static void dump_regs(register_t *reg);
     56 
     57 static void
     58 dump_regs(register_t *reg)
     59 {
     60 	int i;
     61 
     62 	/* register dump before call */
     63 	const char *name[] = {"RDI", "RSI", "RDX", "RCX", "R8", "R9", "R10",
     64 		"R11", "R12", "R13", "R14", "R15", "RBP", "RAX",
     65 		"GS", "FS", "ES", "DS", "TRAPNO", "ERR", "RIP", "CS",
     66 		"RFLAGS", "RSP", "SS"};
     67 
     68 	for (i =0; i < 26; i++)
     69 		printf("reg[%02d] (%6s) = %"PRIx32"\n",
     70 			i, name[i], (uint32_t) reg[i]);
     71 }
     72 #endif
     73 
     74 
     75 /* from sys/arch/amd64/include/frame.h : KEEP IN SYNC */
     76 
     77 /*
     78  * Signal frame
     79  */
     80 struct sigframe_siginfo {
     81 	uint64_t	sf_ra;		/* return address for handler */
     82 	siginfo_t	sf_si;		/* actual saved siginfo */
     83 	ucontext_t	sf_uc;		/* actual saved ucontext */
     84 };
     85 
     86 
     87 /*
     88  * mcontext extensions to handle signal delivery.
     89  */
     90 void
     91 sendsig_siginfo(const ksiginfo_t *ksi, const sigset_t *mask)
     92 {
     93 	struct lwp *l = curlwp;
     94 	struct proc *p = l->l_proc;
     95 	struct pcb *pcb = lwp_getpcb(l);
     96 	struct sigacts *ps = p->p_sigacts;
     97 	struct sigframe_siginfo *fp, frame;
     98 	int sig = ksi->ksi_signo;
     99 	sig_t catcher = SIGACTION(p, sig).sa_handler;
    100 	ucontext_t *ucp;
    101 	register_t *reg;
    102 	int onstack, error;
    103 	char *sp;
    104 
    105 	KASSERT(mutex_owned(p->p_lock));
    106 
    107 	ucp = &pcb->pcb_userret_ucp;
    108 	reg = (register_t *) &ucp->uc_mcontext.__gregs;
    109 #if 0
    110 	thunk_printf("%s: ", __func__);
    111 	thunk_printf("flags %d, ", (int) ksi->ksi_flags);
    112 	thunk_printf("to lwp %d, signo %d, code %d, errno %d\n",
    113 		(int) ksi->ksi_lid,
    114 		ksi->ksi_signo,
    115 		ksi->ksi_code,
    116 		ksi->ksi_errno);
    117 #endif
    118 
    119 	/* do we need to jump onto the signal stack? */
    120 	onstack = (l->l_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0
    121 	    && (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0;
    122 
    123 	sp = ((char *) reg[24] - 128);/* why -128?*//* RSP */
    124 	if (onstack)
    125 		sp = (char *) l->l_sigstk.ss_sp + l->l_sigstk.ss_size;
    126 
    127 	sp -= sizeof(struct sigframe_siginfo);
    128 	/*
    129 	 * Round down the stackpointer to a multiple of 16 for
    130 	 * fxsave and the ABI
    131 	 */
    132 	fp = (struct sigframe_siginfo *) (((unsigned long)sp & ~15) - 8);
    133 
    134 	/* set up stack frame */
    135 	memset(&frame, 0, sizeof(frame));
    136 	frame.sf_ra = (uint64_t) ps->sa_sigdesc[sig].sd_tramp;
    137 	frame.sf_si._info = ksi->ksi_info;
    138 
    139 	/* copy our userret context into sf_uc */
    140 	memcpy(&frame.sf_uc, ucp, sizeof(ucontext_t));
    141 	frame.sf_uc.uc_sigmask = *mask;
    142 	frame.sf_uc.uc_link = l->l_ctxlink;
    143 	frame.sf_uc.uc_flags |= (l->l_sigstk.ss_flags & SS_ONSTACK)
    144 	    ? _UC_SETSTACK : _UC_CLRSTACK;
    145 	memset(&frame.sf_uc.uc_stack, 0, sizeof(frame.sf_uc.uc_stack));
    146 	sendsig_reset(l, sig);
    147 
    148 	/* copyout our frame to the stackframe */
    149 	mutex_exit(p->p_lock);
    150 	error = copyout(&frame, fp, sizeof(frame));
    151 	mutex_enter(p->p_lock);
    152 
    153 	if (error != 0) {
    154 		/*
    155 		 * Process has trashed its stack; give it an illegal
    156 		 * instruction to halt it in its tracks.
    157 		 */
    158 		sigexit(l, SIGILL);
    159 		/* NOTREACHED */
    160 	}
    161 
    162 	/* set catcher and the new stack pointer */
    163 	reg[24] = (register_t) fp;		/* RSP */
    164 	reg[21] = (register_t) catcher;		/* RIP */
    165 
    166 	reg[ 0] = sig;				/* RDI */
    167 	reg[ 1] = (uint64_t) &fp->sf_si;	/* RSI */
    168 	reg[ 2] = (uint64_t) &fp->sf_uc;	/* RDX */
    169 	reg[11] = reg[ 2];			/* R15 = RDX */
    170 
    171 	/* Remember that we're now on the signal stack. */
    172 	if (onstack)
    173 		l->l_sigstk.ss_flags |= SS_ONSTACK;
    174 }
    175 
    176 void
    177 setregs(struct lwp *l, struct exec_package *pack, vaddr_t stack)
    178 {
    179 	struct pcb *pcb = lwp_getpcb(l);
    180 	ucontext_t *ucp;
    181 	register_t *reg;
    182 	int i;
    183 
    184 	/* set up the user context */
    185 	ucp = &pcb->pcb_userret_ucp;
    186 	reg = (register_t *) &ucp->uc_mcontext.__gregs;
    187 	for (i = 0; i < 15; i++)
    188 		reg[i] = 0;
    189 
    190 	reg[13] = l->l_proc->p_psstrp;		/* RBX */
    191 	reg[21] = pack->ep_entry;		/* RIP */
    192 	reg[24] = (register_t) stack;		/* RSP */
    193 
    194 	/* use given stack */
    195 	ucp->uc_stack.ss_sp   = (void *) stack;
    196 	ucp->uc_stack.ss_size = pack->ep_ssize;
    197 
    198 	//dump_regs(reg);
    199 }
    200 
    201 void
    202 md_syscall_get_syscallnumber(ucontext_t *ucp, uint32_t *code)
    203 {
    204 	register_t *reg = (register_t *) &ucp->uc_mcontext.__gregs;
    205 	*code = reg[14];			/* RAX */
    206 }
    207 
    208 int
    209 md_syscall_getargs(lwp_t *l, ucontext_t *ucp, int nargs, int argsize,
    210 	register_t *args)
    211 {
    212 	register_t *reg = (register_t *) &ucp->uc_mcontext.__gregs;
    213 	register_t *sp = (register_t *) reg[24];/* RSP */
    214 	int ret;
    215 
    216 	//dump_regs(reg);
    217 
    218 	/*
    219 	 * 1st 6 syscall args are passed in
    220 	 *    rdi, rsi, rdx, r10, r8 and r9
    221 	 */
    222 	args[0] = reg[ 0];		/* RDI */
    223 	args[1] = reg[ 1];		/* RSI */
    224 	args[2] = reg[ 2];		/* RDX */
    225 	args[3] = reg[ 6];		/* R10 (RCX got clobbered) */
    226 	args[4] = reg[ 4];		/* R8  */
    227 	args[5] = reg[ 5];		/* R9  */
    228 
    229 	ret = 0;
    230 	if (argsize > 6 * 8) {
    231 		ret = copyin(sp + 1,
    232 			args + 6, argsize - 6 * 8);
    233 	}
    234 
    235 	return ret;
    236 }
    237 
    238 void
    239 md_syscall_set_returnargs(lwp_t *l, ucontext_t *ucp,
    240 	int error, register_t *rval)
    241 {
    242 	register_t *reg = (register_t *) &ucp->uc_mcontext.__gregs;
    243 
    244 	reg[23] &= ~PSL_C;		/* RFLAGS */
    245 	if (error > 0) {
    246 		rval[0] = error;
    247 		reg[23] |= PSL_C;	/* RFLAGS */
    248 	}
    249 
    250 	/* set return parameters */
    251 	reg[14]	= rval[0];		/* RAX */
    252 	if (error == 0)
    253 		reg[ 2] = rval[1];	/* RDX */
    254 
    255 	//dump_regs(reg);
    256 }
    257 
    258 register_t
    259 md_get_pc(ucontext_t *ucp)
    260 {
    261 	register_t *reg = (register_t *) &ucp->uc_mcontext.__gregs;
    262 
    263 	return reg[21];			/* RIP */
    264 }
    265 
    266 register_t
    267 md_get_sp(ucontext_t *ucp)
    268 {
    269 	register_t *reg = (register_t *) &ucp->uc_mcontext.__gregs;
    270 
    271 	return reg[24];			/* RSP */
    272 }
    273 
    274 int
    275 md_syscall_check_opcode(ucontext_t *ucp)
    276 {
    277 	uint32_t opcode;
    278 
    279 	md_syscall_get_opcode(ucp, &opcode);
    280 
    281 	switch (opcode) {
    282 	case 0xff0f:	/* UD1      */
    283 	case 0xff0b:	/* UD2      */
    284 	case 0x80cd:	/* int $80  */
    285 	case 0x340f:	/* sysenter */
    286 	case 0x050f:	/* syscall */
    287 		return 1;
    288 	default:
    289 		return 0;
    290 	}
    291 }
    292 
    293 
    294 void
    295 md_syscall_get_opcode(ucontext_t *ucp, uint32_t *opcode)
    296 {
    297 	register_t *reg = (register_t *) &ucp->uc_mcontext.__gregs;
    298 //	uint8_t  *p8  = (uint8_t *) (reg[21]);
    299 	uint16_t *p16 = (uint16_t*) (reg[21]);	/* RIP */
    300 
    301 	switch (*p16) {
    302 	case 0xff0f:	/* UD1      */
    303 	case 0xff0b:	/* UD2      */
    304 	case 0x80cd:	/* int $80  */
    305 	case 0x340f:	/* sysenter */
    306 	case 0x050f:	/* syscall */
    307 		*opcode = *p16;
    308 		break;
    309 	default:
    310 		*opcode = 0;
    311 	}
    312 }
    313 
    314 void
    315 md_syscall_inc_pc(ucontext_t *ucp, uint32_t opcode)
    316 {
    317 	register_t *reg = (register_t *) &ucp->uc_mcontext.__gregs;
    318 
    319 	/* advance program counter */
    320 	switch (opcode) {
    321 	case 0xff0f:	/* UD1      */
    322 	case 0xff0b:	/* UD2      */
    323 	case 0x80cd:	/* int $80  */
    324 	case 0x340f:	/* sysenter */
    325 	case 0x050f:	/* syscall */
    326 		reg[21] += 2;	/* RIP */
    327 		break;
    328 	default:
    329 		panic("%s, unknown illegal instruction: opcode = %x\n",
    330 			__func__, (uint32_t) opcode);
    331 	}
    332 }
    333 
    334 void
    335 md_syscall_dec_pc(ucontext_t *ucp, uint32_t opcode)
    336 {
    337 	register_t *reg = (register_t *) &ucp->uc_mcontext.__gregs;
    338 
    339 	switch (opcode) {
    340 	case 0xff0f:	/* UD1      */
    341 	case 0xff0b:	/* UD2      */
    342 	case 0x80cd:	/* int $80  */
    343 	case 0x340f:	/* sysenter */
    344 	case 0x050f:	/* syscall */
    345 		reg[21] -= 2;	/* RIP */
    346 		break;
    347 	default:
    348 		panic("%s, unknown illegal instruction: opcode = %x\n",
    349 			__func__, (uint32_t) opcode);
    350 	}
    351 }
    352 
    353