CS350 COS
COS
Loading...
Searching...
No Matches
lapic.c
Go to the documentation of this file.
1/*
2 * LAPIC
3 */
4
5#include <stdbool.h>
6#include <stdint.h>
7
8#include <sys/kassert.h>
9#include <sys/kdebug.h>
10
11#include <machine/amd64.h>
12#include <machine/amd64op.h>
13#include <machine/pmap.h>
14#include <machine/trap.h>
15
16#define CPUID_FLAG_APIC 0x100
17
18#define IA32_APIC_BASE_MSR 0x1B
19#define IA32_APIC_BASE_MSR_BSP 0x100
20#define IA32_APIC_BASE_MSR_ENABLE 0x800
21
22#define LAPIC_ID 0x0020 /* CPU ID */
23#define LAPIC_VERSION 0x0030 /* Version */
24#define LAPIC_VERSION_LVTMASK 0x00FF0000
25#define LAPIC_VERSION_LVTSHIFT 0x10
26#define LAPIC_TPR 0x0080 /* Task Priority Register */
27#define LAPIC_EOI 0x00B0 /* End of Interrupt */
28#define LAPIC_SIV 0x00F0 /* Spurious Interrupt Vector */
29#define LAPIC_SIV_ENABLE 0x100
30
31#define LAPIC_ESR 0x0280 /* Error Status Register */
32#define LAPIC_LVT_CMCI 0x02F0 /* LVT CMCI */
33
34#define LAPIC_ICR_LO 0x0300 /* Interrupt Command Register */
35#define LAPIC_ICR_HI 0x0310 /* Interrupt Command Register */
36#define LAPIC_ICR_FIXED 0x0000 /* Delivery Mode */
37#define LAPIC_ICR_NMI 0x0400
38#define LAPIC_ICR_INIT 0x0500
39#define LAPIC_ICR_STARTUP 0x0600
40#define LAPIC_ICR_ASSERT 0x4000
41#define LAPIC_ICR_TRIG 0x8000
42#define LAPIC_ICR_SELF 0x00080000 /* Destination */
43#define LAPIC_ICR_INCSELF 0x00080000
44#define LAPIC_ICR_EXCSELF 0x000C0000
45#define LAPIC_ICR_DELIVERY_PENDING 0x1000 /* Delivery Pending */
46
47#define LAPIC_LVT_TIMER 0x0320 /* LVT Timer */
48#define LAPIC_LVT_TIMER_ONESHOT 0x00000000
49#define LAPIC_LVT_TIMER_PERIODIC 0x00020000
50#define LAPIC_LVT_TIMER_TSCDEADLINE 0x00040000
51#define LAPIC_LVT_THERMAL 0x0330 /* LVT Thermal Sensor */
52#define LAPIC_LVT_PMCR 0x0340 /* LVT Performance Monitoring Counter */
53#define LAPIC_LVT_LINT0 0x0350 /* LVT LINT0 */
54#define LAPIC_LVT_LINT1 0x0360 /* LVT LINT1 */
55#define LAPIC_LVT_ERROR 0x0370 /* LVT Error */
56#define LAPIC_LVT_FLAG_MASKED 0x00010000 /* Masked */
57#define LAPIC_LVT_FLAG_NMI 0x00000400 /* NMI */
58#define LAPIC_LVT_FLAG_EXTINT 0x00000700 /* ExtINT */
59
60#define LAPIC_TICR 0x0380 /* Timer Initial Count Register */
61#define LAPIC_TCCR 0x0390 /* Timer Currnet Count Register */
62#define LAPIC_TDCR 0x03E0 /* Time Divide Configuration Register */
63#define LAPIC_TDCR_X1 0x000B /* Divide counts by 1 */
64
65bool lapicInitialized = false;
66
67static uint32_t *
69{
70 uint64_t base = rdmsr(IA32_APIC_BASE_MSR) & 0xFFFFFFFFFFFFF000ULL;
71
72 return (uint32_t *)DMPA2VA(base);
73}
74
77{
78 uint32_t volatile *lapic = (uint32_t volatile *) LAPIC_GetBase();
79
80 return lapic[reg >> 2];
81}
82
83void
85{
86 uint32_t volatile *lapic = (uint32_t volatile *)LAPIC_GetBase();
87
88 lapic[reg >> 2] = val;
89 lapic[LAPIC_ID >> 2];
90}
91
94{
96 return LAPIC_Read(LAPIC_ID) >> 24;
97 else
98 return 0;
99}
100
101void
103{
105}
106
107void
109{
112 LAPIC_Write(LAPIC_TICR, rate);
113}
114
115void
117{
118 // Setup CMOS stuff
119 outb(0x70, 0x0F);
120 outb(0x71, 0x0A);
121 uint16_t *cmosStartup = (uint16_t *)DMPA2VA(0x467);
122 cmosStartup[0] = 0;
123 cmosStartup[1] = addr >> 4;
124
125 // Send INIT
126 LAPIC_Write(LAPIC_ICR_HI, apicid << 24);
128 // XXX: Delay
129 LAPIC_Write(LAPIC_ICR_HI, apicid << 24);
131 // XXX: Delay
132
133 // Send STARTUP
134 LAPIC_Write(LAPIC_ICR_HI, apicid << 24);
136 // XXX: Delay
137 LAPIC_Write(LAPIC_ICR_HI, apicid << 24);
139 // XXX: Delay
140}
141
142int
144{
145 int i = 0;
147
149 pause();
150
151 if (i > 1000000) {
152 kprintf("IPI not delivered?\n");
153 return -1;
154 }
155 }
156
157 return 0;
158}
159
160int
162{
163 int i = 0;
165
167 pause();
168
169 if (i > 1000000) {
170 kprintf("IPI not delivered?\n");
171 return -1;
172 }
173 }
174
175 return 0;
176}
177
178void
180{
181 uint32_t version;
182 uint32_t lvts;
183 uint32_t edx;
185
186 cpuid(1, NULL, NULL, NULL, &edx);
187 if ((edx & CPUID_FLAG_APIC) == 0)
188 Panic("APIC is required!\n");
189
190 // Disable ATPIC
191 if (LAPIC_CPU() == 0) {
192 outb(0xA1, 0xFF);
193 outb(0x21, 0xFF);
194 }
195
196 // Enable LAPIC
199
200 // Convert to Direct Map Address
201 base = DMPA2VA(base);
202
203 lapicInitialized = true;
204
205 kprintf("LAPIC: CPU %d found at 0x%016llx\n", LAPIC_CPU(), base);
206
207 version = LAPIC_Read(LAPIC_VERSION);
208 lvts = (version & LAPIC_VERSION_LVTMASK) >> LAPIC_VERSION_LVTSHIFT;
209
210 // Enable interrupts
212
213 // Error Interrupt
215
216 // Setup LINT0/1
217 if (LAPIC_CPU() == 0) {
220 } else {
223 }
224
225 // Performance Counter Interrupt
226 if (lvts >= 4) {
228 }
229
230 // Thermal Interrupt
231 if (lvts >= 5) {
233 }
234
235 // Machine Check Interrupt
236 if (lvts >= 6) {
238 }
239
240 LAPIC_Periodic(10000000); // XXX: 100 Hz (changes must update trap.c as well)
241
242 // Clear any remaining errors
245
249 {
250 // XXX: Timeout
251 }
252
254
256}
257
258static void
259Debug_LAPIC(int argc, const char *argv[])
260{
263
264 kprintf("LAPIC %d\n", LAPIC_CPU());
265 kprintf("VERSION: %08x\n", LAPIC_Read(LAPIC_VERSION));
266 kprintf("ESR: %08x\n", LAPIC_Read(LAPIC_ESR));
267 kprintf("ICRLO: %08x\n", LAPIC_Read(LAPIC_ICR_LO));
268 kprintf("ICRHI: %08x\n", LAPIC_Read(LAPIC_ICR_HI));
269 kprintf("SIV: %08x\n", LAPIC_Read(LAPIC_SIV));
270 kprintf("ERROR: %08x\n", LAPIC_Read(LAPIC_LVT_ERROR));
271 if (lvts >= 5) {
272 kprintf("THERMAL: %08x\n", LAPIC_Read(LAPIC_LVT_THERMAL));
273 }
274 kprintf("LINT0: %08x\n", LAPIC_Read(LAPIC_LVT_LINT0));
275 kprintf("LINT1: %08x\n", LAPIC_Read(LAPIC_LVT_LINT1));
276 if (lvts >= 4) {
277 kprintf("PMCR: %08x\n", LAPIC_Read(LAPIC_LVT_PMCR));
278 }
279 if (lvts >= 6) {
280 kprintf("CMCI: %08x\n", LAPIC_Read(LAPIC_LVT_CMCI));
281 }
282}
283
284REGISTER_DBGCMD(lapic, "LAPIC Status", Debug_LAPIC);
285
static INLINE uint64_t rdmsr(uint32_t addr)
Definition: amd64op.h:114
static INLINE void outb(uint16_t port, uint8_t data)
Definition: amd64op.h:431
static INLINE void wrmsr(uint32_t addr, uint64_t val)
Definition: amd64op.h:104
static INLINE void pause()
Definition: amd64op.h:24
static INLINE void cpuid(uint32_t info, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
Definition: amd64op.h:85
int kprintf(const char *fmt,...)
Definition: printf.c:210
#define REGISTER_DBGCMD(_NAME, _DESC, _FUNC)
Definition: kdebug.h:11
#define LAPIC_ICR_EXCSELF
Definition: lapic.c:44
#define LAPIC_LVT_LINT1
Definition: lapic.c:54
#define LAPIC_SIV_ENABLE
Definition: lapic.c:29
#define LAPIC_LVT_THERMAL
Definition: lapic.c:51
#define LAPIC_VERSION_LVTMASK
Definition: lapic.c:24
#define LAPIC_EOI
Definition: lapic.c:27
#define LAPIC_ICR_STARTUP
Definition: lapic.c:39
#define LAPIC_TDCR_X1
Definition: lapic.c:63
#define LAPIC_LVT_FLAG_MASKED
Definition: lapic.c:56
#define LAPIC_ICR_ASSERT
Definition: lapic.c:40
int LAPIC_BroadcastNMI(int vector)
Definition: lapic.c:161
#define LAPIC_TDCR
Definition: lapic.c:62
int LAPIC_Broadcast(int vector)
Definition: lapic.c:143
#define LAPIC_ICR_LO
Definition: lapic.c:34
static void Debug_LAPIC(int argc, const char *argv[])
Definition: lapic.c:259
#define LAPIC_ICR_DELIVERY_PENDING
Definition: lapic.c:45
#define CPUID_FLAG_APIC
Definition: lapic.c:16
#define IA32_APIC_BASE_MSR
Definition: lapic.c:18
#define LAPIC_LVT_PMCR
Definition: lapic.c:52
bool lapicInitialized
Definition: lapic.c:65
#define LAPIC_VERSION_LVTSHIFT
Definition: lapic.c:25
void LAPIC_Periodic(uint64_t rate)
Definition: lapic.c:108
#define LAPIC_TPR
Definition: lapic.c:26
#define LAPIC_LVT_TIMER
Definition: lapic.c:47
#define LAPIC_VERSION
Definition: lapic.c:23
uint32_t LAPIC_Read(uint16_t reg)
Definition: lapic.c:76
#define LAPIC_SIV
Definition: lapic.c:28
void LAPIC_Init()
Definition: lapic.c:179
#define LAPIC_LVT_ERROR
Definition: lapic.c:55
#define LAPIC_ESR
Definition: lapic.c:31
#define LAPIC_LVT_FLAG_NMI
Definition: lapic.c:57
#define LAPIC_LVT_CMCI
Definition: lapic.c:32
static uint32_t * LAPIC_GetBase()
Definition: lapic.c:68
uint32_t LAPIC_CPU()
Definition: lapic.c:93
#define LAPIC_LVT_FLAG_EXTINT
Definition: lapic.c:58
#define LAPIC_LVT_TIMER_PERIODIC
Definition: lapic.c:49
void LAPIC_Write(uint16_t reg, uint32_t val)
Definition: lapic.c:84
#define LAPIC_ID
Definition: lapic.c:22
#define LAPIC_ICR_NMI
Definition: lapic.c:37
#define LAPIC_ICR_TRIG
Definition: lapic.c:41
void LAPIC_SendEOI()
Definition: lapic.c:102
#define IA32_APIC_BASE_MSR_ENABLE
Definition: lapic.c:20
#define LAPIC_TICR
Definition: lapic.c:60
#define LAPIC_ICR_INCSELF
Definition: lapic.c:43
#define LAPIC_LVT_LINT0
Definition: lapic.c:53
void LAPIC_StartAP(uint8_t apicid, uint32_t addr)
Definition: lapic.c:116
#define LAPIC_ICR_HI
Definition: lapic.c:35
#define LAPIC_ICR_INIT
Definition: lapic.c:38
uint64_t addr
Definition: multiboot.h:1
#define DMPA2VA(pa)
Definition: pmap.h:48
static uint16_t base
Definition: sercons.c:37
#define NULL
Definition: stddef.h:6
#define T_IRQ_TIMER
Definition: trap.h:32
#define T_IRQ_ERROR
Definition: trap.h:39
#define T_IRQ_THERMAL
Definition: trap.h:40
#define T_IRQ_SPURIOUS
Definition: trap.h:38
unsigned short uint16_t
Definition: types.h:11
unsigned int uint32_t
Definition: types.h:12
unsigned long uint64_t
Definition: types.h:13
unsigned char uint8_t
Definition: types.h:10
void Panic(const char *str)
Definition: vgacons.c:164