diff --git a/arch/x86/core/ia32/crt0.S b/arch/x86/core/ia32/crt0.S index e611c884274..c5ea161baf4 100644 --- a/arch/x86/core/ia32/crt0.S +++ b/arch/x86/core/ia32/crt0.S @@ -236,6 +236,9 @@ __csSet: lidt z_x86_idt /* load 32-bit operand size IDT */ #ifdef CONFIG_LOAPIC + /* For BSP, cpu_number is 0 */ + xorl %eax, %eax + pushl %eax call z_loapic_enable #endif diff --git a/arch/x86/core/intel64/cpu.c b/arch/x86/core/intel64/cpu.c index 293c9954e8f..44d44a2ce06 100644 --- a/arch/x86/core/intel64/cpu.c +++ b/arch/x86/core/intel64/cpu.c @@ -144,7 +144,8 @@ FUNC_NORETURN void z_x86_cpu_init(struct x86_cpuboot *cpuboot) { x86_sse_init(NULL); - z_loapic_enable(); + /* The internal cpu_number is the index to x86_cpuboot[] */ + z_loapic_enable((unsigned char)(cpuboot - x86_cpuboot)); #ifdef CONFIG_USERSPACE /* Set landing site for 'syscall' instruction */ diff --git a/drivers/interrupt_controller/intc_loapic.c b/drivers/interrupt_controller/intc_loapic.c index 51991ab056f..c2a425c1581 100644 --- a/drivers/interrupt_controller/intc_loapic.c +++ b/drivers/interrupt_controller/intc_loapic.c @@ -71,10 +71,27 @@ static u32_t loapic_device_power_state = DEVICE_PM_ACTIVE_STATE; * Called from early assembly layer (e.g., crt0.S). */ -void z_loapic_enable(void) +void z_loapic_enable(unsigned char cpu_number) { s32_t loApicMaxLvt; /* local APIC Max LVT */ +#ifndef CONFIG_X2APIC + /* + * in xAPIC and flat model, bits 24-31 in LDR (Logical APIC ID) are + * bitmap of target logical APIC ID and it supports maximum 8 local + * APICs. + * + * The logical APIC ID could be arbitrarily selected by system software + * and is different from local APIC ID in local APIC ID register. + * + * We choose 0 for BSP, and the index to x86_cpuboot[] for secondary + * CPUs. + * + * in X2APIC, LDR is read-only. + */ + x86_write_xapic(LOAPIC_LDR, 1 << (cpu_number + 24)); +#endif + /* * enable the local APIC. note that we use xAPIC mode here, since * x2APIC access is not enabled until the next step (if at all). @@ -99,6 +116,7 @@ void z_loapic_enable(void) /* reset the DFR, TPR, TIMER_CONFIG, and TIMER_ICR */ #ifndef CONFIG_X2APIC + /* Flat model */ x86_write_loapic(LOAPIC_DFR, 0xffffffff); /* no DFR in x2APIC mode */ #endif diff --git a/include/drivers/interrupt_controller/loapic.h b/include/drivers/interrupt_controller/loapic.h index 59093408b24..5fbe0662230 100644 --- a/include/drivers/interrupt_controller/loapic.h +++ b/include/drivers/interrupt_controller/loapic.h @@ -54,7 +54,7 @@ extern "C" { #endif -extern void z_loapic_enable(void); +extern void z_loapic_enable(unsigned char cpu_number); extern void z_loapic_int_vec_set(unsigned int irq, unsigned int vector); extern void z_loapic_irq_enable(unsigned int irq); extern void z_loapic_irq_disable(unsigned int irq);