Index: amd64/amd64/cpu_switch.S =================================================================== --- amd64/amd64/cpu_switch.S (revision 262711) +++ amd64/amd64/cpu_switch.S (working copy) @@ -409,8 +409,6 @@ sldt PCB_LDT(%rdi) str PCB_TR(%rdi) -2: movq %rsi,%cr0 /* The previous %cr0 is saved in %rsi. */ - movl $1,%eax ret END(savectx) @@ -550,7 +548,7 @@ END(resumectx) /* - * Wrapper around fpusave to care about TS0_CR. + * Wrapper around fpusave to care about CR0_TS. */ ENTRY(ctx_fpusave) movq %cr0,%rsi Index: i386/acpica/acpi_wakecode.S =================================================================== --- i386/acpica/acpi_wakecode.S (revision 262711) +++ i386/acpica/acpi_wakecode.S (working copy) @@ -151,14 +151,7 @@ movl wakeup_cr3 - wakeup_start(%ebx), %eax mov %eax, %cr3 - /* - * Finally, switch to long bit mode by enabling paging. We have - * to be very careful here because all the segmentation disappears - * out from underneath us. The spec says we can depend on the - * subsequent pipelined branch to execute, but *only if* everthing - * is still identity mapped. If any mappings change, the pipeline - * will flush. - */ + /* Enable paging. */ mov %cr0, %eax orl $CR0_PG, %eax mov %eax, %cr0 Index: i386/i386/genassym.c =================================================================== --- i386/i386/genassym.c (revision 262711) +++ i386/i386/genassym.c (working copy) @@ -155,6 +155,7 @@ ASSYM(PCB_FLAGS, offsetof(struct pcb, pcb_flags)); ASSYM(PCB_SAVEFPU, offsetof(struct pcb, pcb_save)); ASSYM(PCB_SAVEFPU_SIZE, sizeof(union savefpu)); +ASSYM(PCB_FPUSUSPEND, offsetof(struct pcb, pcb_fpususpend)); ASSYM(PCB_ONFAULT, offsetof(struct pcb, pcb_onfault)); ASSYM(PCB_SIZE, sizeof(struct pcb)); Index: i386/i386/swtch.s =================================================================== --- i386/i386/swtch.s (revision 262711) +++ i386/i386/swtch.s (working copy) @@ -417,42 +417,9 @@ str PCB_TR(%ecx) #ifdef DEV_NPX - /* - * If fpcurthread == NULL, then the npx h/w state is irrelevant and the - * state had better already be in the pcb. This is true for forks - * but not for dumps (the old book-keeping with FP flags in the pcb - * always lost for dumps because the dump pcb has 0 flags). - * - * If fpcurthread != NULL, then we have to save the npx h/w state to - * fpcurthread's pcb and copy it to the requested pcb, or save to the - * requested pcb and reload. Copying is easier because we would - * have to handle h/w bugs for reloading. We used to lose the - * parent's npx state for forks by forgetting to reload. - */ - pushfl - CLI - movl PCPU(FPCURTHREAD),%eax - testl %eax,%eax - je 1f - - pushl %ecx - movl TD_PCB(%eax),%eax - movl PCB_SAVEFPU(%eax),%eax - pushl %eax - pushl %eax - call npxsave + pushl PCB_FPUSUSPEND(%ecx) + call npxsuspend addl $4,%esp - popl %eax - popl %ecx - - pushl $PCB_SAVEFPU_SIZE - leal PCB_USERFPU(%ecx),%ecx - pushl %ecx - pushl %eax - call bcopy - addl $12,%esp -1: - popfl #endif /* DEV_NPX */ movl $1,%eax @@ -479,7 +446,7 @@ movzwl PCB_SS(%ecx),%eax mov %ax,%ss - /* Restore CR2, CR4, CR3 and CR0 */ + /* Restore CR2, CR4, and CR3 */ movl PCB_CR2(%ecx),%eax movl %eax,%cr2 movl PCB_CR4(%ecx),%eax @@ -486,7 +453,10 @@ movl %eax,%cr4 movl PCB_CR3(%ecx),%eax movl %eax,%cr3 + + /* Restore CR0 except for FPU mode. */ movl PCB_CR0(%ecx),%eax + andl $~(CR0_EM | CR0_TS),%eax movl %eax,%cr0 jmp 1f 1: @@ -520,7 +490,16 @@ movl %eax,%dr7 #ifdef DEV_NPX - /* XXX FIX ME */ + /* Restore FPU state */ + pushl %ecx + pushl PCB_FPUSUSPEND(%ecx) + call npxresume + addl $4,%esp + popl %ecx + + /* Restore CR0 with FPU mode. */ + movl PCB_CR0(%ecx),%eax + movl %eax,%cr0 #endif /* Restore other registers */ Index: i386/include/npx.h =================================================================== --- i386/include/npx.h (revision 262711) +++ i386/include/npx.h (working copy) @@ -53,8 +53,10 @@ int npxformat(void); int npxgetregs(struct thread *td); void npxinit(void); +void npxresume(union savefpu *addr); void npxsave(union savefpu *addr); void npxsetregs(struct thread *td, union savefpu *addr); +void npxsuspend(union savefpu *addr); int npxtrap_x87(void); int npxtrap_sse(void); void npxuserinited(struct thread *); Index: i386/include/pcb.h =================================================================== --- i386/include/pcb.h (revision 262711) +++ i386/include/pcb.h (working copy) @@ -90,6 +90,8 @@ struct region_descriptor pcb_idt; uint16_t pcb_ldt; uint16_t pcb_tr; + + union savefpu pcb_fpususpend; }; #ifdef _KERNEL Index: i386/isa/npx.c =================================================================== --- i386/isa/npx.c (revision 262711) +++ i386/isa/npx.c (working copy) @@ -761,7 +761,34 @@ PCPU_SET(fpcurthread, NULL); } +/* + * Unconditionally save the current co-processor state across suspend and + * resume. + */ void +npxsuspend(union safefpu *addr) +{ + register_t cr0; + + if (!hw_float) + return; + cr0 = rcr(0); + clts(); + fpusave(addr); + load_cr(0, cr0); +} + +void +npxresume(union savefpu *addr) +{ + + if (!hw_float) + return; + fninit(); + fpurstor(addr); +} + +void npxdrop() { struct thread *td;