- Introduce supppoprt for APIC error handling

- Start IOAPIC base after LAPIC LVT irqs
- Use uncacheable mappings for APIC and ACPI memory
-
This commit is contained in:
Jan Stoess 2008-01-16 13:59:12 +01:00
parent e029062e4e
commit 997eeb3d4a
6 changed files with 86 additions and 24 deletions

View File

@ -169,6 +169,24 @@ private:
} x; } x;
}; };
}; };
class esr_reg_t
{
public:
union {
u32_t raw;
struct {
u32_t tx_csum : 1;
u32_t rx_csum : 1;
u32_t tx_accept : 1;
u32_t rx_accept : 1;
u32_t tx_illegal_vector : 1;
u32_t rx_illegal_vector : 1;
u32_t illegal_reg : 1;
u32_t reserved : 25;
} x;
};
};
void set_prio(regno_t reg, u8_t prio, u8_t subprio) void set_prio(regno_t reg, u8_t prio, u8_t subprio)
{ {
@ -233,7 +251,8 @@ public:
bool set_vector(lvt_t lvt, delivery_mode_t del_mode, bool set_vector(lvt_t lvt, delivery_mode_t del_mode,
pin_polarity_t polarity, pin_polarity_t polarity,
trigger_mode_t trigger_mode); trigger_mode_t trigger_mode);
public: public:
/* Timer handling */ /* Timer handling */
u32_t timer_get() { u32_t timer_get() {
@ -299,6 +318,22 @@ public:
void send_ipi(u8_t apic_id, u8_t vector); void send_ipi(u8_t apic_id, u8_t vector);
void broadcast_ipi(u8_t vector, bool self = false); void broadcast_ipi(u8_t vector, bool self = false);
void broadcast_nmi(bool self = false); void broadcast_nmi(bool self = false);
public:
/* Error handling */
void error_setup(u8_t irq)
{
write_reg((regno_t) APIC_LVT_ERROR, irq);
write_reg((regno_t) APIC_ERR_STATUS, 0);
write_reg((regno_t) APIC_ERR_STATUS, 0);
}
word_t read_error()
{
write_reg((regno_t) APIC_ERR_STATUS, 0);
return read_reg((regno_t) APIC_ERR_STATUS);
}
}; };
@ -339,7 +374,7 @@ INLINE bool local_apic_t<base>::disable()
spurious_int_vector_reg_t svr; spurious_int_vector_reg_t svr;
svr.raw = read_reg(APIC_SVR); svr.raw = read_reg(APIC_SVR);
bool enabled = svr.x.enabled; bool enabled = svr.x.enabled;
svr.x.enabled = 0; svr.x.enabled = 0;
write_reg(APIC_SVR, svr.raw); write_reg(APIC_SVR, svr.raw);
return enabled; return enabled;
} }
@ -347,15 +382,12 @@ INLINE bool local_apic_t<base>::disable()
template <word_t base> template <word_t base>
INLINE void local_apic_t<base>::send_startup_ipi(u8_t apic_id, void(*startup_func)(void)) INLINE void local_apic_t<base>::send_startup_ipi(u8_t apic_id, void(*startup_func)(void))
{ {
//ASSERT(((word_t)startup & ~X86_PAGE_MASK) == 0);
//ASSERT(((word_t)startup >> (X86_PAGE_BITS + 8)) == 0);
// destination // destination
write_reg(APIC_INTR_CMD2, ((word_t)apic_id) << (56 - 32)); write_reg(APIC_INTR_CMD2, ((word_t)apic_id) << (56 - 32));
command_reg_t reg; command_reg_t reg;
reg.raw = read_reg(APIC_INTR_CMD1); reg.raw = read_reg(APIC_INTR_CMD1);
// the startup-address of the receiving processor is // the startup-address of the receiving processor is
// 0x000VV000, where VV is sent with the SIPI. // 0x000VV000, where VV is sent with the SIPI.
word_t startup_vector = (word_t) startup_func; word_t startup_vector = (word_t) startup_func;
reg.x.vector = ((u32_t)startup_vector) >> 12 & 0xff; ; reg.x.vector = ((u32_t)startup_vector) >> 12 & 0xff; ;
reg.x.delivery_mode = startup; reg.x.delivery_mode = startup;
@ -364,30 +396,37 @@ INLINE void local_apic_t<base>::send_startup_ipi(u8_t apic_id, void(*startup_fun
reg.x.level = 0; reg.x.level = 0;
reg.x.trigger_mode = 0; reg.x.trigger_mode = 0;
write_reg(APIC_INTR_CMD1, reg.raw); write_reg(APIC_INTR_CMD1, reg.raw);
} }
template <word_t base> template <word_t base>
INLINE void local_apic_t<base>::send_init_ipi(u8_t apic_id, bool assert) INLINE void local_apic_t<base>::send_init_ipi(u8_t apic_id, bool assert)
{ {
// destination // destination
write_reg(APIC_INTR_CMD2, ((word_t)apic_id) << (56 - 32)); write_reg(APIC_INTR_CMD2, ((word_t)apic_id) << (56 - 32));
command_reg_t reg; command_reg_t reg;
reg.raw = read_reg(APIC_INTR_CMD1); reg.raw = read_reg(APIC_INTR_CMD1);
reg.x.vector = 0; reg.x.vector = 0;
reg.x.delivery_mode = init; reg.x.delivery_mode = init;
reg.x.destination_mode = 0; reg.x.destination_mode = 0;
reg.x.destination = 0; reg.x.destination = 0;
reg.x.level = assert ? 1 : 0; reg.x.level = assert ? 1 : 0;
reg.x.trigger_mode = 1; reg.x.trigger_mode = 1;
write_reg(APIC_INTR_CMD1, reg.raw); write_reg((regno_t) (APIC_INTR_CMD1), reg.raw);
} }
template <word_t base> template <word_t base>
INLINE void local_apic_t<base>::send_nmi(u8_t apic_id) INLINE void local_apic_t<base>::send_nmi(u8_t apic_id)
{ {
command_reg_t reg;
reg.raw = read_reg(APIC_INTR_CMD1);
ASSERT(reg.x.delivery_status == 0);
// destination // destination
write_reg(APIC_INTR_CMD2, ((word_t)apic_id) << (56 - 32)); write_reg(APIC_INTR_CMD2, ((word_t)apic_id) << (56 - 32));
command_reg_t reg;
reg.raw = read_reg(APIC_INTR_CMD1); reg.raw = read_reg(APIC_INTR_CMD1);
reg.x.vector = 0; reg.x.vector = 0;
reg.x.delivery_mode = nmi; reg.x.delivery_mode = nmi;
@ -396,25 +435,34 @@ INLINE void local_apic_t<base>::send_nmi(u8_t apic_id)
reg.x.level = 1; reg.x.level = 1;
reg.x.trigger_mode = 1; reg.x.trigger_mode = 1;
write_reg(APIC_INTR_CMD1, reg.raw); write_reg(APIC_INTR_CMD1, reg.raw);
} }
template <word_t base> template <word_t base>
INLINE void local_apic_t<base>::send_ipi(u8_t apic_id, u8_t vector) INLINE void local_apic_t<base>::send_ipi(u8_t apic_id, u8_t vector)
{ {
command_reg_t reg;
reg.raw = read_reg(APIC_INTR_CMD1);
ASSERT(reg.x.delivery_status == 0);
// destination // destination
write_reg(APIC_INTR_CMD2, ((word_t)apic_id) << (56 - 32)); write_reg(APIC_INTR_CMD2, ((word_t)apic_id) << (56 - 32));
command_reg_t reg;
reg.raw = 0; reg.raw = 0;
reg.x.vector = vector; reg.x.vector = vector;
write_reg(APIC_INTR_CMD1, reg.raw); write_reg(APIC_INTR_CMD1, reg.raw);
} }
template <word_t base> template <word_t base>
INLINE void local_apic_t<base>::broadcast_ipi(u8_t vector, bool self) INLINE void local_apic_t<base>::broadcast_ipi(u8_t vector, bool self)
{ {
command_reg_t reg; command_reg_t reg;
reg.raw = read_reg(APIC_INTR_CMD1);
ASSERT(reg.x.delivery_status == 0);
reg.raw = 0; reg.raw = 0;
reg.x.destination_mode = 1;
reg.x.destination = 2 | (self ? 0 : 1); reg.x.destination = 2 | (self ? 0 : 1);
reg.x.vector = vector; reg.x.vector = vector;
write_reg(APIC_INTR_CMD1, reg.raw); write_reg(APIC_INTR_CMD1, reg.raw);
@ -425,6 +473,9 @@ template <word_t base>
INLINE void local_apic_t<base>::broadcast_nmi(bool self) INLINE void local_apic_t<base>::broadcast_nmi(bool self)
{ {
command_reg_t reg; command_reg_t reg;
reg.raw = read_reg(APIC_INTR_CMD1);
ASSERT(reg.x.delivery_status == 0);
reg.raw = 0; reg.raw = 0;
reg.x.vector = 0; reg.x.vector = 0;
reg.x.delivery_mode = nmi; reg.x.delivery_mode = nmi;
@ -432,7 +483,7 @@ INLINE void local_apic_t<base>::broadcast_nmi(bool self)
reg.x.destination = 2 | (self ? 0 : 1); reg.x.destination = 2 | (self ? 0 : 1);
reg.x.level = 1; reg.x.level = 1;
write_reg(APIC_INTR_CMD1, reg.raw); write_reg(APIC_INTR_CMD1, reg.raw);
} }
#endif /* !__ARCH__X86__APIC_H__ */ #endif /* !__ARCH__X86__APIC_H__ */

View File

@ -1,6 +1,6 @@
/********************************************************************* /*********************************************************************
* *
* Copyright (C) 2002-2005, 2007, Karlsruhe University * Copyright (C) 2002-2005, 2007-2008, Karlsruhe University
* *
* File path: glue/v4-x86/timer-apic.cc * File path: glue/v4-x86/timer-apic.cc
* Description: implementation of apic timer * Description: implementation of apic timer
@ -43,11 +43,7 @@ timer_t timer UNIT("cpulocal");
static local_apic_t<APIC_MAPPINGS_START> local_apic; static local_apic_t<APIC_MAPPINGS_START> local_apic;
extern "C" void timer_interrupt(void); extern "C" void timer_interrupt(void);
#if defined(CONFIG_IS_64BIT)
X86_EXCNO_ERRORCODE(timer_interrupt, 0) X86_EXCNO_ERRORCODE(timer_interrupt, 0)
#else
X86_EXCNO_ERRORCODE(timer_interrupt, 0)
#endif
{ {
local_apic.EOI(); local_apic.EOI();

View File

@ -1,6 +1,6 @@
/********************************************************************* /*********************************************************************
* *
* Copyright (C) 2002-2005, 2007, Karlsruhe University * Copyright (C) 2002-2005, 2007-2008, Karlsruhe University
* *
* File path: glue/v4-x86/x32/config.h * File path: glue/v4-x86/x32/config.h
* Description: configuration of IA32 architecture * Description: configuration of IA32 architecture
@ -183,8 +183,9 @@
#define IDT_LAPIC_TIMER 0x40 #define IDT_LAPIC_TIMER 0x40
#define IDT_LAPIC_THERMAL 0x41 #define IDT_LAPIC_THERMAL 0x41
#define IDT_LAPIC_XCPU_IPI 0x42 #define IDT_LAPIC_XCPU_IPI 0x42
#define IDT_LAPIC_ERROR 0x43
#define IDT_IOAPIC_SPURIOUS 0xfb #define IDT_IOAPIC_SPURIOUS 0xfb
#define IDT_IOAPIC_BASE 0x40 #define IDT_IOAPIC_BASE 0x44
#define IDT_IOAPIC_MAX 0xf0 #define IDT_IOAPIC_MAX 0xf0
/* Page size for APIC and ACPI mappings */ /* Page size for APIC and ACPI mappings */

View File

@ -132,7 +132,7 @@ addr_t acpi_remap(addr_t addr)
get_kernel_space()->add_mapping( get_kernel_space()->add_mapping(
addr_mask (vaddr, ~page_mask (ACPI_PGENTSZ)), addr_mask (vaddr, ~page_mask (ACPI_PGENTSZ)),
addr_mask (paddr, ~page_mask (ACPI_PGENTSZ)), addr_mask (paddr, ~page_mask (ACPI_PGENTSZ)),
ACPI_PGENTSZ, true, true, false); ACPI_PGENTSZ, true, true, false, false);
vaddr = addr_offset(vaddr, page_size(ACPI_PGENTSZ)); vaddr = addr_offset(vaddr, page_size(ACPI_PGENTSZ));
paddr = addr_offset(paddr, page_size(ACPI_PGENTSZ)); paddr = addr_offset(paddr, page_size(ACPI_PGENTSZ));
@ -140,7 +140,7 @@ addr_t acpi_remap(addr_t addr)
get_kernel_space()->add_mapping( get_kernel_space()->add_mapping(
addr_mask (vaddr, ~page_mask (ACPI_PGENTSZ)), addr_mask (vaddr, ~page_mask (ACPI_PGENTSZ)),
addr_mask (paddr, ~page_mask (ACPI_PGENTSZ)), addr_mask (paddr, ~page_mask (ACPI_PGENTSZ)),
ACPI_PGENTSZ, true, true, false); ACPI_PGENTSZ, true, true, false, false);
x86_mmu_t::flush_tlb(); x86_mmu_t::flush_tlb();

View File

@ -1,6 +1,6 @@
/********************************************************************* /*********************************************************************
* *
* Copyright (C) 2002-2007, Karlsruhe University * Copyright (C) 2002-2008, Karlsruhe University
* *
* File path: glue/v4-x86/x64/config.h * File path: glue/v4-x86/x64/config.h
* Description: * Description:
@ -257,6 +257,7 @@
#define IDT_LAPIC_TIMER 0x40 #define IDT_LAPIC_TIMER 0x40
#define IDT_LAPIC_THERMAL 0x41 #define IDT_LAPIC_THERMAL 0x41
#define IDT_LAPIC_XCPU_IPI 0x42 #define IDT_LAPIC_XCPU_IPI 0x42
#define IDT_LAPIC_ERROR 0x43
#define IDT_IOAPIC_BASE 0x44 #define IDT_IOAPIC_BASE 0x44
#define IDT_IOAPIC_MAX 0xf0 #define IDT_IOAPIC_MAX 0xf0
#define IDT_IOAPIC_SPURIOUS 0xfb #define IDT_IOAPIC_SPURIOUS 0xfb

View File

@ -1,6 +1,6 @@
/********************************************************************* /*********************************************************************
* *
* Copyright (C) 2002-2007, Karlsruhe University * Copyright (C) 2002-2008, Karlsruhe University
* *
* File path: platform/generic/intctrl-apic.cc * File path: platform/generic/intctrl-apic.cc
* Description: Implementation of APIC+IOAPIC intctrl (with ACPI) * Description: Implementation of APIC+IOAPIC intctrl (with ACPI)
@ -80,6 +80,13 @@ EXC_INTERRUPT(spurious_interrupt_ioapic)
printf("IO-APIC: spurious interrupt\n"); printf("IO-APIC: spurious interrupt\n");
} }
EXC_INTERRUPT(lapic_error_interrupt)
{
printf("APIC: error interrupt, error %x\n",
intctrl_t::local_apic.read_error());
enter_kdebug("APIC error");
}
typedef void(*hwirqfunc_t)(); typedef void(*hwirqfunc_t)();
INLINE hwirqfunc_t get_interrupt_entry(word_t irq) INLINE hwirqfunc_t get_interrupt_entry(word_t irq)
@ -158,7 +165,7 @@ void intctrl_t::init_arch()
TRACE_INIT("\tAssuming local APIC defaults"); TRACE_INIT("\tAssuming local APIC defaults");
get_kernel_space()->add_mapping(addr_t(APIC_MAPPINGS_START), get_kernel_space()->add_mapping(addr_t(APIC_MAPPINGS_START),
addr_t(0xFEE00000), addr_t(0xFEE00000),
APIC_PGENTSZ, true, true, true); APIC_PGENTSZ, true, true, true, false);
if (local_apic.version() >= 0x20) if (local_apic.version() >= 0x20)
panic("no local APIC found--system unusable"); panic("no local APIC found--system unusable");
@ -222,12 +229,13 @@ void intctrl_t::init_arch()
_madt->local_apic_addr, APIC_MAPPINGS_START); _madt->local_apic_addr, APIC_MAPPINGS_START);
get_kernel_space()->add_mapping(addr_t(APIC_MAPPINGS_START), get_kernel_space()->add_mapping(addr_t(APIC_MAPPINGS_START),
addr_t(_madt->local_apic_addr), addr_t(_madt->local_apic_addr),
APIC_PGENTSZ, true, true, true); APIC_PGENTSZ, true, true, true, false);
// reserve in KIP // reserve in KIP
get_kip()->memory_info.insert(memdesc_t::reserved, 0, false, get_kip()->memory_info.insert(memdesc_t::reserved, 0, false,
addr_t(APIC_MAPPINGS_START), addr_t(APIC_MAPPINGS_START + X86_PAGE_SIZE)); addr_t(APIC_MAPPINGS_START), addr_t(APIC_MAPPINGS_START + X86_PAGE_SIZE));
x86_mmu_t::flush_tlb();
/* local apic */ /* local apic */
{ {
@ -444,6 +452,11 @@ void intctrl_t::init_local_apic()
local_apic.mask(local_apic_t<APIC_MAPPINGS_START>::lvt_thermal_monitor); local_apic.mask(local_apic_t<APIC_MAPPINGS_START>::lvt_thermal_monitor);
#endif #endif
TRACE_INIT("\tlocal APIC error trap gate %d \n", IDT_LAPIC_ERROR);
idt.add_int_gate(IDT_LAPIC_ERROR, lapic_error_interrupt);
local_apic.error_setup(IDT_LAPIC_ERROR);
} }