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