2 * Copyright (c) 2009 The Regents of the University of California
3 * See LICENSE for details.
6 #ifndef ROS_KERN_APIC_H
7 #define ROS_KERN_APIC_H
10 * Functions and definitions for dealing with the APIC and PIC, specific to
11 * Intel. Does not handle an x2APIC.
19 #define PIC1_DATA 0x21
21 #define PIC2_DATA 0xA1
22 // These are also hardcoded into the IRQ_HANDLERs of kern/trapentry.S
23 #define PIC1_OFFSET 0x20
24 #define PIC2_OFFSET 0x28
28 #define LAPIC_BASE 0xfee00000 // this is the default, can be changed
29 #define LAPIC_EOI (LAPIC_BASE + 0x0b0)
30 #define LAPIC_SPURIOUS (LAPIC_BASE + 0x0f0)
31 #define LAPIC_VERSION (LAPIC_BASE + 0x030)
32 #define LAPIC_ERROR (LAPIC_BASE + 0x280)
33 #define LAPIC_ID (LAPIC_BASE + 0x020)
34 // LAPIC Local Vector Table
35 #define LAPIC_LVT_TIMER (LAPIC_BASE + 0x320)
36 #define LAPIC_LVT_LINT0 (LAPIC_BASE + 0x350)
37 #define LAPIC_LVT_LINT1 (LAPIC_BASE + 0x360)
38 #define LAPIC_LVT_ERROR (LAPIC_BASE + 0x370)
39 #define LAPIC_LVT_PERFMON (LAPIC_BASE + 0x340)
40 #define LAPIC_LVT_THERMAL (LAPIC_BASE + 0x330)
41 #define LAPIC_LVT_MASK 0x00010000
43 #define LAPIC_TIMER_INIT (LAPIC_BASE + 0x380)
44 #define LAPIC_TIMER_CURRENT (LAPIC_BASE + 0x390)
45 #define LAPIC_TIMER_DIVIDE (LAPIC_BASE + 0x3e0)
46 // IPI Interrupt Command Register
47 #define LAPIC_IPI_ICR_LOWER (LAPIC_BASE + 0x300)
48 #define LAPIC_IPI_ICR_UPPER (LAPIC_BASE + 0x310)
51 #define IOAPIC_BASE 0xfec00000 // this is the default, can be changed
53 // PIT (Programmable Interrupt Timer)
54 #define PIT_FREQ 1193180
57 void pic_mask_irq(uint8_t irq);
58 void pic_unmask_irq(uint8_t irq);
59 void lapic_set_timer(uint32_t ticks, uint8_t vector, bool periodic);
60 uint32_t lapic_get_default_id(void);
61 void pit_set_timer(uint32_t freq, bool periodic); // consider adding callback func
63 static inline void pic_send_eoi(uint32_t irq);
64 static inline void lapic_send_eoi(void);
65 static inline uint32_t lapic_get_version(void);
66 static inline uint32_t lapic_get_error(void);
67 static inline uint32_t lapic_get_id(void);
68 static inline void lapic_disable(void);
69 static inline void lapic_enable(void);
70 static inline void lapic_wait_to_send(void);
71 static inline void send_init_ipi(void);
72 static inline void send_startup_ipi(uint8_t vector);
73 static inline void send_self_ipi(uint8_t vector);
74 static inline void send_broadcast_ipi(uint8_t vector);
75 static inline void send_all_others_ipi(uint8_t vector);
76 static inline void send_ipi(uint8_t dest, bool logical_mode, uint8_t vector);
78 #define mask_lapic_lvt(entry) \
79 write_mmreg32(entry, read_mmreg32(entry) | LAPIC_LVT_MASK)
80 #define unmask_lapic_lvt(entry) \
81 write_mmreg32(entry, read_mmreg32(entry) & ~LAPIC_LVT_MASK)
83 static inline void pic_send_eoi(uint32_t irq)
85 // all irqs beyond the first seven need to be chained to the slave
87 outb(PIC2_CMD, PIC_EOI);
88 outb(PIC1_CMD, PIC_EOI);
91 static inline void lapic_send_eoi(void)
93 write_mmreg32(LAPIC_EOI, 0);
96 static inline uint32_t lapic_get_version(void)
98 return read_mmreg32(LAPIC_VERSION);
101 static inline uint32_t lapic_get_error(void)
103 write_mmreg32(LAPIC_ERROR, 0xdeadbeef);
104 return read_mmreg32(LAPIC_ERROR);
107 static inline uint32_t lapic_get_id(void)
109 return read_mmreg32(LAPIC_ID) >> 24;
112 /* There are a couple ways to do it. The MSR route doesn't seem to work
113 * in KVM. It's also a somewhat permanent thing
115 static inline void lapic_disable(void)
117 write_mmreg32(LAPIC_SPURIOUS, read_mmreg32(LAPIC_SPURIOUS) & 0xffffefff);
118 //write_msr(IA32_APIC_BASE, read_msr(IA32_APIC_BASE) & ~MSR_APIC_ENABLE);
121 /* Spins until previous IPIs are delivered. Not sure if we want it inlined
122 * Also not sure when we really need to do this.
124 static inline void lapic_wait_to_send(void)
126 while(read_mmreg32(LAPIC_IPI_ICR_LOWER) & 0x1000)
127 asm volatile("pause");
130 static inline void lapic_enable(void)
132 write_mmreg32(LAPIC_SPURIOUS, read_mmreg32(LAPIC_SPURIOUS) | 0x00001000);
135 static inline void send_init_ipi(void)
137 write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x000c4500);
140 static inline void send_startup_ipi(uint8_t vector)
142 write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x000c4600 | vector);
145 static inline void send_self_ipi(uint8_t vector)
147 write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00044000 | vector);
150 static inline void send_broadcast_ipi(uint8_t vector)
152 write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00084000 | vector);
155 static inline void send_all_others_ipi(uint8_t vector)
157 write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x000c4000 | vector);
160 static inline void send_ipi(uint8_t dest, bool logical_mode, uint8_t vector)
162 write_mmreg32(LAPIC_IPI_ICR_UPPER, dest << 24);
163 write_mmreg32(LAPIC_IPI_ICR_LOWER, 0x00004000 | (logical_mode << 11) | vector);
166 /* To change the LAPIC Base (not recommended):
167 msr_val = read_msr(IA32_APIC_BASE);
168 msr_val = msr_val & ~MSR_APIC_BASE_ADDRESS | 0xfaa00000;
169 write_msr(IA32_APIC_BASE, msr_val);
171 #endif /* ROS_KERN_APIC_H */