diff --git a/headers/private/kernel/arch/smp.h b/headers/private/kernel/arch/smp.h index 54a9860c9e..e8a66b97da 100644 --- a/headers/private/kernel/arch/smp.h +++ b/headers/private/kernel/arch/smp.h @@ -18,8 +18,9 @@ struct kernel_args; extern "C" { #endif -int arch_smp_init(struct kernel_args *ka); -void arch_smp_send_ici(int target_cpu); +status_t arch_smp_init(struct kernel_args *args); +status_t arch_smp_per_cpu_init(struct kernel_args *args, int32 cpu); +void arch_smp_send_ici(int32 target_cpu); void arch_smp_send_broadcast_ici(void); #ifdef __cplusplus diff --git a/headers/private/kernel/arch/x86/smp_priv.h b/headers/private/kernel/arch/x86/smp_priv.h index fcd90c9f90..f7df7d4368 100755 --- a/headers/private/kernel/arch/x86/smp_priv.h +++ b/headers/private/kernel/arch/x86/smp_priv.h @@ -5,11 +5,11 @@ #ifndef _KERNEL_ARCH_x86_SMP_PRIV_H #define _KERNEL_ARCH_x86_SMP_PRIV_H -#include +#include int i386_smp_interrupt(int vector); void arch_smp_ack_interrupt(void); -int arch_smp_set_apic_timer(bigtime_t relative_timeout); +status_t arch_smp_set_apic_timer(bigtime_t relativeTimeout); int arch_smp_clear_apic_timer(void); #endif /* _KERNEL_ARCH_x86_SMP_PRIV_H */ diff --git a/headers/private/kernel/smp.h b/headers/private/kernel/smp.h index 2a3a82228d..d22cee8a03 100755 --- a/headers/private/kernel/smp.h +++ b/headers/private/kernel/smp.h @@ -26,7 +26,8 @@ enum { SMP_MSG_FLAG_SYNC, }; -int smp_init(struct kernel_args *ka); +status_t smp_init(struct kernel_args *args); +status_t smp_per_cpu_init(struct kernel_args *args, int32 cpu); int smp_trap_non_boot_cpus(struct kernel_args *ka, int cpu); void smp_wake_up_all_non_boot_cpus(void); void smp_wait_for_ap_cpus(struct kernel_args *ka); diff --git a/src/kernel/boot/arch/x86/smp_boot.c b/src/kernel/boot/arch/x86/smp_boot.c index e26449a64a..7a8d6601d2 100644 --- a/src/kernel/boot/arch/x86/smp_boot.c +++ b/src/kernel/boot/arch/x86/smp_boot.c @@ -259,56 +259,6 @@ smp_find_mp_config(kernel_args *ka) } -static int -smp_setup_apic(kernel_args *ka) -{ - uint32 config; - - TRACE(("setting up the apic...")); - - /* set spurious interrupt vector to 0xff */ - config = apic_read(APIC_SIVR) & 0xfffffc00; - config |= APIC_ENABLE | 0xff; - apic_write(APIC_SIVR, config); -#if 1 - /* setup LINT0 as ExtINT */ - config = (apic_read(APIC_LINT0) & 0xffff1c00); - config |= APIC_LVT_DM_ExtINT | APIC_LVT_IIPP | APIC_LVT_TM; - apic_write(APIC_LINT0, config); - - /* setup LINT1 as NMI */ - config = (apic_read(APIC_LINT1) & 0xffff1c00); - config |= APIC_LVT_DM_NMI | APIC_LVT_IIPP; - apic_write(APIC_LINT1, config); -#endif - - /* setup timer */ - config = apic_read(APIC_LVTT) & ~APIC_LVTT_MASK; - config |= 0xfb | APIC_LVTT_M; // vector 0xfb, timer masked - apic_write(APIC_LVTT, config); - - apic_write(APIC_ICRT, 0); // zero out the clock - - config = apic_read(APIC_TDCR) & ~0x0000000f; - config |= APIC_TDCR_1; // clock division by 1 - apic_write(APIC_TDCR, config); - - /* setup error vector to 0xfe */ - config = (apic_read(APIC_LVT3) & 0xffffff00) | 0xfe; - apic_write(APIC_LVT3, config); - - /* accept all interrupts */ - config = apic_read(APIC_TPRI) & 0xffffff00; - apic_write(APIC_TPRI, config); - - config = apic_read(APIC_SIVR); - apic_write(APIC_EOI, 0); - - TRACE((" done\n")); - return 0; -} - - /** Target function of the trampoline code. * The trampoline code should have the pgdir and a gdt set up for us, * along with us being on the final stack for this processor. We need @@ -331,8 +281,6 @@ smp_cpu_ready(void) asm("cld"); asm("fninit"); - smp_setup_apic(ka); - // Set up the final idt idt_descr.a = IDT_LIMIT - 1; idt_descr.b = (uint32 *)ka->arch_args.vir_idt; @@ -537,9 +485,6 @@ smp_boot(kernel_args *ka, uint32 kernel_entry) TRACE(("apic = %p\n", ka->arch_args.apic)); TRACE(("ioapic = %p\n", ka->arch_args.ioapic)); - // set up the apic - smp_setup_apic(ka); - // calculate how fast the apic timer is calculate_apic_timer_conversion_factor(ka); diff --git a/src/kernel/core/arch/x86/arch_smp.c b/src/kernel/core/arch/x86/arch_smp.c index ad9f03e607..7a6c60b82b 100755 --- a/src/kernel/core/arch/x86/arch_smp.c +++ b/src/kernel/core/arch/x86/arch_smp.c @@ -3,12 +3,9 @@ ** Distributed under the terms of the NewOS License. */ -#include -#include -#include -#include +#include +#include #include -#include #include #include #include @@ -25,10 +22,18 @@ #include +//#define TRACE_ARCH_SMP +#ifdef TRACE_ARCH_SMP +# define TRACE(x) dprintf x +#else +# define TRACE(x) ; +#endif + + static uint32 *apic = NULL; -static uint32 cpu_apic_id[SMP_MAX_CPUS] = {0, 0}; -static uint32 cpu_os_id[SMP_MAX_CPUS] = {0, 0}; -static uint32 cpu_apic_version[SMP_MAX_CPUS] = {0, 0}; +static uint32 cpu_apic_id[B_MAX_CPU_COUNT] = {0, 0}; +static uint32 cpu_os_id[B_MAX_CPU_COUNT] = {0, 0}; +static uint32 cpu_apic_version[B_MAX_CPU_COUNT] = {0, 0}; static uint32 *ioapic = NULL; static uint32 apic_timer_tics_per_sec = 0; @@ -68,7 +73,7 @@ static int32 i386_smp_error_interrupt(void *data) { // smp error interrupt -// dprintf("smp error interrupt on cpu %d\n", arch_smp_get_current_cpu()); + TRACE(("smp error interrupt on cpu %d\n", arch_smp_get_current_cpu())); arch_smp_ack_interrupt(); return B_HANDLED_INTERRUPT; @@ -90,10 +95,10 @@ apic_write(uint32 offset, uint32 data) } -int +status_t arch_smp_init(kernel_args *ka) { - dprintf("arch_smp_init: entry\n"); + TRACE(("arch_smp_init: entry\n")); if (ka->num_cpus > 1) { // setup some globals @@ -110,20 +115,84 @@ arch_smp_init(kernel_args *ka) vm_create_anonymous_region(vm_get_kernel_aspace_id(), "ioapic", (void *)&ioapic, REGION_ADDR_EXACT_ADDRESS, PAGE_SIZE, REGION_WIRING_WIRED_ALREADY, LOCK_RW|LOCK_KERNEL); + // set up the local apic on the boot cpu + arch_smp_per_cpu_init(ka, 0); + install_interrupt_handler(0xfb, &i386_timer_interrupt, NULL); install_interrupt_handler(0xfd, &i386_ici_interrupt, NULL); install_interrupt_handler(0xfe, &i386_smp_error_interrupt, NULL); install_interrupt_handler(0xff, &i386_spurious_interrupt, NULL); } + return B_OK; +} + + +static int +smp_setup_apic(kernel_args *ka) +{ + uint32 config; + + TRACE(("setting up the apic...")); + + /* set spurious interrupt vector to 0xff */ + config = apic_read(APIC_SIVR) & 0xfffffc00; + config |= APIC_ENABLE | 0xff; + apic_write(APIC_SIVR, config); +#if 0 + /* setup LINT0 as ExtINT */ + config = (apic_read(APIC_LINT0) & 0xffff1c00); + config |= APIC_LVT_DM_ExtINT | APIC_LVT_IIPP | APIC_LVT_TM; + apic_write(APIC_LINT0, config); + + /* setup LINT1 as NMI */ + config = (apic_read(APIC_LINT1) & 0xffff1c00); + config |= APIC_LVT_DM_NMI | APIC_LVT_IIPP; + apic_write(APIC_LINT1, config); +#endif + + /* setup timer */ + config = apic_read(APIC_LVTT) & ~APIC_LVTT_MASK; + config |= 0xfb | APIC_LVTT_M; // vector 0xfb, timer masked + apic_write(APIC_LVTT, config); + + apic_write(APIC_ICRT, 0); // zero out the clock + + config = apic_read(APIC_TDCR) & ~0x0000000f; + config |= APIC_TDCR_1; // clock division by 1 + apic_write(APIC_TDCR, config); + + /* setup error vector to 0xfe */ + config = (apic_read(APIC_LVT3) & 0xffffff00) | 0xfe; + apic_write(APIC_LVT3, config); + + /* accept all interrupts */ + config = apic_read(APIC_TPRI) & 0xffffff00; + apic_write(APIC_TPRI, config); + + config = apic_read(APIC_SIVR); + apic_write(APIC_EOI, 0); + + TRACE((" done\n")); return 0; } +status_t +arch_smp_per_cpu_init(kernel_args *args, int32 cpu) +{ + // set up the local apic on the current cpu + TRACE(("arch_smp_init_percpu: setting up the apic on cpu %ld\n", cpu)); + smp_setup_apic(args); + + return B_OK; +} + + void arch_smp_send_broadcast_ici(void) { uint32 config; - int state = disable_interrupts(); + cpu_status state = disable_interrupts(); config = apic_read(APIC_ICR1) & APIC_ICR1_WRITE_MASK; apic_write(APIC_ICR1, config | 0xfd | APIC_ICR1_DELMODE_FIXED | APIC_ICR1_DESTMODE_PHYS | APIC_ICR1_DEST_ALL_BUT_SELF); @@ -133,7 +202,7 @@ arch_smp_send_broadcast_ici(void) void -arch_smp_send_ici(int target_cpu) +arch_smp_send_ici(int32 target_cpu) { uint32 config; int state = disable_interrupts(); @@ -156,21 +225,21 @@ arch_smp_ack_interrupt(void) #define MIN_TIMEOUT 1000 -int -arch_smp_set_apic_timer(bigtime_t relative_timeout) +status_t +arch_smp_set_apic_timer(bigtime_t relativeTimeout) { + cpu_status state; uint32 config; uint32 ticks; - int state; if (apic == NULL) - return -1; + return B_ERROR; - if (relative_timeout < MIN_TIMEOUT) - relative_timeout = MIN_TIMEOUT; + if (relativeTimeout < MIN_TIMEOUT) + relativeTimeout = MIN_TIMEOUT; // calculation should be ok, since it's going to be 64-bit - ticks = ((relative_timeout * apic_timer_tics_per_sec) / 1000000); + ticks = ((relativeTimeout * apic_timer_tics_per_sec) / 1000000); state = disable_interrupts(); @@ -182,19 +251,22 @@ arch_smp_set_apic_timer(bigtime_t relative_timeout) config = apic_read(APIC_LVTT) & ~APIC_LVTT_M; // unmask the timer apic_write(APIC_LVTT, config); + TRACE(("arch_smp_set_apic_timer: config 0x%x, timeout %Ld, tics/sec %d, tics %d\n", + config, relative_timeout, apic_timer_tics_per_sec, ticks)); + apic_write(APIC_ICRT, ticks); // start it up restore_interrupts(state); - return 0; + return B_OK; } int arch_smp_clear_apic_timer(void) { + cpu_status state; uint32 config; - int state; if (apic == NULL) return -1; diff --git a/src/kernel/core/arch/x86/arch_timer.c b/src/kernel/core/arch/x86/arch_timer.c index 1487cd91b0..e289e7770f 100755 --- a/src/kernel/core/arch/x86/arch_timer.c +++ b/src/kernel/core/arch/x86/arch_timer.c @@ -39,13 +39,16 @@ set_isa_hardware_timer(long long relative_timeout) out8(0x30, 0x43); out8(next_event_clocks & 0xff, 0x40); out8((next_event_clocks >> 8) & 0xff, 0x40); + + arch_int_enable_io_interrupt(0); } static void clear_isa_hardware_timer(void) { - // XXX do something here + // mask out the timer + arch_int_disable_io_interrupt(0); } @@ -86,6 +89,8 @@ arch_init_timer(kernel_args *ka) dprintf("arch_init_timer: entry\n"); install_io_interrupt_handler(0, &isa_timer_interrupt, NULL, 0); + clear_isa_hardware_timer(); + // apic timer interrupt set up by smp code return 0; diff --git a/src/kernel/core/main.c b/src/kernel/core/main.c index 99268a4eb4..3e424a4904 100644 --- a/src/kernel/core/main.c +++ b/src/kernel/core/main.c @@ -1,6 +1,9 @@ /* This is main - initializes processors and starts init */ /* +** Copyright 2002-2004, The OpenBeOS Team. All rights reserved. +** Distributed under the terms of the OpenBeOS License. +** ** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. ** Distributed under the terms of the NewOS License. */ @@ -34,8 +37,8 @@ #include -#define TRACE_BOOT 1 -#if TRACE_BOOT +#define TRACE_BOOT +#ifdef TRACE_BOOT # define TRACE(x) dprintf x #else # define TRACE(x) ; @@ -91,9 +94,9 @@ _start(kernel_args *oldka, int cpu_num) sem_init(&ka); - dprintf("##################################################################\n"); - dprintf("semaphores now available\n"); - dprintf("##################################################################\n"); + TRACE(("##################################################################\n")); + TRACE(("semaphores now available\n")); + TRACE(("##################################################################\n")); // now we can create and use semaphores vm_init_postsem(&ka); @@ -118,16 +121,18 @@ _start(kernel_args *oldka, int cpu_num) start_scheduler(); } else { // this is run per cpu for each AP processor after they've been set loose + smp_per_cpu_init(&ka, cpu_num); thread_init_percpu(cpu_num); } - dprintf("##################################################################\n"); - dprintf("interrupts now enabled\n"); - dprintf("##################################################################\n"); + TRACE(("##################################################################\n")); + TRACE(("interrupts now enabled\n")); + TRACE(("##################################################################\n")); + kernel_startup = false; enable_interrupts(); TRACE(("main: done... begin idle loop on cpu %d\n", cpu_num)); - for(;;) + for (;;) arch_cpu_idle(); return 0; diff --git a/src/kernel/core/smp.c b/src/kernel/core/smp.c index 3a07f8d1d6..fae712ffc3 100644 --- a/src/kernel/core/smp.c +++ b/src/kernel/core/smp.c @@ -524,7 +524,7 @@ smp_wait_for_ap_cpus(kernel_args *ka) } -int +status_t smp_init(kernel_args *ka) { struct smp_msg *msg; @@ -554,6 +554,13 @@ smp_init(kernel_args *ka) } +status_t +smp_per_cpu_init(kernel_args *args, int32 cpu) +{ + return arch_smp_per_cpu_init(args, cpu); +} + + void smp_set_num_cpus(int num_cpus) {