Add SMP/i386 suspend/resume support.

Most part is merged from amd64.

- i386/acpica/acpi_wakecode.S
Replaced with amd64 code (from realmode to paging enabling code).

- i386/acpica/acpi_wakeup.c
Replaced with amd64 code (except for wakeup_pagetables stuff).

- i386/include/pcb.h
- i386/i386/genassym.c
Added PCB new members (CR0, CR2, CR4, DS, ED, FS, SS, GDT, IDT, LDT
and TR) needed for suspend/resume, not for context switch.

- i386/i386/swtch.s
Added suspendctx() and resumectx().
Note that savectx() was not changed and used for suspending (while
amd64 code uses it).
BSP and AP execute the same sequence, suspendctx(), acpi_wakecode()
and resumectx() for suspend/resume (in case of UP system also).

- i386/i386/apic_vector.s
Added cpususpend().

- i386/i386/mp_machdep.c
- i386/include/smp.h
Added cpususpend_handler().

- i386/include/apicvar.h
- kern/subr_smp.c
- sys/smp.h
Added IPI_SUSPEND and suspend_cpus().

- i386/i386/initcpu.c
- i386/i386/machdep.c
- i386/include/md_var.h
- pc98/pc98/machdep.c
Moved initializecpu() declarations to md_var.h.

MFC after:	3 days
This commit is contained in:
Mitsuru IWASAKI 2012-05-18 18:55:58 +00:00
parent 11c15f90db
commit e3fd0bc1b2
15 changed files with 616 additions and 442 deletions

View File

@ -1,6 +1,8 @@
/*-
* Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org>
* Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
* Copyright (c) 2001-2012 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
* Copyright (c) 2003 Peter Wemm
* Copyright (c) 2008-2012 Jung-uk Kim <jkim@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -28,7 +30,9 @@
*/
#include <machine/asmacros.h>
#include <machine/ppireg.h>
#include <machine/specialreg.h>
#include <machine/timerreg.h>
#include "assym.s"
@ -39,221 +43,163 @@
* Depending on the previous sleep state, we may need to initialize more
* of the system (i.e., S3 suspend-to-RAM vs. S4 suspend-to-disk).
*/
.align 4
.code16
wakeup_16:
nop
cli
cld
.data /* So we can modify it */
ALIGN_TEXT
.code16
wakeup_start:
/*
* Set up segment registers for real mode, a small stack for
* any calls we make, and clear any flags.
*/
movw %cs,%ax
movw %ax,%ds
movw %ax,%ss
movw $PAGE_SIZE,%sp
pushl $0
popfl
cli /* make sure no interrupts */
mov %cs, %ax /* copy %cs to %ds. Remember these */
mov %ax, %ds /* are offsets rather than selectors */
mov %ax, %ss
movw $PAGE_SIZE, %sp
xorw %ax, %ax
pushw %ax
popfw
/* To debug resume hangs, beep the speaker if the user requested. */
cmpl $1,resume_beep
jne nobeep
movb $0xc0,%al
outb %al,$0x42
movb $0x04,%al
outb %al,$0x42
inb $0x61,%al
orb $0x3,%al
outb %al,$0x61
nobeep:
testb $~0, resume_beep - wakeup_start
jz 1f
movb $0, resume_beep - wakeup_start
/* Set PIC timer2 to beep. */
movb $(TIMER_SEL2 | TIMER_SQWAVE | TIMER_16BIT), %al
outb %al, $TIMER_MODE
/* Turn on speaker. */
inb $IO_PPI, %al
orb $PIT_SPKR, %al
outb %al, $IO_PPI
/* Set frequency. */
movw $0x4c0, %ax
outb %al, $TIMER_CNTR2
shrw $8, %ax
outb %al, $TIMER_CNTR2
1:
/* Re-initialize video BIOS if the reset_video tunable is set. */
cmpl $1,reset_video
jne nobiosreset
lcall $0xc000,$3
testb $~0, reset_video - wakeup_start
jz 1f
movb $0, reset_video - wakeup_start
lcall $0xc000, $3
/*
* Set up segment registers for real mode again in case the
* previous BIOS call clobbers them.
*/
movw %cs,%ax
movw %ax,%ds
movw %ax,%ss
nobiosreset:
/* When we reach here, int 0x10 should be ready. Hide cursor. */
movb $0x01, %ah
movb $0x20, %ch
int $0x10
/* Load GDT for real mode. Use 32 bit prefix for addresses >16 MB. */
lgdtl physical_gdt
/* Restore CR2, CR3 and CR4 */
movl previous_cr2,%eax
movl %eax,%cr2
movl previous_cr3,%eax
movl %eax,%cr3
movl previous_cr4,%eax
movl %eax,%cr4
/* Transfer some values to protected mode with an inline stack */
#define NVALUES 9
#define TRANSFER_STACK32(val, idx) \
movl val,%eax; \
movl %eax,wakeup_32stack+(idx+1)+(idx*4)
TRANSFER_STACK32(previous_ss, (NVALUES - 9))
TRANSFER_STACK32(previous_fs, (NVALUES - 8))
TRANSFER_STACK32(previous_ds, (NVALUES - 7))
TRANSFER_STACK32(physical_gdt+2, (NVALUES - 6))
TRANSFER_STACK32(where_to_recover, (NVALUES - 5))
TRANSFER_STACK32(previous_idt+2, (NVALUES - 4))
TRANSFER_STACK32(previous_ldt, (NVALUES - 3))
TRANSFER_STACK32(previous_gdt+2, (NVALUES - 2))
TRANSFER_STACK32(previous_tr, (NVALUES - 1))
TRANSFER_STACK32(previous_cr0, (NVALUES - 0))
mov physical_esp,%esi /* to be used in 32bit code */
/* Enable protected mode */
movl %cr0,%eax
orl $(CR0_PE),%eax
movl %eax,%cr0
wakeup_sw32:
/* Switch to protected mode by intersegmental jump */
ljmpl $KCSEL,$0x12345678 /* Code location, to be replaced */
/*
* Now switched to protected mode without paging enabled.
* %esi: KERNEL stack pointer (physical address)
*/
.code32
wakeup_32:
nop
/* Set up segment registers for protected mode */
movw $KDSEL,%ax /* KDSEL to segment registers */
movw %ax,%ds
movw %ax,%es
movw %ax,%gs
movw %ax,%ss
movw $KPSEL,%ax /* KPSEL to %fs */
movw %ax,%fs
movl %esi,%esp /* physical address stack pointer */
wakeup_32stack:
/* Operands are overwritten in 16 bit code by TRANSFER_STACK32 macro */
pushl $0xabcdef09 /* ss + dummy */
pushl $0xabcdef08 /* fs + gs */
pushl $0xabcdef07 /* ds + es */
pushl $0xabcdef06 /* gdt:base (physical address) */
pushl $0xabcdef05 /* recover address */
pushl $0xabcdef04 /* idt:base */
pushl $0xabcdef03 /* ldt + idt:limit */
pushl $0xabcdef02 /* gdt:base */
pushl $0xabcdef01 /* TR + gdt:limit */
pushl $0xabcdef00 /* CR0 */
movl %esp,%ebp
#define CR0_REGISTER 0(%ebp)
#define TASK_REGISTER 4(%ebp)
#define PREVIOUS_GDT 6(%ebp)
#define PREVIOUS_LDT 12(%ebp)
#define PREVIOUS_IDT 14(%ebp)
#define RECOVER_ADDR 20(%ebp)
#define PHYSICAL_GDT_BASE 24(%ebp)
#define PREVIOUS_DS 28(%ebp)
#define PREVIOUS_ES 30(%ebp)
#define PREVIOUS_FS 32(%ebp)
#define PREVIOUS_GS 34(%ebp)
#define PREVIOUS_SS 36(%ebp)
/* Fixup TSS type field */
#define TSS_TYPEFIX_MASK 0xf9
xorl %esi,%esi
movl PHYSICAL_GDT_BASE,%ebx
movw TASK_REGISTER,%si
leal (%ebx,%esi),%eax /* get TSS segment descriptor */
andb $TSS_TYPEFIX_MASK,5(%eax)
/* Prepare to return to sleep/wakeup code point */
lgdtl PREVIOUS_GDT
lidtl PREVIOUS_IDT
/* Pack values from the GDT to be loaded into segment registers. */
movl PREVIOUS_DS,%ebx
movl PREVIOUS_FS,%ecx
movl PREVIOUS_SS,%edx
movw TASK_REGISTER,%si
shll $16,%esi
movw PREVIOUS_LDT,%si
movl RECOVER_ADDR,%edi
/* Enable paging and etc. */
movl CR0_REGISTER,%eax
movl %eax,%cr0
/* Flush the prefetch queue */
jmp 1f
1: jmp 1f
/* Re-start in case the previous BIOS call clobbers them. */
jmp wakeup_start
1:
/*
* Now we are in kernel virtual memory addressing with the following
* original register values:
* %ebx: ds + es
* %ecx: fs + gs
* %edx: ss + dummy
* %esi: LDTR + TR
* %edi: recover address
* We'll load these back into the segment registers now.
* Find relocation base and patch the gdt descript and ljmp targets
*/
nop
xorl %ebx, %ebx
mov %cs, %bx
sall $4, %ebx /* %ebx is now our relocation base */
movl %esi,%eax /* LDTR + TR */
lldt %ax /* load LDT register */
shrl $16,%eax
ltr %ax /* load task register */
/*
* Load the descriptor table pointer. We'll need it when running
* in 16-bit protected mode.
*/
lgdtl bootgdtdesc - wakeup_start
/* Restore segment registers */
movl %ebx,%eax /* ds + es */
movw %ax,%ds
shrl $16,%eax
movw %ax,%es
movl %ecx,%eax /* fs + gs */
movw %ax,%fs
shrl $16,%eax
movw %ax,%gs
movl %edx,%eax /* ss */
movw %ax,%ss
/* Enable protected mode */
movl $CR0_PE, %eax
mov %eax, %cr0
/* Jump to acpi_restorecpu() */
/*
* Now execute a far jump to turn on protected mode. This
* causes the segment registers to turn into selectors and causes
* %cs to be loaded from the gdt.
*
* The following instruction is:
* ljmpl $bootcode32 - bootgdt, $wakeup_32 - wakeup_start
* but gas cannot assemble that. And besides, we patch the targets
* in early startup and its a little clearer what we are patching.
*/
wakeup_sw32:
.byte 0x66 /* size override to 32 bits */
.byte 0xea /* opcode for far jump */
.long wakeup_32 - wakeup_start /* offset in segment */
.word bootcode32 - bootgdt /* index in gdt for 32 bit code */
/*
* At this point, we are running in 32 bit legacy protected mode.
*/
ALIGN_TEXT
.code32
wakeup_32:
mov $bootdata32 - bootgdt, %eax
mov %ax, %ds
/* Get PCB and return address. */
movl wakeup_pcb - wakeup_start(%ebx), %esi
movl wakeup_ret - wakeup_start(%ebx), %edi
/* Restore CR4 and CR3. */
movl wakeup_cr4 - wakeup_start(%ebx), %eax
mov %eax, %cr4
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.
*/
mov %cr0, %eax
orl $CR0_PG, %eax
mov %eax, %cr0
jmp 1f
1:
/* Jump to return address. */
jmp *%edi
/* used in real mode */
physical_gdt: .word 0
.long 0
physical_esp: .long 0
previous_cr2: .long 0
previous_cr3: .long 0
previous_cr4: .long 0
resume_beep: .long 0
reset_video: .long 0
.data
/*
* Transfer from real mode to protected mode. The order of these variables
* is very important, DO NOT INSERT OR CHANGE unless you know why.
*/
previous_cr0: .long 0
previous_tr: .word 0
previous_gdt: .word 0
.long 0
previous_ldt: .word 0
previous_idt: .word 0
.long 0
where_to_recover: .long 0
previous_ds: .word 0
previous_es: .word 0
previous_fs: .word 0
previous_gs: .word 0
previous_ss: .word 0
dummy: .word 0
resume_beep:
.byte 0
reset_video:
.byte 0
ALIGN_DATA
bootgdt:
.long 0x00000000
.long 0x00000000
bootcode32:
.long 0x0000ffff
.long 0x00cf9b00
bootdata32:
.long 0x0000ffff
.long 0x00cf9300
bootgdtend:
bootgdtdesc:
.word bootgdtend - bootgdt /* Length */
.long bootgdt - wakeup_start /* Offset plus %ds << 4 */
ALIGN_DATA
wakeup_cr4:
.long 0
wakeup_cr3:
.long 0
wakeup_pcb:
.long 0
wakeup_ret:
.long 0
dummy:

View File

@ -1,6 +1,8 @@
/*-
* Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org>
* Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
* Copyright (c) 2001-2012 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
* Copyright (c) 2003 Peter Wemm
* Copyright (c) 2008-2012 Jung-uk Kim <jkim@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -29,26 +31,29 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/lock.h>
#include <sys/eventhandler.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/memrange.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
#include <sys/smp.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <vm/vm_object.h>
#include <vm/vm_page.h>
#include <vm/vm_map.h>
#include <machine/bus.h>
#include <machine/cpufunc.h>
#include <machine/clock.h>
#include <machine/intr_machdep.h>
#include <x86/mca.h>
#include <machine/segments.h>
#include <machine/pcb.h>
#include <machine/pmap.h>
#include <machine/specialreg.h>
#include <machine/md_var.h>
#ifdef SMP
#include <x86/apicreg.h>
#include <machine/smp.h>
#include <machine/vmparam.h>
#endif
#include <contrib/dev/acpica/include/acpi.h>
@ -57,164 +62,186 @@ __FBSDID("$FreeBSD$");
#include "acpi_wakecode.h"
#include "acpi_wakedata.h"
/* Make sure the code is less than one page and leave room for the stack. */
/* Make sure the code is less than a page and leave room for the stack. */
CTASSERT(sizeof(wakecode) < PAGE_SIZE - 1024);
#ifndef _SYS_CDEFS_H_
#error this file needs sys/cdefs.h as a prerequisite
extern int acpi_resume_beep;
extern int acpi_reset_video;
#ifdef SMP
extern struct pcb **susppcbs;
#else
static struct pcb **susppcbs;
#endif
extern uint32_t acpi_resume_beep;
extern uint32_t acpi_reset_video;
extern void initializecpu(void);
static void *acpi_alloc_wakeup_handler(void);
static void acpi_stop_beep(void *);
static struct region_descriptor __used saved_idt, saved_gdt;
static struct region_descriptor *p_gdt;
static uint16_t __used saved_ldt;
#ifdef SMP
static int acpi_wakeup_ap(struct acpi_softc *, int);
static void acpi_wakeup_cpus(struct acpi_softc *, const cpuset_t *);
#endif
static uint32_t __used r_eax, r_ebx, r_ecx, r_edx, r_ebp, r_esi, r_edi,
r_efl, r_cr0, r_cr2, r_cr3, r_cr4, ret_addr;
static uint16_t __used r_cs, r_ds, r_es, r_fs, r_gs, r_ss, r_tr;
static uint32_t __used r_esp;
static void acpi_printcpu(void);
static void acpi_realmodeinst(void *arg, bus_dma_segment_t *segs,
int nsegs, int error);
static void acpi_alloc_wakeup_handler(void);
/* XXX shut gcc up */
extern int acpi_savecpu(void);
extern int acpi_restorecpu(void);
#ifdef __GNUCLIKE_ASM
__asm__(" \n\
.text \n\
.p2align 2, 0x90 \n\
.type acpi_restorecpu, @function\n\
acpi_restorecpu: \n\
.align 4 \n\
movl r_eax,%eax \n\
movl r_ebx,%ebx \n\
movl r_ecx,%ecx \n\
movl r_edx,%edx \n\
movl r_ebp,%ebp \n\
movl r_esi,%esi \n\
movl r_edi,%edi \n\
movl r_esp,%esp \n\
\n\
pushl r_efl \n\
popfl \n\
\n\
movl ret_addr,%eax \n\
movl %eax,(%esp) \n\
xorl %eax,%eax \n\
ret \n\
\n\
.text \n\
.p2align 2, 0x90 \n\
.type acpi_savecpu, @function \n\
acpi_savecpu: \n\
movw %cs,r_cs \n\
movw %ds,r_ds \n\
movw %es,r_es \n\
movw %fs,r_fs \n\
movw %gs,r_gs \n\
movw %ss,r_ss \n\
\n\
movl %eax,r_eax \n\
movl %ebx,r_ebx \n\
movl %ecx,r_ecx \n\
movl %edx,r_edx \n\
movl %ebp,r_ebp \n\
movl %esi,r_esi \n\
movl %edi,r_edi \n\
\n\
movl %cr0,%eax \n\
movl %eax,r_cr0 \n\
movl %cr2,%eax \n\
movl %eax,r_cr2 \n\
movl %cr3,%eax \n\
movl %eax,r_cr3 \n\
movl %cr4,%eax \n\
movl %eax,r_cr4 \n\
\n\
pushfl \n\
popl r_efl \n\
\n\
movl %esp,r_esp \n\
\n\
sgdt saved_gdt \n\
sidt saved_idt \n\
sldt saved_ldt \n\
str r_tr \n\
\n\
movl (%esp),%eax \n\
movl %eax,ret_addr \n\
movl $1,%eax \n\
ret \n\
");
#endif /* __GNUCLIKE_ASM */
static void
acpi_printcpu(void)
{
printf("======== acpi_printcpu() debug dump ========\n");
printf("gdt[%04x:%08x] idt[%04x:%08x] ldt[%04x] tr[%04x] efl[%08x]\n",
saved_gdt.rd_limit, saved_gdt.rd_base,
saved_idt.rd_limit, saved_idt.rd_base,
saved_ldt, r_tr, r_efl);
printf("eax[%08x] ebx[%08x] ecx[%08x] edx[%08x]\n",
r_eax, r_ebx, r_ecx, r_edx);
printf("esi[%08x] edi[%08x] ebp[%08x] esp[%08x]\n",
r_esi, r_edi, r_ebp, r_esp);
printf("cr0[%08x] cr2[%08x] cr3[%08x] cr4[%08x]\n",
r_cr0, r_cr2, r_cr3, r_cr4);
printf("cs[%04x] ds[%04x] es[%04x] fs[%04x] gs[%04x] ss[%04x]\n",
r_cs, r_ds, r_es, r_fs, r_gs, r_ss);
}
#define WAKECODE_FIXUP(offset, type, val) do { \
type *addr; \
addr = (type *)(sc->acpi_wakeaddr + offset); \
*addr = val; \
#define ACPI_PAGETABLES 0
#define WAKECODE_VADDR(sc) ((sc)->acpi_wakeaddr + (ACPI_PAGETABLES * PAGE_SIZE))
#define WAKECODE_PADDR(sc) ((sc)->acpi_wakephys + (ACPI_PAGETABLES * PAGE_SIZE))
#define WAKECODE_FIXUP(offset, type, val) do { \
type *addr; \
addr = (type *)(WAKECODE_VADDR(sc) + offset); \
*addr = val; \
} while (0)
#define WAKECODE_BCOPY(offset, type, val) do { \
void *addr; \
addr = (void *)(sc->acpi_wakeaddr + offset); \
bcopy(&(val), addr, sizeof(type)); \
} while (0)
/* Turn off bits 1&2 of the PIT, stopping the beep. */
static void
acpi_stop_beep(void *arg)
{
outb(0x61, inb(0x61) & ~0x3);
if (acpi_resume_beep != 0)
timer_spkr_release();
}
#ifdef SMP
static int
acpi_wakeup_ap(struct acpi_softc *sc, int cpu)
{
int vector = (WAKECODE_PADDR(sc) >> 12) & 0xff;
int apic_id = cpu_apic_ids[cpu];
int ms;
WAKECODE_FIXUP(wakeup_pcb, struct pcb *, susppcbs[cpu]);
/* do an INIT IPI: assert RESET */
lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
APIC_LEVEL_ASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT, apic_id);
/* wait for pending status end */
lapic_ipi_wait(-1);
/* do an INIT IPI: deassert RESET */
lapic_ipi_raw(APIC_DEST_ALLESELF | APIC_TRIGMOD_LEVEL |
APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_INIT, 0);
/* wait for pending status end */
DELAY(10000); /* wait ~10mS */
lapic_ipi_wait(-1);
/*
* next we do a STARTUP IPI: the previous INIT IPI might still be
* latched, (P5 bug) this 1st STARTUP would then terminate
* immediately, and the previously started INIT IPI would continue. OR
* the previous INIT IPI has already run. and this STARTUP IPI will
* run. OR the previous INIT IPI was ignored. and this STARTUP IPI
* will run.
*/
/* do a STARTUP IPI */
lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
vector, apic_id);
lapic_ipi_wait(-1);
DELAY(200); /* wait ~200uS */
/*
* finally we do a 2nd STARTUP IPI: this 2nd STARTUP IPI should run IF
* the previous STARTUP IPI was cancelled by a latched INIT IPI. OR
* this STARTUP IPI will be ignored, as only ONE STARTUP IPI is
* recognized after hardware RESET or INIT IPI.
*/
lapic_ipi_raw(APIC_DEST_DESTFLD | APIC_TRIGMOD_EDGE |
APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP |
vector, apic_id);
lapic_ipi_wait(-1);
DELAY(200); /* wait ~200uS */
/* Wait up to 5 seconds for it to start. */
for (ms = 0; ms < 5000; ms++) {
if (susppcbs[cpu]->pcb_eip == 0)
return (1); /* return SUCCESS */
DELAY(1000);
}
return (0); /* return FAILURE */
}
#define WARMBOOT_TARGET 0
#define WARMBOOT_OFF (KERNBASE + 0x0467)
#define WARMBOOT_SEG (KERNBASE + 0x0469)
#define CMOS_REG (0x70)
#define CMOS_DATA (0x71)
#define BIOS_RESET (0x0f)
#define BIOS_WARM (0x0a)
static void
acpi_wakeup_cpus(struct acpi_softc *sc, const cpuset_t *wakeup_cpus)
{
uint32_t mpbioswarmvec;
int cpu;
u_char mpbiosreason;
/* save the current value of the warm-start vector */
mpbioswarmvec = *((uint32_t *)WARMBOOT_OFF);
outb(CMOS_REG, BIOS_RESET);
mpbiosreason = inb(CMOS_DATA);
/* setup a vector to our boot code */
*((volatile u_short *)WARMBOOT_OFF) = WARMBOOT_TARGET;
*((volatile u_short *)WARMBOOT_SEG) = WAKECODE_PADDR(sc) >> 4;
outb(CMOS_REG, BIOS_RESET);
outb(CMOS_DATA, BIOS_WARM); /* 'warm-start' */
/* Wake up each AP. */
for (cpu = 1; cpu < mp_ncpus; cpu++) {
if (!CPU_ISSET(cpu, wakeup_cpus))
continue;
if (acpi_wakeup_ap(sc, cpu) == 0) {
/* restore the warmstart vector */
*(uint32_t *)WARMBOOT_OFF = mpbioswarmvec;
panic("acpi_wakeup: failed to resume AP #%d (PHY #%d)",
cpu, cpu_apic_ids[cpu]);
}
}
/* restore the warmstart vector */
*(uint32_t *)WARMBOOT_OFF = mpbioswarmvec;
outb(CMOS_REG, BIOS_RESET);
outb(CMOS_DATA, mpbiosreason);
}
#endif
int
acpi_sleep_machdep(struct acpi_softc *sc, int state)
{
ACPI_STATUS status;
struct pmap *pm;
int ret;
uint32_t cr3;
u_long ef;
#ifdef SMP
cpuset_t wakeup_cpus;
#endif
register_t cr3, rf;
ACPI_STATUS status;
struct pmap *pm;
int ret;
ret = -1;
if (sc->acpi_wakeaddr == 0)
if (sc->acpi_wakeaddr == 0ul)
return (ret);
AcpiSetFirmwareWakingVector(sc->acpi_wakephys);
#ifdef SMP
wakeup_cpus = all_cpus;
CPU_CLR(PCPU_GET(cpuid), &wakeup_cpus);
#endif
ef = intr_disable();
if (acpi_resume_beep != 0)
timer_spkr_acquire();
AcpiSetFirmwareWakingVector(WAKECODE_PADDR(sc));
rf = intr_disable();
intr_suspend();
/*
* Temporarily switch to the kernel pmap because it provides an
* identity mapping (setup at boot) for the low physical memory
* region containing the wakeup code.
* Temporarily switch to the kernel pmap because it provides
* an identity mapping (setup at boot) for the low physical
* memory region containing the wakeup code.
*/
pm = kernel_pmap;
cr3 = rcr3();
@ -224,39 +251,22 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
load_cr3(vtophys(pm->pm_pdir));
#endif
ret_addr = 0;
if (acpi_savecpu()) {
/* Execute Sleep */
if (suspendctx(susppcbs[0])) {
#ifdef SMP
if (!CPU_EMPTY(&wakeup_cpus) &&
suspend_cpus(wakeup_cpus) == 0) {
device_printf(sc->acpi_dev, "Failed to suspend APs\n");
goto out;
}
#endif
p_gdt = (struct region_descriptor *)
(sc->acpi_wakeaddr + physical_gdt);
p_gdt->rd_limit = saved_gdt.rd_limit;
p_gdt->rd_base = vtophys(saved_gdt.rd_base);
WAKECODE_FIXUP(resume_beep, uint8_t, (acpi_resume_beep != 0));
WAKECODE_FIXUP(reset_video, uint8_t, (acpi_reset_video != 0));
WAKECODE_FIXUP(physical_esp, uint32_t, vtophys(r_esp));
WAKECODE_FIXUP(previous_cr0, uint32_t, r_cr0);
WAKECODE_FIXUP(previous_cr2, uint32_t, r_cr2);
WAKECODE_FIXUP(previous_cr3, uint32_t, r_cr3);
WAKECODE_FIXUP(previous_cr4, uint32_t, r_cr4);
WAKECODE_FIXUP(wakeup_cr4, register_t, susppcbs[0]->pcb_cr4);
WAKECODE_FIXUP(wakeup_cr3, register_t, susppcbs[0]->pcb_cr3);
WAKECODE_FIXUP(resume_beep, uint32_t, acpi_resume_beep);
WAKECODE_FIXUP(reset_video, uint32_t, acpi_reset_video);
WAKECODE_FIXUP(previous_tr, uint16_t, r_tr);
WAKECODE_BCOPY(previous_gdt, struct region_descriptor, saved_gdt);
WAKECODE_FIXUP(previous_ldt, uint16_t, saved_ldt);
WAKECODE_BCOPY(previous_idt, struct region_descriptor, saved_idt);
WAKECODE_FIXUP(where_to_recover, void *, acpi_restorecpu);
WAKECODE_FIXUP(previous_ds, uint16_t, r_ds);
WAKECODE_FIXUP(previous_es, uint16_t, r_es);
WAKECODE_FIXUP(previous_fs, uint16_t, r_fs);
WAKECODE_FIXUP(previous_gs, uint16_t, r_gs);
WAKECODE_FIXUP(previous_ss, uint16_t, r_ss);
if (bootverbose)
acpi_printcpu();
WAKECODE_FIXUP(wakeup_pcb, struct pcb *, susppcbs[0]);
/* Call ACPICA to enter the desired sleep state */
if (state == ACPI_STATE_S4 && sc->acpi_s4bios)
@ -266,8 +276,8 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
if (status != AE_OK) {
device_printf(sc->acpi_dev,
"AcpiEnterSleepState failed - %s\n",
AcpiFormatException(status));
"AcpiEnterSleepState failed - %s\n",
AcpiFormatException(status));
goto out;
}
@ -275,97 +285,96 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
ia32_pause();
} else {
pmap_init_pat();
initializecpu();
PCPU_SET(switchtime, 0);
PCPU_SET(switchticks, ticks);
if (bootverbose) {
acpi_savecpu();
acpi_printcpu();
}
#ifdef SMP
if (!CPU_EMPTY(&wakeup_cpus))
acpi_wakeup_cpus(sc, &wakeup_cpus);
#endif
ret = 0;
}
out:
#ifdef SMP
if (!CPU_EMPTY(&wakeup_cpus))
restart_cpus(wakeup_cpus);
#endif
load_cr3(cr3);
mca_resume();
intr_resume();
intr_restore(ef);
intr_restore(rf);
AcpiSetFirmwareWakingVector(0);
if (ret == 0 && mem_range_softc.mr_op != NULL &&
mem_range_softc.mr_op->reinit != NULL)
mem_range_softc.mr_op->reinit(&mem_range_softc);
/* If we beeped, turn it off after a delay. */
if (acpi_resume_beep)
timeout(acpi_stop_beep, NULL, 3 * hz);
return (ret);
}
static bus_dma_tag_t acpi_waketag;
static bus_dmamap_t acpi_wakemap;
static vm_offset_t acpi_wakeaddr;
static void
static void *
acpi_alloc_wakeup_handler(void)
{
void *wakeaddr;
if (!cold)
return;
void *wakeaddr;
int i;
/*
* Specify the region for our wakeup code. We want it in the low 1 MB
* region, excluding video memory and above (0xa0000). We ask for
* it to be page-aligned, just to be safe.
* region, excluding real mode IVT (0-0x3ff), BDA (0x400-0x4ff), EBDA
* (less than 128KB, below 0xa0000, must be excluded by SMAP and DSDT),
* and ROM area (0xa0000 and above). The temporary page tables must be
* page-aligned.
*/
if (bus_dma_tag_create(/*parent*/ NULL,
/*alignment*/ PAGE_SIZE, /*no boundary*/ 0,
/*lowaddr*/ 0x9ffff, /*highaddr*/ BUS_SPACE_MAXADDR, NULL, NULL,
/*maxsize*/ PAGE_SIZE, /*segments*/ 1, /*maxsegsize*/ PAGE_SIZE,
0, busdma_lock_mutex, &Giant, &acpi_waketag) != 0) {
printf("acpi_alloc_wakeup_handler: can't create wake tag\n");
return;
wakeaddr = contigmalloc((ACPI_PAGETABLES + 1) * PAGE_SIZE, M_DEVBUF,
M_NOWAIT, 0x500, 0xa0000, PAGE_SIZE, 0ul);
if (wakeaddr == NULL) {
printf("%s: can't alloc wake memory\n", __func__);
return (NULL);
}
if (bus_dmamem_alloc(acpi_waketag, &wakeaddr, BUS_DMA_NOWAIT,
&acpi_wakemap) != 0) {
printf("acpi_alloc_wakeup_handler: can't alloc wake memory\n");
return;
if (EVENTHANDLER_REGISTER(power_resume, acpi_stop_beep, NULL,
EVENTHANDLER_PRI_LAST) == NULL) {
printf("%s: can't register event handler\n", __func__);
contigfree(wakeaddr, (ACPI_PAGETABLES + 1) * PAGE_SIZE, M_DEVBUF);
return (NULL);
}
acpi_wakeaddr = (vm_offset_t)wakeaddr;
}
SYSINIT(acpiwakeup, SI_SUB_KMEM, SI_ORDER_ANY, acpi_alloc_wakeup_handler, 0);
static void
acpi_realmodeinst(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
{
struct acpi_softc *sc;
uint32_t *addr;
/* Overwrite the ljmp target with the real address */
sc = arg;
sc->acpi_wakephys = segs[0].ds_addr;
addr = (uint32_t *)&wakecode[wakeup_sw32 + 2];
*addr = sc->acpi_wakephys + wakeup_32;
/* Copy the wake code into our low page and save its physical addr. */
bcopy(wakecode, (void *)sc->acpi_wakeaddr, sizeof(wakecode));
if (bootverbose) {
device_printf(sc->acpi_dev, "wakeup code va %#x pa %#jx\n",
acpi_wakeaddr, (uintmax_t)sc->acpi_wakephys);
susppcbs = malloc(mp_ncpus * sizeof(*susppcbs), M_DEVBUF, M_WAITOK);
for (i = 0; i < mp_ncpus; i++) {
susppcbs[i] = malloc(sizeof(**susppcbs), M_DEVBUF, M_WAITOK);
}
return (wakeaddr);
}
void
acpi_install_wakeup_handler(struct acpi_softc *sc)
{
if (acpi_wakeaddr == 0)
static void *wakeaddr = NULL;
if (wakeaddr != NULL)
return;
sc->acpi_waketag = acpi_waketag;
sc->acpi_wakeaddr = acpi_wakeaddr;
sc->acpi_wakemap = acpi_wakemap;
wakeaddr = acpi_alloc_wakeup_handler();
if (wakeaddr == NULL)
return;
bus_dmamap_load(sc->acpi_waketag, sc->acpi_wakemap,
(void *)sc->acpi_wakeaddr, PAGE_SIZE, acpi_realmodeinst, sc, 0);
sc->acpi_wakeaddr = (vm_offset_t)wakeaddr;
sc->acpi_wakephys = vtophys(wakeaddr);
bcopy(wakecode, (void *)WAKECODE_VADDR(sc), sizeof(wakecode));
/* Patch GDT base address, ljmp target. */
WAKECODE_FIXUP((bootgdtdesc + 2), uint32_t,
WAKECODE_PADDR(sc) + bootgdt);
WAKECODE_FIXUP((wakeup_sw32 + 2), uint32_t,
WAKECODE_PADDR(sc) + wakeup_32);
/* Save pointers to some global data. */
WAKECODE_FIXUP(wakeup_ret, void *, resumectx);
if (bootverbose)
device_printf(sc->acpi_dev, "wakeup code va %p pa %p\n",
(void *)sc->acpi_wakeaddr, (void *)sc->acpi_wakephys);
}

View File

@ -333,6 +333,24 @@ IDTVEC(cpustop)
POP_FRAME
iret
/*
* Executed by a CPU when it receives an IPI_SUSPEND from another CPU.
*/
.text
SUPERALIGN_TEXT
IDTVEC(cpususpend)
PUSH_FRAME
SET_KERNEL_SREGS
cld
movl lapic, %eax
movl $0, LA_EOI(%eax) /* End Of Interrupt to APIC */
call cpususpend_handler
POP_FRAME
jmp doreti_iret
/*
* Executed by a CPU when it receives a RENDEZVOUS IPI from another CPU.
*

View File

@ -121,7 +121,10 @@ ASSYM(VM_MAXUSER_ADDRESS, VM_MAXUSER_ADDRESS);
ASSYM(KERNBASE, KERNBASE);
ASSYM(KERNLOAD, KERNLOAD);
ASSYM(MCLBYTES, MCLBYTES);
ASSYM(PCB_CR0, offsetof(struct pcb, pcb_cr0));
ASSYM(PCB_CR2, offsetof(struct pcb, pcb_cr2));
ASSYM(PCB_CR3, offsetof(struct pcb, pcb_cr3));
ASSYM(PCB_CR4, offsetof(struct pcb, pcb_cr4));
ASSYM(PCB_EDI, offsetof(struct pcb, pcb_edi));
ASSYM(PCB_ESI, offsetof(struct pcb, pcb_esi));
ASSYM(PCB_EBP, offsetof(struct pcb, pcb_ebp));
@ -130,7 +133,11 @@ ASSYM(PCB_EBX, offsetof(struct pcb, pcb_ebx));
ASSYM(PCB_EIP, offsetof(struct pcb, pcb_eip));
ASSYM(TSS_ESP0, offsetof(struct i386tss, tss_esp0));
ASSYM(PCB_DS, offsetof(struct pcb, pcb_ds));
ASSYM(PCB_ES, offsetof(struct pcb, pcb_es));
ASSYM(PCB_FS, offsetof(struct pcb, pcb_fs));
ASSYM(PCB_GS, offsetof(struct pcb, pcb_gs));
ASSYM(PCB_SS, offsetof(struct pcb, pcb_ss));
ASSYM(PCB_DR0, offsetof(struct pcb, pcb_dr0));
ASSYM(PCB_DR1, offsetof(struct pcb, pcb_dr1));
ASSYM(PCB_DR2, offsetof(struct pcb, pcb_dr2));
@ -143,6 +150,7 @@ ASSYM(PCB_DBREGS, PCB_DBREGS);
ASSYM(PCB_EXT, offsetof(struct pcb, pcb_ext));
ASSYM(PCB_FSD, offsetof(struct pcb, pcb_fsd));
ASSYM(PCB_GSD, offsetof(struct pcb, pcb_gsd));
ASSYM(PCB_VM86, offsetof(struct pcb, pcb_vm86));
ASSYM(PCB_FLAGS, offsetof(struct pcb, pcb_flags));
ASSYM(PCB_SAVEFPU, offsetof(struct pcb, pcb_save));
@ -152,6 +160,11 @@ ASSYM(PCB_ONFAULT, offsetof(struct pcb, pcb_onfault));
ASSYM(PCB_SIZE, sizeof(struct pcb));
ASSYM(PCB_VM86CALL, PCB_VM86CALL);
ASSYM(PCB_GDT, offsetof(struct pcb, pcb_gdt));
ASSYM(PCB_IDT, offsetof(struct pcb, pcb_idt));
ASSYM(PCB_LDT, offsetof(struct pcb, pcb_ldt));
ASSYM(PCB_TR, offsetof(struct pcb, pcb_tr));
ASSYM(TF_TRAPNO, offsetof(struct trapframe, tf_trapno));
ASSYM(TF_ERR, offsetof(struct trapframe, tf_err));
ASSYM(TF_EIP, offsetof(struct trapframe, tf_eip));

View File

@ -48,7 +48,6 @@ __FBSDID("$FreeBSD$");
#define CPU_ENABLE_SSE
#endif
void initializecpu(void);
#if defined(I586_CPU) && defined(CPU_WT_ALLOC)
void enable_K5_wt_alloc(void);
void enable_K6_wt_alloc(void);

View File

@ -180,7 +180,6 @@ extern void dblfault_handler(void);
extern void printcpuinfo(void); /* XXX header file */
extern void finishidentcpu(void);
extern void panicifcpuunsupported(void);
extern void initializecpu(void);
#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL)
#define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)

View File

@ -146,6 +146,7 @@ void *bootstacks[MAXCPU];
static void *dpcpu;
struct pcb stoppcbs[MAXCPU];
struct pcb **susppcbs = NULL;
/* Variables needed for SMP tlb shootdown. */
vm_offset_t smp_tlb_addr1;
@ -587,6 +588,9 @@ cpu_mp_start(void)
setidt(IPI_STOP, IDTVEC(cpustop),
SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
/* Install an inter-CPU IPI for CPU suspend/resume */
setidt(IPI_SUSPEND, IDTVEC(cpususpend),
SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
/* Set boot_cpu_id if needed. */
if (boot_cpu_id == -1) {
@ -1497,6 +1501,38 @@ cpustop_handler(void)
}
}
/*
* Handle an IPI_SUSPEND by saving our current context and spinning until we
* are resumed.
*/
void
cpususpend_handler(void)
{
u_int cpu;
cpu = PCPU_GET(cpuid);
if (suspendctx(susppcbs[cpu])) {
wbinvd();
CPU_SET_ATOMIC(cpu, &stopped_cpus);
} else {
pmap_init_pat();
PCPU_SET(switchtime, 0);
PCPU_SET(switchticks, ticks);
susppcbs[cpu]->pcb_eip = 0;
}
/* Wait for resume */
while (!CPU_ISSET(cpu, &started_cpus))
ia32_pause();
CPU_CLR_ATOMIC(cpu, &started_cpus);
CPU_CLR_ATOMIC(cpu, &stopped_cpus);
/* Resume MCA and local APIC */
mca_resume();
lapic_setup(0);
}
/*
* This is called once the rest of the system is up and running and we're
* ready to let the AP's out of the pen.

View File

@ -427,3 +427,140 @@ ENTRY(savectx)
ret
END(savectx)
/*
* suspendctx(pcb)
* Update pcb, suspending current processor state.
*/
ENTRY(suspendctx)
/* Fetch PCB. */
movl 4(%esp),%ecx
/* Save context by calling savectx(). */
pushl %ecx
call savectx
addl $4,%esp
/* Fetch PCB again. */
movl 4(%esp),%ecx
/* Update caller's return address and stack pointer. */
movl (%esp),%eax
movl %eax,PCB_EIP(%ecx)
movl %esp,PCB_ESP(%ecx)
/* Save other registers and descriptor tables. */
movl %cr0,%eax
movl %eax,PCB_CR0(%ecx)
movl %cr2,%eax
movl %eax,PCB_CR2(%ecx)
movl %cr4,%eax
movl %eax,PCB_CR4(%ecx)
movl %dr0,%eax
movl %eax,PCB_DR0(%ecx)
movl %dr1,%eax
movl %eax,PCB_DR1(%ecx)
movl %dr2,%eax
movl %eax,PCB_DR2(%ecx)
movl %dr3,%eax
movl %eax,PCB_DR3(%ecx)
movl %dr6,%eax
movl %eax,PCB_DR6(%ecx)
movl %dr7,%eax
movl %eax,PCB_DR7(%ecx)
mov %ds,PCB_DS(%ecx)
mov %es,PCB_ES(%ecx)
mov %fs,PCB_FS(%ecx)
mov %ss,PCB_SS(%ecx)
sgdt PCB_GDT(%ecx)
sidt PCB_IDT(%ecx)
sldt PCB_LDT(%ecx)
str PCB_TR(%ecx)
movl $1,%eax
ret
END(suspendctx)
/*
* resumectx(pcb in %esi)
* Resuming processor state from pcb.
*/
ENTRY(resumectx)
/* Fetch PCB. */
movl %esi,%ecx
/* Restore GDT. */
lgdt PCB_GDT(%ecx)
/* Restore segment registers */
movzwl PCB_DS(%ecx),%eax
mov %ax,%ds
movzwl PCB_ES(%ecx),%eax
mov %ax,%es
movzwl PCB_FS(%ecx),%eax
mov %ax,%fs
movzwl PCB_GS(%ecx),%eax
movw %ax,%gs
movzwl PCB_SS(%ecx),%eax
mov %ax,%ss
/* Restore CR2, CR4, CR3 and CR0 */
movl PCB_CR2(%ecx),%eax
movl %eax,%cr2
movl PCB_CR4(%ecx),%eax
movl %eax,%cr4
movl PCB_CR3(%ecx),%eax
movl %eax,%cr3
movl PCB_CR0(%ecx),%eax
movl %eax,%cr0
jmp 1f
1:
/* Restore descriptor tables */
lidt PCB_IDT(%ecx)
lldt PCB_LDT(%ecx)
#define SDT_SYS386TSS 9
#define SDT_SYS386BSY 11
/* Clear "task busy" bit and reload TR */
movl PCPU(TSS_GDT),%eax
andb $(~SDT_SYS386BSY | SDT_SYS386TSS),5(%eax)
movzwl PCB_TR(%ecx),%eax
ltr %ax
#undef SDT_SYS386TSS
#undef SDT_SYS386BSY
/* Restore debug registers */
movl PCB_DR0(%ecx),%eax
movl %eax,%dr0
movl PCB_DR1(%ecx),%eax
movl %eax,%dr1
movl PCB_DR2(%ecx),%eax
movl %eax,%dr2
movl PCB_DR3(%ecx),%eax
movl %eax,%dr3
movl PCB_DR6(%ecx),%eax
movl %eax,%dr6
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
movl PCB_EBP(%ecx),%ebp
movl PCB_ESP(%ecx),%esp
movl PCB_EBX(%ecx),%ebx
/* reload code selector by turning return into intersegmental return */
pushl PCB_EIP(%ecx)
movl $KCSEL,4(%esp)
xorl %eax,%eax
lret
END(resumectx)

View File

@ -126,7 +126,8 @@
#define IPI_IS_BITMAPED(x) ((x) <= IPI_BITMAP_LAST)
#define IPI_STOP (APIC_IPI_INTS + 7) /* Stop CPU until restarted. */
#define IPI_STOP_HARD (APIC_IPI_INTS + 8) /* Stop CPU with a NMI. */
#define IPI_SUSPEND (APIC_IPI_INTS + 8) /* Suspend CPU until restarted. */
#define IPI_STOP_HARD (APIC_IPI_INTS + 9) /* Stop CPU with a NMI. */
/*
* The spurious interrupt can share the priority class with the IPIs since

View File

@ -91,6 +91,7 @@ void doreti_popl_fs(void) __asm(__STRING(doreti_popl_fs));
void doreti_popl_fs_fault(void) __asm(__STRING(doreti_popl_fs_fault));
void dump_add_page(vm_paddr_t);
void dump_drop_page(vm_paddr_t);
void initializecpu(void);
void enable_sse(void);
void fillw(int /*u_short*/ pat, void *base, size_t cnt);
void i686_pagezero(void *addr);

View File

@ -45,7 +45,10 @@
#include <machine/npx.h>
struct pcb {
int pcb_cr0;
int pcb_cr2;
int pcb_cr3;
int pcb_cr4;
int pcb_edi;
int pcb_esi;
int pcb_ebp;
@ -71,13 +74,22 @@ struct pcb {
#define PCB_KERNNPX 0x40 /* kernel uses npx */
caddr_t pcb_onfault; /* copyin/out fault recovery */
int pcb_ds;
int pcb_es;
int pcb_fs;
int pcb_gs;
int pcb_ss;
struct segment_descriptor pcb_fsd;
struct segment_descriptor pcb_gsd;
struct pcb_ext *pcb_ext; /* optional pcb extension */
int pcb_psl; /* process status long */
u_long pcb_vm86[2]; /* vm86bios scratch space */
union savefpu *pcb_save;
struct region_descriptor pcb_gdt;
struct region_descriptor pcb_idt;
uint16_t pcb_ldt;
uint16_t pcb_tr;
};
#ifdef _KERNEL
@ -85,6 +97,8 @@ struct trapframe;
void makectx(struct trapframe *, struct pcb *);
void savectx(struct pcb *) __returns_twice;
int suspendctx(struct pcb *) __returns_twice;
void resumectx(struct pcb *);
#endif
#endif /* _I386_PCB_H_ */

View File

@ -53,12 +53,14 @@ inthand_t
IDTVEC(invlcache), /* Write back and invalidate cache */
IDTVEC(ipi_intr_bitmap_handler), /* Bitmap based IPIs */
IDTVEC(cpustop), /* CPU stops & waits to be restarted */
IDTVEC(cpususpend), /* CPU suspends & waits to be resumed */
IDTVEC(rendezvous), /* handle CPU rendezvous */
IDTVEC(lazypmap); /* handle lazy pmap release */
/* functions in mp_machdep.c */
void cpu_add(u_int apic_id, char boot_cpu);
void cpustop_handler(void);
void cpususpend_handler(void);
void init_secondary(void);
void ipi_all_but_self(u_int ipi);
#ifndef XEN

View File

@ -209,7 +209,7 @@ generic_stop_cpus(cpuset_t map, u_int type)
int i;
KASSERT(
#if defined(__amd64__)
#if defined(__amd64__) || defined(__i386__)
type == IPI_STOP || type == IPI_STOP_HARD || type == IPI_SUSPEND,
#else
type == IPI_STOP || type == IPI_STOP_HARD,
@ -260,7 +260,7 @@ stop_cpus_hard(cpuset_t map)
return (generic_stop_cpus(map, IPI_STOP_HARD));
}
#if defined(__amd64__)
#if defined(__amd64__) || defined(__i386__)
int
suspend_cpus(cpuset_t map)
{

View File

@ -151,7 +151,6 @@ extern void dblfault_handler(void);
extern void printcpuinfo(void); /* XXX header file */
extern void finishidentcpu(void);
extern void panicifcpuunsupported(void);
extern void initializecpu(void);
#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL)
#define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0)

View File

@ -163,7 +163,7 @@ void forward_signal(struct thread *);
int restart_cpus(cpuset_t);
int stop_cpus(cpuset_t);
int stop_cpus_hard(cpuset_t);
#if defined(__amd64__)
#if defined(__amd64__) || defined(__i386__)
int suspend_cpus(cpuset_t);
#endif
void smp_rendezvous_action(void);