From 9e12630d75f21f67db7d5ddf6c167e17389a8eb4 Mon Sep 17 00:00:00 2001 From: Tomas Hruby Date: Wed, 15 Sep 2010 14:10:30 +0000 Subject: [PATCH] SMP - APs are fully enabled - apic_send_ipi() to send inter-processor interrupts (IPIs) - APIC IPI schedule and halt handlers to signal x-cpu that a cpu shold reschedule or halt - various little changes to let APs run - no processes are scheduled at the APs and therefore they are idle except being interrupted by a timer time to time --- kernel/arch/i386/apic.c | 67 ++++++++++++++++++++++++----- kernel/arch/i386/apic.h | 29 +++++++++++-- kernel/arch/i386/apic_asm.S | 22 ++-------- kernel/arch/i386/arch_smp.c | 42 ++++++++++++------ kernel/arch/i386/exception.c | 7 +-- kernel/arch/i386/include/arch_smp.h | 17 +------- kernel/smp.c | 2 - kernel/smp.h | 7 --- 8 files changed, 122 insertions(+), 71 deletions(-) diff --git a/kernel/arch/i386/apic.c b/kernel/arch/i386/apic.c index fc6a313ef..a55a389d0 100644 --- a/kernel/arch/i386/apic.c +++ b/kernel/arch/i386/apic.c @@ -294,6 +294,11 @@ PUBLIC void ioapic_eoi(int irq) irq_8259_eoi(irq); } +PUBLIC void ioapic_set_id(u32_t addr, unsigned int id) +{ + ioapic_write(addr, IOAPIC_ID, id << 24); +} + PUBLIC int ioapic_enable_all(void) { i8259_disable(); @@ -389,14 +394,17 @@ PUBLIC void ioapic_mask_irq(unsigned irq) irq_8259_mask(irq); } -PUBLIC unsigned int apicid(void) +PUBLIC void apic_ipi_sched_handler(void) { - return lapic_read(LAPIC_ID); } -PUBLIC void ioapic_set_id(u32_t addr, unsigned int id) +PUBLIC void apic_ipi_halt_handler(void) { - ioapic_write(addr, IOAPIC_ID, id << 24); +} + +PUBLIC unsigned int apicid(void) +{ + return lapic_read(LAPIC_ID); } PRIVATE int calib_clk_handler(irq_hook_t * UNUSED(hook)) @@ -793,10 +801,8 @@ PRIVATE struct gate_table_s gate_table_common[] = { #ifdef CONFIG_SMP PRIVATE struct gate_table_s gate_table_smp[] = { - { smp_ipi_sched, SMP_SCHED_PROC, INTR_PRIVILEGE }, - { smp_ipi_dequeue, SMP_DEQUEUE_PROC, INTR_PRIVILEGE }, - { smp_ipi_reboot,SMP_CPU_REBOOT, INTR_PRIVILEGE }, - { smp_ipi_stop, SMP_CPU_HALT, INTR_PRIVILEGE }, + { apic_ipi_sched_intr, APIC_SMP_SCHED_PROC_VECTOR, INTR_PRIVILEGE }, + { apic_ipi_halt_intr, APIC_SMP_CPU_HALT_VECTOR, INTR_PRIVILEGE }, { NULL, 0, 0} }; #endif @@ -909,6 +915,45 @@ PUBLIC int detect_ioapics(void) #ifdef CONFIG_SMP +PUBLIC void apic_send_ipi(unsigned vector, unsigned cpu, int type) +{ + u32_t icr1, icr2; + + if (ncpus == 1) + /* no need of sending an IPI */ + return; + + while (lapic_read_icr1() & APIC_ICR_DELIVERY_PENDING) + arch_pause(); + + icr1 = lapic_read_icr1() & 0xFFF0F800; + icr2 = lapic_read_icr2() & 0xFFFFFF; + + switch (type) { + case APIC_IPI_DEST: + if (!cpu_is_ready(cpu)) + return; + lapic_write_icr2(icr2 | (cpuid2apicid[cpu] << 24)); + lapic_write_icr1(icr1 | APIC_ICR_DEST_FIELD | vector); + break; + case APIC_IPI_SELF: + lapic_write_icr2(icr2); + lapic_write_icr1(icr1 | APIC_ICR_DEST_SELF | vector); + break; + case APIC_IPI_TO_ALL_BUT_SELF: + lapic_write_icr2(icr2); + lapic_write_icr1(icr1 | APIC_ICR_DEST_ALL_BUT_SELF | vector); + break; + case APIC_IPI_TO_ALL: + lapic_write_icr2(icr2); + lapic_write_icr1(icr1 | APIC_ICR_DEST_ALL | vector); + break; + default: + printf("WARNING : unknown send ipi type request\n"); + } + +} + PUBLIC int apic_send_startup_ipi(unsigned cpu, phys_bytes trampoline) { int timeout; @@ -919,6 +964,8 @@ PUBLIC int apic_send_startup_ipi(unsigned cpu, phys_bytes trampoline) for (i = 0; i < 2; i++) { u32_t val; + + /* clear err status */ lapic_errstatus(); /* set target pe */ @@ -938,8 +985,8 @@ PUBLIC int apic_send_startup_ipi(unsigned cpu, phys_bytes trampoline) lapic_microsec_sleep (200); errstatus = 0; - while ((lapic_read(LAPIC_ICR1) & APIC_ICR_DELIVERY_PENDING) && !errstatus) - { + while ((lapic_read(LAPIC_ICR1) & APIC_ICR_DELIVERY_PENDING) && + !errstatus) { errstatus = lapic_errstatus(); timeout--; if (!timeout) break; diff --git a/kernel/arch/i386/apic.h b/kernel/arch/i386/apic.h index ca7f6a9c3..03f28c2e3 100644 --- a/kernel/arch/i386/apic.h +++ b/kernel/arch/i386/apic.h @@ -88,6 +88,8 @@ #define IOAPIC_REDIR_TABLE 0x10 #define APIC_TIMER_INT_VECTOR 0xf0 +#define APIC_SMP_SCHED_PROC_VECTOR 0xf1 +#define APIC_SMP_CPU_HALT_VECTOR 0xf2 #define APIC_ERROR_INT_VECTOR 0xfe #define APIC_SPURIOUS_INT_VECTOR 0xff @@ -157,12 +159,31 @@ _PROTOTYPE(void ioapic_unset_irq, (unsigned irq)); /* signal the end of interrupt handler to apic */ _PROTOTYPE(void ioapic_eoi, (int irq)); -_PROTOTYPE(void lapic_disable, (void)); -_PROTOTYPE(void ioapic_disable_all, (void)); -_PROTOTYPE(void ioapic_reset_pic, (void)); - _PROTOTYPE(void dump_apic_irq_state, (void)); +_PROTOTYPE(void apic_send_ipi, (unsigned vector, unsigned cpu, int type)); + +_PROTOTYPE(void apic_ipi_sched_intr, (void)); +_PROTOTYPE(void apic_ipi_halt_intr, (void)); + +_PROTOTYPE(void apic_ipi_sched_handler, (void)); +_PROTOTYPE(void apic_ipi_halt_handler, (void)); + +#define APIC_IPI_DEST 0 +#define APIC_IPI_SELF 1 +#define APIC_IPI_TO_ALL 2 +#define APIC_IPI_TO_ALL_BUT_SELF 3 + +#define apic_send_ipi_single(vector,cpu) \ + apic_send_ipi(vector, cpu, APIC_IPI_DEST); +#define apic_send_ipi_self(vector) \ + apic_send_ipi(vector, 0, APIC_IPI_SELF) +#define apic_send_ipi_all(vector) \ + apic_send_ipi (vector, 0, APIC_IPI_TO_ALL) +#define apic_send_ipi_allbutself(vector) \ + apic_send_ipi (vector, 0, APIC_IPI_TO_ALL_BUT_SELF); + + #include #define cpu_feature_apic_on_chip() _cpufeature(_CPUF_I386_APIC_ON_CHIP) diff --git a/kernel/arch/i386/apic_asm.S b/kernel/arch/i386/apic_asm.S index 34c651baf..1988dd194 100644 --- a/kernel/arch/i386/apic_asm.S +++ b/kernel/arch/i386/apic_asm.S @@ -68,26 +68,12 @@ ENTRY(lapic_timer_int_handler) lapic_intr(_C_LABEL(timer_int_handler)) #ifdef CONFIG_SMP -#include "arch_smp.h" -/* FIXME dummy stubs */ -ENTRY(smp_ipi_sched) -1: jmp 1b +ENTRY(apic_ipi_sched_intr) + lapic_intr(_C_LABEL(apic_ipi_sched_handler)) -ENTRY(smp_ipi_dequeue) -1: jmp 1b - -ENTRY(smp_ipi_stop) -1: jmp 1b - -ENTRY(smp_ipi_reboot) -1: jmp 1b - -ENTRY(smp_ipi_err_int) -1: jmp 1b - -ENTRY(smp_ipi_spv_int) -1: jmp 1b +ENTRY(apic_ipi_halt_intr) + lapic_intr(_C_LABEL(apic_ipi_halt_handler)) #endif /* CONFIG_SMP */ diff --git a/kernel/arch/i386/arch_smp.c b/kernel/arch/i386/arch_smp.c index e45d0439a..26c19b79e 100644 --- a/kernel/arch/i386/arch_smp.c +++ b/kernel/arch/i386/arch_smp.c @@ -126,13 +126,10 @@ PRIVATE void smp_start_aps(void) * using the processor's apic id values. */ for (cpu = 0; cpu < ncpus; cpu++) { - printf("Booting cpu %d\n", cpu); ap_cpu_ready = -1; /* Don't send INIT/SIPI to boot cpu. */ if((apicid() == cpuid2apicid[cpu]) && (apicid() == bsp_lapic_id)) { - cpu_set_flag(cpu, CPU_IS_READY); - printf("Skiping bsp\n"); continue; } @@ -150,7 +147,6 @@ PRIVATE void smp_start_aps(void) while (lapic_read(LAPIC_TIMER_CCR)) { if (ap_cpu_ready == cpu) { - printf("CPU %d is up\n", cpu); cpu_set_flag(cpu, CPU_IS_READY); break; } @@ -176,14 +172,42 @@ PUBLIC void smp_halt_cpu (void) PUBLIC void smp_shutdown_aps (void) { - NOT_IMPLEMENTED; + u8_t cpu; + unsigned aid = apicid(); + + if (ncpus == 1) + goto exit_shutdown_aps; + + for (cpu = 0; cpu < ncpus; cpu++) { + u16_t i; + if (!cpu_is_ready(cpu)) + continue; + if ((aid == cpuid2apicid[cpu]) && (aid == bsp_lapic_id)) + continue; + apic_send_ipi(APIC_SMP_CPU_HALT_VECTOR, cpu, APIC_IPI_DEST); + /* TODO wait for the cpu to be down */ + } + + /* Sending INIT to a processor makes it to wait in a halt state */ + for (cpu = 0; cpu < ncpus; cpu++) { + if ((aid == cpuid2apicid[cpu]) && (aid == bsp_lapic_id)) + continue; + apic_send_init_ipi (cpu, 0); + } +exit_shutdown_aps: + ioapic_disable_all(); + + lapic_disable(); + + ncpus = 1; /* hopefully !!! */ + lapic_addr = lapic_eoi_addr = 0; + return; } PRIVATE void ap_finish_booting(void) { unsigned cpu = cpuid; - printf("CPU %d says hello world!\n", cpu); /* inform the world of our presence. */ ap_cpu_ready = cpu; @@ -222,12 +246,6 @@ PRIVATE void ap_finish_booting(void) ap_boot_finished(cpu); spinlock_unlock(&boot_lock); - /* finish processor initialisation. */ - lapic_enable(cpu); - - BKL_UNLOCK(); - for(;;); - switch_to_user(); NOT_REACHABLE; } diff --git a/kernel/arch/i386/exception.c b/kernel/arch/i386/exception.c index 5c9094e5b..86eb54101 100644 --- a/kernel/arch/i386/exception.c +++ b/kernel/arch/i386/exception.c @@ -69,8 +69,9 @@ PRIVATE void pagefault( struct proc *pr, /* Page fault we can't / don't want to * handle. */ - printf("pagefault for process %d ('%s'), pc = 0x%x, addr = 0x%x, flags = 0x%x, is_nested %d\n", - pr->p_endpoint, pr->p_name, pr->p_reg.pc, + printf("pagefault for process %d ('%s') on CPU %d, " + "pc = 0x%x, addr = 0x%x, flags = 0x%x, is_nested %d\n", + pr->p_endpoint, pr->p_name, cpuid, pr->p_reg.pc, pagefaultcr2, frame->errcode, is_nested); proc_stacktrace(pr); printf("pc of pagefault: 0x%lx\n", frame->eip); @@ -207,7 +208,7 @@ PUBLIC void exception_handler(int is_nested, struct exception_frame * frame) printf("\nIntel-reserved exception %d\n", frame->vector); else printf("\n%s\n", ep->msg); - printf("is_nested = %d ", is_nested); + printf("cpu %d is_nested = %d ", cpuid, is_nested); printf("vec_nr= %d, trap_errno= 0x%x, eip= 0x%x, " "cs= 0x%x, eflags= 0x%x trap_esp 0x%08x\n", diff --git a/kernel/arch/i386/include/arch_smp.h b/kernel/arch/i386/include/arch_smp.h index 90e70223d..4885c0f06 100644 --- a/kernel/arch/i386/include/arch_smp.h +++ b/kernel/arch/i386/include/arch_smp.h @@ -5,21 +5,6 @@ #define MAX_NR_INTERRUPT_ENTRIES 128 -#define SMP_SCHED_PROC 0xF0 -#define SMP_DEQUEUE_PROC 0xF1 -#define SMP_CPU_REBOOT 0xF2 -#define SMP_CPU_HALT 0xF3 -#define SMP_ERROR_INT 0xF4 - -/* currently only 2 interrupt priority levels are used */ -#define SPL0 0x0 -#define SPLHI 0xF - -#define SMP_IPI_DEST 0 -#define SMP_IPI_SELF 1 -#define SMP_IPI_TO_ALL 2 -#define SMP_IPI_TO_ALL_BUT_SELF 3 - #ifndef __ASSEMBLY__ /* returns the current cpu id */ @@ -31,6 +16,8 @@ */ #define smp_single_cpu_fallback() do { \ tss_init(0, get_k_stack_top(0)); \ + bsp_cpu_id = 0; \ + ncpus = 1; \ bsp_finish_booting(); \ } while(0) diff --git a/kernel/smp.c b/kernel/smp.c index 367be5947..3f6e9b5ec 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -23,7 +23,5 @@ void wait_for_APs_to_finish_booting(void) void ap_boot_finished(unsigned cpu) { - printf("CPU %d is running\n", cpu); - ap_cpus_booted++; } diff --git a/kernel/smp.h b/kernel/smp.h index 312dd144f..01e00c0f7 100644 --- a/kernel/smp.h +++ b/kernel/smp.h @@ -28,13 +28,6 @@ EXTERN unsigned bsp_cpu_id; */ _PROTOTYPE(void smp_init, (void)); -_PROTOTYPE(void smp_ipi_err_int, (void)); -_PROTOTYPE(void smp_ipi_spv_int, (void)); -_PROTOTYPE(void smp_ipi_sched, (void)); -_PROTOTYPE(void smp_ipi_dequeue, (void)); -_PROTOTYPE(void smp_ipi_stop, (void)); -_PROTOTYPE(void smp_ipi_reboot, (void)); - #define CPU_IS_BSP 1 #define CPU_IS_READY 2 -- 2.44.0