1use bitfield_struct::bitfield;
7use open_enum::open_enum;
8
9pub const APIC_BASE_ADDRESS: u32 = 0xfee00000;
11pub const APIC_BASE_PAGE: u32 = APIC_BASE_ADDRESS >> 12;
13
14pub const APIC_LEGACY_ID_COUNT: u32 = 255;
15
16#[bitfield(u64)]
18#[derive(PartialEq, Eq)]
19pub struct ApicBase {
20    _reserved: u8,
21    pub bsp: bool,
23    _reserved2: bool,
24    pub x2apic: bool,
25    pub enable: bool,
26    #[bits(24)]
28    pub base_page: u32,
29    #[bits(28)]
30    _reserved3: u64,
31}
32
33#[bitfield(u32)]
35pub struct Svr {
36    pub vector: u8,
37    pub enable: bool,
38    pub focus_processor_checking: bool,
39    #[bits(2)]
40    _rsvd: u32,
41    pub eoi_broadcast_suppression: bool,
42    #[bits(19)]
43    _rsvd2: u32,
44}
45
46#[bitfield(u32)]
48pub struct Lvt {
49    pub vector: u8,
50    #[bits(3)]
51    pub delivery_mode: u8,
52    _rsvd: bool,
53    pub delivery_status: bool,
54    pub input_pin_polarity: bool,
55    pub remote_irr: bool,
56    pub trigger_mode_level: bool,
57    pub masked: bool,
58    #[bits(2)]
59    pub timer_mode: u8,
60    #[bits(13)]
61    _rsvd2: u32,
62}
63
64open_enum! {
65    pub enum TimerMode: u8 {
66        ONE_SHOT = 0,
67        PERIODIC = 1,
68        TSC_DEADLINE = 2,
69    }
70}
71
72#[bitfield(u32)]
73pub struct Dcr {
74    #[bits(2)]
75    pub value_low: u8,
76    _rsvd: bool,
77    #[bits(1)]
78    pub value_high: u8,
79    #[bits(28)]
80    _rsvd2: u32,
81}
82
83open_enum! {
84    pub enum Dfr: u32 {
85        FLAT_MODE = 0xffff_ffff,
86        CLUSTERED_MODE = 0x0fff_ffff,
87    }
88}
89
90#[bitfield(u64)]
91pub struct Icr {
92    pub vector: u8,
93    #[bits(3)]
94    pub delivery_mode: u8,
95    pub destination_mode_logical: bool,
96    pub delivery_pending: bool,
97    pub reserved1: bool,
98    pub level_assert: bool,
99    pub trigger_mode_level: bool,
100    #[bits(2)]
101    pub remote_read_status: u8,
102    #[bits(2)]
103    pub destination_shorthand: u8,
104    #[bits(12)]
105    pub reserved3: u16,
106    pub x2apic_mda: u32,
107}
108
109impl Icr {
110    pub const fn xapic_mda(&self) -> u8 {
111        (self.x2apic_mda() >> 24) as u8
112    }
113
114    pub fn set_xapic_mda(&mut self, value: u8) {
115        *self = self.with_xapic_mda(value);
116    }
117
118    pub const fn with_xapic_mda(self, value: u8) -> Self {
119        self.with_x2apic_mda((value as u32) << 24)
120    }
121}
122
123#[bitfield(u32)]
124pub struct X2ApicLogicalId {
125    pub logical_id: u16,
126    pub cluster_id: u16,
127}
128
129#[bitfield(u8)]
130pub struct XApicClusterLogicalId {
131    #[bits(4)]
132    pub logical_id: u8,
133    #[bits(4)]
134    pub cluster_id: u8,
135}
136
137open_enum! {
138    pub enum DeliveryMode: u8 {
139        FIXED = 0,
140        LOWEST_PRIORITY = 1,
141        SMI = 2,
142        REMOTE_READ = 3,
143        NMI = 4,
144        INIT = 5,
145        SIPI = 6,
146        EXTINT = 7,
147    }
148}
149
150open_enum! {
151    pub enum DestinationShorthand: u8 {
152        NONE = 0,
153        SELF = 1,
154        ALL_INCLUDING_SELF = 2,
155        ALL_EXCLUDING_SELF = 3,
156    }
157}
158
159open_enum! {
160    pub enum ApicRegister: u8 {
161        ID = 0x2,               VERSION = 0x3,          TPR = 0x8,              APR = 0x9,              PPR = 0xa,              EOI = 0xb,              RRD = 0xc,              LDR = 0xd,              DFR = 0xe,              SVR = 0xf,              ISR0 = 0x10,            ISR1 = 0x11,
173        ISR2 = 0x12,
174        ISR3 = 0x13,
175        ISR4 = 0x14,
176        ISR5 = 0x15,
177        ISR6 = 0x16,
178        ISR7 = 0x17,
179        TMR0 = 0x18,            TMR1 = 0x19,
181        TMR2 = 0x1a,
182        TMR3 = 0x1b,
183        TMR4 = 0x1c,
184        TMR5 = 0x1d,
185        TMR6 = 0x1e,
186        TMR7 = 0x1f,
187        IRR0 = 0x20,            IRR1 = 0x21,
189        IRR2 = 0x22,
190        IRR3 = 0x23,
191        IRR4 = 0x24,
192        IRR5 = 0x25,
193        IRR6 = 0x26,
194        IRR7 = 0x27,
195        ESR = 0x28,             INTEL_LVT_CMCI = 0x2f,  ICR0 = 0x30,            ICR1 = 0x31,            LVT_TIMER = 0x32,       LVT_THERMAL = 0x33,     LVT_PMC = 0x34,         LVT_LINT0 = 0x35,       LVT_LINT1 = 0x36,       LVT_ERROR = 0x37,       TIMER_ICR = 0x38,       TIMER_CCR = 0x39,       TIMER_DCR = 0x3e,       SELF_IPI = 0x3f,        }
210}
211
212pub const X2APIC_MSR_BASE: u32 = 0x800;
213pub const X2APIC_MSR_END: u32 = 0x83f;
214
215impl ApicRegister {
216    pub fn x2apic_msr(&self) -> u32 {
217        X2APIC_MSR_BASE + self.0 as u32
218    }
219}
220
221#[bitfield(u32)]
222pub struct ApicVersion {
223    pub version: u8,
224    _rsvd: u8,
225    pub max_lvt_entry: u8,
226    pub eoi_broadcast_suppression: bool,
227    #[bits(7)]
228    _rsvd: u8,
229}