summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--payloads/libpayload/arch/x86/apic.c34
-rw-r--r--payloads/libpayload/include/x86/arch/apic.h2
2 files changed, 33 insertions, 3 deletions
diff --git a/payloads/libpayload/arch/x86/apic.c b/payloads/libpayload/arch/x86/apic.c
index a484163054..62011612a5 100644
--- a/payloads/libpayload/arch/x86/apic.c
+++ b/payloads/libpayload/arch/x86/apic.c
@@ -104,7 +104,7 @@ uint8_t apic_id(void)
return id;
}
-void apic_delay(unsigned int usec)
+void apic_start_delay(unsigned int usec)
{
die_if(!ticks_per_ms, "apic_init_timer was not run.");
die_if(timer_waiting, "timer already started.");
@@ -124,9 +124,17 @@ void apic_delay(unsigned int usec)
timer_waiting = 1;
apic_write32(APIC_TIMER_INIT_COUNT, ticks);
+ enable_interrupts();
+}
+
+void apic_wait_delay(void)
+{
/* Loop in case another interrupt has fired and resumed execution. */
- do {
+ disable_interrupts();
+ /* Note: when we test timer_waiting, interrupts are disabled by the line
+ * above and the cli below. */
+ while (timer_waiting) {
asm volatile(
"sti\n\t"
"hlt\n\t"
@@ -134,15 +142,22 @@ void apic_delay(unsigned int usec)
* between checking timer_waiting and executing the hlt
* instruction again. */
"cli\n\t");
- } while (timer_waiting);
+ }
/* Leave hardware interrupts enabled. */
enable_interrupts();
}
+void apic_delay(unsigned int usec)
+{
+ apic_start_delay(usec);
+ apic_wait_delay();
+}
+
static void timer_interrupt_handler(u8 vector)
{
timer_waiting = 0;
+ apic_eoi(APIC_TIMER_VECTOR);
}
static void suprious_interrupt_handler(u8 vector) {}
@@ -204,6 +219,7 @@ static void apic_reset_all_lvts(void)
uint8_t max = apic_max_lvt_entries();
for (int i = 0; i <= max; ++i) {
uint32_t offset = APIC_LVT_TIMER + APIC_LVT_SIZE * i;
+ apic_eoi(i);
apic_write32(offset, APIC_MASKED_BIT);
}
}
@@ -248,6 +264,16 @@ static void apic_init_timer(void)
apic_write32(APIC_LVT_TIMER, APIC_TIMER_VECTOR);
}
+static void apic_sw_disable(void)
+{
+ uint32_t reg = apic_read32(APIC_SPURIOUS);
+
+ reg &= ~APIC_SW_ENABLED_BIT;
+ printf("%s: writing %#x to %#x\n", __func__, reg, APIC_SPURIOUS);
+
+ apic_write32(APIC_SPURIOUS, reg);
+}
+
static void apic_sw_enable(void)
{
uint32_t reg = apic_read32(APIC_SPURIOUS);
@@ -280,6 +306,7 @@ void apic_init(void)
die_if(!(apic_capabilities() & XACPI), "APIC is not supported");
apic_bar_reg = _rdmsr(APIC_BASE_MSR);
+ printf("apic_bar_reg is 0x%llx\n", apic_bar_reg);
die_if(!(apic_bar_reg & XAPIC_ENABLED_BIT), "APIC is not enabled");
die_if(apic_bar_reg & X2APIC_ENABLED_BIT,
@@ -287,6 +314,7 @@ void apic_init(void)
apic_bar = (uint32_t)(apic_bar_reg & APIC_BASE_MASK);
+ apic_sw_disable();
apic_reset_all_lvts();
apic_set_task_priority(0);
apic_setup_spurious();
diff --git a/payloads/libpayload/include/x86/arch/apic.h b/payloads/libpayload/include/x86/arch/apic.h
index 3c9877cb54..eedf1b4b2b 100644
--- a/payloads/libpayload/include/x86/arch/apic.h
+++ b/payloads/libpayload/include/x86/arch/apic.h
@@ -40,5 +40,7 @@ uint8_t apic_id(void);
void apic_eoi(uint8_t vector);
void apic_delay(unsigned int usec);
+void apic_start_delay(unsigned int usec);
+void apic_wait_delay(void);
#endif /* __ARCH_X86_INCLUDES_ARCH_APIC_H__ */