Index: sys/amd64/include/intr_machdep.h =================================================================== --- sys/amd64/include/intr_machdep.h +++ sys/amd64/include/intr_machdep.h @@ -173,6 +173,7 @@ int intr_register_source(struct intsrc *isrc); int intr_remove_handler(void *cookie); void intr_resume(bool suspend_cancelled); +int intr_clear_all_handlers(void); void intr_suspend(void); void intr_reprogram(void); void intrcnt_add(const char *name, u_long **countp); Index: sys/kern/kern_module.c =================================================================== --- sys/kern/kern_module.c +++ sys/kern/kern_module.c @@ -63,7 +63,6 @@ static TAILQ_HEAD(modulelist, module) modules; struct sx modules_sx; static int nextid = 1; -static void module_shutdown(void *, int); static int modevent_nop(module_t mod, int what, void *arg) @@ -91,7 +90,7 @@ SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0); -static void +void module_shutdown(void *arg1, int arg2) { module_t mod; Index: sys/kern/kern_shutdown.c =================================================================== --- sys/kern/kern_shutdown.c +++ sys/kern/kern_shutdown.c @@ -318,6 +318,14 @@ { static int once = 0; + /* + * Do not use kload if we're coming to this code via panic + */ + if (panicstr == NULL) + howto |= RB_KLOAD; /* if kload is setup and ready */ + else + howto &= ~RB_KLOAD; /* do not use kload in panic situations */ + #if defined(SMP) /* * Bind us to CPU 0 so that all shutdown code runs there. Some Index: sys/sys/eventhandler.h =================================================================== --- sys/sys/eventhandler.h +++ sys/sys/eventhandler.h @@ -173,6 +173,7 @@ #define SHUTDOWN_PRI_FIRST EVENTHANDLER_PRI_FIRST #define SHUTDOWN_PRI_DEFAULT EVENTHANDLER_PRI_ANY #define SHUTDOWN_PRI_LAST EVENTHANDLER_PRI_LAST +#define SHUTDOWN_PRI_KLOAD EVENTHANDLER_PRI_LAST - 100 EVENTHANDLER_DECLARE(shutdown_pre_sync, shutdown_fn); /* before fs sync */ EVENTHANDLER_DECLARE(shutdown_post_sync, shutdown_fn); /* after fs sync */ Index: sys/sys/kload.h =================================================================== --- sys/sys/kload.h +++ sys/sys/kload.h @@ -85,7 +85,6 @@ */ pt_entry_t * kload_build_page_table(void); void setup_freebsd_gdt(uint64_t *); -void kload_module_shutdown(void); /* * defined in /kload_exec.S Index: sys/sys/module.h =================================================================== --- sys/sys/module.h +++ sys/sys/module.h @@ -179,6 +179,7 @@ const char * module_getname(module_t); void module_setspecific(module_t, modspecific_t *); struct linker_file *module_file(module_t); +void module_shutdown(void *arg1, int arg2); #ifdef MOD_DEBUG extern int mod_debug; Index: sys/sys/reboot.h =================================================================== --- sys/sys/reboot.h +++ sys/sys/reboot.h @@ -60,6 +60,7 @@ #define RB_RESERVED2 0x80000 /* reserved for internal use of boot blocks */ #define RB_PAUSE 0x100000 /* pause after each output line during probe */ #define RB_REROOT 0x200000 /* unmount the rootfs and mount it again */ +#define RB_KLOAD 0x400000 /* reboot using kload'ed kernel image */ #define RB_MULTIPLE 0x20000000 /* use multiple consoles */ #define RB_BOOTINFO 0x80000000 /* have `struct bootinfo *' arg */ Index: sys/x86/include/apicvar.h =================================================================== --- sys/x86/include/apicvar.h +++ sys/x86/include/apicvar.h @@ -456,6 +456,7 @@ void lapic_handle_intr(int vector, struct trapframe *frame); void lapic_handle_timer(struct trapframe *frame); void hv_vector_handler(struct trapframe *frame); +void lapic_clear_lapic(u_int); extern int x2apic_mode; extern int lapic_eoi_suppression; Index: sys/x86/x86/intr_machdep.c =================================================================== --- sys/x86/x86/intr_machdep.c +++ sys/x86/x86/intr_machdep.c @@ -194,6 +194,24 @@ } int +intr_clear_all_handlers(void) +{ + struct intsrc *isrc; + int i; + + mtx_lock(&intr_table_lock); + for (i = 0; i < NUM_IO_INTS; i++) { + isrc = interrupt_sources[i]; + if (isrc != NULL) { + isrc->is_pic->pic_disable_source(isrc, PIC_EOI); + isrc->is_pic->pic_disable_intr(isrc); + } + } + mtx_unlock(&intr_table_lock); + return (0); +} + +int intr_remove_handler(void *cookie) { struct intsrc *isrc; Index: sys/x86/x86/local_apic.c =================================================================== --- sys/x86/x86/local_apic.c +++ sys/x86/x86/local_apic.c @@ -561,6 +561,62 @@ intr_restore(saveintr); } +void +lapic_clear_lapic(u_int disable) { + + struct lapic *la; + la = &lapics[lapic_id()]; + + uint32_t value; + + if (bootverbose) + printf("%s lapic_id(%d) cpu(%d) la %p lapic_map %p\n",__FUNCTION__, + lapic_id(), PCPU_GET(cpuid), la, lapic_map); + + /* + * Fist we set the mask bit to keep and new interrupts from + * arriving but allowing any pending interrupts to finish + * *THEN* set the registers to default values + * If the interrupts are not allowed to clear a kload'ed / booted + * kernel will see the old interrupts before the appropriate handlers + * are in place and trigger a panic. + */ +#ifdef notyet + /* this seems to be causing APIC error in the new kernel */ + value = lapic_read32(LAPIC_LVT_ERROR); + value |= APIC_LVT_M; + lapic_write32(LAPIC_LVT_ERROR, value); +#endif + + value = lapic_read32(LAPIC_LVT_TIMER); + value |= APIC_LVT_M; + lapic_write32(LAPIC_LVT_TIMER, value); + + value = lapic_read32(LAPIC_LVT_LINT0); + value |= APIC_LVT_M; + lapic_write32(LAPIC_LVT_LINT0, value); + + value = lapic_read32(LAPIC_LVT_LINT1); + value |= APIC_LVT_M; + lapic_write32(LAPIC_LVT_LINT1, value); + + value = lapic_read32(LAPIC_LVT_PCINT); + value |= APIC_LVT_M; + lapic_write32(LAPIC_LVT_PCINT, value); + + /* Program timer LVT and setup handler. */ + lapic_write32(LAPIC_LVT_TIMER, APIC_LVTT_M); /* masked */ + lapic_write32(LAPIC_LVT_LINT0, APIC_LVT_M); /* masked */ + lapic_write32(LAPIC_LVT_LINT1, APIC_LVT_M); /* masked */ + //lapic_write32(LAPIC_LVT_PCINT, APIC_LVT_M); /* masked */ + + if (disable) { + if (bootverbose) + printf("lapic disable\n"); + lapic_disable(); + } +} + static void native_lapic_setup(int boot) { Index: sys/x86/x86/mp_x86.c =================================================================== --- sys/x86/x86/mp_x86.c +++ sys/x86/x86/mp_x86.c @@ -35,6 +35,7 @@ #include "opt_pmap.h" #include "opt_sched.h" #include "opt_smp.h" +#include "opt_kload.h" #include #include @@ -90,6 +91,13 @@ extern struct pcpu __pcpu[]; +#ifdef KLOAD +/* page table setup by kload so we can set the APs to a known page table */ +extern pt_entry_t kload_pgtbl; +#else +static pt_entry_t kload_pgtbl = 0; +#endif + /* AP uses this during bootstrap. Do not staticize. */ char *bootSTK; int bootAP; @@ -1014,6 +1022,12 @@ mtx_assert(&smp_ipi_mtx, MA_NOTOWNED); + /* + * shutdown interrupts to the cpu + * and then set the mask as stopped + */ + lapic_clear_lapic(1 /* disable lapic */); + cpu = PCPU_GET(cpuid); if (savectx(&susppcbs[cpu]->sp_pcb)) { #ifdef __amd64__ @@ -1038,6 +1052,29 @@ CPU_CLR_ATOMIC(cpu, &suspended_cpus); } + if (kload_pgtbl) { + /* + * Set the pagetable to boot capable PT in case this is + * kload suspend. If a normal suspend resume we restore + * the originnal page table + */ + (void)intr_disable(); + load_cr3(kload_pgtbl); + + /* Disable PGE. */ + load_cr4(rcr4() & ~CR4_PGE); + + /* Disable caches (CD = 1, NW = 0) and paging*/ + load_cr0((rcr0() & ~CR0_NW) | CR0_CD | CR0_PG); + + /* Flushes caches and TLBs. */ + wbinvd(); + invltlb(); + + halt(); + + } + /* Wait for resume */ while (!CPU_ISSET(cpu, &started_cpus)) ia32_pause(); Index: sys/x86/x86/nexus.c =================================================================== --- sys/x86/x86/nexus.c +++ sys/x86/x86/nexus.c @@ -59,6 +59,7 @@ #include #include #include +#include #include #include