diff --git a/hermit/arch/x86/kernel/apic.c b/hermit/arch/x86/kernel/apic.c index a5d7fc755..63276083d 100644 --- a/hermit/arch/x86/kernel/apic.c +++ b/hermit/arch/x86/kernel/apic.c @@ -681,6 +681,25 @@ static void apic_err_handler(struct state *s) kprintf("Got APIC error 0x%x\n", lapic_read(APIC_ESR)); } +static void apic_shutdown(struct state *s) +{ + kprintf("Receive an IPI to shutdown HermitCore\n"); + + kprintf("Diable APIC timer\n"); + apic_disable_timer(); + + kprintf("Disable APIC\n"); + lapic_write(APIC_LVT_TSR, 0x10000); // disable thermal sensor interrupt + lapic_write(APIC_LVT_PMC, 0x10000); // disable performance counter interrupt + lapic_write(APIC_SVR, 0x00); // disable the apic + + kprintf("System goes down...\n"); + + HALT; + kprintf("Ups, we should never reach this point!\n"); + while(1); +} + int apic_init(void) { int ret; @@ -697,6 +716,7 @@ int apic_init(void) #if MAX_CORES > 1 irq_install_handler(124, apic_tlb_handler); #endif + irq_install_handler(122, apic_shutdown); kprintf("Boot processor %u (ID %u)\n", boot_processor, apic_processors[boot_processor]->id); online[boot_processor] = 1; diff --git a/hermit/arch/x86/kernel/entry.asm b/hermit/arch/x86/kernel/entry.asm index 1cce9aa5d..417c9d737 100644 --- a/hermit/arch/x86/kernel/entry.asm +++ b/hermit/arch/x86/kernel/entry.asm @@ -289,6 +289,13 @@ isrstub_pseudo_error 9 %assign i i+1 %endrep +global apic_shutdown +align 16 +apic_shutdown: + push byte 0 ; pseudo error code + push byte 122 + jmp common_stub + global apic_timer align 16 apic_timer: diff --git a/hermit/arch/x86/kernel/irq.c b/hermit/arch/x86/kernel/irq.c index e6c9bee1e..9fa6058fe 100644 --- a/hermit/arch/x86/kernel/irq.c +++ b/hermit/arch/x86/kernel/irq.c @@ -71,6 +71,7 @@ extern void irq20(void); extern void irq21(void); extern void irq22(void); extern void irq23(void); +extern void apic_shutdown(void); extern void apic_timer(void); extern void apic_lint0(void); extern void apic_lint1(void); @@ -211,6 +212,8 @@ static int irq_install(void) IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP); // add APIC interrupt handler + idt_set_gate(122, (size_t)apic_shutdown, KERNEL_CODE_SELECTOR, + IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP); idt_set_gate(123, (size_t)apic_timer, KERNEL_CODE_SELECTOR, IDT_FLAG_PRESENT|IDT_FLAG_RING0|IDT_FLAG_32BIT|IDT_FLAG_INTTRAP); idt_set_gate(124, (size_t)apic_lint0, KERNEL_CODE_SELECTOR,