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, ®s->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, ®s->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