/rust/registry/src/index.crates.io-1949cf8c6b5b557f/x86-0.47.0/src/apic/x2apic.rs
Line | Count | Source |
1 | | //! x2APIC, the most recent APIC on x86 for large servers with more than 255 cores. |
2 | | use bit_field::BitField; |
3 | | |
4 | | use super::*; |
5 | | use crate::msr::{ |
6 | | rdmsr, wrmsr, IA32_APIC_BASE, IA32_TSC_DEADLINE, IA32_X2APIC_APICID, IA32_X2APIC_EOI, |
7 | | IA32_X2APIC_ESR, IA32_X2APIC_ICR, IA32_X2APIC_LDR, IA32_X2APIC_LVT_LINT0, |
8 | | IA32_X2APIC_LVT_TIMER, IA32_X2APIC_SELF_IPI, IA32_X2APIC_SIVR, IA32_X2APIC_VERSION, |
9 | | }; |
10 | | |
11 | | /// Represents an x2APIC driver instance. |
12 | | #[derive(Debug)] |
13 | | pub struct X2APIC { |
14 | | /// Initial BASE msr register value. |
15 | | base: u64, |
16 | | } |
17 | | |
18 | | impl Default for X2APIC { |
19 | 0 | fn default() -> Self { |
20 | | unsafe { |
21 | 0 | X2APIC { |
22 | 0 | base: rdmsr(IA32_APIC_BASE), |
23 | 0 | } |
24 | | } |
25 | 0 | } |
26 | | } |
27 | | |
28 | | impl X2APIC { |
29 | | /// Create a new x2APIC driver object for the local core. |
30 | 0 | pub fn new() -> X2APIC { |
31 | 0 | Default::default() |
32 | 0 | } |
33 | | |
34 | | /// Attach to APIC (enable x2APIC mode, initialize LINT0) |
35 | 0 | pub fn attach(&mut self) { |
36 | | // Enable |
37 | 0 | unsafe { |
38 | 0 | // Enable x2APIC mode globally |
39 | 0 | self.base = rdmsr(IA32_APIC_BASE); |
40 | 0 | self.base.set_bit(10, true); // Enable x2APIC |
41 | 0 | self.base.set_bit(11, true); // Enable xAPIC |
42 | 0 | wrmsr(IA32_APIC_BASE, self.base); |
43 | 0 |
|
44 | 0 | // Enable this XAPIC (set bit 8, spurious IRQ vector 15) |
45 | 0 | let svr: u64 = 1 << 8 | 15; |
46 | 0 | wrmsr(IA32_X2APIC_SIVR, svr); |
47 | 0 |
|
48 | 0 | // TODO: Fix magic number? |
49 | 0 | let lint0 = 1 << 16 | (1 << 15) | (0b111 << 8) | 0x20; |
50 | 0 | wrmsr(IA32_X2APIC_LVT_LINT0, lint0); |
51 | 0 |
|
52 | 0 | let _esr = rdmsr(IA32_X2APIC_ESR); |
53 | 0 | } |
54 | 0 | } |
55 | | |
56 | | /// Detach from APIC (disable x2APIC and xAPIC mode). |
57 | 0 | pub fn detach(&mut self) { |
58 | 0 | unsafe { |
59 | 0 | self.base = rdmsr(IA32_APIC_BASE); |
60 | 0 | self.base.set_bit(10, false); // x2APIC |
61 | 0 | self.base.set_bit(11, false); // xAPIC |
62 | 0 | wrmsr(IA32_APIC_BASE, self.base); |
63 | 0 | } |
64 | 0 | } |
65 | | |
66 | | /// Send an IPI to yourself. |
67 | | /// |
68 | | /// # Safety |
69 | | /// Will interrupt core with `vector`. |
70 | 0 | pub unsafe fn send_self_ipi(&self, vector: u64) { |
71 | 0 | wrmsr(IA32_X2APIC_SELF_IPI, vector); |
72 | 0 | } |
73 | | } |
74 | | |
75 | | /// Abstracts common interface of APIC (x2APIC, xAPIC) hardware devices. |
76 | | impl ApicControl for X2APIC { |
77 | | /// Is a bootstrap processor? |
78 | 0 | fn bsp(&self) -> bool { |
79 | 0 | (self.base & (1 << 8)) > 0 |
80 | 0 | } |
81 | | |
82 | | /// Read local x2APIC ID. |
83 | 0 | fn id(&self) -> u32 { |
84 | 0 | unsafe { rdmsr(IA32_X2APIC_APICID) as u32 } |
85 | 0 | } |
86 | | |
87 | | /// In x2APIC mode, the 32-bit logical x2APIC ID, can be read from LDR. |
88 | 0 | fn logical_id(&self) -> u32 { |
89 | 0 | unsafe { rdmsr(IA32_X2APIC_LDR) as u32 } |
90 | 0 | } |
91 | | |
92 | | /// Read APIC version. |
93 | 0 | fn version(&self) -> u32 { |
94 | 0 | unsafe { rdmsr(IA32_X2APIC_VERSION) as u32 } |
95 | 0 | } |
96 | | |
97 | | /// Enable TSC timer |
98 | 0 | fn tsc_enable(&mut self, vector: u8) { |
99 | 0 | unsafe { |
100 | 0 | wrmsr(IA32_TSC_DEADLINE, 0); |
101 | 0 |
|
102 | 0 | let mut lvt: u64 = rdmsr(IA32_X2APIC_LVT_TIMER); |
103 | 0 | lvt &= !0xff; |
104 | 0 | lvt |= vector as u64; |
105 | 0 |
|
106 | 0 | // Unmask timer IRQ |
107 | 0 | lvt.set_bit(16, false); |
108 | 0 |
|
109 | 0 | // Enable TSC deadline mode |
110 | 0 | lvt.set_bit(17, false); |
111 | 0 | lvt.set_bit(18, true); |
112 | 0 | wrmsr(IA32_X2APIC_LVT_TIMER, lvt); |
113 | 0 | } |
114 | 0 | } |
115 | | |
116 | | /// Set tsc deadline. |
117 | 0 | fn tsc_set(&self, value: u64) { |
118 | 0 | unsafe { |
119 | 0 | crate::fence::mfence(); |
120 | 0 | wrmsr(IA32_TSC_DEADLINE, value); |
121 | 0 | } |
122 | 0 | } |
123 | | |
124 | | /// End Of Interrupt -- Acknowledge interrupt delivery. |
125 | 0 | fn eoi(&mut self) { |
126 | 0 | unsafe { |
127 | 0 | wrmsr(IA32_X2APIC_EOI, 0); |
128 | 0 | } |
129 | 0 | } |
130 | | |
131 | | /// Send a INIT IPI to a core. |
132 | 0 | unsafe fn ipi_init(&mut self, core: ApicId) { |
133 | 0 | let icr = Icr::for_x2apic( |
134 | | 0, |
135 | 0 | core, |
136 | 0 | DestinationShorthand::NoShorthand, |
137 | 0 | DeliveryMode::Init, |
138 | 0 | DestinationMode::Physical, |
139 | 0 | DeliveryStatus::Idle, |
140 | 0 | Level::Assert, |
141 | 0 | TriggerMode::Level, |
142 | | ); |
143 | 0 | self.send_ipi(icr); |
144 | 0 | } |
145 | | |
146 | | /// Deassert INIT IPI. |
147 | 0 | unsafe fn ipi_init_deassert(&mut self) { |
148 | 0 | let icr = Icr::for_x2apic( |
149 | | 0, |
150 | 0 | ApicId::X2Apic(0), |
151 | | // INIT deassert is always sent to everyone, so we are supposed to specify: |
152 | 0 | DestinationShorthand::AllIncludingSelf, |
153 | 0 | DeliveryMode::Init, |
154 | 0 | DestinationMode::Physical, |
155 | 0 | DeliveryStatus::Idle, |
156 | 0 | Level::Deassert, |
157 | 0 | TriggerMode::Level, |
158 | | ); |
159 | 0 | self.send_ipi(icr); |
160 | 0 | } |
161 | | |
162 | | /// Send a STARTUP IPI to a core. |
163 | 0 | unsafe fn ipi_startup(&mut self, core: ApicId, start_page: u8) { |
164 | 0 | let icr = Icr::for_x2apic( |
165 | 0 | start_page, |
166 | 0 | core, |
167 | 0 | DestinationShorthand::NoShorthand, |
168 | 0 | DeliveryMode::StartUp, |
169 | 0 | DestinationMode::Physical, |
170 | 0 | DeliveryStatus::Idle, |
171 | 0 | Level::Assert, |
172 | 0 | TriggerMode::Edge, |
173 | | ); |
174 | 0 | self.send_ipi(icr); |
175 | 0 | } |
176 | | |
177 | | /// Send a generic IPI. |
178 | 0 | unsafe fn send_ipi(&mut self, icr: Icr) { |
179 | 0 | wrmsr(IA32_X2APIC_ESR, 0); |
180 | 0 | wrmsr(IA32_X2APIC_ESR, 0); |
181 | | |
182 | 0 | wrmsr(IA32_X2APIC_ICR, icr.0); |
183 | | |
184 | | loop { |
185 | 0 | let icr = rdmsr(IA32_X2APIC_ICR); |
186 | 0 | if (icr >> 12 & 0x1) == 0 { |
187 | 0 | break; |
188 | 0 | } |
189 | 0 | if rdmsr(IA32_X2APIC_ESR) > 0 { |
190 | 0 | break; |
191 | 0 | } |
192 | | } |
193 | 0 | } |
194 | | } |