mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2026-01-04 15:14:27 +00:00
hv: pirq: rename related source files
To make the file structure clearer, change the file names: - rename arch/x86/interrupt.c to virq.c, for the virtual irq relavant code, such as irq injection etc; - merge arch/x86/intr_main.c into arch/x86/irq.c; - rename arch/x86/intr_lapic.c to lapic.c Signed-off-by: Yan, Like <like.yan@intel.com> Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
456
hypervisor/arch/x86/lapic.c
Normal file
456
hypervisor/arch/x86/lapic.c
Normal file
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <hypervisor.h>
|
||||
|
||||
/* Rate range 1 to 1000 or 1uSec to 1mSec */
|
||||
#define APIC_TIMER_MAX 0xffffffff
|
||||
#define HYPE_PERIOD_MAX 1000
|
||||
#define APIC_DIVIDE_BY_ONE 0x0b
|
||||
#define PIT_TARGET 0x3FFF
|
||||
|
||||
/* xAPIC/x2APIC Interrupt Command Register (ICR) structure */
|
||||
union apic_icr {
|
||||
uint64_t value;
|
||||
struct {
|
||||
uint32_t lo_32;
|
||||
uint32_t hi_32;
|
||||
} value_32;
|
||||
struct {
|
||||
uint64_t vector:8;
|
||||
uint64_t delivery_mode:3;
|
||||
uint64_t destination_mode:1;
|
||||
uint64_t delivery_status:1;
|
||||
uint64_t rsvd_1:1;
|
||||
uint64_t level:1;
|
||||
uint64_t trigger_mode:1;
|
||||
uint64_t rsvd_2:2;
|
||||
uint64_t shorthand:2;
|
||||
uint64_t rsvd_3:12;
|
||||
uint64_t rsvd_4:32;
|
||||
} bits;
|
||||
struct {
|
||||
uint64_t rsvd_1:32;
|
||||
uint64_t rsvd_2:24;
|
||||
uint64_t dest_field:8;
|
||||
} x_bits;
|
||||
struct {
|
||||
uint64_t rsvd_1:32;
|
||||
uint64_t dest_field:32;
|
||||
} x2_bits;
|
||||
};
|
||||
|
||||
/* xAPIC/x2APIC Interrupt Command Register (ICR) structure */
|
||||
union apic_lvt {
|
||||
uint32_t value;
|
||||
union {
|
||||
struct {
|
||||
uint32_t vector:8;
|
||||
uint32_t rsvd_1:4;
|
||||
uint32_t delivery_status:1;
|
||||
uint32_t rsvd_2:3;
|
||||
uint32_t mask:1;
|
||||
uint32_t mode:2;
|
||||
uint32_t rsvd_3:13;
|
||||
} timer;
|
||||
struct {
|
||||
uint32_t vector:8;
|
||||
uint32_t delivery_mode:3;
|
||||
uint32_t rsvd_1:1;
|
||||
uint32_t delivery_status:1;
|
||||
uint32_t rsvd_2:3;
|
||||
uint32_t mask:1;
|
||||
uint32_t rsvd_3:15;
|
||||
} cmci;
|
||||
struct {
|
||||
uint32_t vector:8;
|
||||
uint32_t delivery_mode:3;
|
||||
uint32_t rsvd_1:1;
|
||||
uint32_t delivery_status:1;
|
||||
uint32_t polarity:1;
|
||||
uint32_t remote_irr:1;
|
||||
uint32_t trigger_mode:1;
|
||||
uint32_t mask:1;
|
||||
uint32_t rsvd_2:15;
|
||||
} lint;
|
||||
struct {
|
||||
uint32_t vector:8;
|
||||
uint32_t rsvd_1:4;
|
||||
uint32_t delivery_status:1;
|
||||
uint32_t rsvd_2:3;
|
||||
uint32_t mask:1;
|
||||
uint32_t rsvd_3:15;
|
||||
} error;
|
||||
struct {
|
||||
uint32_t vector:8;
|
||||
uint32_t delivery_mode:3;
|
||||
uint32_t rsvd_1:1;
|
||||
uint32_t delivery_status:1;
|
||||
uint32_t rsvd_2:3;
|
||||
uint32_t mask:1;
|
||||
uint32_t rsvd_3:15;
|
||||
} pmc;
|
||||
struct {
|
||||
uint32_t vector:8;
|
||||
uint32_t delivery_mode:3;
|
||||
uint32_t rsvd_1:1;
|
||||
uint32_t delivery_status:1;
|
||||
uint32_t rsvd_2:3;
|
||||
uint32_t mask:1;
|
||||
uint32_t rsvd_3:15;
|
||||
} thermal;
|
||||
struct {
|
||||
uint32_t vector:8;
|
||||
uint32_t rsvd_1:4;
|
||||
uint32_t delivery_status:1;
|
||||
uint32_t rsvd_2:3;
|
||||
uint32_t mask:1;
|
||||
uint32_t rsvd_3:15;
|
||||
} common;
|
||||
} bits;
|
||||
};
|
||||
|
||||
union lapic_base_msr {
|
||||
uint64_t value;
|
||||
struct {
|
||||
uint64_t rsvd_1:8;
|
||||
uint64_t bsp:1;
|
||||
uint64_t rsvd_2:1;
|
||||
uint64_t x2APIC_enable:1;
|
||||
uint64_t xAPIC_enable:1;
|
||||
uint64_t lapic_paddr:24;
|
||||
uint64_t rsvd_3:28;
|
||||
} fields;
|
||||
};
|
||||
|
||||
struct lapic_info {
|
||||
int init_status;
|
||||
struct {
|
||||
uint64_t paddr;
|
||||
void *vaddr;
|
||||
} xapic;
|
||||
};
|
||||
|
||||
static struct lapic_info lapic_info;
|
||||
static struct lapic_regs saved_lapic_regs;
|
||||
static union lapic_base_msr lapic_base_msr;
|
||||
|
||||
static inline uint32_t read_lapic_reg32(uint32_t offset)
|
||||
{
|
||||
if (offset < 0x20 || offset > 0x3ff)
|
||||
return 0;
|
||||
|
||||
return mmio_read_long(lapic_info.xapic.vaddr + offset);
|
||||
}
|
||||
|
||||
inline void write_lapic_reg32(uint32_t offset, uint32_t value)
|
||||
{
|
||||
if (offset < 0x20 || offset > 0x3ff)
|
||||
return;
|
||||
|
||||
mmio_write_long(value, lapic_info.xapic.vaddr + offset);
|
||||
}
|
||||
|
||||
static void clear_lapic_isr(void)
|
||||
{
|
||||
uint64_t isr_reg = LAPIC_IN_SERVICE_REGISTER_0;
|
||||
|
||||
/* This is a Intel recommended procedure and assures that the processor
|
||||
* does not get hung up due to already set "in-service" interrupts left
|
||||
* over from the boot loader environment. This actually occurs in real
|
||||
* life, therefore we will ensure all the in-service bits are clear.
|
||||
*/
|
||||
do {
|
||||
if (read_lapic_reg32(isr_reg) != 0U) {
|
||||
write_lapic_reg32(LAPIC_EOI_REGISTER, 0);
|
||||
continue;
|
||||
}
|
||||
isr_reg += 0x10;
|
||||
} while (isr_reg <= LAPIC_IN_SERVICE_REGISTER_7);
|
||||
}
|
||||
|
||||
static void map_lapic(void)
|
||||
{
|
||||
/* At some point we may need to translate this paddr to a vaddr. 1:1
|
||||
* mapping for now.
|
||||
*/
|
||||
lapic_info.xapic.vaddr = HPA2HVA(lapic_info.xapic.paddr);
|
||||
}
|
||||
|
||||
int early_init_lapic(void)
|
||||
{
|
||||
/* Get local APIC base address */
|
||||
lapic_base_msr.value = msr_read(MSR_IA32_APIC_BASE);
|
||||
|
||||
/* Initialize globals only 1 time */
|
||||
if (lapic_info.init_status == false) {
|
||||
/* Get Local APIC physical address. */
|
||||
lapic_info.xapic.paddr = LAPIC_BASE;
|
||||
|
||||
/* Map in the local xAPIC */
|
||||
map_lapic();
|
||||
|
||||
lapic_info.init_status = true;
|
||||
}
|
||||
|
||||
/* Check if xAPIC mode enabled */
|
||||
if (lapic_base_msr.fields.xAPIC_enable == 0) {
|
||||
/* Ensure in xAPIC mode */
|
||||
lapic_base_msr.fields.xAPIC_enable = 1;
|
||||
lapic_base_msr.fields.x2APIC_enable = 0;
|
||||
msr_write(MSR_IA32_APIC_BASE, lapic_base_msr.value);
|
||||
} else {
|
||||
/* Check if x2apic is disabled */
|
||||
ASSERT(lapic_base_msr.fields.x2APIC_enable == 0,
|
||||
"Disable X2APIC in BIOS");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int init_lapic(uint16_t cpu_id)
|
||||
{
|
||||
/* Set the Logical Destination Register */
|
||||
write_lapic_reg32(LAPIC_LOGICAL_DESTINATION_REGISTER,
|
||||
((1U << cpu_id) << 24));
|
||||
|
||||
/* Set the Destination Format Register */
|
||||
write_lapic_reg32(LAPIC_DESTINATION_FORMAT_REGISTER, 0xf << 28);
|
||||
|
||||
/* Mask all LAPIC LVT entries before enabling the local APIC */
|
||||
write_lapic_reg32(LAPIC_LVT_CMCI_REGISTER, LAPIC_LVT_MASK);
|
||||
write_lapic_reg32(LAPIC_LVT_TIMER_REGISTER, LAPIC_LVT_MASK);
|
||||
write_lapic_reg32(LAPIC_LVT_THERMAL_SENSOR_REGISTER, LAPIC_LVT_MASK);
|
||||
write_lapic_reg32(LAPIC_LVT_PMC_REGISTER, LAPIC_LVT_MASK);
|
||||
write_lapic_reg32(LAPIC_LVT_LINT0_REGISTER, LAPIC_LVT_MASK);
|
||||
write_lapic_reg32(LAPIC_LVT_LINT1_REGISTER, LAPIC_LVT_MASK);
|
||||
write_lapic_reg32(LAPIC_LVT_ERROR_REGISTER, LAPIC_LVT_MASK);
|
||||
|
||||
/* Enable Local APIC */
|
||||
/* TODO: add spurious-interrupt handler */
|
||||
write_lapic_reg32(LAPIC_SPURIOUS_VECTOR_REGISTER,
|
||||
LAPIC_SVR_APIC_ENABLE_MASK | LAPIC_SVR_VECTOR);
|
||||
|
||||
/* Ensure there are no ISR bits set. */
|
||||
clear_lapic_isr();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void save_lapic(struct lapic_regs *regs)
|
||||
{
|
||||
regs->id = read_lapic_reg32(LAPIC_ID_REGISTER);
|
||||
regs->tpr = read_lapic_reg32(LAPIC_TASK_PRIORITY_REGISTER);
|
||||
regs->apr = read_lapic_reg32(LAPIC_ARBITRATION_PRIORITY_REGISTER);
|
||||
regs->ppr = read_lapic_reg32(LAPIC_PROCESSOR_PRIORITY_REGISTER);
|
||||
regs->ldr = read_lapic_reg32(LAPIC_LOGICAL_DESTINATION_REGISTER);
|
||||
regs->dfr = read_lapic_reg32(LAPIC_DESTINATION_FORMAT_REGISTER);
|
||||
regs->tmr[0] = read_lapic_reg32(LAPIC_TRIGGER_MODE_REGISTER_0);
|
||||
regs->tmr[1] = read_lapic_reg32(LAPIC_TRIGGER_MODE_REGISTER_1);
|
||||
regs->tmr[2] = read_lapic_reg32(LAPIC_TRIGGER_MODE_REGISTER_2);
|
||||
regs->tmr[3] = read_lapic_reg32(LAPIC_TRIGGER_MODE_REGISTER_3);
|
||||
regs->tmr[4] = read_lapic_reg32(LAPIC_TRIGGER_MODE_REGISTER_4);
|
||||
regs->tmr[5] = read_lapic_reg32(LAPIC_TRIGGER_MODE_REGISTER_5);
|
||||
regs->tmr[6] = read_lapic_reg32(LAPIC_TRIGGER_MODE_REGISTER_6);
|
||||
regs->tmr[7] = read_lapic_reg32(LAPIC_TRIGGER_MODE_REGISTER_7);
|
||||
regs->svr = read_lapic_reg32(LAPIC_SPURIOUS_VECTOR_REGISTER);
|
||||
regs->lvtt = read_lapic_reg32(LAPIC_LVT_TIMER_REGISTER);
|
||||
regs->lvt0 = read_lapic_reg32(LAPIC_LVT_LINT0_REGISTER);
|
||||
regs->lvt1 = read_lapic_reg32(LAPIC_LVT_LINT1_REGISTER);
|
||||
regs->lvterr = read_lapic_reg32(LAPIC_LVT_ERROR_REGISTER);
|
||||
regs->ticr = read_lapic_reg32(LAPIC_INITIAL_COUNT_REGISTER);
|
||||
regs->tccr = read_lapic_reg32(LAPIC_CURRENT_COUNT_REGISTER);
|
||||
regs->tdcr = read_lapic_reg32(LAPIC_DIVIDE_CONFIGURATION_REGISTER);
|
||||
}
|
||||
|
||||
static void restore_lapic(struct lapic_regs *regs)
|
||||
{
|
||||
write_lapic_reg32(LAPIC_ID_REGISTER, regs->id);
|
||||
write_lapic_reg32(LAPIC_TASK_PRIORITY_REGISTER, regs->tpr);
|
||||
write_lapic_reg32(LAPIC_LOGICAL_DESTINATION_REGISTER, regs->ldr );
|
||||
write_lapic_reg32(LAPIC_DESTINATION_FORMAT_REGISTER, regs->dfr );
|
||||
write_lapic_reg32(LAPIC_SPURIOUS_VECTOR_REGISTER, regs->svr );
|
||||
write_lapic_reg32(LAPIC_LVT_TIMER_REGISTER, regs->lvtt );
|
||||
|
||||
write_lapic_reg32(LAPIC_LVT_LINT0_REGISTER, regs->lvt0 );
|
||||
write_lapic_reg32(LAPIC_LVT_LINT1_REGISTER, regs->lvt1 );
|
||||
|
||||
write_lapic_reg32(LAPIC_LVT_ERROR_REGISTER, regs->lvterr );
|
||||
write_lapic_reg32(LAPIC_INITIAL_COUNT_REGISTER, regs->ticr );
|
||||
write_lapic_reg32(LAPIC_DIVIDE_CONFIGURATION_REGISTER, regs->tdcr );
|
||||
|
||||
|
||||
write_lapic_reg32(LAPIC_ARBITRATION_PRIORITY_REGISTER, regs->apr );
|
||||
write_lapic_reg32(LAPIC_PROCESSOR_PRIORITY_REGISTER, regs->ppr );
|
||||
write_lapic_reg32(LAPIC_TRIGGER_MODE_REGISTER_0, regs->tmr[0] );
|
||||
write_lapic_reg32(LAPIC_TRIGGER_MODE_REGISTER_1, regs->tmr[1] );
|
||||
write_lapic_reg32(LAPIC_TRIGGER_MODE_REGISTER_2, regs->tmr[2] );
|
||||
write_lapic_reg32(LAPIC_TRIGGER_MODE_REGISTER_3, regs->tmr[3] );
|
||||
write_lapic_reg32(LAPIC_TRIGGER_MODE_REGISTER_4, regs->tmr[4] );
|
||||
write_lapic_reg32(LAPIC_TRIGGER_MODE_REGISTER_5, regs->tmr[5] );
|
||||
write_lapic_reg32(LAPIC_TRIGGER_MODE_REGISTER_6, regs->tmr[6] );
|
||||
write_lapic_reg32(LAPIC_TRIGGER_MODE_REGISTER_7, regs->tmr[7] );
|
||||
write_lapic_reg32(LAPIC_CURRENT_COUNT_REGISTER, regs->tccr );
|
||||
}
|
||||
|
||||
void suspend_lapic(void)
|
||||
{
|
||||
uint32_t val = 0;
|
||||
|
||||
save_lapic(&saved_lapic_regs);
|
||||
|
||||
/* disable APIC with software flag */
|
||||
val = read_lapic_reg32(LAPIC_SPURIOUS_VECTOR_REGISTER);
|
||||
write_lapic_reg32(LAPIC_SPURIOUS_VECTOR_REGISTER,
|
||||
(~LAPIC_SVR_APIC_ENABLE_MASK) & val);
|
||||
}
|
||||
|
||||
void resume_lapic(void)
|
||||
{
|
||||
msr_write(MSR_IA32_APIC_BASE, lapic_base_msr.value);
|
||||
|
||||
/* ACPI software flag will be restored also */
|
||||
restore_lapic(&saved_lapic_regs);
|
||||
}
|
||||
|
||||
void send_lapic_eoi(void)
|
||||
{
|
||||
write_lapic_reg32(LAPIC_EOI_REGISTER, 0);
|
||||
}
|
||||
|
||||
static void wait_for_delivery(void)
|
||||
{
|
||||
union apic_icr tmp;
|
||||
|
||||
do {
|
||||
tmp.value_32.lo_32 =
|
||||
read_lapic_reg32(LAPIC_INT_COMMAND_REGISTER_0);
|
||||
} while (tmp.bits.delivery_status != 0U);
|
||||
}
|
||||
|
||||
uint32_t get_cur_lapic_id(void)
|
||||
{
|
||||
uint32_t lapic_id;
|
||||
|
||||
lapic_id = read_lapic_reg32(LAPIC_ID_REGISTER);
|
||||
lapic_id = (lapic_id >> 24);
|
||||
|
||||
return lapic_id;
|
||||
}
|
||||
|
||||
int
|
||||
send_startup_ipi(enum intr_cpu_startup_shorthand cpu_startup_shorthand,
|
||||
uint32_t cpu_startup_dest, uint64_t cpu_startup_start_address)
|
||||
{
|
||||
union apic_icr icr;
|
||||
uint8_t shorthand;
|
||||
int status = 0;
|
||||
|
||||
if (cpu_startup_shorthand >= INTR_CPU_STARTUP_UNKNOWN)
|
||||
status = -EINVAL;
|
||||
|
||||
ASSERT(status == 0, "Incorrect arguments");
|
||||
|
||||
icr.value = 0;
|
||||
icr.bits.destination_mode = INTR_LAPIC_ICR_PHYSICAL;
|
||||
|
||||
if (cpu_startup_shorthand == INTR_CPU_STARTUP_USE_DEST) {
|
||||
shorthand = INTR_LAPIC_ICR_USE_DEST_ARRAY;
|
||||
icr.x_bits.dest_field = per_cpu(lapic_id, cpu_startup_dest);
|
||||
} else { /* Use destination shorthand */
|
||||
shorthand = INTR_LAPIC_ICR_ALL_EX_SELF;
|
||||
icr.value_32.hi_32 = 0;
|
||||
}
|
||||
|
||||
/* Assert INIT IPI */
|
||||
write_lapic_reg32(LAPIC_INT_COMMAND_REGISTER_1, icr.value_32.hi_32);
|
||||
icr.bits.shorthand = shorthand;
|
||||
icr.bits.delivery_mode = INTR_LAPIC_ICR_INIT;
|
||||
icr.bits.level = INTR_LAPIC_ICR_ASSERT;
|
||||
icr.bits.trigger_mode = INTR_LAPIC_ICR_LEVEL;
|
||||
write_lapic_reg32(LAPIC_INT_COMMAND_REGISTER_0, icr.value_32.lo_32);
|
||||
wait_for_delivery();
|
||||
|
||||
/* Give 10ms for INIT sequence to complete for old processors.
|
||||
* Modern processors (family == 6) don't need to wait here.
|
||||
*/
|
||||
if (boot_cpu_data.x86 != 6)
|
||||
mdelay(10);
|
||||
|
||||
/* De-assert INIT IPI */
|
||||
write_lapic_reg32(LAPIC_INT_COMMAND_REGISTER_1, icr.value_32.hi_32);
|
||||
icr.bits.level = INTR_LAPIC_ICR_DEASSERT;
|
||||
write_lapic_reg32(LAPIC_INT_COMMAND_REGISTER_0, icr.value_32.lo_32);
|
||||
wait_for_delivery();
|
||||
|
||||
/* Send Start IPI with page number of secondary reset code */
|
||||
write_lapic_reg32(LAPIC_INT_COMMAND_REGISTER_1, icr.value_32.hi_32);
|
||||
icr.value_32.lo_32 = 0;
|
||||
icr.bits.shorthand = shorthand;
|
||||
icr.bits.delivery_mode = INTR_LAPIC_ICR_STARTUP;
|
||||
icr.bits.vector = ((uint64_t) cpu_startup_start_address) >> 12;
|
||||
write_lapic_reg32(LAPIC_INT_COMMAND_REGISTER_0, icr.value_32.lo_32);
|
||||
wait_for_delivery();
|
||||
|
||||
if (boot_cpu_data.x86 == 6) /* 10us is enough for Modern processors */
|
||||
udelay(10);
|
||||
else /* 200us for old processors */
|
||||
udelay(200);
|
||||
|
||||
/* Send another start IPI as per the Intel Arch specification */
|
||||
write_lapic_reg32(LAPIC_INT_COMMAND_REGISTER_1, icr.value_32.hi_32);
|
||||
write_lapic_reg32(LAPIC_INT_COMMAND_REGISTER_0, icr.value_32.lo_32);
|
||||
wait_for_delivery();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void send_single_ipi(uint16_t pcpu_id, uint32_t vector)
|
||||
{
|
||||
uint32_t dest_lapic_id, hi_32, lo_32;
|
||||
|
||||
/* Get the lapic ID of the destination processor. */
|
||||
dest_lapic_id = per_cpu(lapic_id, pcpu_id);
|
||||
|
||||
/* Set the target processor. */
|
||||
hi_32 = dest_lapic_id << 24;
|
||||
|
||||
/* Set the vector ID. */
|
||||
lo_32 = vector;
|
||||
|
||||
/* Set the destination field to the target processor. */
|
||||
write_lapic_reg32(LAPIC_INT_COMMAND_REGISTER_1, hi_32);
|
||||
|
||||
/* Write the vector ID to ICR. */
|
||||
write_lapic_reg32(LAPIC_INT_COMMAND_REGISTER_0, lo_32);
|
||||
|
||||
wait_for_delivery();
|
||||
}
|
||||
|
||||
int send_shorthand_ipi(uint8_t vector,
|
||||
enum intr_lapic_icr_shorthand shorthand,
|
||||
enum intr_lapic_icr_delivery_mode delivery_mode)
|
||||
{
|
||||
union apic_icr icr;
|
||||
int status = 0;
|
||||
|
||||
if ((shorthand < INTR_LAPIC_ICR_SELF)
|
||||
|| (shorthand > INTR_LAPIC_ICR_ALL_EX_SELF)
|
||||
|| (delivery_mode > INTR_LAPIC_ICR_NMI))
|
||||
status = -EINVAL;
|
||||
|
||||
ASSERT(status == 0, "Incorrect arguments");
|
||||
|
||||
icr.value = 0;
|
||||
icr.bits.shorthand = shorthand;
|
||||
icr.bits.delivery_mode = delivery_mode;
|
||||
icr.bits.vector = vector;
|
||||
write_lapic_reg32(LAPIC_INT_COMMAND_REGISTER_1, icr.value_32.hi_32);
|
||||
write_lapic_reg32(LAPIC_INT_COMMAND_REGISTER_0, icr.value_32.lo_32);
|
||||
wait_for_delivery();
|
||||
|
||||
return status;
|
||||
}
|
||||
Reference in New Issue
Block a user