From owner-svn-src-stable-10@FreeBSD.ORG Mon Sep 22 20:34:40 2014 Return-Path: Delivered-To: svn-src-stable-10@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 34B99DD6; Mon, 22 Sep 2014 20:34:40 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 03725371; Mon, 22 Sep 2014 20:34:40 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s8MKYdbN005718; Mon, 22 Sep 2014 20:34:39 GMT (envelope-from jhb@FreeBSD.org) Received: (from jhb@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s8MKYasg005704; Mon, 22 Sep 2014 20:34:36 GMT (envelope-from jhb@FreeBSD.org) Message-Id: <201409222034.s8MKYasg005704@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: jhb set sender to jhb@FreeBSD.org using -f From: John Baldwin Date: Mon, 22 Sep 2014 20:34:36 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r271999 - in stable/10/sys: amd64/amd64 amd64/include i386/i386 i386/include i386/isa x86/acpica X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-10@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for only the 10-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 22 Sep 2014 20:34:40 -0000 Author: jhb Date: Mon Sep 22 20:34:36 2014 New Revision: 271999 URL: http://svnweb.freebsd.org/changeset/base/271999 Log: MFC 270850,271053,271192,271717: Save and restore FPU state across suspend and resume on i386. - Create a separate structure for per-CPU state saved across suspend and resume that is a superset of a pcb. - Store the FPU state for suspend and resume in the new structure (for amd64, this moves it out of the PCB) - On both i386 and amd64, all of the FPU suspend/resume handling is now done in C. Approved by: re (hrs) Modified: stable/10/sys/amd64/amd64/cpu_switch.S stable/10/sys/amd64/amd64/fpu.c stable/10/sys/amd64/amd64/genassym.c stable/10/sys/amd64/amd64/mp_machdep.c stable/10/sys/amd64/include/fpu.h stable/10/sys/amd64/include/pcb.h stable/10/sys/i386/i386/mp_machdep.c stable/10/sys/i386/i386/swtch.s stable/10/sys/i386/include/npx.h stable/10/sys/i386/include/pcb.h stable/10/sys/i386/isa/npx.c stable/10/sys/x86/acpica/acpi_wakeup.c Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/amd64/amd64/cpu_switch.S ============================================================================== --- stable/10/sys/amd64/amd64/cpu_switch.S Mon Sep 22 20:10:45 2014 (r271998) +++ stable/10/sys/amd64/amd64/cpu_switch.S Mon Sep 22 20:34:36 2014 (r271999) @@ -399,10 +399,6 @@ ENTRY(savectx) rdmsr movl %eax,PCB_SFMASK(%rdi) movl %edx,PCB_SFMASK+4(%rdi) - movl xsave_mask,%eax - movl %eax,PCB_XSMASK(%rdi) - movl xsave_mask+4,%eax - movl %eax,PCB_XSMASK+4(%rdi) sgdt PCB_GDT(%rdi) sidt PCB_IDT(%rdi) @@ -467,12 +463,9 @@ ENTRY(resumectx) movl PCB_SFMASK(%rdi),%eax wrmsr - /* Restore CR0 except for FPU mode. */ + /* Restore CR0, CR2, CR4 and CR3. */ movq PCB_CR0(%rdi),%rax - andq $~(CR0_EM | CR0_TS),%rax movq %rax,%cr0 - - /* Restore CR2, CR4 and CR3. */ movq PCB_CR2(%rdi),%rax movq %rax,%cr2 movq PCB_CR4(%rdi),%rax @@ -510,26 +503,6 @@ ENTRY(resumectx) movq PCB_DR7(%rdi),%rax movq %rax,%dr7 - /* Restore FPU state. */ - fninit - movq PCB_FPUSUSPEND(%rdi),%rbx - movq PCB_XSMASK(%rdi),%rax - testq %rax,%rax - jz 1f - movq %rax,%rdx - shrq $32,%rdx - movl $XCR0,%ecx - xsetbv - xrstor (%rbx) - jmp 2f -1: - fxrstor (%rbx) -2: - - /* Reload CR0. */ - movq PCB_CR0(%rdi),%rax - movq %rax,%cr0 - /* Restore other callee saved registers. */ movq PCB_R15(%rdi),%r15 movq PCB_R14(%rdi),%r14 Modified: stable/10/sys/amd64/amd64/fpu.c ============================================================================== --- stable/10/sys/amd64/amd64/fpu.c Mon Sep 22 20:10:45 2014 (r271998) +++ stable/10/sys/amd64/amd64/fpu.c Mon Sep 22 20:34:36 2014 (r271999) @@ -173,6 +173,20 @@ fpususpend(void *addr) load_cr0(cr0); } +void +fpuresume(void *addr) +{ + u_long cr0; + + cr0 = rcr0(); + stop_emulating(); + fninit(); + if (use_xsave) + load_xcr(XCR0, xsave_mask); + fpurestore(addr); + load_cr0(cr0); +} + /* * Enable XSAVE if supported and allowed by user. * Calculate the xsave_mask. Modified: stable/10/sys/amd64/amd64/genassym.c ============================================================================== --- stable/10/sys/amd64/amd64/genassym.c Mon Sep 22 20:10:45 2014 (r271998) +++ stable/10/sys/amd64/amd64/genassym.c Mon Sep 22 20:34:36 2014 (r271999) @@ -163,8 +163,6 @@ ASSYM(PCB_STAR, offsetof(struct pcb, pcb ASSYM(PCB_LSTAR, offsetof(struct pcb, pcb_lstar)); ASSYM(PCB_CSTAR, offsetof(struct pcb, pcb_cstar)); ASSYM(PCB_SFMASK, offsetof(struct pcb, pcb_sfmask)); -ASSYM(PCB_XSMASK, offsetof(struct pcb, pcb_xsmask)); -ASSYM(PCB_FPUSUSPEND, offsetof(struct pcb, pcb_fpususpend)); ASSYM(PCB_SIZE, sizeof(struct pcb)); ASSYM(PCB_FULL_IRET, PCB_FULL_IRET); ASSYM(PCB_DBREGS, PCB_DBREGS); Modified: stable/10/sys/amd64/amd64/mp_machdep.c ============================================================================== --- stable/10/sys/amd64/amd64/mp_machdep.c Mon Sep 22 20:10:45 2014 (r271998) +++ stable/10/sys/amd64/amd64/mp_machdep.c Mon Sep 22 20:34:36 2014 (r271999) @@ -101,7 +101,7 @@ char *nmi_stack; void *dpcpu; struct pcb stoppcbs[MAXCPU]; -struct pcb **susppcbs; +struct susppcb **susppcbs; /* Variables needed for SMP tlb shootdown. */ vm_offset_t smp_tlb_addr2; @@ -1463,11 +1463,12 @@ cpususpend_handler(void) mtx_assert(&smp_ipi_mtx, MA_NOTOWNED); cpu = PCPU_GET(cpuid); - if (savectx(susppcbs[cpu])) { - fpususpend(susppcbs[cpu]->pcb_fpususpend); + if (savectx(&susppcbs[cpu]->sp_pcb)) { + fpususpend(susppcbs[cpu]->sp_fpususpend); wbinvd(); CPU_SET_ATOMIC(cpu, &suspended_cpus); } else { + fpuresume(susppcbs[cpu]->sp_fpususpend); pmap_init_pat(); initializecpu(); PCPU_SET(switchtime, 0); Modified: stable/10/sys/amd64/include/fpu.h ============================================================================== --- stable/10/sys/amd64/include/fpu.h Mon Sep 22 20:10:45 2014 (r271998) +++ stable/10/sys/amd64/include/fpu.h Mon Sep 22 20:34:36 2014 (r271999) @@ -58,6 +58,7 @@ int fpuformat(void); int fpugetregs(struct thread *td); void fpuinit(void); void fpurestore(void *addr); +void fpuresume(void *addr); void fpusave(void *addr); int fpusetregs(struct thread *td, struct savefpu *addr, char *xfpustate, size_t xfpustate_size); Modified: stable/10/sys/amd64/include/pcb.h ============================================================================== --- stable/10/sys/amd64/include/pcb.h Mon Sep 22 20:10:45 2014 (r271998) +++ stable/10/sys/amd64/include/pcb.h Mon Sep 22 20:34:36 2014 (r271999) @@ -97,14 +97,18 @@ struct pcb { register_t pcb_lstar; register_t pcb_cstar; register_t pcb_sfmask; - register_t pcb_xsmask; - - /* fpu context for suspend/resume */ - void *pcb_fpususpend; struct savefpu *pcb_save; - uint64_t pcb_pad[3]; + uint64_t pcb_pad[5]; +}; + +/* Per-CPU state saved during suspend and resume. */ +struct susppcb { + struct pcb sp_pcb; + + /* fpu context for suspend/resume */ + void *sp_fpususpend; }; #endif Modified: stable/10/sys/i386/i386/mp_machdep.c ============================================================================== --- stable/10/sys/i386/i386/mp_machdep.c Mon Sep 22 20:10:45 2014 (r271998) +++ stable/10/sys/i386/i386/mp_machdep.c Mon Sep 22 20:34:36 2014 (r271999) @@ -147,7 +147,7 @@ void *bootstacks[MAXCPU]; static void *dpcpu; struct pcb stoppcbs[MAXCPU]; -struct pcb **susppcbs = NULL; +struct susppcb **susppcbs; /* Variables needed for SMP tlb shootdown. */ vm_offset_t smp_tlb_addr1; @@ -1523,10 +1523,12 @@ cpususpend_handler(void) mtx_assert(&smp_ipi_mtx, MA_NOTOWNED); cpu = PCPU_GET(cpuid); - if (savectx(susppcbs[cpu])) { + if (savectx(&susppcbs[cpu]->sp_pcb)) { + npxsuspend(&susppcbs[cpu]->sp_fpususpend); wbinvd(); CPU_SET_ATOMIC(cpu, &suspended_cpus); } else { + npxresume(&susppcbs[cpu]->sp_fpususpend); pmap_init_pat(); PCPU_SET(switchtime, 0); PCPU_SET(switchticks, ticks); Modified: stable/10/sys/i386/i386/swtch.s ============================================================================== --- stable/10/sys/i386/i386/swtch.s Mon Sep 22 20:10:45 2014 (r271998) +++ stable/10/sys/i386/i386/swtch.s Mon Sep 22 20:34:36 2014 (r271999) @@ -416,45 +416,6 @@ ENTRY(savectx) sldt PCB_LDT(%ecx) 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 - 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 ret END(savectx) @@ -519,10 +480,6 @@ ENTRY(resumectx) movl PCB_DR7(%ecx),%eax movl %eax,%dr7 -#ifdef DEV_NPX - /* XXX FIX ME */ -#endif - /* Restore other registers */ movl PCB_EDI(%ecx),%edi movl PCB_ESI(%ecx),%esi Modified: stable/10/sys/i386/include/npx.h ============================================================================== --- stable/10/sys/i386/include/npx.h Mon Sep 22 20:10:45 2014 (r271998) +++ stable/10/sys/i386/include/npx.h Mon Sep 22 20:34:36 2014 (r271999) @@ -53,8 +53,10 @@ void npxexit(struct thread *td); 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 *); Modified: stable/10/sys/i386/include/pcb.h ============================================================================== --- stable/10/sys/i386/include/pcb.h Mon Sep 22 20:10:45 2014 (r271998) +++ stable/10/sys/i386/include/pcb.h Mon Sep 22 20:34:36 2014 (r271999) @@ -92,6 +92,11 @@ struct pcb { uint16_t pcb_tr; }; +struct susppcb { + struct pcb sp_pcb; + union savefpu sp_fpususpend; +}; + #ifdef _KERNEL struct trapframe; Modified: stable/10/sys/i386/isa/npx.c ============================================================================== --- stable/10/sys/i386/isa/npx.c Mon Sep 22 20:10:45 2014 (r271998) +++ stable/10/sys/i386/isa/npx.c Mon Sep 22 20:34:36 2014 (r271999) @@ -761,6 +761,43 @@ npxsave(addr) PCPU_SET(fpcurthread, NULL); } +/* + * Unconditionally save the current co-processor state across suspend and + * resume. + */ +void +npxsuspend(union savefpu *addr) +{ + register_t cr0; + + if (!hw_float) + return; + if (PCPU_GET(fpcurthread) == NULL) { + *addr = npx_initialstate; + return; + } + cr0 = rcr0(); + clts(); + fpusave(addr); + load_cr0(cr0); +} + +void +npxresume(union savefpu *addr) +{ + register_t cr0; + + if (!hw_float) + return; + + cr0 = rcr0(); + clts(); + npxinit(); + stop_emulating(); + fpurstor(addr); + load_cr0(cr0); +} + void npxdrop() { Modified: stable/10/sys/x86/acpica/acpi_wakeup.c ============================================================================== --- stable/10/sys/x86/acpica/acpi_wakeup.c Mon Sep 22 20:10:45 2014 (r271998) +++ stable/10/sys/x86/acpica/acpi_wakeup.c Mon Sep 22 20:34:36 2014 (r271999) @@ -30,6 +30,10 @@ #include __FBSDID("$FreeBSD$"); +#ifdef __i386__ +#include "opt_npx.h" +#endif + #include #include #include @@ -71,10 +75,10 @@ extern int acpi_resume_beep; extern int acpi_reset_video; #ifdef SMP -extern struct pcb **susppcbs; +extern struct susppcb **susppcbs; static cpuset_t suspcpus; #else -static struct pcb **susppcbs; +static struct susppcb **susppcbs; #endif static void *acpi_alloc_wakeup_handler(void); @@ -113,14 +117,15 @@ acpi_stop_beep(void *arg) static int acpi_wakeup_ap(struct acpi_softc *sc, int cpu) { + struct pcb *pcb; int vector = (WAKECODE_PADDR(sc) >> 12) & 0xff; int apic_id = cpu_apic_ids[cpu]; int ms; - WAKECODE_FIXUP(wakeup_pcb, struct pcb *, susppcbs[cpu]); - WAKECODE_FIXUP(wakeup_gdt, uint16_t, susppcbs[cpu]->pcb_gdt.rd_limit); - WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t, - susppcbs[cpu]->pcb_gdt.rd_base); + pcb = &susppcbs[cpu]->sp_pcb; + WAKECODE_FIXUP(wakeup_pcb, struct pcb *, pcb); + WAKECODE_FIXUP(wakeup_gdt, uint16_t, pcb->pcb_gdt.rd_limit); + WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t, pcb->pcb_gdt.rd_base); ipi_startup(apic_id, vector); @@ -184,6 +189,7 @@ int acpi_sleep_machdep(struct acpi_softc *sc, int state) { ACPI_STATUS status; + struct pcb *pcb; if (sc->acpi_wakeaddr == 0ul) return (-1); /* couldn't alloc wake memory */ @@ -200,9 +206,12 @@ acpi_sleep_machdep(struct acpi_softc *sc intr_suspend(); - if (savectx(susppcbs[0])) { + pcb = &susppcbs[0]->sp_pcb; + if (savectx(pcb)) { #ifdef __amd64__ - fpususpend(susppcbs[0]->pcb_fpususpend); + fpususpend(susppcbs[0]->sp_fpususpend); +#elif defined(DEV_NPX) + npxsuspend(&susppcbs[0]->sp_fpususpend); #endif #ifdef SMP if (!CPU_EMPTY(&suspcpus) && suspend_cpus(suspcpus) == 0) { @@ -215,13 +224,11 @@ acpi_sleep_machdep(struct acpi_softc *sc WAKECODE_FIXUP(reset_video, uint8_t, (acpi_reset_video != 0)); #ifndef __amd64__ - WAKECODE_FIXUP(wakeup_cr4, register_t, susppcbs[0]->pcb_cr4); + WAKECODE_FIXUP(wakeup_cr4, register_t, pcb->pcb_cr4); #endif - WAKECODE_FIXUP(wakeup_pcb, struct pcb *, susppcbs[0]); - WAKECODE_FIXUP(wakeup_gdt, uint16_t, - susppcbs[0]->pcb_gdt.rd_limit); - WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t, - susppcbs[0]->pcb_gdt.rd_base); + WAKECODE_FIXUP(wakeup_pcb, struct pcb *, pcb); + WAKECODE_FIXUP(wakeup_gdt, uint16_t, pcb->pcb_gdt.rd_limit); + WAKECODE_FIXUP(wakeup_gdt + 2, uint64_t, pcb->pcb_gdt.rd_base); /* Call ACPICA to enter the desired sleep state */ if (state == ACPI_STATE_S4 && sc->acpi_s4bios) @@ -237,6 +244,12 @@ acpi_sleep_machdep(struct acpi_softc *sc for (;;) ia32_pause(); + } else { +#ifdef __amd64__ + fpuresume(susppcbs[0]->sp_fpususpend); +#elif defined(DEV_NPX) + npxresume(&susppcbs[0]->sp_fpususpend); +#endif } return (1); /* wakeup successfully */ @@ -315,7 +328,7 @@ acpi_alloc_wakeup_handler(void) for (i = 0; i < mp_ncpus; i++) { susppcbs[i] = malloc(sizeof(**susppcbs), M_DEVBUF, M_WAITOK); #ifdef __amd64__ - susppcbs[i]->pcb_fpususpend = alloc_fpusave(M_WAITOK); + susppcbs[i]->sp_fpususpend = alloc_fpusave(M_WAITOK); #endif }