#include <config.h>
#include <arch/kernel/xapic.h>
#include <arch/kernel/x2apic.h>
#ifdef CONFIG_XAPIC
#ifdef CONFIG_USE_LOGICAL_IDS
compile_assert(number_of_cores_invalid_for_logical_ids, CONFIG_MAX_NUM_NODES <= 8)
BOOT_CODE static void
init_xapic_ldr(void)
{
uint32_t ldr;
apic_write_reg(APIC_DEST_FORMAT, XAPIC_DFR_FLAT);
ldr = apic_read_reg(APIC_LOGICAL_DEST) & MASK(XAPIC_LDR_SHIFT);
ldr |= (BIT(getCurrentCPUIndex()) << XAPIC_LDR_SHIFT);
apic_write_reg(APIC_LOGICAL_DEST, ldr);
}
#endif
BOOT_CODE bool_t
apic_enable(void)
{
apic_base_msr_t apic_base_msr;
apic_base_msr.words[0] = x86_rdmsr_low(IA32_APIC_BASE_MSR);
if (!apic_base_msr_get_enabled(apic_base_msr)) {
printf("APIC: Enabled bit not set\n");
return false;
}
if (x2apic_is_enabled()) {
printf("x2APIC enabled in BIOS but kernel does not support that\n");
return false;
}
#ifdef CONFIG_USE_LOGICAL_IDS
init_xapic_ldr();
#endif
return true;
}
bool_t apic_is_interrupt_pending(void)
{
word_t i;
assert(int_irq_min % 32 == 0);
for (i = int_irq_min; i <= int_irq_max; i += 32) {
if (apic_read_reg(APIC_IRR_BASE + i / 2) != 0) {
return true;
}
}
return false;
}
BOOT_CODE void
apic_send_init_ipi(cpu_id_t cpu_id)
{
apic_write_icr(
apic_icr2_new(
cpu_id
).words[0],
apic_icr1_new(
0,
1,
1,
0,
0,
5,
0
).words[0]
);
apic_write_icr(
apic_icr2_new(
cpu_id
).words[0],
apic_icr1_new(
0,
1,
0,
0,
0,
5,
0
).words[0]
);
}
BOOT_CODE void
apic_send_startup_ipi(cpu_id_t cpu_id, paddr_t startup_addr)
{
assert(IS_ALIGNED(startup_addr, PAGE_BITS));
assert(startup_addr < 0xa0000);
startup_addr >>= PAGE_BITS;
apic_write_icr(
apic_icr2_new(
cpu_id
).words[0],
apic_icr1_new(
0,
0,
0,
0,
0,
6,
startup_addr
).words[0]
);
}
void apic_send_ipi_core(irq_t vector, cpu_id_t cpu_id)
{
apic_icr1_t icr1;
do {
icr1.words[0] = apic_read_reg(APIC_ICR1);
} while (apic_icr1_get_delivery_status(icr1));
apic_write_icr(
apic_icr2_new(
cpu_id
).words[0],
apic_icr1_new(
0,
0,
0,
0,
0,
0,
vector
).words[0]
);
}
void apic_send_ipi_cluster(irq_t vector, word_t mda)
{
apic_icr1_t icr1;
do {
icr1.words[0] = apic_read_reg(APIC_ICR1);
} while (apic_icr1_get_delivery_status(icr1));
apic_write_icr(
apic_icr2_new(
mda
).words[0],
apic_icr1_new(
0,
0,
0,
0,
1,
0,
vector
).words[0]
);
}
#endif