blob: d5e5edca9a603465c855cdd9ccb2a3651fbd62bc [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
Arthur Heymans6f77ff72021-05-21 09:32:45 +020032static __always_inline void xapic_send_ipi(uint32_t icrlow, uint32_t apicid)
33{
34 xapic_write_atomic(LAPIC_ICR2, SET_LAPIC_DEST_FIELD(apicid));
35 xapic_write_atomic(LAPIC_ICR, icrlow);
36}
37
Arthur Heymansa4ceba42021-05-21 09:32:45 +020038static __always_inline int xapic_busy(void)
39{
40 return xapic_read(LAPIC_ICR) & LAPIC_ICR_BUSY;
41}
42
Kyösti Mälkki41e62162021-05-31 12:38:41 +030043#define lapic_read_around(x) lapic_read(x)
44#define lapic_write_around(x, y) xapic_write_atomic((x), (y))
45
Kyösti Mälkki41e62162021-05-31 12:38:41 +030046static __always_inline uint32_t x2apic_read(unsigned int reg)
47{
48 uint32_t value, index;
49 msr_t msr;
50
51 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
52 msr = rdmsr(index);
53 value = msr.lo;
54 return value;
55}
56
57static __always_inline void x2apic_write(unsigned int reg, uint32_t v)
58{
59 uint32_t index;
60 msr_t msr;
61
62 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
63 msr.hi = 0x0;
64 msr.lo = v;
65 wrmsr(index, msr);
66}
67
68static __always_inline void x2apic_send_ipi(uint32_t icrlow, uint32_t apicid)
69{
70 msr_t icr;
71 icr.hi = apicid;
72 icr.lo = icrlow;
73 wrmsr(X2APIC_MSR_ICR_ADDRESS, icr);
74}
75
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070076static inline bool is_x2apic_mode(void)
77{
Kyösti Mälkki176c8872021-05-29 20:33:22 +030078 if (CONFIG(XAPIC_ONLY))
79 return false;
80
81 if (CONFIG(X2APIC_ONLY))
82 return true;
83
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070084 msr_t msr;
85 msr = rdmsr(LAPIC_BASE_MSR);
Wonkyu Kima04256f2021-04-27 01:52:57 -070086 return ((msr.lo & LAPIC_BASE_X2APIC_ENABLED) == LAPIC_BASE_X2APIC_ENABLED);
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -070087}
88
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +010089static __always_inline uint32_t lapic_read(unsigned int reg)
Eric Biedermanc84c1902004-10-14 20:13:01 +000090{
Kyösti Mälkki41e62162021-05-31 12:38:41 +030091 if (is_x2apic_mode())
92 return x2apic_read(reg);
93 else
94 return xapic_read(reg);
Eric Biedermanc84c1902004-10-14 20:13:01 +000095}
96
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +010097static __always_inline void lapic_write(unsigned int reg, uint32_t v)
Eric Biedermanc84c1902004-10-14 20:13:01 +000098{
Kyösti Mälkki41e62162021-05-31 12:38:41 +030099 if (is_x2apic_mode())
100 x2apic_write(reg, v);
101 else
102 xapic_write(reg, v);
Eric Biedermanc84c1902004-10-14 20:13:01 +0000103}
104
Kyösti Mälkki0cfa9112021-05-31 10:38:45 +0300105static __always_inline void lapic_update32(unsigned int reg, uint32_t mask, uint32_t or)
106{
107 if (is_x2apic_mode()) {
108 uint32_t index;
109 msr_t msr;
110 index = X2APIC_MSR_BASE_ADDRESS + (uint32_t)(reg >> 4);
111 msr = rdmsr(index);
112 msr.lo &= mask;
113 msr.lo |= or;
114 wrmsr(index, msr);
115 } else {
116 uint32_t value;
117 value = xapic_read(reg);
118 value &= mask;
119 value |= or;
120 xapic_write_atomic(reg, value);
121 }
122}
123
Arthur Heymans6f77ff72021-05-21 09:32:45 +0200124static __always_inline void lapic_send_ipi(uint32_t icrlow, uint32_t apicid)
125{
126 if (is_x2apic_mode())
127 x2apic_send_ipi(icrlow, apicid);
128 else
129 xapic_send_ipi(icrlow, apicid);
130}
131
Arthur Heymansa4ceba42021-05-21 09:32:45 +0200132static __always_inline int lapic_busy(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000133{
Arthur Heymansa4ceba42021-05-21 09:32:45 +0200134 if (is_x2apic_mode())
135 return 0;
136 else
137 return xapic_busy();
Eric Biedermanc84c1902004-10-14 20:13:01 +0000138}
139
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700140static __always_inline unsigned int initial_lapicid(void)
141{
142 uint32_t lapicid;
Wonkyu Kima04256f2021-04-27 01:52:57 -0700143 if (is_x2apic_mode() && cpuid_get_max_func() >= 0xb)
144 lapicid = cpuid_ext(0xb, 0).edx;
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700145 else
146 lapicid = cpuid_ebx(1) >> 24;
147 return lapicid;
148}
149
Patrick Rudolphfc57d6c2019-11-12 16:30:14 +0100150static __always_inline unsigned int lapicid(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000151{
Wonkyu Kim26ab9bf2021-03-22 19:59:18 -0700152 uint32_t lapicid = lapic_read(LAPIC_ID);
153
154 /* check x2apic mode and return accordingly */
155 if (!is_x2apic_mode())
156 lapicid >>= 24;
157 return lapicid;
Eric Biedermanc84c1902004-10-14 20:13:01 +0000158}
159
Julius Wernercd49cce2019-03-05 16:53:33 -0800160#if !CONFIG(AP_IN_SIPI_WAIT)
Sven Schnelle51676b12012-07-29 19:18:03 +0200161/* If we need to go back to sipi wait, we use the long non-inlined version of
Kyösti Mälkki36c90172021-05-29 22:50:22 +0300162 * this function in lapic_cpu_stop.c
Sven Schnelle51676b12012-07-29 19:18:03 +0200163 */
Aaron Durbin75a62e72018-09-13 02:10:45 -0600164static __always_inline void stop_this_cpu(void)
Eric Biedermanc84c1902004-10-14 20:13:01 +0000165{
Sven Schnelle51676b12012-07-29 19:18:03 +0200166 /* Called by an AP when it is ready to halt and wait for a new task */
Patrick Georgibd79c5e2014-11-28 22:35:36 +0100167 halt();
Eric Biedermanc84c1902004-10-14 20:13:01 +0000168}
Sven Schnelle51676b12012-07-29 19:18:03 +0200169#else
170void stop_this_cpu(void);
171#endif
Eric Biedermanc84c1902004-10-14 20:13:01 +0000172
Kyösti Mälkki242f1d92021-06-06 16:58:19 +0300173void enable_lapic(void);
174void disable_lapic(void);
175void setup_lapic(void);
Kyösti Mälkkiff284f62017-08-18 12:11:16 +0300176
Eric Biedermanc84c1902004-10-14 20:13:01 +0000177#endif /* CPU_X86_LAPIC_H */