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 @@ -64,6 +64,7 @@ struct sx modules_sx; static int nextid = 1; static void module_shutdown(void *, int); +void kload_module_shutdown(void); static int modevent_nop(module_t mod, int what, void *arg) @@ -107,6 +108,12 @@ } void +kload_module_shutdown(void) { + module_shutdown(NULL, 0); +} + + +void module_register_init(const void *arg) { const moduledata_t *data = (const moduledata_t *)arg; 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/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 @@ -457,6 +457,7 @@ void lapic_handle_timer(struct trapframe *frame); void xen_intr_handle_upcall(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,25 @@ } int +intr_clear_all_handlers(void) +{ + struct intsrc *isrc; + int i; + + printf("%s\n", __func__); + 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) { @@ -1145,7 +1201,20 @@ lapic_write32(LAPIC_ESR, 0); esr = lapic_read32(LAPIC_ESR); - printf("CPU%d: local APIC error 0x%x\n", PCPU_GET(cpuid), esr); + printf("CPU%d: local APIC error 0x%x\t", PCPU_GET(cpuid), esr); + if (esr & APIC_ESR_SEND_CS_ERROR) + printf("send_cs_error\n"); + if (esr & APIC_ESR_RECEIVE_CS_ERROR) + printf("receive_cs_error\n"); + if (esr & APIC_ESR_SEND_ACCEPT) + printf("send_accept\n"); + if (esr & APIC_ESR_RECEIVE_ACCEPT) + printf("receive_accept\n"); + if (esr & APIC_ESR_SEND_ILLEGAL_VECTOR) + printf("send_illegal_vector\n"); + if (esr & APIC_ESR_ILLEGAL_REGISTER) + printf("illegal_register\n"); + lapic_eoi(); } 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,9 @@ mtx_assert(&smp_ipi_mtx, MA_NOTOWNED); + lapic_clear_lapic(1 /* disable lapic */); + /* shutdown interrupts to the cpu and then set the mask as stopped */ + cpu = PCPU_GET(cpuid); if (savectx(&susppcbs[cpu]->sp_pcb)) { #ifdef __amd64__ @@ -1038,6 +1049,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 @@ -677,6 +678,38 @@ } static int +smap_hdlr(SYSCTL_HANDLER_ARGS) +{ + /* + SYSCTL_HANDLER_ARGS + struct sysctl_oid *oidp, void *arg1, + intptr_t arg2, struct sysctl_req *req + */ + struct bios_smap *smapbase; + caddr_t kmdp; + uint32_t smapsize = 0; + + /* Retrieve the system memory map from the loader. */ + kmdp = preload_search_by_type("elf kernel"); + if (kmdp == NULL) + kmdp = preload_search_by_type(ELF_KERN_STR); + if (kmdp != NULL) { + smapbase = (struct bios_smap *)preload_search_info(kmdp, + MODINFO_METADATA | MODINFOMD_SMAP); + } else { + smapbase = NULL; + goto out; + } + + smapsize = *((u_int32_t *)smapbase - 1); +out: + return (sysctl_handle_opaque(oidp, smapbase, smapsize, req)); +} +SYSCTL_PROC(_hw, OID_AUTO, smap, CTLTYPE_OPAQUE|CTLFLAG_RD|CTLFLAG_MPSAFE, + 0, sizeof(struct bios_smap), smap_hdlr, "S,smap", + "Bios System Map"); + +static int ram_attach(device_t dev) { struct bios_smap *smapbase, *smap, *smapend;