1/* $NetBSD: process_machdep.c,v 1.71 2009/10/21 21:12:00 rmind Exp $ */ 2 3/*- 4 * Copyright (c) 1998, 2000, 2001, 2008 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 * 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_sstep(proc) 48 * Arrange for the process to trap after executing a single instruction. 49 * 50 * process_set_pc(proc) 51 * Set the process's program counter. 52 */ 53 54#include <sys/cdefs.h> 55__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.71 2009/10/21 21:12:00 rmind Exp $"); 56 57#include "opt_vm86.h" 58#include "opt_ptrace.h" 59#include "npx.h" 60 61#include <sys/param.h> 62#include <sys/systm.h> 63#include <sys/time.h> 64#include <sys/kernel.h> 65#include <sys/proc.h> 66#include <sys/vnode.h> 67#include <sys/ptrace.h> 68 69#include <uvm/uvm_extern.h> 70 71#include <machine/psl.h> 72#include <machine/reg.h> 73#include <machine/segments.h> 74 75#ifdef VM86 76#include <machine/vm86.h> 77#endif 78 79static inline struct trapframe * 80process_frame(struct lwp *l) 81{ 82 83 return (l->l_md.md_regs); 84} 85 86static inline union savefpu * 87process_fpframe(struct lwp *l) 88{ 89 struct pcb *pcb = lwp_getpcb(l); 90 91 return &pcb->pcb_savefpu; 92} 93 94static int 95xmm_to_s87_tag(const uint8_t *fpac, int regno, uint8_t tw) 96{ 97 static const uint8_t empty_significand[8] = { 0 }; 98 int tag; 99 uint16_t exponent; 100 101 if (tw & (1U << regno)) { 102 exponent = fpac[8] | (fpac[9] << 8); 103 switch (exponent) { 104 case 0x7fff: 105 tag = 2; 106 break; 107 108 case 0x0000: 109 if (memcmp(empty_significand, fpac, 110 sizeof(empty_significand)) == 0) 111 tag = 1; 112 else 113 tag = 2; 114 break; 115 116 default: 117 if ((fpac[7] & 0x80) == 0) 118 tag = 2; 119 else 120 tag = 0; 121 break; 122 } 123 } else 124 tag = 3; 125 126 return (tag); 127} 128 129void 130process_xmm_to_s87(const struct savexmm *sxmm, struct save87 *s87) 131{ 132 int i; 133 134 /* FPU control/status */ 135 s87->sv_env.en_cw = sxmm->sv_env.en_cw; 136 s87->sv_env.en_sw = sxmm->sv_env.en_sw; 137 /* tag word handled below */ 138 s87->sv_env.en_fip = sxmm->sv_env.en_fip; 139 s87->sv_env.en_fcs = sxmm->sv_env.en_fcs; 140 s87->sv_env.en_opcode = sxmm->sv_env.en_opcode; 141 s87->sv_env.en_foo = sxmm->sv_env.en_foo; 142 s87->sv_env.en_fos = sxmm->sv_env.en_fos; 143 144 /* Tag word and registers. */ 145 s87->sv_env.en_tw = 0; 146 s87->sv_ex_tw = 0; 147 for (i = 0; i < 8; i++) { 148 s87->sv_env.en_tw |= 149 (xmm_to_s87_tag(sxmm->sv_ac[i].fp_bytes, i, 150 sxmm->sv_env.en_tw) << (i * 2)); 151 152 s87->sv_ex_tw |= 153 (xmm_to_s87_tag(sxmm->sv_ac[i].fp_bytes, i, 154 sxmm->sv_ex_tw) << (i * 2)); 155 156 memcpy(&s87->sv_ac[i].fp_bytes, &sxmm->sv_ac[i].fp_bytes, 157 sizeof(s87->sv_ac[i].fp_bytes)); 158 } 159 160 s87->sv_ex_sw = sxmm->sv_ex_sw; 161} 162 163void 164process_s87_to_xmm(const struct save87 *s87, struct savexmm *sxmm) 165{ 166 int i; 167 168 /* FPU control/status */ 169 sxmm->sv_env.en_cw = s87->sv_env.en_cw; 170 sxmm->sv_env.en_sw = s87->sv_env.en_sw; 171 /* tag word handled below */ 172 sxmm->sv_env.en_fip = s87->sv_env.en_fip; 173 sxmm->sv_env.en_fcs = s87->sv_env.en_fcs; 174 sxmm->sv_env.en_opcode = s87->sv_env.en_opcode; 175 sxmm->sv_env.en_foo = s87->sv_env.en_foo; 176 sxmm->sv_env.en_fos = s87->sv_env.en_fos; 177 178 /* Tag word and registers. */ 179 for (i = 0; i < 8; i++) { 180 if (((s87->sv_env.en_tw >> (i * 2)) & 3) == 3) 181 sxmm->sv_env.en_tw &= ~(1U << i); 182 else 183 sxmm->sv_env.en_tw |= (1U << i); 184 185#if 0 186 /* 187 * Software-only word not provided by the userland fpreg 188 * structure. 189 */ 190 if (((s87->sv_ex_tw >> (i * 2)) & 3) == 3) 191 sxmm->sv_ex_tw &= ~(1U << i); 192 else 193 sxmm->sv_ex_tw |= (1U << i); 194#endif 195 196 memcpy(&sxmm->sv_ac[i].fp_bytes, &s87->sv_ac[i].fp_bytes, 197 sizeof(sxmm->sv_ac[i].fp_bytes)); 198 } 199#if 0 200 /* 201 * Software-only word not provided by the userland fpreg 202 * structure. 203 */ 204 sxmm->sv_ex_sw = s87->sv_ex_sw; 205#endif 206} 207 208int 209process_read_regs(struct lwp *l, struct reg *regs) 210{ 211 struct trapframe *tf = process_frame(l); 212 213#ifdef VM86 214 if (tf->tf_eflags & PSL_VM) { 215 regs->r_gs = tf->tf_vm86_gs; 216 regs->r_fs = tf->tf_vm86_fs; 217 regs->r_es = tf->tf_vm86_es; 218 regs->r_ds = tf->tf_vm86_ds; 219 regs->r_eflags = get_vflags(l); 220 } else 221#endif 222 { 223 regs->r_gs = tf->tf_gs & 0xffff; 224 regs->r_fs = tf->tf_fs & 0xffff; 225 regs->r_es = tf->tf_es & 0xffff; 226 regs->r_ds = tf->tf_ds & 0xffff; 227 regs->r_eflags = tf->tf_eflags; 228 } 229 regs->r_edi = tf->tf_edi; 230 regs->r_esi = tf->tf_esi; 231 regs->r_ebp = tf->tf_ebp; 232 regs->r_ebx = tf->tf_ebx; 233 regs->r_edx = tf->tf_edx; 234 regs->r_ecx = tf->tf_ecx; 235 regs->r_eax = tf->tf_eax; 236 regs->r_eip = tf->tf_eip; 237 regs->r_cs = tf->tf_cs & 0xffff; 238 regs->r_esp = tf->tf_esp; 239 regs->r_ss = tf->tf_ss & 0xffff; 240 241 return (0); 242} 243 244int 245process_read_fpregs(struct lwp *l, struct fpreg *regs) 246{ 247 union savefpu *frame = process_fpframe(l); 248 249 if (l->l_md.md_flags & MDL_USEDFPU) { 250#if NNPX > 0 251 npxsave_lwp(l, true); 252#endif 253 } else { 254 /* 255 * Fake a FNINIT. 256 * The initial control word was already set by setregs(), so 257 * save it temporarily. 258 */ 259 if (i386_use_fxsave) { 260 uint32_t mxcsr = frame->sv_xmm.sv_env.en_mxcsr; 261 uint16_t cw = frame->sv_xmm.sv_env.en_cw; 262 263 /* XXX Don't zero XMM regs? */ 264 memset(&frame->sv_xmm, 0, sizeof(frame->sv_xmm)); 265 frame->sv_xmm.sv_env.en_cw = cw; 266 frame->sv_xmm.sv_env.en_mxcsr = mxcsr; 267 frame->sv_xmm.sv_env.en_sw = 0x0000; 268 frame->sv_xmm.sv_env.en_tw = 0x00; 269 } else { 270 uint16_t cw = frame->sv_87.sv_env.en_cw; 271 272 memset(&frame->sv_87, 0, sizeof(frame->sv_87)); 273 frame->sv_87.sv_env.en_cw = cw; 274 frame->sv_87.sv_env.en_sw = 0x0000; 275 frame->sv_87.sv_env.en_tw = 0xffff; 276 } 277 l->l_md.md_flags |= MDL_USEDFPU; 278 } 279 280 if (i386_use_fxsave) { 281 struct save87 s87; 282 283 /* XXX Yuck */ 284 process_xmm_to_s87(&frame->sv_xmm, &s87); 285 memcpy(regs, &s87, sizeof(*regs)); 286 } else 287 memcpy(regs, &frame->sv_87, sizeof(*regs)); 288 return (0); 289} 290 291#ifdef PTRACE 292int 293process_write_regs(struct lwp *l, const struct reg *regs) 294{ 295 struct trapframe *tf = process_frame(l); 296 297#ifdef VM86 298 if (regs->r_eflags & PSL_VM) { 299 void syscall_vm86(struct trapframe *); 300 301 tf->tf_vm86_gs = regs->r_gs; 302 tf->tf_vm86_fs = regs->r_fs; 303 tf->tf_vm86_es = regs->r_es; 304 tf->tf_vm86_ds = regs->r_ds; 305 set_vflags(l, regs->r_eflags); 306 /* 307 * Make sure that attempts at system calls from vm86 308 * mode die horribly. 309 */ 310 l->l_proc->p_md.md_syscall = syscall_vm86; 311 } else 312#endif 313 { 314 /* 315 * Check for security violations. 316 */ 317 if (((regs->r_eflags ^ tf->tf_eflags) & PSL_USERSTATIC) != 0 || 318 !USERMODE(regs->r_cs, regs->r_eflags)) 319 return (EINVAL); 320 321 tf->tf_gs = regs->r_gs; 322 tf->tf_fs = regs->r_fs; 323 tf->tf_es = regs->r_es; 324 tf->tf_ds = regs->r_ds; 325#ifdef VM86 326 /* Restore normal syscall handler */ 327 if (tf->tf_eflags & PSL_VM) 328 (*l->l_proc->p_emul->e_syscall_intern)(l->l_proc); 329#endif 330 tf->tf_eflags = regs->r_eflags; 331 } 332 tf->tf_edi = regs->r_edi; 333 tf->tf_esi = regs->r_esi; 334 tf->tf_ebp = regs->r_ebp; 335 tf->tf_ebx = regs->r_ebx; 336 tf->tf_edx = regs->r_edx; 337 tf->tf_ecx = regs->r_ecx; 338 tf->tf_eax = regs->r_eax; 339 tf->tf_eip = regs->r_eip; 340 tf->tf_cs = regs->r_cs; 341 tf->tf_esp = regs->r_esp; 342 tf->tf_ss = regs->r_ss; 343 344 return (0); 345} 346 347int 348process_write_fpregs(struct lwp *l, const struct fpreg *regs) 349{ 350 union savefpu *frame = process_fpframe(l); 351 352 if (l->l_md.md_flags & MDL_USEDFPU) { 353#if NNPX > 0 354 npxsave_lwp(l, false); 355#endif 356 } else { 357 l->l_md.md_flags |= MDL_USEDFPU; 358 } 359 360 if (i386_use_fxsave) { 361 struct save87 s87; 362 363 /* XXX Yuck. */ 364 memcpy(&s87, regs, sizeof(*regs)); 365 process_s87_to_xmm(&s87, &frame->sv_xmm); 366 } else 367 memcpy(&frame->sv_87, regs, sizeof(*regs)); 368 return (0); 369} 370 371int 372process_sstep(struct lwp *l, int sstep) 373{ 374 struct trapframe *tf = process_frame(l); 375 376 if (sstep) 377 tf->tf_eflags |= PSL_T; 378 else 379 tf->tf_eflags &= ~PSL_T; 380 381 return (0); 382} 383 384int 385process_set_pc(struct lwp *l, void *addr) 386{ 387 struct trapframe *tf = process_frame(l); 388 389 tf->tf_eip = (int)addr; 390 391 return (0); 392} 393 394#ifdef __HAVE_PTRACE_MACHDEP 395static int 396process_machdep_read_xmmregs(struct lwp *l, struct xmmregs *regs) 397{ 398 union savefpu *frame = process_fpframe(l); 399 400 if (i386_use_fxsave == 0) 401 return (EINVAL); 402 403 if (l->l_md.md_flags & MDL_USEDFPU) { 404#if NNPX > 0 405 struct pcb *pcb = lwp_getpcb(l); 406 407 if (pcb->pcb_fpcpu != NULL) { 408 npxsave_lwp(l, true); 409 } 410#endif 411 } else { 412 /* 413 * Fake a FNINIT. 414 * The initial control word was already set by setregs(), 415 * so save it temporarily. 416 */ 417 uint32_t mxcsr = frame->sv_xmm.sv_env.en_mxcsr; 418 uint16_t cw = frame->sv_xmm.sv_env.en_cw; 419 420 /* XXX Don't zero XMM regs? */ 421 memset(&frame->sv_xmm, 0, sizeof(frame->sv_xmm)); 422 frame->sv_xmm.sv_env.en_cw = cw; 423 frame->sv_xmm.sv_env.en_mxcsr = mxcsr; 424 frame->sv_xmm.sv_env.en_sw = 0x0000; 425 frame->sv_xmm.sv_env.en_tw = 0x00; 426 427 l->l_md.md_flags |= MDL_USEDFPU; 428 } 429 430 memcpy(regs, &frame->sv_xmm, sizeof(*regs)); 431 return (0); 432} 433 434static int 435process_machdep_write_xmmregs(struct lwp *l, struct xmmregs *regs) 436{ 437 union savefpu *frame = process_fpframe(l); 438 439 if (i386_use_fxsave == 0) 440 return (EINVAL); 441 442 if (l->l_md.md_flags & MDL_USEDFPU) { 443#if NNPX > 0 444 struct pcb *pcb = lwp_getpcb(l); 445 446 /* If we were using the FPU, drop it. */ 447 if (pcb->pcb_fpcpu != NULL) { 448 npxsave_lwp(l, false); 449 } 450#endif 451 } else { 452 l->l_md.md_flags |= MDL_USEDFPU; 453 } 454 455 memcpy(&frame->sv_xmm, regs, sizeof(*regs)); 456 return (0); 457} 458 459int 460ptrace_machdep_dorequest( 461 struct lwp *l, 462 struct lwp *lt, 463 int req, 464 void *addr, 465 int data 466) 467{ 468 struct uio uio; 469 struct iovec iov; 470 int write = 0; 471 472 switch (req) { 473 case PT_SETXMMREGS: 474 write = 1; 475 476 case PT_GETXMMREGS: 477 /* write = 0 done above. */ 478 if (!process_machdep_validxmmregs(lt->l_proc)) 479 return (EINVAL); 480 else { 481 struct vmspace *vm; 482 int error; 483 484 error = proc_vmspace_getref(l->l_proc, &vm); 485 if (error) { 486 return error; 487 } 488 iov.iov_base = addr; 489 iov.iov_len = sizeof(struct xmmregs); 490 uio.uio_iov = &iov; 491 uio.uio_iovcnt = 1; 492 uio.uio_offset = 0; 493 uio.uio_resid = sizeof(struct xmmregs); 494 uio.uio_rw = write ? UIO_WRITE : UIO_READ; 495 uio.uio_vmspace = vm; 496 error = process_machdep_doxmmregs(l, lt, &uio); 497 uvmspace_free(vm); 498 return error; 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 513int 514process_machdep_doxmmregs(struct lwp *curl, struct lwp *l, struct uio *uio) 515 /* curl: tracer */ 516 /* l: traced */ 517{ 518 int error; 519 struct xmmregs r; 520 char *kv; 521 int kl; 522 523 kl = sizeof(r); 524 kv = (char *) &r; 525 526 kv += uio->uio_offset; 527 kl -= uio->uio_offset; 528 if (kl > uio->uio_resid) 529 kl = uio->uio_resid; 530 531 if (kl < 0) 532 error = EINVAL; 533 else 534 error = process_machdep_read_xmmregs(l, &r); 535 if (error == 0) 536 error = uiomove(kv, kl, uio); 537 if (error == 0 && uio->uio_rw == UIO_WRITE) { 538 if (l->l_proc->p_stat != SSTOP) 539 error = EBUSY; 540 else 541 error = process_machdep_write_xmmregs(l, &r); 542 } 543 544 uio->uio_offset = 0; 545 return (error); 546} 547 548int 549process_machdep_validxmmregs(struct proc *p) 550{ 551 552 if (p->p_flag & PK_SYSTEM) 553 return (0); 554 555 return (i386_use_fxsave); 556} 557#endif /* __HAVE_PTRACE_MACHDEP */ 558#endif /* PTRACE */ 559