Index: i386/acpica/acpi_wakecode.S =================================================================== RCS file: /home/ncvs/src/sys/i386/acpica/acpi_wakecode.S,v retrieving revision 1.14.2.1 diff -u -r1.14.2.1 acpi_wakecode.S --- i386/acpica/acpi_wakecode.S 23 Sep 2011 00:51:37 -0000 1.14.2.1 +++ i386/acpica/acpi_wakecode.S 17 May 2012 14:57:20 -0000 @@ -1,6 +1,8 @@ /*- * Copyright (c) 2001 Takanori Watanabe - * Copyright (c) 2001 Mitsuru IWASAKI + * Copyright (c) 2001-2012 Mitsuru IWASAKI + * Copyright (c) 2003 Peter Wemm + * Copyright (c) 2008-2012 Jung-uk Kim * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,7 +30,9 @@ */ #include +#include #include +#include #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 + + /* When we reach here, int 0x10 should be ready. Hide cursor. */ + movb $0x01, %ah + movb $0x20, %ch + int $0x10 + + /* Re-start in case the previous BIOS call clobbers them. */ + jmp wakeup_start +1: /* - * Set up segment registers for real mode again in case the - * previous BIOS call clobbers them. + * Find relocation base and patch the gdt descript and ljmp targets */ - movw %cs,%ax - movw %ax,%ds - movw %ax,%ss -nobiosreset: - - /* 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)) + xorl %ebx, %ebx + mov %cs, %bx + sall $4, %ebx /* %ebx is now our relocation base */ - mov physical_esp,%esi /* to be used in 32bit code */ + /* + * Load the descriptor table pointer. We'll need it when running + * in 16-bit protected mode. + */ + lgdtl bootgdtdesc - wakeup_start /* Enable protected mode */ - movl %cr0,%eax - orl $(CR0_PE),%eax - movl %eax,%cr0 + movl $CR0_PE, %eax + mov %eax, %cr0 + /* + * 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: - /* Switch to protected mode by intersegmental jump */ - ljmpl $KCSEL,$0x12345678 /* Code location, to be replaced */ + .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 */ /* - * Now switched to protected mode without paging enabled. - * %esi: KERNEL stack pointer (physical address) + * At this point, we are running in 32 bit legacy protected mode. */ + ALIGN_TEXT .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 + mov $bootdata32 - bootgdt, %eax + mov %ax, %ds - /* Flush the prefetch queue */ - jmp 1f -1: jmp 1f -1: + /* 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 /* - * 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. + * 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. */ - nop - - movl %esi,%eax /* LDTR + TR */ - lldt %ax /* load LDT register */ - shrl $16,%eax - ltr %ax /* load task register */ - - /* 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 + mov %cr0, %eax + orl $CR0_PG, %eax + mov %eax, %cr0 - /* Jump to acpi_restorecpu() */ + 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: Index: i386/acpica/acpi_wakeup.c =================================================================== RCS file: /home/ncvs/src/sys/i386/acpica/acpi_wakeup.c,v retrieving revision 1.53.2.2 diff -u -r1.53.2.2 acpi_wakeup.c --- i386/acpica/acpi_wakeup.c 11 Apr 2012 19:37:08 -0000 1.53.2.2 +++ i386/acpica/acpi_wakeup.c 17 May 2012 14:22:09 -0000 @@ -1,6 +1,8 @@ /*- * Copyright (c) 2001 Takanori Watanabe - * Copyright (c) 2001 Mitsuru IWASAKI + * Copyright (c) 2001-2012 Mitsuru IWASAKI + * Copyright (c) 2003 Peter Wemm + * Copyright (c) 2008-2012 Jung-uk Kim * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,26 +31,29 @@ __FBSDID("$FreeBSD: src/sys/i386/acpica/acpi_wakeup.c,v 1.53.2.2 2012/04/11 19:37:08 jhb Exp $"); #include -#include -#include #include -#include +#include +#include #include #include -#include -#include +#include #include #include -#include -#include -#include -#include -#include +#include #include #include -#include +#include +#include +#include +#include + +#ifdef SMP +#include +#include +#include +#endif #include @@ -57,164 +62,186 @@ #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 + +static void *acpi_alloc_wakeup_handler(void); +static void acpi_stop_beep(void *); + +#ifdef SMP +static int acpi_wakeup_ap(struct acpi_softc *, int); +static void acpi_wakeup_cpus(struct acpi_softc *, const cpuset_t *); #endif -extern uint32_t acpi_resume_beep; -extern uint32_t acpi_reset_video; -extern void initializecpu(void); - -static struct region_descriptor __used saved_idt, saved_gdt; -static struct region_descriptor *p_gdt; -static uint16_t __used saved_ldt; - -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 */ +#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) static void -acpi_printcpu(void) +acpi_stop_beep(void *arg) { - 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); + + if (acpi_resume_beep != 0) + timer_spkr_release(); } -#define WAKECODE_FIXUP(offset, type, val) do { \ - type *addr; \ - addr = (type *)(sc->acpi_wakeaddr + offset); \ - *addr = val; \ -} while (0) +#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); -#define WAKECODE_BCOPY(offset, type, val) do { \ - void *addr; \ - addr = (void *)(sc->acpi_wakeaddr + offset); \ - bcopy(&(val), addr, sizeof(type)); \ -} while (0) + /* + * 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) -/* Turn off bits 1&2 of the PIT, stopping the beep. */ static void -acpi_stop_beep(void *arg) +acpi_wakeup_cpus(struct acpi_softc *sc, const cpuset_t *wakeup_cpus) { - outb(0x61, inb(0x61) & ~0x3); + 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 + + if (acpi_resume_beep != 0) + timer_spkr_acquire(); - ef = intr_disable(); + 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 @@ load_cr3(vtophys(pm->pm_pdir)); #endif - ret_addr = 0; - if (acpi_savecpu()) { - /* Execute Sleep */ - - 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(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(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 (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 + + WAKECODE_FIXUP(resume_beep, uint8_t, (acpi_resume_beep != 0)); + WAKECODE_FIXUP(reset_video, uint8_t, (acpi_reset_video != 0)); + + WAKECODE_FIXUP(wakeup_cr4, register_t, susppcbs[0]->pcb_cr4); + WAKECODE_FIXUP(wakeup_cr3, register_t, susppcbs[0]->pcb_cr3); - 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 @@ 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 @@ 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; + + sc->acpi_wakeaddr = (vm_offset_t)wakeaddr; + sc->acpi_wakephys = vtophys(wakeaddr); + + bcopy(wakecode, (void *)WAKECODE_VADDR(sc), sizeof(wakecode)); - bus_dmamap_load(sc->acpi_waketag, sc->acpi_wakemap, - (void *)sc->acpi_wakeaddr, PAGE_SIZE, acpi_realmodeinst, sc, 0); + /* 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 %#x pa %#jx\n", + sc->acpi_wakeaddr, (uintmax_t)sc->acpi_wakephys); } Index: i386/i386/apic_vector.s =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/apic_vector.s,v retrieving revision 1.119.2.1 diff -u -r1.119.2.1 apic_vector.s --- i386/i386/apic_vector.s 23 Sep 2011 00:51:37 -0000 1.119.2.1 +++ i386/i386/apic_vector.s 15 May 2012 15:28:15 -0000 @@ -334,6 +334,24 @@ 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. * * - Calls the generic rendezvous action function. Index: i386/i386/genassym.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/genassym.c,v retrieving revision 1.170.2.1 diff -u -r1.170.2.1 genassym.c --- i386/i386/genassym.c 23 Sep 2011 00:51:37 -0000 1.170.2.1 +++ i386/i386/genassym.c 15 May 2012 15:28:15 -0000 @@ -121,7 +121,10 @@ 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_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_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_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)); Index: i386/i386/initcpu.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/initcpu.c,v retrieving revision 1.70.2.1 diff -u -r1.70.2.1 initcpu.c --- i386/i386/initcpu.c 23 Sep 2011 00:51:37 -0000 1.70.2.1 +++ i386/i386/initcpu.c 15 May 2012 15:28:15 -0000 @@ -48,7 +48,6 @@ #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); Index: i386/i386/machdep.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/machdep.c,v retrieving revision 1.736.2.6 diff -u -r1.736.2.6 machdep.c --- i386/i386/machdep.c 11 May 2012 04:10:23 -0000 1.736.2.6 +++ i386/i386/machdep.c 15 May 2012 17:31:05 -0000 @@ -180,7 +180,6 @@ 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) Index: i386/i386/mp_machdep.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/mp_machdep.c,v retrieving revision 1.328.2.3 diff -u -r1.328.2.3 mp_machdep.c --- i386/i386/mp_machdep.c 11 May 2012 04:10:23 -0000 1.328.2.3 +++ i386/i386/mp_machdep.c 17 May 2012 15:38:56 -0000 @@ -149,6 +149,7 @@ extern pt_entry_t *KPTphys; struct pcb stoppcbs[MAXCPU]; +struct pcb **susppcbs = NULL; /* Variables needed for SMP tlb shootdown. */ vm_offset_t smp_tlb_addr1; @@ -590,6 +591,9 @@ 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) { @@ -1505,6 +1509,38 @@ } /* + * 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. */ Index: i386/i386/swtch.s =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/swtch.s,v retrieving revision 1.160.2.1 diff -u -r1.160.2.1 swtch.s --- i386/i386/swtch.s 23 Sep 2011 00:51:37 -0000 1.160.2.1 +++ i386/i386/swtch.s 15 May 2012 15:57:03 -0000 @@ -427,3 +427,140 @@ 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) Index: i386/include/apicvar.h =================================================================== RCS file: /home/ncvs/src/sys/i386/include/apicvar.h,v retrieving revision 1.41.2.1 diff -u -r1.41.2.1 apicvar.h --- i386/include/apicvar.h 23 Sep 2011 00:51:37 -0000 1.41.2.1 +++ i386/include/apicvar.h 15 May 2012 15:28:15 -0000 @@ -128,7 +128,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. */ #else /* XEN */ /* These are the normal i386 APIC definitions */ @@ -155,7 +156,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. */ #endif /* XEN */ /* Index: i386/include/md_var.h =================================================================== RCS file: /home/ncvs/src/sys/i386/include/md_var.h,v retrieving revision 1.81.2.1 diff -u -r1.81.2.1 md_var.h --- i386/include/md_var.h 23 Sep 2011 00:51:37 -0000 1.81.2.1 +++ i386/include/md_var.h 17 May 2012 16:01:32 -0000 @@ -91,6 +91,7 @@ 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); Index: i386/include/pcb.h =================================================================== RCS file: /home/ncvs/src/sys/i386/include/pcb.h,v retrieving revision 1.59.2.1 diff -u -r1.59.2.1 pcb.h --- i386/include/pcb.h 23 Sep 2011 00:51:37 -0000 1.59.2.1 +++ i386/include/pcb.h 15 May 2012 15:28:15 -0000 @@ -45,7 +45,10 @@ #include 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 @@ #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 @@ void makectx(struct trapframe *, struct pcb *); void savectx(struct pcb *); +int suspendctx(struct pcb *); +void resumectx(struct pcb *); #endif #endif /* _I386_PCB_H_ */ Index: i386/include/smp.h =================================================================== RCS file: /home/ncvs/src/sys/i386/include/smp.h,v retrieving revision 1.103.2.1 diff -u -r1.103.2.1 smp.h --- i386/include/smp.h 23 Sep 2011 00:51:37 -0000 1.103.2.1 +++ i386/include/smp.h 15 May 2012 15:28:15 -0000 @@ -53,12 +53,14 @@ 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 Index: kern/subr_smp.c =================================================================== RCS file: /home/ncvs/src/sys/kern/subr_smp.c,v retrieving revision 1.233.2.2 diff -u -r1.233.2.2 subr_smp.c --- kern/subr_smp.c 23 Nov 2011 15:37:03 -0000 1.233.2.2 +++ kern/subr_smp.c 15 May 2012 15:28:15 -0000 @@ -208,7 +208,7 @@ 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, @@ -259,7 +259,7 @@ return (generic_stop_cpus(map, IPI_STOP_HARD)); } -#if defined(__amd64__) +#if defined(__amd64__) || defined(__i386__) int suspend_cpus(cpuset_t map) { Index: pc98/pc98/machdep.c =================================================================== RCS file: /home/ncvs/src/sys/pc98/pc98/machdep.c,v retrieving revision 1.450.2.4 diff -u -r1.450.2.4 machdep.c --- pc98/pc98/machdep.c 11 May 2012 04:10:23 -0000 1.450.2.4 +++ pc98/pc98/machdep.c 17 May 2012 16:04:54 -0000 @@ -151,7 +151,6 @@ 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) Index: sys/smp.h =================================================================== RCS file: /home/ncvs/src/sys/sys/smp.h,v retrieving revision 1.97.2.1 diff -u -r1.97.2.1 smp.h --- sys/smp.h 23 Sep 2011 00:51:37 -0000 1.97.2.1 +++ sys/smp.h 15 May 2012 15:28:15 -0000 @@ -163,7 +163,7 @@ 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);