3 * Copyright 2018 Google LLC
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <libpayload.h>
30 #include <arch/apic.h>
31 #include <arch/cpuid.h>
33 #include <exception.h>
35 #define APIC_BASE_MSR 0x0000001B
36 #define APIC_BASE_MASK (0xFFFFFFFULL << 12)
38 #define CPUID_XAPIC_ENABLED_BIT (1 << 9)
39 #define CPUID_XAPIC2_ENABLED_BIT (1 << 21)
41 #define XAPIC_ENABLED_BIT (1 << 11)
42 #define X2APIC_ENABLED_BIT (1 << 10)
43 #define APIC_MASKED_BIT (1 << 16)
46 #define APIC_ID_SHIFT 24
47 #define APIC_ID_MASK (0xFFUL << APIC_ID_SHIFT)
48 #define APIC_VERSION 0x030
49 #define APIC_MAX_LVT_SHIFT 16
50 #define APIC_MAX_LVT_MASK (0xFFUL << APIC_MAX_LVT_SHIFT)
51 #define APIC_TASK_PRIORITY 0x080
52 #define APIC_TASK_PRIORITY_MASK 0xFFUL
53 #define APIC_EOI 0x0B0
54 #define APIC_SPURIOUS 0x0F0
55 #define APIC_SW_ENABLED_BIT (1 << 8)
56 #define APIC_SPURIOUS_VECTOR_MASK 0xFFUL
57 #define APIC_SPURIOUS 0x0F0
58 #define APIC_LVT_TIMER 0x320
59 #define APIC_TIMER_INIT_COUNT 0x380
60 #define APIC_TIMER_CUR_COUNT 0x390
61 #define APIC_TIMER_DIV_CFG 0x3E0
62 #define APIC_ISR_0 0x100
63 #define APIC_ISR_OFFSET 0x010
65 #define APIC_LVT_SIZE 0x010
67 #define APIC_TIMER_VECTOR 0x20UL
68 #define APIC_SPURIOUS_VECTOR 0xFFUL
70 static uint32_t apic_bar
;
71 static int _apic_initialized
;
72 // TODO: Build a lookup table to avoid calculating it.
73 static uint32_t ticks_per_ms
;
74 static volatile uint8_t timer_waiting
;
76 enum APIC_CAPABILITY
{
82 int apic_initialized(void)
84 return _apic_initialized
;
87 static inline uint32_t apic_read32(uint32_t offset
)
89 return read32((void *)(apic_bar
+ offset
));
92 static inline void apic_write32(uint32_t offset
, uint32_t value
)
94 write32((void *)(apic_bar
+ offset
), value
);
99 die_if(!apic_bar
, "APIC is not initialized");
102 (apic_read32(APIC_ID
) & APIC_ID_MASK
) >> APIC_ID_SHIFT
;
107 void apic_start_delay(unsigned int usec
)
109 die_if(!ticks_per_ms
, "apic_init_timer was not run.");
110 die_if(timer_waiting
, "timer already started.");
111 die_if(!interrupts_enabled(), "Interrupts disabled.");
113 /* The order is important so we don't underflow */
114 uint64_t ticks
= usec
* ticks_per_ms
/ USECS_PER_MSEC
;
116 /* Not enough resolution */
120 /* Disable interrupts so we don't get a race condition between
121 * starting the timer and the hlt instruction. */
122 disable_interrupts();
126 apic_write32(APIC_TIMER_INIT_COUNT
, ticks
);
130 void apic_wait_delay(void)
132 /* Loop in case another interrupt has fired and resumed execution. */
133 disable_interrupts();
134 /* Note: when we test timer_waiting, interrupts are disabled by the line
135 * above and the cli below. */
136 while (timer_waiting
) {
140 /* Disable interrupts to prevent a race condition
141 * between checking timer_waiting and executing the hlt
142 * instruction again. */
146 /* Leave hardware interrupts enabled. */
150 void apic_delay(unsigned int usec
)
152 apic_start_delay(usec
);
156 static void timer_interrupt_handler(u8 vector
)
159 apic_eoi(APIC_TIMER_VECTOR
);
162 static void suprious_interrupt_handler(u8 vector
) {}
164 void apic_eoi(uint8_t vector
)
166 die_if(!apic_bar
, "APIC is not initialized");
169 * Local and I/O APICs support 240 vectors (in the range of 16 to 255)
170 * as valid interrupts.
175 /* Each bank handles 32 vectors */
176 uint8_t bank
= vector
/ 32;
178 uint32_t offset
= APIC_ISR_0
+ bank
* APIC_ISR_OFFSET
;
180 uint32_t mask
= apic_read32(offset
);
182 uint8_t shift
= vector
% 32;
184 if (mask
& (1 << shift
))
185 apic_write32(APIC_EOI
, 0);
188 static enum APIC_CAPABILITY
apic_capabilities(void)
190 uint32_t eax
, ebx
, ecx
, edx
;
192 cpuid(1, eax
, ebx
, ecx
, edx
);
194 enum APIC_CAPABILITY capabilities
= DISABLED
;
196 if (edx
& CPUID_XAPIC_ENABLED_BIT
)
197 capabilities
|= XACPI
;
199 if (ecx
& CPUID_XAPIC2_ENABLED_BIT
)
200 capabilities
|= X2ACPI
;
205 static uint8_t apic_max_lvt_entries(void)
207 die_if(!apic_bar
, "APIC is not initialized");
209 uint32_t reg
= apic_read32(APIC_VERSION
);
210 reg
&= APIC_MAX_LVT_MASK
;
211 reg
>>= APIC_MAX_LVT_SHIFT
;
216 static void apic_reset_all_lvts(void)
218 uint8_t max
= apic_max_lvt_entries();
219 for (int i
= 0; i
<= max
; ++i
) {
220 uint32_t offset
= APIC_LVT_TIMER
+ APIC_LVT_SIZE
* i
;
222 apic_write32(offset
, APIC_MASKED_BIT
);
226 static void apic_set_task_priority(uint8_t priority
)
228 die_if(!apic_bar
, "APIC is not initialized");
230 uint32_t tpr
= apic_read32(APIC_TASK_PRIORITY
);
231 tpr
&= ~APIC_TASK_PRIORITY_MASK
;
234 apic_write32(APIC_TASK_PRIORITY
, priority
);
237 static void apic_init_timer(void)
239 die_if(!apic_bar
, "APIC is not initialized");
241 apic_write32(APIC_LVT_TIMER
, APIC_MASKED_BIT
);
243 /* Divide the clock by 1. */
244 apic_write32(APIC_TIMER_DIV_CFG
, 0xB);
246 /* Calibrate the APIC timer */
248 /* Set APIC init counter to MAX and count for 1 ms */
249 apic_write32(APIC_TIMER_INIT_COUNT
, UINT32_MAX
);
251 /* This is safe because apic_initialized() returns false so
252 * arch_ndelay() falls back to a busy loop. */
256 UINT32_MAX
- apic_read32(APIC_TIMER_CUR_COUNT
);
259 /* Clear the count so we don't get any stale interrupts */
260 apic_write32(APIC_TIMER_INIT_COUNT
, 0);
262 /* Unmask the timer and set the vector. */
263 apic_write32(APIC_LVT_TIMER
, APIC_TIMER_VECTOR
);
266 static void apic_sw_disable(void)
268 uint32_t reg
= apic_read32(APIC_SPURIOUS
);
270 reg
&= ~APIC_SW_ENABLED_BIT
;
271 printf("%s: writing %#x to %#x\n", __func__
, reg
, APIC_SPURIOUS
);
273 apic_write32(APIC_SPURIOUS
, reg
);
276 static void apic_sw_enable(void)
278 uint32_t reg
= apic_read32(APIC_SPURIOUS
);
279 if (reg
& APIC_SW_ENABLED_BIT
)
282 reg
|= APIC_SW_ENABLED_BIT
;
284 apic_write32(APIC_SPURIOUS
, reg
);
287 static void apic_setup_spurious(void)
289 uint32_t reg
= apic_read32(APIC_SPURIOUS
);
291 reg
&= ~APIC_SPURIOUS_VECTOR_MASK
;
293 reg
|= APIC_SPURIOUS_VECTOR
;
295 apic_write32(APIC_SPURIOUS
, reg
);
300 uint64_t apic_bar_reg
;
302 printf("APIC Init Started\n");
304 die_if(apic_initialized(), "APIC already initialized");
305 die_if(!(apic_capabilities() & XACPI
), "APIC is not supported");
307 apic_bar_reg
= _rdmsr(APIC_BASE_MSR
);
308 printf("apic_bar_reg is 0x%llx\n", apic_bar_reg
);
310 die_if(!(apic_bar_reg
& XAPIC_ENABLED_BIT
), "APIC is not enabled");
311 die_if(apic_bar_reg
& X2APIC_ENABLED_BIT
,
312 "APIC is configured in x2APIC mode which is not supported");
314 apic_bar
= (uint32_t)(apic_bar_reg
& APIC_BASE_MASK
);
317 apic_reset_all_lvts();
318 apic_set_task_priority(0);
319 apic_setup_spurious();
325 set_interrupt_handler(APIC_TIMER_VECTOR
, &timer_interrupt_handler
);
326 set_interrupt_handler(APIC_SPURIOUS_VECTOR
,
327 &suprious_interrupt_handler
);
329 _apic_initialized
= 1;
331 printf("APIC Configured\n");