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