Create a separate structure for per-CPU state saved across suspend and
resume that is a superset of a pcb. Move the FPU state out of the pcb and into this new structure. As part of this, move the FPU resume code on amd64 into a C function. This allows resumectx() to still operate only on a pcb and more closely mirrors the i386 code. Reviewed by: kib (earlier version)
This commit is contained in:
parent
00eea22f11
commit
b1d735ba4c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=271192
@ -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
|
||||
|
@ -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.
|
||||
|
@ -163,8 +163,6 @@ ASSYM(PCB_STAR, offsetof(struct pcb, pcb_star));
|
||||
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);
|
||||
|
@ -102,7 +102,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;
|
||||
@ -1461,11 +1461,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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -1211,6 +1211,11 @@ acpi_set_resource(device_t dev, device_t child, int type, int rid,
|
||||
if (!(type == SYS_RES_IOPORT && start == CONF1_ADDR_PORT))
|
||||
#endif
|
||||
{
|
||||
if (bootverbose)
|
||||
device_printf(dev,
|
||||
"Ignoring %s range %#lx-%#lx for %s\n",
|
||||
type == SYS_RES_MEMORY ? "memory" : "I/O",
|
||||
start, start + count - 1, acpi_name(ad->ad_handle));
|
||||
AcpiOsFree(devinfo);
|
||||
return (0);
|
||||
}
|
||||
|
@ -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;
|
||||
@ -1521,12 +1521,12 @@ cpususpend_handler(void)
|
||||
mtx_assert(&smp_ipi_mtx, MA_NOTOWNED);
|
||||
|
||||
cpu = PCPU_GET(cpuid);
|
||||
if (savectx(susppcbs[cpu])) {
|
||||
npxsuspend(&susppcbs[cpu]->pcb_fpususpend);
|
||||
if (savectx(&susppcbs[cpu]->sp_pcb)) {
|
||||
npxsuspend(&susppcbs[cpu]->sp_fpususpend);
|
||||
wbinvd();
|
||||
CPU_SET_ATOMIC(cpu, &suspended_cpus);
|
||||
} else {
|
||||
npxresume(&susppcbs[cpu]->pcb_fpususpend);
|
||||
npxresume(&susppcbs[cpu]->sp_fpususpend);
|
||||
pmap_init_pat();
|
||||
PCPU_SET(switchtime, 0);
|
||||
PCPU_SET(switchticks, ticks);
|
||||
|
@ -90,8 +90,11 @@ struct pcb {
|
||||
struct region_descriptor pcb_idt;
|
||||
uint16_t pcb_ldt;
|
||||
uint16_t pcb_tr;
|
||||
};
|
||||
|
||||
union savefpu pcb_fpususpend;
|
||||
struct susppcb {
|
||||
struct pcb sp_pcb;
|
||||
union savefpu sp_fpususpend;
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
@ -447,25 +447,31 @@ psycho_attach(device_t dev)
|
||||
panic("%s: failed to set up memory rman", __func__);
|
||||
|
||||
i = OF_getprop_alloc(node, "ranges", sizeof(*range), (void **)&range);
|
||||
/*
|
||||
* Make sure that the expected ranges are present. The
|
||||
* OFW_PCI_CS_MEM64 one is not currently used though.
|
||||
*/
|
||||
if (i != PSYCHO_NRANGE)
|
||||
panic("%s: unsupported number of ranges", __func__);
|
||||
/*
|
||||
* Find the addresses of the various bus spaces.
|
||||
* There should not be multiple ones of one kind.
|
||||
* The physical start addresses of the ranges are the configuration,
|
||||
* memory and I/O handles.
|
||||
*/
|
||||
for (i = 0; i < PSYCHO_NRANGE; i++) {
|
||||
for (; i >= 0; i--) {
|
||||
j = OFW_PCI_RANGE_CS(&range[i]);
|
||||
if (sc->sc_pci_bh[j] != 0)
|
||||
panic("%s: duplicate range for space %d",
|
||||
__func__, j);
|
||||
sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure that the expected ranges are present. The
|
||||
* OFW_PCI_CS_MEM64 one is not currently used.
|
||||
*/
|
||||
if (sc->sc_pci_bh[OFW_PCI_CS_CONFIG] == 0)
|
||||
panic("%s: missing CONFIG range", __func__);
|
||||
if (sc->sc_pci_bh[OFW_PCI_CS_IO] == 0)
|
||||
panic("%s: missing IO range", __func__);
|
||||
if (sc->sc_pci_bh[OFW_PCI_CS_MEM32] == 0)
|
||||
panic("%s: missing MEM32 range", __func__);
|
||||
|
||||
free(range, M_OFWPROP);
|
||||
|
||||
/* Register the softc, this is needed for paired Psychos. */
|
||||
|
@ -75,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);
|
||||
@ -117,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);
|
||||
|
||||
@ -188,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 */
|
||||
@ -204,11 +206,12 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
|
||||
|
||||
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]->pcb_fpususpend);
|
||||
npxsuspend(&susppcbs[0]->sp_fpususpend);
|
||||
#endif
|
||||
#ifdef SMP
|
||||
if (!CPU_EMPTY(&suspcpus) && suspend_cpus(suspcpus) == 0) {
|
||||
@ -221,13 +224,11 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
|
||||
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)
|
||||
@ -244,8 +245,10 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
|
||||
for (;;)
|
||||
ia32_pause();
|
||||
} else {
|
||||
#ifdef DEV_NPX
|
||||
npxresume(&susppcbs[0]->pcb_fpususpend);
|
||||
#ifdef __amd64__
|
||||
fpuresume(susppcbs[0]->sp_fpususpend);
|
||||
#elif defined(DEV_NPX)
|
||||
npxresume(&susppcbs[0]->sp_fpususpend);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -325,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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user