1 /* $NetBSD: process_machdep.c,v 1.44 2002/05/10 05:45:50 thorpej 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.44 2002/05/10 05:45:50 thorpej 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 extern struct proc *npxproc; 262 263 if (npxproc == p) 264 npxsave(); 265 #endif 266 } else { 267 /* 268 * Fake a FNINIT. 269 * The initial control word was already set by setregs(), so 270 * save it temporarily. 271 */ 272 if (i386_use_fxsave) { 273 uint32_t mxcsr = frame->sv_xmm.sv_env.en_mxcsr; 274 uint16_t cw = frame->sv_xmm.sv_env.en_cw; 275 276 /* XXX Don't zero XMM regs? */ 277 memset(&frame->sv_xmm, 0, sizeof(frame->sv_xmm)); 278 frame->sv_xmm.sv_env.en_cw = cw; 279 frame->sv_xmm.sv_env.en_mxcsr = mxcsr; 280 frame->sv_xmm.sv_env.en_sw = 0x0000; 281 frame->sv_xmm.sv_env.en_tw = 0x00; 282 } else { 283 uint16_t cw = frame->sv_87.sv_env.en_cw; 284 285 memset(&frame->sv_87, 0, sizeof(frame->sv_87)); 286 frame->sv_87.sv_env.en_cw = cw; 287 frame->sv_87.sv_env.en_sw = 0x0000; 288 frame->sv_87.sv_env.en_tw = 0xffff; 289 } 290 p->p_md.md_flags |= MDP_USEDFPU; 291 } 292 293 if (i386_use_fxsave) { 294 struct save87 s87; 295 296 /* XXX Yuck */ 297 process_xmm_to_s87(&frame->sv_xmm, &s87); 298 memcpy(regs, &s87, sizeof(*regs)); 299 } else 300 memcpy(regs, &frame->sv_87, sizeof(*regs)); 301 return (0); 302 } 303 304 int 305 process_write_regs(p, regs) 306 struct proc *p; 307 struct reg *regs; 308 { 309 struct trapframe *tf = process_frame(p); 310 311 #ifdef VM86 312 if (regs->r_eflags & PSL_VM) { 313 void syscall_vm86 __P((struct trapframe)); 314 315 tf->tf_vm86_gs = regs->r_gs; 316 tf->tf_vm86_fs = regs->r_fs; 317 tf->tf_vm86_es = regs->r_es; 318 tf->tf_vm86_ds = regs->r_ds; 319 set_vflags(p, regs->r_eflags); 320 p->p_md.md_syscall = syscall_vm86; 321 } else 322 #endif 323 { 324 /* 325 * Check for security violations. 326 */ 327 if (((regs->r_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 || 328 !USERMODE(regs->r_cs, regs->r_eflags)) 329 return (EINVAL); 330 331 tf->tf_gs = regs->r_gs; 332 tf->tf_fs = regs->r_fs; 333 tf->tf_es = regs->r_es; 334 tf->tf_ds = regs->r_ds; 335 #ifdef VM86 336 if (tf->tf_eflags & PSL_VM) 337 (*p->p_emul->e_syscall_intern)(p); 338 #endif 339 tf->tf_eflags = regs->r_eflags; 340 } 341 tf->tf_edi = regs->r_edi; 342 tf->tf_esi = regs->r_esi; 343 tf->tf_ebp = regs->r_ebp; 344 tf->tf_ebx = regs->r_ebx; 345 tf->tf_edx = regs->r_edx; 346 tf->tf_ecx = regs->r_ecx; 347 tf->tf_eax = regs->r_eax; 348 tf->tf_eip = regs->r_eip; 349 tf->tf_cs = regs->r_cs; 350 tf->tf_esp = regs->r_esp; 351 tf->tf_ss = regs->r_ss; 352 353 return (0); 354 } 355 356 int 357 process_write_fpregs(p, regs) 358 struct proc *p; 359 struct fpreg *regs; 360 { 361 union savefpu *frame = process_fpframe(p); 362 363 if (p->p_md.md_flags & MDP_USEDFPU) { 364 #if NNPX > 0 365 extern struct proc *npxproc; 366 367 if (npxproc == p) 368 npxdrop(); 369 #endif 370 } else { 371 p->p_md.md_flags |= MDP_USEDFPU; 372 } 373 374 if (i386_use_fxsave) { 375 struct save87 s87; 376 377 /* XXX Yuck. */ 378 memcpy(&s87, regs, sizeof(*regs)); 379 process_s87_to_xmm(&s87, &frame->sv_xmm); 380 } else 381 memcpy(&frame->sv_87, regs, sizeof(*regs)); 382 return (0); 383 } 384 385 int 386 process_sstep(p, sstep) 387 struct proc *p; 388 { 389 struct trapframe *tf = process_frame(p); 390 391 if (sstep) 392 tf->tf_eflags |= PSL_T; 393 else 394 tf->tf_eflags &= ~PSL_T; 395 396 return (0); 397 } 398 399 int 400 process_set_pc(p, addr) 401 struct proc *p; 402 caddr_t addr; 403 { 404 struct trapframe *tf = process_frame(p); 405 406 tf->tf_eip = (int)addr; 407 408 return (0); 409 } 410 411 #ifdef __HAVE_PTRACE_MACHDEP 412 static int 413 process_machdep_read_xmmregs(struct proc *p, struct xmmregs *regs) 414 { 415 union savefpu *frame = process_fpframe(p); 416 417 if (i386_use_fxsave == 0) 418 return (EINVAL); 419 420 if (p->p_md.md_flags & MDP_USEDFPU) { 421 #if NNPX > 0 422 extern struct proc *npxproc; 423 424 if (npxproc == p) 425 npxsave(); 426 #endif 427 } else { 428 /* 429 * Fake a FNINIT. 430 * The initial control word was already set by setregs(), 431 * so save it temporarily. 432 */ 433 uint32_t mxcsr = frame->sv_xmm.sv_env.en_mxcsr; 434 uint16_t cw = frame->sv_xmm.sv_env.en_cw; 435 436 /* XXX Don't zero XMM regs? */ 437 memset(&frame->sv_xmm, 0, sizeof(frame->sv_xmm)); 438 frame->sv_xmm.sv_env.en_cw = cw; 439 frame->sv_xmm.sv_env.en_mxcsr = mxcsr; 440 frame->sv_xmm.sv_env.en_sw = 0x0000; 441 frame->sv_xmm.sv_env.en_tw = 0x00; 442 443 p->p_md.md_flags |= MDP_USEDFPU; 444 } 445 446 memcpy(regs, &frame->sv_xmm, sizeof(*regs)); 447 return (0); 448 } 449 450 static int 451 process_machdep_write_xmmregs(struct proc *p, struct xmmregs *regs) 452 { 453 union savefpu *frame = process_fpframe(p); 454 455 if (i386_use_fxsave == 0) 456 return (EINVAL); 457 458 if (p->p_md.md_flags & MDP_USEDFPU) { 459 #if NNPX > 0 460 extern struct proc *npxproc; 461 462 if (npxproc == p) 463 npxdrop(); 464 #endif 465 } else { 466 p->p_md.md_flags |= MDP_USEDFPU; 467 } 468 469 memcpy(&frame->sv_xmm, regs, sizeof(*regs)); 470 return (0); 471 } 472 473 int 474 ptrace_machdep_dorequest(p, t, req, addr, data) 475 struct proc *p, *t; 476 int req; 477 caddr_t addr; 478 int data; 479 { 480 struct uio uio; 481 struct iovec iov; 482 int write = 0; 483 484 switch (req) { 485 case PT_SETXMMREGS: 486 write = 1; 487 488 case PT_GETXMMREGS: 489 /* write = 0 done above. */ 490 if (!process_machdep_validxmmregs(t)) 491 return (EINVAL); 492 else { 493 iov.iov_base = addr; 494 iov.iov_len = sizeof(struct xmmregs); 495 uio.uio_iov = &iov; 496 uio.uio_iovcnt = 1; 497 uio.uio_offset = 0; 498 uio.uio_resid = sizeof(struct xmmregs); 499 uio.uio_segflg = UIO_USERSPACE; 500 uio.uio_rw = write ? UIO_WRITE : UIO_READ; 501 uio.uio_procp = p; 502 return (process_machdep_doxmmregs(p, t, &uio)); 503 } 504 } 505 506 #ifdef DIAGNOSTIC 507 panic("ptrace_machdep: impossible"); 508 #endif 509 510 return (0); 511 } 512 513 /* 514 * The following functions are used by both ptrace(2) and procfs. 515 */ 516 517 int 518 process_machdep_doxmmregs(curp, p, uio) 519 struct proc *curp; /* tracer */ 520 struct proc *p; /* traced */ 521 struct uio *uio; 522 { 523 int error; 524 struct xmmregs r; 525 char *kv; 526 int kl; 527 528 if ((error = process_checkioperm(curp, p)) != 0) 529 return (error); 530 531 kl = sizeof(r); 532 kv = (char *) &r; 533 534 kv += uio->uio_offset; 535 kl -= uio->uio_offset; 536 if (kl > uio->uio_resid) 537 kl = uio->uio_resid; 538 539 PHOLD(p); 540 541 if (kl < 0) 542 error = EINVAL; 543 else 544 error = process_machdep_read_xmmregs(p, &r); 545 if (error == 0) 546 error = uiomove(kv, kl, uio); 547 if (error == 0 && uio->uio_rw == UIO_WRITE) { 548 if (p->p_stat != SSTOP) 549 error = EBUSY; 550 else 551 error = process_machdep_write_xmmregs(p, &r); 552 } 553 554 PRELE(p); 555 556 uio->uio_offset = 0; 557 return (error); 558 } 559 560 int 561 process_machdep_validxmmregs(p) 562 struct proc *p; 563 { 564 565 if (p->p_flag & P_SYSTEM) 566 return (0); 567 568 return (i386_use_fxsave); 569 } 570 #endif /* __HAVE_PTRACE_MACHDEP */ 571