blob: a3d0fcbf8911662fb00f8e0b8ca6fd785a0a3f02 [file] [log] [blame]
Eric Biedermanc84c1902004-10-14 20:13:01 +00001#ifndef CPU_X86_LAPIC_H
2#define CPU_X86_LAPIC_H
3
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +01004#include <arch/mmio.h>
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -07005#include <arch/cpu.h>
Eric Biedermanc84c1902004-10-14 20:13:01 +00006#include <cpu/x86/lapic_def.h>
7#include <cpu/x86/msr.h>
Patrick Georgibd79c5e2014-11-28 22:35:36 +01008#include <halt.h>
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +01009#include <stdint.h>
Eric Biedermanc84c1902004-10-14 20:13:01 +000010
Kyösti Mälkki41e62162021-05-31 12:38:41 +030011static __always_inline uint32_t xapic_read(unsigned int reg)
12{
13 return read32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE + reg));
14}
15
16static __always_inline void xapic_write(unsigned int reg, uint32_t v)
17{
18 write32((volatile void *)(uintptr_t)(LAPIC_DEFAULT_BASE + reg), v);
19}
20
21static inline void xapic_write_atomic(unsigned long reg, uint32_t v)
22{
23 volatile uint32_t *ptr;
24
25 ptr = (volatile uint32_t *)(LAPIC_DEFAULT_BASE + reg);
26
27 asm volatile ("xchgl %0, %1\n"
28 : "+r" (v), "+m" (*(ptr))
29 : : "memory", "cc");
30}
31
32#define lapic_read_around(x) lapic_read(x)
33#define lapic_write_around(x, y) xapic_write_atomic((x), (y))
34
35
36static __always_inline uint32_t x2apic_read(unsigned int reg)
37{
38 uint32_t value, index;
39 msr_t msr;
40
41 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
42 msr = rdmsr(index);
43 value = msr.lo;
44 return value;
45}
46
47static __always_inline void x2apic_write(unsigned int reg, uint32_t v)
48{
49 uint32_t index;
50 msr_t msr;
51
52 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
53 msr.hi = 0x0;
54 msr.lo = v;
55 wrmsr(index, msr);
56}
57
58static __always_inline void x2apic_send_ipi(uint32_t icrlow, uint32_t apicid)
59{
60 msr_t icr;
61 icr.hi = apicid;
62 icr.lo = icrlow;
63 wrmsr(X2APIC_MSR_ICR_ADDRESS, icr);
64}
65
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070066static inline bool is_x2apic_mode(void)
67{
Kyösti Mälkki176c8872021-05-29 20:33:22 +030068 if (CONFIG(XAPIC_ONLY))
69 return false;
70
71 if (CONFIG(X2APIC_ONLY))
72 return true;
73
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070074 msr_t msr;
75 msr = rdmsr(LAPIC_BASE_MSR);
Wonkyu Kima04256f2021-04-27 01:52:57 -070076 return ((msr.lo & LAPIC_BASE_X2APIC_ENABLED) == LAPIC_BASE_X2APIC_ENABLED);
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070077}
78
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +010079static __always_inline uint32_t lapic_read(unsigned int reg)
Eric Biedermanc84c1902004-10-14 20:13:01 +000080{
Kyösti Mälkki41e62162021-05-31 12:38:41 +030081 if (is_x2apic_mode())
82 return x2apic_read(reg);
83 else
84 return xapic_read(reg);
Eric Biedermanc84c1902004-10-14 20:13:01 +000085}
86
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +010087static __always_inline void lapic_write(unsigned int reg, uint32_t v)
Eric Biedermanc84c1902004-10-14 20:13:01 +000088{
Kyösti Mälkki41e62162021-05-31 12:38:41 +030089 if (is_x2apic_mode())
90 x2apic_write(reg, v);
91 else
92 xapic_write(reg, v);
Eric Biedermanc84c1902004-10-14 20:13:01 +000093}
94
Kyösti Mälkki0cfa9112021-05-31 10:38:45 +030095static __always_inline void lapic_update32(unsigned int reg, uint32_t mask, uint32_t or)
96{
97 if (is_x2apic_mode()) {
98 uint32_t index;
99 msr_t msr;
100 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
101 msr = rdmsr(index);
102 msr.lo &= mask;
103 msr.lo |= or;
104 wrmsr(index, msr);
105 } else {
106 uint32_t value;
107 value = xapic_read(reg);
108 value &= mask;
109 value |= or;
110 xapic_write_atomic(reg, value);
111 }
112}
113
Aaron Durbin75a62e72018-09-13 02:10:45 -0600114static __always_inline void lapic_wait_icr_idle(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000115{
Lee Leahy91d1e762017-03-07 14:31:19 -0800116 do { } while (lapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY);
Eric Biedermanc84c1902004-10-14 20:13:01 +0000117}
118
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700119static __always_inline unsigned int initial_lapicid(void)
120{
121 uint32_t lapicid;
Wonkyu Kima04256f2021-04-27 01:52:57 -0700122 if (is_x2apic_mode() && cpuid_get_max_func() >= 0xb)
123 lapicid = cpuid_ext(0xb, 0).edx;
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700124 else
125 lapicid = cpuid_ebx(1) >> 24;
126 return lapicid;
127}
128
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +0100129static __always_inline unsigned int lapicid(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000130{
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700131 uint32_t lapicid = lapic_read(LAPIC_ID);
132
133 /* check x2apic mode and return accordingly */
134 if (!is_x2apic_mode())
135 lapicid >>= 24;
136 return lapicid;
Eric Biedermanc84c1902004-10-14 20:13:01 +0000137}
138
Julius Wernercd49cce2019-03-05 16:53:33 -0800139#if !CONFIG(AP_IN_SIPI_WAIT)
Sven Schnelle51676b12012-07-29 19:18:03 +0200140/* If we need to go back to sipi wait, we use the long non-inlined version of
141 * this function in lapic_cpu_init.c
142 */
Aaron Durbin75a62e72018-09-13 02:10:45 -0600143static __always_inline void stop_this_cpu(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000144{
Sven Schnelle51676b12012-07-29 19:18:03 +0200145 /* Called by an AP when it is ready to halt and wait for a new task */
Patrick Georgibd79c5e2014-11-28 22:35:36 +0100146 halt();
Eric Biedermanc84c1902004-10-14 20:13:01 +0000147}
Sven Schnelle51676b12012-07-29 19:18:03 +0200148#else
149void stop_this_cpu(void);
150#endif
Eric Biedermanc84c1902004-10-14 20:13:01 +0000151
Kyösti Mälkki242f1d92021-06-06 16:58:19 +0300152void enable_lapic(void);
153void disable_lapic(void);
154void setup_lapic(void);
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300155
Eric Biedermanc84c1902004-10-14 20:13:01 +0000156#endif /* CPU_X86_LAPIC_H */