Skip to main content

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}