1 /* $NetBSD: process_machdep.c,v 1.45 2002/10/01 12:56:59 fvdl Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 2000, 2001 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; by Jason R. Thorpe of Wasabi Systems, Inc. 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * This file may seem a bit stylized, but that so that it's easier to port. 41 * Functions to be implemented here are: 42 * 43 * process_read_regs(proc, regs) 44 * Get the current user-visible register set from the process 45 * and copy it into the regs structure (<machine/reg.h>). 46 * The process is stopped at the time read_regs is called. 47 * 48 * process_write_regs(proc, regs) 49 * Update the current register set from the passed in regs 50 * structure. Take care to avoid clobbering special CPU 51 * registers or privileged bits in the PSL. 52 * The process is stopped at the time write_regs is called. 53 * 54 * process_sstep(proc) 55 * Arrange for the process to trap after executing a single instruction. 56 * 57 * process_set_pc(proc) 58 * Set the process's program counter. 59 */ 60 61 #include <sys/cdefs.h> 62 __KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.45 2002/10/01 12:56:59 fvdl Exp $"); 63 64 #include "opt_vm86.h" 65 #include "npx.h" 66 67 #include <sys/param.h> 68 #include <sys/systm.h> 69 #include <sys/time.h> 70 #include <sys/kernel.h> 71 #include <sys/proc.h> 72 #include <sys/user.h> 73 #include <sys/vnode.h> 74 #include <sys/ptrace.h> 75 76 #include <uvm/uvm_extern.h> 77 78 #include <machine/psl.h> 79 #include <machine/reg.h> 80 #include <machine/segments.h> 81 82 #ifdef VM86 83 #include <machine/vm86.h> 84 #endif 85 86 static __inline struct trapframe * 87 process_frame(struct proc *p) 88 { 89 90 return (p->p_md.md_regs); 91 } 92 93 static __inline union savefpu * 94 process_fpframe(struct proc *p) 95 { 96 97 return (&p->p_addr->u_pcb.pcb_savefpu); 98 } 99 100 static int 101 xmm_to_s87_tag(const uint8_t *fpac, int regno, uint8_t tw) 102 { 103 static const uint8_t empty_significand[8] = { 0 }; 104 int tag; 105 uint16_t exponent; 106 107 if (tw & (1U << regno)) { 108 exponent = fpac[8] | (fpac[9] << 8); 109 switch (exponent) { 110 case 0x7fff: 111 tag = 2; 112 break; 113 114 case 0x0000: 115 if (memcmp(empty_significand, fpac, 116 sizeof(empty_significand)) == 0) 117 tag = 1; 118 else 119 tag = 2; 120 break; 121 122 default: 123 if ((fpac[7] & 0x80) == 0) 124 tag = 2; 125 else 126 tag = 0; 127 break; 128 } 129 } else 130 tag = 3; 131 132 return (tag); 133 } 134 135 void 136 process_xmm_to_s87(const struct savexmm *sxmm, struct save87 *s87) 137 { 138 int i; 139 140 /* FPU control/status */ 141 s87->sv_env.en_cw = sxmm->sv_env.en_cw; 142 s87->sv_env.en_sw = sxmm->sv_env.en_sw; 143 /* tag word handled below */ 144 s87->sv_env.en_fip = sxmm->sv_env.en_fip; 145 s87->sv_env.en_fcs = sxmm->sv_env.en_fcs; 146 s87->sv_env.en_opcode = sxmm->sv_env.en_opcode; 147 s87->sv_env.en_foo = sxmm->sv_env.en_foo; 148 s87->sv_env.en_fos = sxmm->sv_env.en_fos; 149 150 /* Tag word and registers. */ 151 s87->sv_env.en_tw = 0; 152 s87->sv_ex_tw = 0; 153 for (i = 0; i < 8; i++) { 154 s87->sv_env.en_tw |= 155 (xmm_to_s87_tag(sxmm->sv_ac[i].fp_bytes, i, 156 sxmm->sv_env.en_tw) << (i * 2)); 157 158 s87->sv_ex_tw |= 159 (xmm_to_s87_tag(sxmm->sv_ac[i].fp_bytes, i, 160 sxmm->sv_ex_tw) << (i * 2)); 161 162 memcpy(&s87->sv_ac[i].fp_bytes, &sxmm->sv_ac[i].fp_bytes, 163 sizeof(s87->sv_ac[i].fp_bytes)); 164 } 165 166 s87->sv_ex_sw = sxmm->sv_ex_sw; 167 } 168 169 void 170 process_s87_to_xmm(const struct save87 *s87, struct savexmm *sxmm) 171 { 172 int i; 173 174 /* FPU control/status */ 175 sxmm->sv_env.en_cw = s87->sv_env.en_cw; 176 sxmm->sv_env.en_sw = s87->sv_env.en_sw; 177 /* tag word handled below */ 178 sxmm->sv_env.en_fip = s87->sv_env.en_fip; 179 sxmm->sv_env.en_fcs = s87->sv_env.en_fcs; 180 sxmm->sv_env.en_opcode = s87->sv_env.en_opcode; 181 sxmm->sv_env.en_foo = s87->sv_env.en_foo; 182 sxmm->sv_env.en_fos = s87->sv_env.en_fos; 183 184 /* Tag word and registers. */ 185 for (i = 0; i < 8; i++) { 186 if (((s87->sv_env.en_tw >> (i * 2)) & 3) == 3) 187 sxmm->sv_env.en_tw &= ~(1U << i); 188 else 189 sxmm->sv_env.en_tw |= (1U << i); 190 191 #if 0 192 /* 193 * Software-only word not provided by the userland fpreg 194 * structure. 195 */ 196 if (((s87->sv_ex_tw >> (i * 2)) & 3) == 3) 197 sxmm->sv_ex_tw &= ~(1U << i); 198 else 199 sxmm->sv_ex_tw |= (1U << i); 200 #endif 201 202 memcpy(&sxmm->sv_ac[i].fp_bytes, &s87->sv_ac[i].fp_bytes, 203 sizeof(sxmm->sv_ac[i].fp_bytes)); 204 } 205 #if 0 206 /* 207 * Software-only word not provided by the userland fpreg 208 * structure. 209 */ 210 sxmm->sv_ex_sw = s87->sv_ex_sw; 211 #endif 212 } 213 214 int 215 process_read_regs(p, regs) 216 struct proc *p; 217 struct reg *regs; 218 { 219 struct trapframe *tf = process_frame(p); 220 221 #ifdef VM86 222 if (tf->tf_eflags & PSL_VM) { 223 regs->r_gs = tf->tf_vm86_gs; 224 regs->r_fs = tf->tf_vm86_fs; 225 regs->r_es = tf->tf_vm86_es; 226 regs->r_ds = tf->tf_vm86_ds; 227 regs->r_eflags = get_vflags(p); 228 } else 229 #endif 230 { 231 regs->r_gs = tf->tf_gs & 0xffff; 232 regs->r_fs = tf->tf_fs & 0xffff; 233 regs->r_es = tf->tf_es & 0xffff; 234 regs->r_ds = tf->tf_ds & 0xffff; 235 regs->r_eflags = tf->tf_eflags; 236 } 237 regs->r_edi = tf->tf_edi; 238 regs->r_esi = tf->tf_esi; 239 regs->r_ebp = tf->tf_ebp; 240 regs->r_ebx = tf->tf_ebx; 241 regs->r_edx = tf->tf_edx; 242 regs->r_ecx = tf->tf_ecx; 243 regs->r_eax = tf->tf_eax; 244 regs->r_eip = tf->tf_eip; 245 regs->r_cs = tf->tf_cs & 0xffff; 246 regs->r_esp = tf->tf_esp; 247 regs->r_ss = tf->tf_ss & 0xffff; 248 249 return (0); 250 } 251 252 int 253 process_read_fpregs(p, regs) 254 struct proc *p; 255 struct fpreg *regs; 256 { 257 union savefpu *frame = process_fpframe(p); 258 259 if (p->p_md.md_flags & MDP_USEDFPU) { 260 #if NNPX > 0 261 npxsave_proc(p, 1); 262 #endif 263 } else { 264 /* 265 * Fake a FNINIT. 266 * The initial control word was already set by setregs(), so 267 * save it temporarily. 268 */ 269 if (i386_use_fxsave) { 270 uint32_t mxcsr = frame->sv_xmm.sv_env.en_mxcsr; 271 uint16_t cw = frame->sv_xmm.sv_env.en_cw; 272 273 /* XXX Don't zero XMM regs? */ 274 memset(&frame->sv_xmm, 0, sizeof(frame->sv_xmm)); 275 frame->sv_xmm.sv_env.en_cw = cw; 276 frame->sv_xmm.sv_env.en_mxcsr = mxcsr; 277 frame->sv_xmm.sv_env.en_sw = 0x0000; 278 frame->sv_xmm.sv_env.en_tw = 0x00; 279 } else { 280 uint16_t cw = frame->sv_87.sv_env.en_cw; 281 282 memset(&frame->sv_87, 0, sizeof(frame->sv_87)); 283 frame->sv_87.sv_env.en_cw = cw; 284 frame->sv_87.sv_env.en_sw = 0x0000; 285 frame->sv_87.sv_env.en_tw = 0xffff; 286 } 287 p->p_md.md_flags |= MDP_USEDFPU; 288 } 289 290 if (i386_use_fxsave) { 291 struct save87 s87; 292 293 /* XXX Yuck */ 294 process_xmm_to_s87(&frame->sv_xmm, &s87); 295 memcpy(regs, &s87, sizeof(*regs)); 296 } else 297 memcpy(regs, &frame->sv_87, sizeof(*regs)); 298 return (0); 299 } 300 301 int 302 process_write_regs(p, regs) 303 struct proc *p; 304 struct reg *regs; 305 { 306 struct trapframe *tf = process_frame(p); 307 308 #ifdef VM86 309 if (regs->r_eflags & PSL_VM) { 310 void syscall_vm86 __P((struct trapframe)); 311 312 tf->tf_vm86_gs = regs->r_gs; 313 tf->tf_vm86_fs = regs->r_fs; 314 tf->tf_vm86_es = regs->r_es; 315 tf->tf_vm86_ds = regs->r_ds; 316 set_vflags(p, regs->r_eflags); 317 /* 318 * Make sure that attempts at system calls from vm86 319 * mode die horribly. 320 */ 321 p->p_md.md_syscall = syscall_vm86; 322 } else 323 #endif 324 { 325 /* 326 * Check for security violations. 327 */ 328 if (((regs->r_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 || 329 !USERMODE(regs->r_cs, regs->r_eflags)) 330 return (EINVAL); 331 332 tf->tf_gs = regs->r_gs; 333 tf->tf_fs = regs->r_fs; 334 tf->tf_es = regs->r_es; 335 tf->tf_ds = regs->r_ds; 336 #ifdef VM86 337 /* Restore normal syscall handler */ 338 if (tf->tf_eflags & PSL_VM) 339 (*p->p_emul->e_syscall_intern)(p); 340 #endif 341 tf->tf_eflags = regs->r_eflags; 342 } 343 tf->tf_edi = regs->r_edi; 344 tf->tf_esi = regs->r_esi; 345 tf->tf_ebp = regs->r_ebp; 346 tf->tf_ebx = regs->r_ebx; 347 tf->tf_edx = regs->r_edx; 348 tf->tf_ecx = regs->r_ecx; 349 tf->tf_eax = regs->r_eax; 350 tf->tf_eip = regs->r_eip; 351 tf->tf_cs = regs->r_cs; 352 tf->tf_esp = regs->r_esp; 353 tf->tf_ss = regs->r_ss; 354 355 return (0); 356 } 357 358 int 359 process_write_fpregs(p, regs) 360 struct proc *p; 361 struct fpreg *regs; 362 { 363 union savefpu *frame = process_fpframe(p); 364 365 if (p->p_md.md_flags & MDP_USEDFPU) { 366 #if NNPX > 0 367 npxsave_proc(p, 0); 368 #endif 369 } else { 370 p->p_md.md_flags |= MDP_USEDFPU; 371 } 372 373 if (i386_use_fxsave) { 374 struct save87 s87; 375 376 /* XXX Yuck. */ 377 memcpy(&s87, regs, sizeof(*regs)); 378 process_s87_to_xmm(&s87, &frame->sv_xmm); 379 } else 380 memcpy(&frame->sv_87, regs, sizeof(*regs)); 381 return (0); 382 } 383 384 int 385 process_sstep(p, sstep) 386 struct proc *p; 387 { 388 struct trapframe *tf = process_frame(p); 389 390 if (sstep) 391 tf->tf_eflags |= PSL_T; 392 else 393 tf->tf_eflags &= ~PSL_T; 394 395 return (0); 396 } 397 398 int 399 process_set_pc(p, addr) 400 struct proc *p; 401 caddr_t addr; 402 { 403 struct trapframe *tf = process_frame(p); 404 405 tf->tf_eip = (int)addr; 406 407 return (0); 408 } 409 410 #ifdef __HAVE_PTRACE_MACHDEP 411 static int 412 process_machdep_read_xmmregs(struct proc *p, struct xmmregs *regs) 413 { 414 union savefpu *frame = process_fpframe(p); 415 416 if (i386_use_fxsave == 0) 417 return (EINVAL); 418 419 if (p->p_md.md_flags & MDP_USEDFPU) { 420 #if NNPX > 0 421 if (p->p_addr->u_pcb.pcb_fpcpu != NULL) 422 npxsave_proc(p, 1); 423 #endif 424 } else { 425 /* 426 * Fake a FNINIT. 427 * The initial control word was already set by setregs(), 428 * so save it temporarily. 429 */ 430 uint32_t mxcsr = frame->sv_xmm.sv_env.en_mxcsr; 431 uint16_t cw = frame->sv_xmm.sv_env.en_cw; 432 433 /* XXX Don't zero XMM regs? */ 434 memset(&frame->sv_xmm, 0, sizeof(frame->sv_xmm)); 435 frame->sv_xmm.sv_env.en_cw = cw; 436 frame->sv_xmm.sv_env.en_mxcsr = mxcsr; 437 frame->sv_xmm.sv_env.en_sw = 0x0000; 438 frame->sv_xmm.sv_env.en_tw = 0x00; 439 440 p->p_md.md_flags |= MDP_USEDFPU; 441 } 442 443 memcpy(regs, &frame->sv_xmm, sizeof(*regs)); 444 return (0); 445 } 446 447 static int 448 process_machdep_write_xmmregs(struct proc *p, struct xmmregs *regs) 449 { 450 union savefpu *frame = process_fpframe(p); 451 452 if (i386_use_fxsave == 0) 453 return (EINVAL); 454 455 if (p->p_md.md_flags & MDP_USEDFPU) { 456 #if NNPX > 0 457 /* If we were using the FPU, drop it. */ 458 if (p->p_addr->u_pcb.pcb_fpcpu != NULL) 459 npxsave_proc(p, 0); 460 #endif 461 } else { 462 p->p_md.md_flags |= MDP_USEDFPU; 463 } 464 465 memcpy(&frame->sv_xmm, regs, sizeof(*regs)); 466 return (0); 467 } 468 469 int 470 ptrace_machdep_dorequest(p, t, req, addr, data) 471 struct proc *p, *t; 472 int req; 473 caddr_t addr; 474 int data; 475 { 476 struct uio uio; 477 struct iovec iov; 478 int write = 0; 479 480 switch (req) { 481 case PT_SETXMMREGS: 482 write = 1; 483 484 case PT_GETXMMREGS: 485 /* write = 0 done above. */ 486 if (!process_machdep_validxmmregs(t)) 487 return (EINVAL); 488 else { 489 iov.iov_base = addr; 490 iov.iov_len = sizeof(struct xmmregs); 491 uio.uio_iov = &iov; 492 uio.uio_iovcnt = 1; 493 uio.uio_offset = 0; 494 uio.uio_resid = sizeof(struct xmmregs); 495 uio.uio_segflg = UIO_USERSPACE; 496 uio.uio_rw = write ? UIO_WRITE : UIO_READ; 497 uio.uio_procp = p; 498 return (process_machdep_doxmmregs(p, t, &uio)); 499 } 500 } 501 502 #ifdef DIAGNOSTIC 503 panic("ptrace_machdep: impossible"); 504 #endif 505 506 return (0); 507 } 508 509 /* 510 * The following functions are used by both ptrace(2) and procfs. 511 */ 512 513 int 514 process_machdep_doxmmregs(curp, p, uio) 515 struct proc *curp; /* tracer */ 516 struct proc *p; /* traced */ 517 struct uio *uio; 518 { 519 int error; 520 struct xmmregs r; 521 char *kv; 522 int kl; 523 524 if ((error = process_checkioperm(curp, p)) != 0) 525 return (error); 526 527 kl = sizeof(r); 528 kv = (char *) &r; 529 530 kv += uio->uio_offset; 531 kl -= uio->uio_offset; 532 if (kl > uio->uio_resid) 533 kl = uio->uio_resid; 534 535 PHOLD(p); 536 537 if (kl < 0) 538 error = EINVAL; 539 else 540 error = process_machdep_read_xmmregs(p, &r); 541 if (error == 0) 542 error = uiomove(kv, kl, uio); 543 if (error == 0 && uio->uio_rw == UIO_WRITE) { 544 if (p->p_stat != SSTOP) 545 error = EBUSY; 546 else 547 error = process_machdep_write_xmmregs(p, &r); 548 } 549 550 PRELE(p); 551 552 uio->uio_offset = 0; 553 return (error); 554 } 555 556 int 557 process_machdep_validxmmregs(p) 558 struct proc *p; 559 { 560 561 if (p->p_flag & P_SYSTEM) 562 return (0); 563 564 return (i386_use_fxsave); 565 } 566 #endif /* __HAVE_PTRACE_MACHDEP */ 567