39807ca816
Absorb redundant kernel patches into v2 carriers, remove debug and suspend patches no longer needed. Wire v2 patches in recipe.toml. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
223 lines
6.7 KiB
Diff
223 lines
6.7 KiB
Diff
diff --git a/src/arch/x86_shared/device/msi.rs b/src/arch/x86_shared/device/msi.rs
|
|
--- a/src/arch/x86_shared/device/msi.rs
|
|
+++ b/src/arch/x86_shared/device/msi.rs
|
|
@@ -1,66 +1,183 @@
|
|
+// MSI/MSI-X support for x86 — kernel-level message composition and validation
|
|
+// Cross-referenced from Linux 7.0: arch/x86/kernel/apic/msi.c (391 lines)
|
|
+
|
|
use crate::arch::device::local_apic::ApicId;
|
|
|
|
pub const MSI_ADDRESS_BASE: u64 = 0xFEE0_0000;
|
|
+pub const MSI_ADDRESS_MASK: u64 = 0xFEEF_F000;
|
|
+const MSI_DEST_MODE_LOGICAL: u64 = 1 << 2;
|
|
+const MSI_REDIRECTION_HINT: u64 = 1 << 3;
|
|
+
|
|
+#[derive(Debug, Clone, Copy)]
|
|
+pub struct MsiAddress {
|
|
+ pub raw: u64,
|
|
+}
|
|
+
|
|
+#[derive(Debug, Clone, Copy)]
|
|
+pub struct MsiData {
|
|
+ pub raw: u32,
|
|
+}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct MsiMessage {
|
|
- pub address: u64,
|
|
- pub data: u32,
|
|
+ pub address: MsiAddress,
|
|
+ pub data: MsiData,
|
|
+}
|
|
+
|
|
+impl MsiAddress {
|
|
+ pub fn new(dest_apic_id: u8, redirection_hint: bool, dest_mode_logical: bool) -> Self {
|
|
+ let mut addr = MSI_ADDRESS_BASE;
|
|
+ addr |= u64::from(dest_apic_id) << 12;
|
|
+ if redirection_hint {
|
|
+ addr |= MSI_REDIRECTION_HINT;
|
|
+ }
|
|
+ if dest_mode_logical {
|
|
+ addr |= MSI_DEST_MODE_LOGICAL;
|
|
+ }
|
|
+ Self { raw: addr }
|
|
+ }
|
|
+
|
|
+ pub fn validate(addr: u64) -> bool {
|
|
+ (addr & MSI_ADDRESS_MASK) == MSI_ADDRESS_BASE
|
|
+ }
|
|
+
|
|
+ pub fn dest_apic_id(&self) -> u8 {
|
|
+ ((self.raw >> 12) & 0xFF) as u8
|
|
+ }
|
|
+}
|
|
+
|
|
+impl MsiData {
|
|
+ pub fn new(vector: u8, delivery_mode: u8, trigger_mode: u8) -> Self {
|
|
+ let mut data = u32::from(vector);
|
|
+ data |= u32::from(delivery_mode) << 8;
|
|
+ data |= u32::from(trigger_mode) << 15;
|
|
+ Self { raw: data }
|
|
+ }
|
|
+
|
|
+ pub fn vector(&self) -> u8 {
|
|
+ (self.raw & 0xFF) as u8
|
|
+ }
|
|
+
|
|
+ pub fn delivery_mode(&self) -> u8 {
|
|
+ ((self.raw >> 8) & 0x7) as u8
|
|
+ }
|
|
+
|
|
+ pub fn trigger_mode(&self) -> u8 {
|
|
+ ((self.raw >> 15) & 0x1) as u8
|
|
+ }
|
|
}
|
|
|
|
impl MsiMessage {
|
|
- pub fn compose(dest: ApicId, vector: u8, delivery_mode: u8) -> Self {
|
|
- let address = MSI_ADDRESS_BASE | (u64::from(dest.get()) << 12);
|
|
- let data = u32::from(vector) | (u32::from(delivery_mode) << 8);
|
|
+ pub fn compose(dest: ApicId, vector: u8, delivery_mode: u8, trigger_mode: u8) -> Self {
|
|
+ let address = MsiAddress::new(dest.get() as u8, false, false);
|
|
+ let data = MsiData::new(vector, delivery_mode, trigger_mode);
|
|
Self { address, data }
|
|
}
|
|
|
|
pub fn validate(&self) -> bool {
|
|
- (self.address & 0xFFF0_0000) == MSI_ADDRESS_BASE
|
|
- && self.data & 0xFF >= 32
|
|
- && self.data & 0xFF < 255
|
|
+ MsiAddress::validate(self.address.raw)
|
|
+ && self.data.vector() >= 32
|
|
+ && self.data.vector() < 255
|
|
}
|
|
}
|
|
|
|
-pub fn is_valid_msi_address(addr: u64) -> bool { (addr & 0xFFF0_0000) == MSI_ADDRESS_BASE }
|
|
-pub fn is_valid_msi_vector(vector: u8) -> bool { vector >= 32 && vector < 255 }
|
|
+pub fn is_valid_msi_address(addr: u64) -> bool {
|
|
+ MsiAddress::validate(addr)
|
|
+}
|
|
+
|
|
+pub fn is_valid_msi_vector(vector: u8) -> bool {
|
|
+ vector >= 32 && vector < 255
|
|
+}
|
|
|
|
#[derive(Debug)]
|
|
pub struct MsiCapability {
|
|
- pub msg_ctl: u16, pub msg_addr_lo: u32, pub msg_data: u16,
|
|
- pub is_64bit: bool, pub is_maskable: bool, pub multiple_message_capable: u8,
|
|
+ pub msg_ctl: u16,
|
|
+ pub msg_addr_lo: u32,
|
|
+ pub msg_addr_hi: u32,
|
|
+ pub msg_data: u16,
|
|
+ pub mask_bits: u32,
|
|
+ pub pending_bits: u32,
|
|
+ pub is_64bit: bool,
|
|
+ pub is_maskable: bool,
|
|
+ pub multiple_message_capable: u8,
|
|
}
|
|
|
|
impl MsiCapability {
|
|
- pub fn parse(raw: &[u32], msg_ctl: u16) -> Option<Self> {
|
|
- let msg_addr_lo = *raw.get(1)?;
|
|
- let msg_data = if msg_ctl & (1<<7) != 0 {
|
|
- (*raw.get(3)? & 0xFFFF) as u16
|
|
- } else {
|
|
- (*raw.get(2)? & 0xFFFF) as u16
|
|
- };
|
|
- Some(Self {
|
|
- msg_ctl, msg_addr_lo, msg_data,
|
|
- is_64bit: msg_ctl & (1<<7) != 0,
|
|
- is_maskable: msg_ctl & (1<<8) != 0,
|
|
- multiple_message_capable: ((msg_ctl>>1)&0x7) as u8,
|
|
- })
|
|
+ pub fn parse(raw: &[u32; 6], msg_ctl: u16) -> Self {
|
|
+ Self {
|
|
+ msg_ctl,
|
|
+ msg_addr_lo: raw[1],
|
|
+ msg_addr_hi: if msg_ctl & (1 << 7) != 0 { raw[2] } else { 0 },
|
|
+ msg_data: if msg_ctl & (1 << 7) != 0 {
|
|
+ (raw[3] & 0xFFFF) as u16
|
|
+ } else {
|
|
+ (raw[2] & 0xFFFF) as u16
|
|
+ },
|
|
+ mask_bits: if msg_ctl & (1 << 8) != 0 {
|
|
+ if msg_ctl & (1 << 7) != 0 {
|
|
+ raw[3] >> 16
|
|
+ } else {
|
|
+ raw[3]
|
|
+ }
|
|
+ } else {
|
|
+ 0
|
|
+ },
|
|
+ pending_bits: if msg_ctl & (1 << 8) != 0 { raw[4] } else { 0 },
|
|
+ is_64bit: msg_ctl & (1 << 7) != 0,
|
|
+ is_maskable: msg_ctl & (1 << 8) != 0,
|
|
+ multiple_message_capable: ((msg_ctl >> 1) & 0x7) as u8,
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+#[derive(Debug)]
|
|
pub struct MsixCapability {
|
|
- pub table_offset: u32, pub table_bar: u8,
|
|
- pub pba_offset: u32, pub pba_bar: u8, pub table_size: u16,
|
|
+ pub msg_ctl: u16,
|
|
+ pub table_offset: u32,
|
|
+ pub table_bar: u8,
|
|
+ pub pba_offset: u32,
|
|
+ pub pba_bar: u8,
|
|
+ pub table_size: u16,
|
|
}
|
|
|
|
impl MsixCapability {
|
|
- pub fn parse(raw: &[u32], msg_ctl: u16) -> Option<Self> {
|
|
- let r1 = *raw.get(1)?;
|
|
- let r2 = *raw.get(2)?;
|
|
- Some(Self {
|
|
- table_offset: r1 & !0x7, table_bar: (r1&0x7) as u8,
|
|
- pba_offset: r2 & !0x7, pba_bar: (r2&0x7) as u8,
|
|
- table_size: ((msg_ctl>>1)&0x7FF) as u16 + 1,
|
|
- })
|
|
+ pub fn parse(raw: &[u32; 3], msg_ctl: u16) -> Self {
|
|
+ Self {
|
|
+ msg_ctl,
|
|
+ table_offset: raw[1] & !0x7,
|
|
+ table_bar: (raw[1] & 0x7) as u8,
|
|
+ pba_offset: raw[2] & !0x7,
|
|
+ pba_bar: (raw[2] & 0x7) as u8,
|
|
+ table_size: ((msg_ctl >> 1) & 0x7FF) as u16 + 1,
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+#[cfg(test)]
|
|
+mod tests {
|
|
+ use super::*;
|
|
+
|
|
+ #[test]
|
|
+ fn test_compose_message() {
|
|
+ let msg = MsiMessage::compose(ApicId::new(3), 48, 0b101, 1);
|
|
+ assert!(msg.validate());
|
|
+ assert_eq!(msg.address.dest_apic_id(), 3);
|
|
+ assert_eq!(msg.data.vector(), 48);
|
|
+ assert_eq!(msg.data.delivery_mode(), 0b101);
|
|
+ assert_eq!(msg.data.trigger_mode(), 1);
|
|
+ }
|
|
+
|
|
+ #[test]
|
|
+ fn test_invalid_address() {
|
|
+ assert!(!is_valid_msi_address(0xDEAD_BEEF));
|
|
+ assert!(is_valid_msi_address(0xFEE0_0000));
|
|
+ }
|
|
+
|
|
+ #[test]
|
|
+ fn test_msi_parse() {
|
|
+ let raw = [0u32; 6];
|
|
+ let cap = MsiCapability::parse(&raw, 0);
|
|
+ assert!(!cap.is_64bit);
|
|
+ assert!(!cap.is_maskable);
|
|
}
|
|
}
|