minix/kernel/arch/i386/apic.h

202 lines
5.4 KiB
C
Raw Normal View History

#ifndef __APIC_H__
#define __APIC_H__
NMI watchdog is an awesome feature for debugging locked up kernels. There is not that much use for it on a single CPU, however, deadlock between kernel and system task can be delected. Or a runaway loop. If a kernel gets locked up the timer interrupts don't occure (as all interrupts are disabled in kernel mode). The only chance is to interrupt the kernel by a non-maskable interrupt. This patch generates NMIs using performance counters. It uses the most widely available performace counters. As the performance counters are highly model-specific this patch is not guaranteed to work on every machine. Unfortunately this is also true for KVM :-/ On the other hand adding this feature for other models is not extremely difficult and the framework makes it hopefully easy enough. Depending on the frequency of the CPU an NMI is generated at most about every 0.5s If the cpu's speed is less then 2Ghz it is generated at most every 1s. In general an NMI is generated much less often as the performance counter counts down only if the cpu is not idle. Therefore the overhead of this feature is fairly minimal even if the load is high. Uppon detecting that the kernel is locked up the kernel dumps the state of the kernel registers and panics. Local APIC must be enabled for the watchdog to work. The code is _always_ compiled in, however, it is only enabled if watchdog=<non-zero> is set in the boot monitor. One corner case is serial console debugging. As dumping a lot of stuff to the serial link may take a lot of time, the watchdog does not detect lockups during this time!!! as it would result in too many false positives. 10 nmi have to be handled before the lockup is detected. This means something between ~5s to 10s. Another corner case is that the watchdog is enabled only after the paging is enabled as it would be pure madness to try to get it right.
2010-01-16 21:53:55 +01:00
#define APIC_ENABLE 0x100
#define APIC_FOCUS_DISABLED (1 << 9)
#define APIC_SIV 0xFF
#define APIC_TDCR_2 0x00
#define APIC_TDCR_4 0x01
#define APIC_TDCR_8 0x02
#define APIC_TDCR_16 0x03
#define APIC_TDCR_32 0x08
#define APIC_TDCR_64 0x09
#define APIC_TDCR_128 0x0a
#define APIC_TDCR_1 0x0b
#define APIC_LVTT_VECTOR_MASK 0x000000FF
#define APIC_LVTT_DS_PENDING (1 << 12)
#define APIC_LVTT_MASK (1 << 16)
#define APIC_LVTT_TM (1 << 17)
#define APIC_LVT_IIPP_MASK 0x00002000
#define APIC_LVT_IIPP_AH 0x00002000
#define APIC_LVT_IIPP_AL 0x00000000
#define IOAPIC_REGSEL 0x0
#define IOAPIC_RW 0x10
#define APIC_ICR_DM_MASK 0x00000700
#define APIC_ICR_VECTOR APIC_LVTT_VECTOR_MASK
#define APIC_ICR_DM_FIXED (0 << 8)
#define APIC_ICR_DM_LOWEST_PRIORITY (1 << 8)
#define APIC_ICR_DM_SMI (2 << 8)
#define APIC_ICR_DM_RESERVED (3 << 8)
#define APIC_ICR_DM_NMI (4 << 8)
#define APIC_ICR_DM_INIT (5 << 8)
#define APIC_ICR_DM_STARTUP (6 << 8)
#define APIC_ICR_DM_EXTINT (7 << 8)
#define APIC_ICR_DM_PHYSICAL (0 << 11)
#define APIC_ICR_DM_LOGICAL (1 << 11)
#define APIC_ICR_DELIVERY_PENDING (1 << 12)
#define APIC_ICR_INT_POLARITY (1 << 13)
#define APIC_ICR_LEVEL_ASSERT (1 << 14)
#define APIC_ICR_LEVEL_DEASSERT (0 << 14)
#define APIC_ICR_TRIGGER (1 << 15)
#define APIC_ICR_INT_MASK (1 << 16)
#define APIC_ICR_DEST_FIELD (0 << 18)
#define APIC_ICR_DEST_SELF (1 << 18)
#define APIC_ICR_DEST_ALL (2 << 18)
#define APIC_ICR_DEST_ALL_BUT_SELF (3 << 18)
#define LOCAL_APIC_DEF_ADDR 0xfee00000 /* default local apic address */
#define IO_APIC_DEF_ADDR 0xfec00000 /* default i/o apic address */
#define LAPIC_ID (lapic_addr + 0x020)
#define LAPIC_VERSION (lapic_addr + 0x030)
#define LAPIC_TPR (lapic_addr + 0x080)
#define LAPIC_EOI (lapic_addr + 0x0b0)
#define LAPIC_LDR (lapic_addr + 0x0d0)
#define LAPIC_DFR (lapic_addr + 0x0e0)
#define LAPIC_SIVR (lapic_addr + 0x0f0)
#define LAPIC_ISR (lapic_addr + 0x100)
#define LAPIC_TMR (lapic_addr + 0x180)
#define LAPIC_IRR (lapic_addr + 0x200)
#define LAPIC_ESR (lapic_addr + 0x280)
#define LAPIC_ICR1 (lapic_addr + 0x300)
#define LAPIC_ICR2 (lapic_addr + 0x310)
#define LAPIC_LVTTR (lapic_addr + 0x320)
#define LAPIC_LVTTMR (lapic_addr + 0x330)
#define LAPIC_LVTPCR (lapic_addr + 0x340)
#define LAPIC_LINT0 (lapic_addr + 0x350)
#define LAPIC_LINT1 (lapic_addr + 0x360)
#define LAPIC_LVTER (lapic_addr + 0x370)
#define LAPIC_TIMER_ICR (lapic_addr + 0x380)
#define LAPIC_TIMER_CCR (lapic_addr + 0x390)
#define LAPIC_TIMER_DCR (lapic_addr + 0x3e0)
#define IOAPIC_ID 0x0
#define IOAPIC_VERSION 0x1
#define IOAPIC_ARB 0x2
#define IOAPIC_REDIR_TABLE 0x10
#define APIC_TIMER_INT_VECTOR 0xf0
#define APIC_SMP_SCHED_PROC_VECTOR 0xf1
#define APIC_SMP_CPU_HALT_VECTOR 0xf2
#define APIC_ERROR_INT_VECTOR 0xfe
#define APIC_SPURIOUS_INT_VECTOR 0xff
#ifndef __ASSEMBLY__
2010-04-02 00:22:33 +02:00
#include "kernel/kernel.h"
2010-03-22 21:43:06 +01:00
EXTERN vir_bytes lapic_addr;
EXTERN vir_bytes lapic_eoi_addr;
EXTERN int ioapic_enabled;
EXTERN int bsp_lapic_id;
#define MAX_NR_IOAPICS 32
#define MAX_IOAPIC_IRQS 64
EXTERN int ioapic_enabled;
struct io_apic {
unsigned id;
vir_bytes addr; /* presently used address */
phys_bytes paddr; /* where is it in phys space */
vir_bytes vaddr; /* address after paging is on */
unsigned pins;
unsigned gsi_base;
};
EXTERN struct io_apic io_apic[MAX_NR_IOAPICS];
EXTERN unsigned nioapics;
EXTERN u32_t lapic_addr_vaddr; /* we remember the virtual address here until we
switch to paging */
int lapic_enable(unsigned cpu);
void ioapic_unmask_irq(unsigned irq);
void ioapic_mask_irq(unsigned irq);
void ioapic_reset_pic(void);
EXTERN int ioapic_enabled;
EXTERN unsigned nioapics;
void lapic_microsec_sleep(unsigned count);
void ioapic_disable_irqs(u32_t irqs);
void ioapic_enable_irqs(u32_t irqs);
int lapic_enable(unsigned cpu);
void lapic_disable(void);
void ioapic_disable_all(void);
int ioapic_enable_all(void);
int detect_ioapics(void);
void apic_idt_init(int reset);
#ifdef CONFIG_SMP
int apic_send_startup_ipi(unsigned cpu, phys_bytes trampoline);
int apic_send_init_ipi(unsigned cpu, phys_bytes trampoline);
unsigned int apicid(void);
void ioapic_set_id(u32_t addr, unsigned int id);
#else
int apic_single_cpu_init(void);
#endif
void lapic_set_timer_periodic(const unsigned freq);
void lapic_set_timer_one_shot(const u32_t value);
void lapic_stop_timer(void);
void lapic_restart_timer(void);
void ioapic_set_irq(unsigned irq);
void ioapic_unset_irq(unsigned irq);
/* signal the end of interrupt handler to apic */
#define apic_eoi() do { *((volatile u32_t *) lapic_eoi_addr) = 0; } while(0)
void ioapic_eoi(int irq);
void dump_apic_irq_state(void);
void apic_send_ipi(unsigned vector, unsigned cpu, int type);
void apic_ipi_sched_intr(void);
void apic_ipi_halt_intr(void);
#define APIC_IPI_DEST 0
#define APIC_IPI_SELF 1
#define APIC_IPI_TO_ALL 2
#define APIC_IPI_TO_ALL_BUT_SELF 3
#define apic_send_ipi_single(vector,cpu) \
apic_send_ipi(vector, cpu, APIC_IPI_DEST);
#define apic_send_ipi_self(vector) \
apic_send_ipi(vector, 0, APIC_IPI_SELF)
#define apic_send_ipi_all(vector) \
apic_send_ipi (vector, 0, APIC_IPI_TO_ALL)
#define apic_send_ipi_allbutself(vector) \
apic_send_ipi (vector, 0, APIC_IPI_TO_ALL_BUT_SELF);
#include <minix/cpufeature.h>
#define cpu_feature_apic_on_chip() _cpufeature(_CPUF_I386_APIC_ON_CHIP)
#define lapic_read(what) (*((volatile u32_t *)((what))))
#define lapic_write(what, data) do { \
(*((volatile u32_t *)((what)))) = data; \
} while(0)
#endif /* __ASSEMBLY__ */
#endif /* __APIC_H__ */