machdep.c revision 94606
1/*- 2 * Copyright (c) 2001 Jake Burkholder. 3 * Copyright (c) 1992 Terrence R. Lambert. 4 * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * William Jolitz. 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 University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 39 * from: FreeBSD: src/sys/i386/i386/machdep.c,v 1.477 2001/08/27 40 * $FreeBSD: head/sys/sparc64/sparc64/machdep.c 94606 2002-04-13 19:17:49Z alc $ 41 */ 42 43#include "opt_ddb.h" 44#include "opt_msgbuf.h" 45 46#include <sys/param.h> 47#include <sys/systm.h> 48#include <sys/cons.h> 49#include <sys/kernel.h> 50#include <sys/ktr.h> 51#include <sys/linker.h> 52#include <sys/lock.h> 53#include <sys/malloc.h> 54#include <sys/msgbuf.h> 55#include <sys/mutex.h> 56#include <sys/pcpu.h> 57#include <sys/proc.h> 58#include <sys/reboot.h> 59#include <sys/bio.h> 60#include <sys/buf.h> 61#include <sys/bus.h> 62#include <sys/eventhandler.h> 63#include <sys/interrupt.h> 64#include <sys/ptrace.h> 65#include <sys/signalvar.h> 66#include <sys/smp.h> 67#include <sys/sysent.h> 68#include <sys/sysproto.h> 69#include <sys/timetc.h> 70#include <sys/user.h> 71#include <sys/ucontext.h> 72#include <sys/user.h> 73#include <sys/ucontext.h> 74#include <sys/exec.h> 75 76#include <dev/ofw/openfirm.h> 77 78#include <vm/vm.h> 79#include <vm/vm_param.h> 80#include <vm/vm_kern.h> 81#include <vm/vm_object.h> 82#include <vm/vm_page.h> 83#include <vm/vm_map.h> 84#include <vm/vm_pager.h> 85#include <vm/vm_extern.h> 86 87#include <ddb/ddb.h> 88 89#include <machine/cache.h> 90#include <machine/clock.h> 91#include <machine/cpu.h> 92#include <machine/fp.h> 93#include <machine/intr_machdep.h> 94#include <machine/md_var.h> 95#include <machine/metadata.h> 96#include <machine/ofw_machdep.h> 97#include <machine/smp.h> 98#include <machine/pmap.h> 99#include <machine/pstate.h> 100#include <machine/reg.h> 101#include <machine/sigframe.h> 102#include <machine/tick.h> 103#include <machine/tlb.h> 104#include <machine/tstate.h> 105#include <machine/upa.h> 106#include <machine/ver.h> 107 108typedef int ofw_vec_t(void *); 109 110struct tte *kernel_ttes; 111int kernel_tlb_slots; 112 113int physmem; 114int cold = 1; 115int Maxmem; 116 117char pcpu0[PCPU_PAGES * PAGE_SIZE]; 118char uarea0[UAREA_PAGES * PAGE_SIZE]; 119struct trapframe frame0; 120 121vm_offset_t kstack0; 122vm_offset_t kstack0_phys; 123 124struct kva_md_info kmi; 125 126u_long ofw_vec; 127u_long ofw_tba; 128 129static struct timecounter tick_tc; 130 131static timecounter_get_t tick_get_timecount; 132void sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, 133 ofw_vec_t *vec); 134void sparc64_shutdown_final(void *dummy, int howto); 135 136static void cpu_startup(void *); 137SYSINIT(cpu, SI_SUB_CPU, SI_ORDER_FIRST, cpu_startup, NULL); 138 139CTASSERT((1 << INT_SHIFT) == sizeof(int)); 140CTASSERT((1 << PTR_SHIFT) == sizeof(char *)); 141 142CTASSERT(sizeof(struct pcpu) <= ((PCPU_PAGES * PAGE_SIZE) / 2)); 143 144static void 145cpu_startup(void *arg) 146{ 147 phandle_t child; 148 phandle_t root; 149 char type[8]; 150 u_int clock; 151 152 root = OF_peer(0); 153 for (child = OF_child(root); child != 0; child = OF_peer(child)) { 154 OF_getprop(child, "device_type", type, sizeof(type)); 155 if (strcmp(type, "cpu") == 0) 156 break; 157 } 158 if (child == 0) 159 panic("cpu_startup: no cpu\n"); 160 OF_getprop(child, "clock-frequency", &clock, sizeof(clock)); 161 162 tick_tc.tc_get_timecount = tick_get_timecount; 163 tick_tc.tc_poll_pps = NULL; 164 tick_tc.tc_counter_mask = ~0u; 165 tick_tc.tc_frequency = clock; 166 tick_tc.tc_name = "tick"; 167 tc_init(&tick_tc); 168 169 cpu_identify(rdpr(ver), clock, PCPU_GET(cpuid)); 170 cache_init(child); 171 172 vm_ksubmap_init(&kmi); 173 174 bufinit(); 175 vm_pager_bufferinit(); 176 177 tick_start(clock, tick_hardclock); 178 179 EVENTHANDLER_REGISTER(shutdown_final, sparc64_shutdown_final, NULL, 180 SHUTDOWN_PRI_LAST); 181} 182 183void 184cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size) 185{ 186} 187 188unsigned 189tick_get_timecount(struct timecounter *tc) 190{ 191 return ((unsigned)rd(tick)); 192} 193 194void 195sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec) 196{ 197 struct pcpu *pc; 198 vm_offset_t end; 199 vm_offset_t off; 200 caddr_t kmdp; 201 202 end = 0; 203 kmdp = NULL; 204 205 /* 206 * Initialize openfirmware (needed for console). 207 */ 208 OF_init(vec); 209 210 /* 211 * Parse metadata if present and fetch parameters. Must be before the 212 * console is inited so cninit gets the right value of boothowto. 213 */ 214 if (mdp != NULL) { 215 preload_metadata = mdp; 216 kmdp = preload_search_by_type("elf kernel"); 217 if (kmdp != NULL) { 218 boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int); 219 kern_envp = MD_FETCH(kmdp, MODINFOMD_ENVP, char *); 220 end = MD_FETCH(kmdp, MODINFOMD_KERNEND, vm_offset_t); 221 kernel_tlb_slots = MD_FETCH(kmdp, MODINFOMD_DTLB_SLOTS, 222 int); 223 kernel_ttes = (struct tte *)preload_search_info(kmdp, 224 MODINFO_METADATA | MODINFOMD_DTLB); 225 } 226 } 227 228 /* 229 * Initialize the console before printing anything. 230 */ 231 cninit(); 232 233 /* 234 * Panic is there is no metadata. Most likely the kernel was booted 235 * directly, instead of through loader(8). 236 */ 237 if (mdp == NULL || kmdp == NULL) { 238 printf("sparc64_init: no loader metadata.\n" 239 "This probably means you are not using loader(8).\n"); 240 panic("sparc64_init"); 241 } 242 243 /* 244 * Sanity check the kernel end, which is important. 245 */ 246 if (end == 0) { 247 printf("sparc64_init: warning, kernel end not specified.\n" 248 "Attempting to continue anyway.\n"); 249 end = (vm_offset_t)_end; 250 } 251 252#ifdef DDB 253 kdb_init(); 254#endif 255 256#ifdef SMP 257 mp_tramp = mp_tramp_alloc(); 258#endif 259 260 /* 261 * Initialize virtual memory and calculate physmem. 262 */ 263 pmap_bootstrap(end); 264 265 /* 266 * Initialize tunables. 267 */ 268 init_param1(); 269 init_param2(physmem); 270 271 /* 272 * Disable tick for now. 273 */ 274 tick_stop(); 275 276 /* 277 * Initialize the interrupt tables. 278 */ 279 intr_init1(); 280 281 /* 282 * Initialize proc0 stuff (p_contested needs to be done early). 283 */ 284 proc_linkup(&proc0, &proc0.p_ksegrp, &proc0.p_kse, &thread0); 285 proc0.p_md.md_utrap = NULL; 286 proc0.p_uarea = (struct user *)uarea0; 287 proc0.p_stats = &proc0.p_uarea->u_stats; 288 thread0.td_kstack = kstack0; 289 thread0.td_pcb = (struct pcb *) 290 (thread0.td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1; 291 frame0.tf_tstate = TSTATE_IE | TSTATE_PEF; 292 thread0.td_frame = &frame0; 293 294 /* 295 * Prime our per-cpu data page for use. Note, we are using it for our 296 * stack, so don't pass the real size (PAGE_SIZE) to pcpu_init or 297 * it'll zero it out from under us. 298 */ 299 pc = (struct pcpu *)(pcpu0 + (PCPU_PAGES * PAGE_SIZE)) - 1; 300 pcpu_init(pc, 0, sizeof(struct pcpu)); 301 pc->pc_curthread = &thread0; 302 pc->pc_curpcb = thread0.td_pcb; 303 pc->pc_mid = UPA_CR_GET_MID(ldxa(0, ASI_UPA_CONFIG_REG)); 304 pc->pc_addr = (vm_offset_t)pcpu0; 305 pc->pc_tlb_ctx = TLB_CTX_USER_MIN; 306 pc->pc_tlb_ctx_min = TLB_CTX_USER_MIN; 307 pc->pc_tlb_ctx_max = TLB_CTX_USER_MAX; 308 309 /* 310 * Initialize global registers. 311 */ 312 cpu_setregs(pc); 313 314 /* 315 * Map and initialize the message buffer (after setting trap table). 316 */ 317 for (off = 0; off < round_page(MSGBUF_SIZE); off += PAGE_SIZE) 318 pmap_kenter((vm_offset_t)msgbufp + off, msgbuf_phys + off); 319 msgbufinit(msgbufp, MSGBUF_SIZE); 320 321 mutex_init(); 322 intr_init2(); 323} 324 325void 326set_openfirm_callback(ofw_vec_t *vec) 327{ 328 ofw_tba = rdpr(tba); 329 ofw_vec = (u_long)vec; 330} 331 332void 333sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) 334{ 335 struct trapframe *tf; 336 struct sigframe *sfp; 337 struct sigacts *psp; 338 struct sigframe sf; 339 struct thread *td; 340 struct frame *fp; 341 struct proc *p; 342 int oonstack; 343 u_long sp; 344 345 oonstack = 0; 346 td = curthread; 347 p = td->td_proc; 348 psp = p->p_sigacts; 349 tf = td->td_frame; 350 sp = tf->tf_sp + SPOFF; 351 oonstack = sigonstack(sp); 352 353 CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm, 354 catcher, sig); 355 356 /* Save user context. */ 357 bzero(&sf, sizeof(sf)); 358 sf.sf_uc.uc_sigmask = *mask; 359 sf.sf_uc.uc_stack = p->p_sigstk; 360 sf.sf_uc.uc_stack.ss_flags = (p->p_flag & P_ALTSTACK) 361 ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; 362 sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; 363 bcopy(tf->tf_global, sf.sf_uc.uc_mcontext.mc_global, 364 sizeof (tf->tf_global)); 365 bcopy(tf->tf_out, sf.sf_uc.uc_mcontext.mc_out, sizeof (tf->tf_out)); 366 sf.sf_uc.uc_mcontext.mc_tpc = tf->tf_tpc; 367 sf.sf_uc.uc_mcontext.mc_tnpc = tf->tf_tnpc; 368 sf.sf_uc.uc_mcontext.mc_tstate = tf->tf_tstate; 369 370 /* Allocate and validate space for the signal handler context. */ 371 if ((p->p_flag & P_ALTSTACK) != 0 && !oonstack && 372 SIGISMEMBER(psp->ps_sigonstack, sig)) { 373 sfp = (struct sigframe *)(p->p_sigstk.ss_sp + 374 p->p_sigstk.ss_size - sizeof(struct sigframe)); 375#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 376 p->p_sigstk.ss_flags |= SS_ONSTACK; 377#endif 378 } else 379 sfp = (struct sigframe *)sp - 1; 380 PROC_UNLOCK(p); 381 382 fp = (struct frame *)sfp - 1; 383 384 /* Translate the signal if appropriate. */ 385 if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize) 386 sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; 387 388 /* Build the argument list for the signal handler. */ 389 tf->tf_out[0] = sig; 390 tf->tf_out[2] = (register_t)&sfp->sf_uc; 391 tf->tf_out[3] = tf->tf_type; 392 tf->tf_out[4] = (register_t)catcher; 393 PROC_LOCK(p); 394 if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { 395 /* Signal handler installed with SA_SIGINFO. */ 396 tf->tf_out[1] = (register_t)&sfp->sf_si; 397 398 /* Fill siginfo structure. */ 399 sf.sf_si.si_signo = sig; 400 sf.sf_si.si_code = code; 401 sf.sf_si.si_addr = (void *)tf->tf_sfar; 402 } else { 403 /* Old FreeBSD-style arguments. */ 404 tf->tf_out[1] = code; 405 } 406 PROC_UNLOCK(p); 407 408 /* Copy the sigframe out to the user's stack. */ 409 if (rwindow_save(td) != 0 || copyout(&sf, sfp, sizeof(*sfp)) != 0 || 410 suword(&fp->fr_in[6], tf->tf_out[6]) != 0) { 411 /* 412 * Something is wrong with the stack pointer. 413 * ...Kill the process. 414 */ 415 CTR2(KTR_SIG, "sendsig: sigexit td=%p sfp=%p", td, sfp); 416 PROC_LOCK(p); 417 sigexit(td, SIGILL); 418 /* NOTREACHED */ 419 } 420 421 tf->tf_tpc = PS_STRINGS - *(p->p_sysent->sv_szsigcode); 422 tf->tf_tnpc = tf->tf_tpc + 4; 423 tf->tf_sp = (u_long)fp - SPOFF; 424 425 CTR3(KTR_SIG, "sendsig: return td=%p pc=%#lx sp=%#lx", td, tf->tf_tpc, 426 tf->tf_sp); 427 428 PROC_LOCK(p); 429} 430 431/* 432 * Stub to satisfy the reference to osigreturn in the syscall table. This 433 * is needed even for newer arches that don't support old signals because 434 * the syscall table is machine-independent. 435 * 436 * MPSAFE 437 */ 438int 439osigreturn(struct thread *td, struct osigreturn_args *uap) 440{ 441 442 return (nosys(td, (struct nosys_args *)uap)); 443} 444 445#ifndef _SYS_SYSPROTO_H_ 446struct sigreturn_args { 447 ucontext_t *ucp; 448}; 449#endif 450 451/* 452 * MPSAFE 453 */ 454int 455sigreturn(struct thread *td, struct sigreturn_args *uap) 456{ 457 struct trapframe *tf; 458 struct proc *p; 459 ucontext_t uc; 460 461 p = td->td_proc; 462 if (rwindow_save(td)) { 463 PROC_LOCK(p); 464 sigexit(td, SIGILL); 465 } 466 467 CTR2(KTR_SIG, "sigreturn: td=%p ucp=%p", td, uap->sigcntxp); 468 if (copyin(uap->sigcntxp, &uc, sizeof(uc)) != 0) { 469 CTR1(KTR_SIG, "sigreturn: efault td=%p", td); 470 return (EFAULT); 471 } 472 473 if (((uc.uc_mcontext.mc_tpc | uc.uc_mcontext.mc_tnpc) & 3) != 0) 474 return (EINVAL); 475 if (!TSTATE_SECURE(uc.uc_mcontext.mc_tstate)) 476 return (EINVAL); 477 478 tf = td->td_frame; 479 bcopy(uc.uc_mcontext.mc_global, tf->tf_global, 480 sizeof(tf->tf_global)); 481 bcopy(uc.uc_mcontext.mc_out, tf->tf_out, sizeof(tf->tf_out)); 482 tf->tf_tpc = uc.uc_mcontext.mc_tpc; 483 tf->tf_tnpc = uc.uc_mcontext.mc_tnpc; 484 tf->tf_tstate = uc.uc_mcontext.mc_tstate; 485 PROC_LOCK(p); 486#if defined(COMPAT_43) || defined(COMPAT_SUNOS) 487 if (uc.uc_mcontext.mc_onstack & 1) 488 p->p_sigstk.ss_flags |= SS_ONSTACK; 489 else 490 p->p_sigstk.ss_flags &= ~SS_ONSTACK; 491#endif 492 493 p->p_sigmask = uc.uc_sigmask; 494 SIG_CANTMASK(p->p_sigmask); 495 signotify(p); 496 PROC_UNLOCK(p); 497 CTR4(KTR_SIG, "sigreturn: return td=%p pc=%#lx sp=%#lx tstate=%#lx", 498 td, tf->tf_tpc, tf->tf_sp, tf->tf_tstate); 499 return (EJUSTRETURN); 500} 501 502/* 503 * Exit the kernel and execute a firmware call that will not return, as 504 * specified by the arguments. 505 */ 506void 507cpu_shutdown(void *args) 508{ 509 510#ifdef SMP 511 cpu_mp_shutdown(); 512#endif 513 openfirmware_exit(args); 514} 515 516/* 517 * Duplicate OF_exit() with a different firmware call function that restores 518 * the trap table, otherwise a RED state exception is triggered in at least 519 * some firmware versions. 520 */ 521void 522cpu_halt(void) 523{ 524 static struct { 525 cell_t name; 526 cell_t nargs; 527 cell_t nreturns; 528 } args = { 529 (cell_t)"exit", 530 0, 531 0 532 }; 533 534 cpu_shutdown(&args); 535} 536 537void 538sparc64_shutdown_final(void *dummy, int howto) 539{ 540 static struct { 541 cell_t name; 542 cell_t nargs; 543 cell_t nreturns; 544 } args = { 545 (cell_t)"SUNW,power-off", 546 0, 547 0 548 }; 549 550 /* Turn the power off? */ 551 if ((howto & RB_POWEROFF) != 0) 552 cpu_shutdown(&args); 553 /* In case of halt, return to the firmware */ 554 if ((howto & RB_HALT) != 0) 555 cpu_halt(); 556} 557 558int 559ptrace_set_pc(struct thread *td, u_long addr) 560{ 561 562 td->td_frame->tf_tpc = addr; 563 td->td_frame->tf_tnpc = addr + 4; 564 return (0); 565} 566 567int 568ptrace_single_step(struct thread *td) 569{ 570 TODO; 571 return (0); 572} 573 574void 575setregs(struct thread *td, u_long entry, u_long stack, u_long ps_strings) 576{ 577 struct trapframe *tf; 578 struct md_utrap *ut; 579 struct pcb *pcb; 580 u_long sp; 581 582 /* XXX no cpu_exec */ 583 if ((ut = td->td_proc->p_md.md_utrap) != NULL) { 584 ut->ut_refcnt--; 585 if (ut->ut_refcnt == 0) 586 free(ut, M_SUBPROC); 587 td->td_proc->p_md.md_utrap = NULL; 588 } 589 590 pcb = td->td_pcb; 591 sp = rounddown(stack, 16); 592 tf = td->td_frame; 593 fp_init_thread(td); 594 bzero(pcb->pcb_rw, sizeof(pcb->pcb_rw)); 595 bzero(pcb->pcb_rwsp, sizeof(pcb->pcb_rwsp)); 596 pcb->pcb_nsaved = 0; 597 bzero(tf, sizeof (*tf)); 598 tf->tf_out[0] = stack; 599 tf->tf_out[3] = PS_STRINGS; 600 tf->tf_out[6] = sp - SPOFF - sizeof(struct frame); 601 tf->tf_tnpc = entry + 4; 602 tf->tf_tpc = entry; 603 tf->tf_tstate = TSTATE_IE | TSTATE_PEF | TSTATE_MM_TSO; 604 605 td->td_retval[0] = tf->tf_out[0]; 606 td->td_retval[1] = tf->tf_out[1]; 607} 608 609void 610Debugger(const char *msg) 611{ 612 613 printf("Debugger(\"%s\")\n", msg); 614 critical_enter(); 615 breakpoint(); 616 critical_exit(); 617} 618 619int 620fill_regs(struct thread *td, struct reg *regs) 621{ 622 struct trapframe *tf; 623 624 tf = td->td_frame; 625 regs->r_tstate = tf->tf_tstate; 626 regs->r_pc = tf->tf_tpc; 627 regs->r_npc = tf->tf_tnpc; 628 regs->r_y = tf->tf_y; 629 bcopy(tf->tf_global, regs->r_global, sizeof(tf->tf_global)); 630 bcopy(tf->tf_out, regs->r_out, sizeof(tf->tf_out)); 631 /* XXX - these are a pain to get at */ 632 bzero(regs->r_in, sizeof(regs->r_in)); 633 bzero(regs->r_local, sizeof(regs->r_local)); 634 return (0); 635} 636 637int 638set_regs(struct thread *td, struct reg *regs) 639{ 640 struct trapframe *tf; 641 642 tf = td->td_frame; 643 if (((regs->r_pc | regs->r_npc) & 3) != 0) 644 return (EINVAL); 645 if (!TSTATE_SECURE(regs->r_tstate)) 646 return (EINVAL); 647 tf->tf_tstate = regs->r_tstate; 648 tf->tf_tpc = regs->r_pc; 649 tf->tf_tnpc = regs->r_npc; 650 tf->tf_y = regs->r_y; 651 bcopy(regs->r_global, tf->tf_global, sizeof(regs->r_global)); 652 bcopy(regs->r_out, tf->tf_out, sizeof(regs->r_out)); 653 return (0); 654} 655 656int 657fill_dbregs(struct thread *td, struct dbreg *dbregs) 658{ 659 660 return (ENOSYS); 661} 662 663int 664set_dbregs(struct thread *td, struct dbreg *dbregs) 665{ 666 667 return (ENOSYS); 668} 669 670int 671fill_fpregs(struct thread *td, struct fpreg *fpregs) 672{ 673 struct trapframe *tf; 674 struct pcb *pcb; 675 676 pcb = td->td_pcb; 677 tf = td->td_frame; 678 bcopy(pcb->pcb_fpstate.fp_fb, fpregs->fr_regs, 679 sizeof(pcb->pcb_fpstate.fp_fb)); 680 fpregs->fr_fprs = tf->tf_fprs; 681 fpregs->fr_fsr = tf->tf_fsr; 682 return (0); 683} 684 685int 686set_fpregs(struct thread *td, struct fpreg *fpregs) 687{ 688 struct trapframe *tf; 689 struct pcb *pcb; 690 691 pcb = td->td_pcb; 692 tf = td->td_frame; 693 bcopy(fpregs->fr_regs, pcb->pcb_fpstate.fp_fb, 694 sizeof(fpregs->fr_regs)); 695 tf->tf_fprs = fpregs->fr_fprs; 696 tf->tf_fsr = fpregs->fr_fsr; 697 return (0); 698} 699