Add a handler for the local APIC error interrupt. For now it just prints

out the current value of the local APIC error register when the interrupt
fires.

MFC after:	1 week
This commit is contained in:
jhb 2010-03-29 19:13:34 +00:00
parent 78907598c0
commit f3f4fff664
6 changed files with 90 additions and 40 deletions

View File

@ -104,6 +104,18 @@ IDTVEC(timerint)
MEXITCOUNT
jmp doreti
/*
* Local APIC error interrupt handler.
*/
.text
SUPERALIGN_TEXT
IDTVEC(errorint)
PUSH_FRAME
FAKE_MCOUNT(TF_RIP(%rsp))
call lapic_handle_error
MEXITCOUNT
jmp doreti
#ifdef SMP
/*
* Global address space TLB shootdown.

View File

@ -115,14 +115,12 @@ struct lapic {
int la_ioint_irqs[APIC_NUM_IOINTS + 1];
} static lapics[MAX_APIC_ID + 1];
/* XXX: should thermal be an NMI? */
/* Global defaults for local APIC LVT entries. */
static struct lvt lvts[LVT_MAX + 1] = {
{ 1, 1, 1, 1, APIC_LVT_DM_EXTINT, 0 }, /* LINT0: masked ExtINT */
{ 1, 1, 0, 1, APIC_LVT_DM_NMI, 0 }, /* LINT1: NMI */
{ 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_TIMER_INT }, /* Timer */
{ 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_ERROR_INT }, /* Error */
{ 1, 1, 0, 1, APIC_LVT_DM_FIXED, APIC_ERROR_INT }, /* Error */
{ 1, 1, 1, 1, APIC_LVT_DM_NMI, 0 }, /* PMC */
{ 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_THERMAL_INT }, /* Thermal */
};
@ -225,7 +223,10 @@ lapic_init(vm_paddr_t addr)
/* Local APIC timer interrupt. */
setidt(APIC_TIMER_INT, IDTVEC(timerint), SDT_SYSIGT, SEL_KPL, 0);
/* XXX: error/thermal interrupts */
/* Local APIC error interrupt. */
setidt(APIC_ERROR_INT, IDTVEC(errorint), SDT_SYSIGT, SEL_KPL, 0);
/* XXX: Thermal interrupt */
}
/*
@ -278,7 +279,7 @@ lapic_dump(const char* str)
lapic->id, lapic->version, lapic->ldr, lapic->dfr);
printf(" lint0: 0x%08x lint1: 0x%08x TPR: 0x%08x SVR: 0x%08x\n",
lapic->lvt_lint0, lapic->lvt_lint1, lapic->tpr, lapic->svr);
printf(" timer: 0x%08x therm: 0x%08x err: 0x%08x pcm: 0x%08x\n",
printf(" timer: 0x%08x therm: 0x%08x err: 0x%08x pmc: 0x%08x\n",
lapic->lvt_timer, lapic->lvt_thermal, lapic->lvt_error,
lapic->lvt_pcint);
}
@ -326,7 +327,11 @@ lapic_setup(int boot)
lapic_timer_enable_intr();
}
/* XXX: Error and thermal LVTs */
/* Program error LVT and clear any existing errors. */
lapic->lvt_error = lvt_mode(la, LVT_ERROR, lapic->lvt_error);
lapic->esr = 0;
/* XXX: Thermal LVT */
intr_restore(eflags);
}
@ -725,18 +730,6 @@ lapic_eoi(void)
lapic->eoi = 0;
}
/*
* Read the contents of the error status register. We have to write
* to the register first before reading from it.
*/
u_int
lapic_error(void)
{
lapic->esr = 0;
return (lapic->esr);
}
void
lapic_handle_intr(int vector, struct trapframe *frame)
{
@ -863,6 +856,24 @@ lapic_timer_enable_intr(void)
lapic->lvt_timer = value;
}
void
lapic_handle_error(void)
{
u_int32_t esr;
/*
* Read the contents of the error status register. Write to
* the register first before reading from it to force the APIC
* to update its value to indicate any errors that have
* occurred since the previous write to the register.
*/
lapic->esr = 0;
esr = lapic->esr;
printf("CPU%d: local APIC error 0x%x\n", PCPU_GET(cpuid), esr);
lapic_eoi();
}
u_int
apic_cpuid(u_int apic_id)
{

View File

@ -179,7 +179,8 @@ struct apic_enumerator {
inthand_t
IDTVEC(apic_isr1), IDTVEC(apic_isr2), IDTVEC(apic_isr3),
IDTVEC(apic_isr4), IDTVEC(apic_isr5), IDTVEC(apic_isr6),
IDTVEC(apic_isr7), IDTVEC(spuriousint), IDTVEC(timerint);
IDTVEC(apic_isr7), IDTVEC(errorint), IDTVEC(spuriousint),
IDTVEC(timerint);
extern vm_paddr_t lapic_paddr;
extern int apic_cpuids[];
@ -211,13 +212,13 @@ void lapic_disable_pmc(void);
void lapic_dump(const char *str);
int lapic_enable_pmc(void);
void lapic_eoi(void);
u_int lapic_error(void);
int lapic_id(void);
void lapic_init(vm_paddr_t addr);
int lapic_intr_pending(u_int vector);
void lapic_ipi_raw(register_t icrlo, u_int dest);
void lapic_ipi_vectored(u_int vector, int dest);
int lapic_ipi_wait(int delay);
void lapic_handle_error(void);
void lapic_handle_intr(int vector, struct trapframe *frame);
void lapic_handle_timer(struct trapframe *frame);
void lapic_reenable_pmc(void);

View File

@ -110,6 +110,19 @@ IDTVEC(timerint)
MEXITCOUNT
jmp doreti
/*
* Local APIC error interrupt handler.
*/
.text
SUPERALIGN_TEXT
IDTVEC(errorint)
PUSH_FRAME
SET_KERNEL_SREGS
FAKE_MCOUNT(TF_EIP(%esp))
call lapic_handle_error
MEXITCOUNT
jmp doreti
#ifdef SMP
/*
* Global address space TLB shootdown.

View File

@ -116,14 +116,12 @@ struct lapic {
int la_ioint_irqs[APIC_NUM_IOINTS + 1];
} static lapics[MAX_APIC_ID + 1];
/* XXX: should thermal be an NMI? */
/* Global defaults for local APIC LVT entries. */
static struct lvt lvts[LVT_MAX + 1] = {
{ 1, 1, 1, 1, APIC_LVT_DM_EXTINT, 0 }, /* LINT0: masked ExtINT */
{ 1, 1, 0, 1, APIC_LVT_DM_NMI, 0 }, /* LINT1: NMI */
{ 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_TIMER_INT }, /* Timer */
{ 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_ERROR_INT }, /* Error */
{ 1, 1, 0, 1, APIC_LVT_DM_FIXED, APIC_ERROR_INT }, /* Error */
{ 1, 1, 1, 1, APIC_LVT_DM_NMI, 0 }, /* PMC */
{ 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_THERMAL_INT }, /* Thermal */
};
@ -228,7 +226,11 @@ lapic_init(vm_paddr_t addr)
setidt(APIC_TIMER_INT, IDTVEC(timerint), SDT_SYS386IGT, SEL_KPL,
GSEL(GCODE_SEL, SEL_KPL));
/* XXX: error/thermal interrupts */
/* Local APIC error interrupt. */
setidt(APIC_ERROR_INT, IDTVEC(errorint), SDT_SYS386IGT, SEL_KPL,
GSEL(GCODE_SEL, SEL_KPL));
/* XXX: Thermal interrupt */
}
/*
@ -281,7 +283,7 @@ lapic_dump(const char* str)
lapic->id, lapic->version, lapic->ldr, lapic->dfr);
printf(" lint0: 0x%08x lint1: 0x%08x TPR: 0x%08x SVR: 0x%08x\n",
lapic->lvt_lint0, lapic->lvt_lint1, lapic->tpr, lapic->svr);
printf(" timer: 0x%08x therm: 0x%08x err: 0x%08x pcm: 0x%08x\n",
printf(" timer: 0x%08x therm: 0x%08x err: 0x%08x pmc: 0x%08x\n",
lapic->lvt_timer, lapic->lvt_thermal, lapic->lvt_error,
lapic->lvt_pcint);
}
@ -329,7 +331,11 @@ lapic_setup(int boot)
lapic_timer_enable_intr();
}
/* XXX: Error and thermal LVTs */
/* Program error LVT and clear any existing errors. */
lapic->lvt_error = lvt_mode(la, LVT_ERROR, lapic->lvt_error);
lapic->esr = 0;
/* XXX: Thermal LVT */
intr_restore(eflags);
}
@ -725,18 +731,6 @@ lapic_eoi(void)
lapic->eoi = 0;
}
/*
* Read the contents of the error status register. We have to write
* to the register first before reading from it.
*/
u_int
lapic_error(void)
{
lapic->esr = 0;
return (lapic->esr);
}
void
lapic_handle_intr(int vector, struct trapframe *frame)
{
@ -863,6 +857,24 @@ lapic_timer_enable_intr(void)
lapic->lvt_timer = value;
}
void
lapic_handle_error(void)
{
u_int32_t esr;
/*
* Read the contents of the error status register. Write to
* the register first before reading from it to force the APIC
* to update its value to indicate any errors that have
* occurred since the previous write to the register.
*/
lapic->esr = 0;
esr = lapic->esr;
printf("CPU%d: local APIC error 0x%x\n", PCPU_GET(cpuid), esr);
lapic_eoi();
}
u_int
apic_cpuid(u_int apic_id)
{

View File

@ -208,7 +208,8 @@ struct apic_enumerator {
inthand_t
IDTVEC(apic_isr1), IDTVEC(apic_isr2), IDTVEC(apic_isr3),
IDTVEC(apic_isr4), IDTVEC(apic_isr5), IDTVEC(apic_isr6),
IDTVEC(apic_isr7), IDTVEC(spuriousint), IDTVEC(timerint);
IDTVEC(apic_isr7), IDTVEC(errorint), IDTVEC(spuriousint),
IDTVEC(timerint);
extern vm_paddr_t lapic_paddr;
extern int apic_cpuids[];
@ -240,13 +241,13 @@ void lapic_disable_pmc(void);
void lapic_dump(const char *str);
int lapic_enable_pmc(void);
void lapic_eoi(void);
u_int lapic_error(void);
int lapic_id(void);
void lapic_init(vm_paddr_t addr);
int lapic_intr_pending(u_int vector);
void lapic_ipi_raw(register_t icrlo, u_int dest);
void lapic_ipi_vectored(u_int vector, int dest);
int lapic_ipi_wait(int delay);
void lapic_handle_error(void);
void lapic_handle_intr(int vector, struct trapframe *frame);
void lapic_handle_timer(struct trapframe *frame);
void lapic_reenable_pmc(void);