Home | History | Annotate | Line # | Download | only in amd64
      1 /*	$NetBSD: process_machdep.c,v 1.50 2023/11/20 03:05:48 simonb Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1998, 2000 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  * This file may seem a bit stylized, but that so that it's easier to port.
     34  * Functions to be implemented here are:
     35  *
     36  * process_read_regs(proc, regs)
     37  *	Get the current user-visible register set from the process
     38  *	and copy it into the regs structure (<machine/reg.h>).
     39  *	The process is stopped at the time read_regs is called.
     40  *
     41  * process_write_regs(proc, regs)
     42  *	Update the current register set from the passed in regs
     43  *	structure.  Take care to avoid clobbering special CPU
     44  *	registers or privileged bits in the PSL.
     45  *	The process is stopped at the time write_regs is called.
     46  *
     47  * process_read_fpregs(proc, regs, sz)
     48  *	Get the current user-visible register set from the process
     49  *	and copy it into the regs structure (<machine/reg.h>).
     50  *	The process is stopped at the time read_fpregs is called.
     51  *
     52  * process_write_fpregs(proc, regs, sz)
     53  *	Update the current register set from the passed in regs
     54  *	structure.  Take care to avoid clobbering special CPU
     55  *	registers or privileged bits in the PSL.
     56  *	The process is stopped at the time write_fpregs is called.
     57  *
     58  * process_read_dbregs(proc, regs, sz)
     59  *	Get the current user-visible register set from the process
     60  *	and copy it into the regs structure (<machine/reg.h>).
     61  *	The process is stopped at the time read_dbregs is called.
     62  *
     63  * process_write_dbregs(proc, regs, sz)
     64  *	Update the current register set from the passed in regs
     65  *	structure.  Take care to avoid clobbering special CPU
     66  *	registers or privileged bits in the PSL.
     67  *	The process is stopped at the time write_dbregs is called.
     68  *
     69  * process_sstep(proc)
     70  *	Arrange for the process to trap after executing a single instruction.
     71  *
     72  * process_set_pc(proc)
     73  *	Set the process's program counter.
     74  */
     75 
     76 #include <sys/cdefs.h>
     77 __KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.50 2023/11/20 03:05:48 simonb Exp $");
     78 
     79 #ifdef _KERNEL_OPT
     80 #include "opt_xen.h"
     81 #endif
     82 
     83 #include <sys/param.h>
     84 #include <sys/systm.h>
     85 #include <sys/time.h>
     86 #include <sys/kernel.h>
     87 #include <sys/proc.h>
     88 #include <sys/ptrace.h>
     89 #include <sys/compat_stub.h>
     90 
     91 #include <uvm/uvm_extern.h>
     92 
     93 #include <compat/netbsd32/netbsd32.h>
     94 #include <machine/psl.h>
     95 #include <machine/reg.h>
     96 #include <machine/segments.h>
     97 #include <x86/dbregs.h>
     98 #include <x86/fpu.h>
     99 
    100 struct netbsd32_process_doxmmregs_hook_t netbsd32_process_doxmmregs_hook;
    101 
    102 static inline struct trapframe *process_frame(struct lwp *);
    103 
    104 static inline struct trapframe *
    105 process_frame(struct lwp *l)
    106 {
    107 
    108 	return l->l_md.md_regs;
    109 }
    110 
    111 int
    112 process_read_regs(struct lwp *l, struct reg *regp)
    113 {
    114 	struct trapframe *tf = process_frame(l);
    115 	long *regs = regp->regs;
    116 	const bool pk32 = (l->l_proc->p_flag & PK_32) != 0;
    117 
    118 	regs[_REG_RDI] = tf->tf_rdi;
    119 	regs[_REG_RSI] = tf->tf_rsi;
    120 	regs[_REG_RDX] = tf->tf_rdx;
    121 	regs[_REG_R10] = tf->tf_r10;
    122 	regs[_REG_R8]  = tf->tf_r8;
    123 	regs[_REG_R9]  = tf->tf_r9;
    124 	/* argX not touched */
    125 	regs[_REG_RCX] = tf->tf_rcx;
    126 	regs[_REG_R11] = tf->tf_r11;
    127 	regs[_REG_R12] = tf->tf_r12;
    128 	regs[_REG_R13] = tf->tf_r13;
    129 	regs[_REG_R14] = tf->tf_r14;
    130 	regs[_REG_R15] = tf->tf_r15;
    131 	regs[_REG_RBP] = tf->tf_rbp;
    132 	regs[_REG_RBX] = tf->tf_rbx;
    133 	regs[_REG_RAX] = tf->tf_rax;
    134 	if (pk32) {
    135 		regs[_REG_GS] = tf->tf_gs & 0xffff;
    136 		regs[_REG_FS] = tf->tf_fs & 0xffff;
    137 		regs[_REG_ES] = tf->tf_es & 0xffff;
    138 		regs[_REG_DS] = tf->tf_ds & 0xffff;
    139 		regs[_REG_CS] = tf->tf_cs & 0xffff;
    140 		regs[_REG_SS] = tf->tf_ss & 0xffff;
    141 	} else {
    142 		regs[_REG_GS] = 0;
    143 		regs[_REG_FS] = 0;
    144 		regs[_REG_ES] = GSEL(GUDATA_SEL, SEL_UPL);
    145 		regs[_REG_DS] = GSEL(GUDATA_SEL, SEL_UPL);
    146 		regs[_REG_CS] = LSEL(LUCODE_SEL, SEL_UPL);
    147 		regs[_REG_SS] = LSEL(LUDATA_SEL, SEL_UPL);
    148 	}
    149 	regs[_REG_TRAPNO] = tf->tf_trapno;
    150 	regs[_REG_ERR] = tf->tf_err;
    151 	regs[_REG_RIP] = tf->tf_rip;
    152 	regs[_REG_RFLAGS] = tf->tf_rflags;
    153 	regs[_REG_RSP] = tf->tf_rsp;
    154 
    155 	return 0;
    156 }
    157 
    158 int
    159 process_read_fpregs(struct lwp *l, struct fpreg *regs, size_t *sz)
    160 {
    161 
    162 	process_read_fpregs_xmm(l, &regs->fxstate);
    163 
    164 	return 0;
    165 }
    166 
    167 int
    168 process_read_dbregs(struct lwp *l, struct dbreg *regs, size_t *sz)
    169 {
    170 
    171 	x86_dbregs_read(l, regs);
    172 
    173 	return 0;
    174 }
    175 
    176 int
    177 process_write_regs(struct lwp *l, const struct reg *regp)
    178 {
    179 	struct trapframe *tf = process_frame(l);
    180 	int error;
    181 	const long *regs = regp->regs;
    182 	const bool pk32 = (l->l_proc->p_flag & PK_32) != 0;
    183 
    184 	/*
    185 	 * Check for security violations. Note that struct regs is compatible
    186 	 * with the __gregs array in mcontext_t.
    187 	 */
    188 	if (pk32) {
    189 		MODULE_HOOK_CALL(netbsd32_reg_validate_hook, (l, regp), EINVAL,
    190 		    error);
    191 	} else {
    192 		error = cpu_mcontext_validate(l, (const mcontext_t *)regs);
    193 	}
    194 	if (error != 0)
    195 		return error;
    196 
    197 	tf->tf_rdi  = regs[_REG_RDI];
    198 	tf->tf_rsi  = regs[_REG_RSI];
    199 	tf->tf_rdx  = regs[_REG_RDX];
    200 	tf->tf_r10  = regs[_REG_R10];
    201 	tf->tf_r8   = regs[_REG_R8];
    202 	tf->tf_r9   = regs[_REG_R9];
    203 	/* argX not touched */
    204 	tf->tf_rcx  = regs[_REG_RCX];
    205 	tf->tf_r11  = regs[_REG_R11];
    206 	tf->tf_r12  = regs[_REG_R12];
    207 	tf->tf_r13  = regs[_REG_R13];
    208 	tf->tf_r14  = regs[_REG_R14];
    209 	tf->tf_r15  = regs[_REG_R15];
    210 	tf->tf_rbp  = regs[_REG_RBP];
    211 	tf->tf_rbx  = regs[_REG_RBX];
    212 	tf->tf_rax  = regs[_REG_RAX];
    213 	if (pk32) {
    214 		tf->tf_gs = regs[_REG_GS] & 0xffff;
    215 		tf->tf_fs = regs[_REG_FS] & 0xffff;
    216 		tf->tf_es = regs[_REG_ES] & 0xffff;
    217 		tf->tf_ds = regs[_REG_DS] & 0xffff;
    218 		tf->tf_cs = regs[_REG_CS] & 0xffff;
    219 		tf->tf_ss = regs[_REG_SS] & 0xffff;
    220 	} else {
    221 		tf->tf_gs = 0;
    222 		tf->tf_fs = 0;
    223 		tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL);
    224 		tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL);
    225 		tf->tf_cs = LSEL(LUCODE_SEL, SEL_UPL);
    226 		tf->tf_ss = LSEL(LUDATA_SEL, SEL_UPL);
    227 	}
    228 	/* trapno, err not touched */
    229 	tf->tf_rip  = regs[_REG_RIP];
    230 	tf->tf_rflags = regs[_REG_RFLAGS];
    231 	tf->tf_rsp  = regs[_REG_RSP];
    232 
    233 	return 0;
    234 }
    235 
    236 int
    237 process_write_fpregs(struct lwp *l, const struct fpreg *regs, size_t sz)
    238 {
    239 
    240 	process_write_fpregs_xmm(l, &regs->fxstate);
    241 	return 0;
    242 }
    243 
    244 int
    245 process_write_dbregs(struct lwp *l, const struct dbreg *regs, size_t sz)
    246 {
    247 	int error;
    248 
    249 	/*
    250 	 * Check for security violations.
    251 	 */
    252 	error = x86_dbregs_validate(regs);
    253 	if (error != 0)
    254 		return error;
    255 
    256 	x86_dbregs_write(l, regs);
    257 
    258 	return 0;
    259 }
    260 
    261 int
    262 process_sstep(struct lwp *l, int sstep)
    263 {
    264 	struct trapframe *tf = process_frame(l);
    265 
    266 	if (sstep)
    267 		tf->tf_rflags |= PSL_T;
    268 	else
    269 		tf->tf_rflags &= ~PSL_T;
    270 
    271 	return 0;
    272 }
    273 
    274 int
    275 process_set_pc(struct lwp *l, void *addr)
    276 {
    277 	struct trapframe *tf = process_frame(l);
    278 	const bool pk32 = (l->l_proc->p_flag & PK_32) != 0;
    279 	const uint64_t rip = (uint64_t)addr;
    280 
    281 	if (rip >= (pk32 ? VM_MAXUSER_ADDRESS32 : VM_MAXUSER_ADDRESS))
    282 		return EINVAL;
    283 	tf->tf_rip = rip;
    284 
    285 	return 0;
    286 }
    287 
    288 #ifdef __HAVE_PTRACE_MACHDEP
    289 static int
    290 process_machdep_read_xstate(struct lwp *l, struct xstate *regs)
    291 {
    292 	return process_read_xstate(l, regs);
    293 }
    294 
    295 static int
    296 process_machdep_write_xstate(struct lwp *l, const struct xstate *regs)
    297 {
    298 	int error;
    299 
    300 	/*
    301 	 * Check for security violations.
    302 	 */
    303 	error = process_verify_xstate(regs);
    304 	if (error != 0)
    305 		return error;
    306 
    307 	return process_write_xstate(l, regs);
    308 }
    309 
    310 int
    311 ptrace_machdep_dorequest(
    312     struct lwp *l,
    313     struct lwp **lt,
    314     int req,
    315     void *addr,
    316     int data
    317 )
    318 {
    319 	struct uio uio;
    320 	struct iovec iov;
    321 	struct vmspace *vm;
    322 	int error;
    323 	bool write = false;
    324 
    325 	switch (req) {
    326 	case PT_SETXSTATE:
    327 		write = true;
    328 
    329 		/* FALLTHROUGH */
    330 	case PT_GETXSTATE:
    331 		/* write = false done above. */
    332 		if ((error = ptrace_update_lwp((*lt)->l_proc, lt, data)) != 0)
    333 			return error;
    334 		if (!process_machdep_validfpu((*lt)->l_proc))
    335 			return EINVAL;
    336 		if (__predict_false(l->l_proc->p_flag & PK_32)) {
    337 			struct netbsd32_iovec user_iov;
    338 			if ((error = copyin(addr, &user_iov, sizeof(user_iov)))
    339 			    != 0)
    340 				return error;
    341 
    342 			iov.iov_base = NETBSD32PTR64(user_iov.iov_base);
    343 			iov.iov_len = user_iov.iov_len;
    344 		} else {
    345 			struct iovec user_iov;
    346 			if ((error = copyin(addr, &user_iov, sizeof(user_iov)))
    347 			    != 0)
    348 				return error;
    349 
    350 			iov.iov_base = user_iov.iov_base;
    351 			iov.iov_len = user_iov.iov_len;
    352 		}
    353 
    354 		error = proc_vmspace_getref(l->l_proc, &vm);
    355 		if (error)
    356 			return error;
    357 		if (iov.iov_len > sizeof(struct xstate))
    358 			iov.iov_len = sizeof(struct xstate);
    359 		uio.uio_iov = &iov;
    360 		uio.uio_iovcnt = 1;
    361 		uio.uio_offset = 0;
    362 		uio.uio_resid = iov.iov_len;
    363 		uio.uio_rw = write ? UIO_WRITE : UIO_READ;
    364 		uio.uio_vmspace = vm;
    365 		error = process_machdep_doxstate(l, *lt, &uio);
    366 		uvmspace_free(vm);
    367 		return error;
    368 
    369 	case PT_SETXMMREGS:		/* only for COMPAT_NETBSD32 */
    370 		write = true;
    371 
    372 		/* FALLTHROUGH */
    373 	case PT_GETXMMREGS:		/* only for COMPAT_NETBSD32 */
    374 		/* write = false done above. */
    375 		if ((error = ptrace_update_lwp((*lt)->l_proc, lt, data)) != 0)
    376 			return error;
    377 		MODULE_HOOK_CALL(netbsd32_process_doxmmregs_hook,
    378 		    (l, *lt, addr, write), EINVAL, error);
    379 		return error;
    380 	}
    381 
    382 #ifdef DIAGNOSTIC
    383 	panic("ptrace_machdep: impossible");
    384 #endif
    385 
    386 	return 0;
    387 }
    388 
    389 /*
    390  * The following functions are used by both ptrace(2) and procfs.
    391  */
    392 
    393 int
    394 process_machdep_doxstate(struct lwp *curl, struct lwp *l, struct uio *uio)
    395 	/* curl:		 tracer */
    396 	/* l:			 traced */
    397 {
    398 	int error;
    399 	struct xstate r;	/* XXX FIXME big stack object */
    400 	char *kv;
    401 	ssize_t kl;
    402 
    403 	memset(&r, 0, sizeof(r));
    404 	kl = MIN(uio->uio_iov->iov_len, sizeof(r));
    405 	kv = (char *) &r;
    406 
    407 	kv += uio->uio_offset;
    408 	kl -= uio->uio_offset;
    409 	if (kl > uio->uio_resid)
    410 		kl = uio->uio_resid;
    411 
    412 	if (kl < 0)
    413 		error = EINVAL;
    414 	else
    415 		error = process_machdep_read_xstate(l, &r);
    416 	if (error == 0)
    417 		error = uiomove(kv, kl, uio);
    418 	if (error == 0 && uio->uio_rw == UIO_WRITE)
    419 		error = process_machdep_write_xstate(l, &r);
    420 
    421 	uio->uio_offset = 0;
    422 	return error;
    423 }
    424 
    425 int
    426 process_machdep_validfpu(struct proc *p)
    427 {
    428 
    429 	if (p->p_flag & PK_SYSTEM)
    430 		return 0;
    431 
    432 	return 1;
    433 }
    434 #endif /* __HAVE_PTRACE_MACHDEP */
    435