intel_vtd/spec/irte.rs
1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Interrupt Remapping Table Entry (IRTE) for the Intel VT-d IOMMU.
5//!
6//! Based on Intel VT-d Specification Rev 4.1, §9.9. VT-d IRTEs are 128-bit
7//! (16 bytes), indexed by the interrupt index extracted from remappable-format
8//! MSI address/data. The IRTE specifies the remapped interrupt vector,
9//! destination, delivery mode, and source validation fields.
10
11use bitfield_struct::bitfield;
12use inspect::Inspect;
13use open_enum::open_enum;
14use zerocopy::FromBytes;
15use zerocopy::Immutable;
16use zerocopy::IntoBytes;
17use zerocopy::KnownLayout;
18
19/// A 128-bit Interrupt Remapping Table Entry (§9.9).
20///
21/// Layout:
22/// - Low 64 bits: remapping control fields, vector, destination
23/// - High 64 bits: source validation (SID, SQ, SVT)
24#[derive(Debug, Copy, Clone, FromBytes, IntoBytes, Immutable, KnownLayout)]
25#[repr(C)]
26pub struct Irte {
27 /// Low 64 bits: present, FPD, mode, vector, destination.
28 pub lo: IrteLo,
29 /// High 64 bits: source ID, source qualifier, source validation type.
30 pub hi: IrteHi,
31}
32
33/// IRTE — low 64 bits.
34///
35/// Contains the interrupt remapping control fields:
36/// - P (present), FPD, DM, RH, TM, DLM, IM, Vector, DST
37#[bitfield(u64)]
38#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
39#[rustfmt::skip]
40pub struct IrteLo {
41 /// Present — 1 = this IRTE is valid.
42 pub p: bool,
43 /// Fault Processing Disable — 1 = suppress fault recording for this entry.
44 pub fpd: bool,
45 /// Destination Mode — 0 = physical, 1 = logical.
46 pub dm: bool,
47 /// Redirection Hint — 0 = directed to single destination,
48 /// 1 = may be redirected (for lowest priority delivery).
49 pub rh: bool,
50 /// Trigger Mode — 0 = edge, 1 = level.
51 pub tm: bool,
52 /// Delivery Mode (3 bits).
53 #[bits(3)]
54 pub dlm: u8,
55 /// Available for software use (4 bits).
56 #[bits(4)]
57 pub avail: u8,
58 #[bits(3)]
59 _reserved1: u64,
60 /// IRTE Mode — 0 = remapped interrupt, 1 = posted interrupt (not supported).
61 pub im: bool,
62 /// Interrupt Vector (8 bits).
63 #[bits(8)]
64 pub vector: u8,
65 #[bits(8)]
66 _reserved2: u64,
67 /// Destination ID (32 bits).
68 /// - xAPIC mode (EIME=0): only bits 47:40 (8-bit APIC ID) are significant.
69 /// - x2APIC mode (EIME=1): full 32-bit APIC ID.
70 #[bits(32)]
71 pub dst: u32,
72}
73
74impl IrteLo {
75 /// Get the xAPIC destination (8-bit, from bits 47:40 of the DST field).
76 ///
77 /// In xAPIC mode (EIME=0), only bits 15:8 of the 32-bit DST field are
78 /// used as the APIC destination ID.
79 pub fn xapic_destination(&self) -> u8 {
80 ((self.dst() >> 8) & 0xFF) as u8
81 }
82}
83
84/// IRTE — high 64 bits.
85///
86/// Contains source validation fields for verifying that an interrupt comes
87/// from the expected device.
88#[bitfield(u64)]
89#[derive(IntoBytes, Immutable, KnownLayout, FromBytes, Inspect)]
90#[rustfmt::skip]
91pub struct IrteHi {
92 /// Source Identifier (16 bits) — expected source BDF or bus range.
93 #[bits(16)]
94 pub sid: u16,
95 /// Source-ID Qualifier (2 bits) — controls how SID matching works.
96 #[bits(2)]
97 pub sq: u8,
98 /// Source Validation Type (2 bits).
99 /// 00 = no validation, 01 = verify SID, 10 = verify bus range.
100 #[bits(2)]
101 pub svt: u8,
102 #[bits(44)]
103 _reserved: u64,
104}
105
106open_enum! {
107 /// Delivery mode for interrupt remapping (§9.9).
108 #[derive(Inspect)]
109 #[inspect(debug)]
110 pub enum DeliveryMode: u8 {
111 /// Fixed delivery to the specified destination(s).
112 FIXED = 0b000,
113 /// Lowest priority delivery.
114 LOWEST_PRIORITY = 0b001,
115 /// SMI (System Management Interrupt).
116 SMI = 0b010,
117 /// NMI (Non-Maskable Interrupt).
118 NMI = 0b100,
119 /// INIT.
120 INIT = 0b101,
121 /// ExtINT (external interrupt).
122 EXTINTR = 0b111,
123 }
124}
125
126open_enum! {
127 /// Source validation type for IRTE (§9.9).
128 #[derive(Inspect)]
129 #[inspect(debug)]
130 pub enum SourceValidationType: u8 {
131 /// No source validation — any device can use this IRTE.
132 NONE = 0b00,
133 /// Verify source ID matches IRTE.SID (per SQ mask).
134 VERIFY_SID = 0b01,
135 /// Verify source bus number is in range [SID[7:0], SID[15:8]].
136 VERIFY_BUS_RANGE = 0b10,
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 #[test]
145 fn test_xapic_destination() {
146 let lo = IrteLo::new().with_dst(0x0000_0300);
147 assert_eq!(lo.xapic_destination(), 3);
148 }
149}