091f19167b
- Mirror usr/plugins/*.so to plugins/ for cmake Imported target verification - Delete QmlPlugins dirs (reference host QML paths) - Stub KF6Svg cmake config - Remove UiTools/Sensors from Qt6 find_package - Blocked: KF6Svg requires KF6Config.cmake component registration
169 lines
4.9 KiB
Diff
169 lines
4.9 KiB
Diff
--- /dev/null 2026-05-03 20:55:05.750445686 +0100
|
|
+++ /mnt/data/homes/kellito/Builds/rbos/recipes/core/kernel/source/src/arch/x86_shared/device/msi.rs 2026-05-04 16:29:00.566790704 +0100
|
|
@@ -0,0 +1,165 @@
|
|
+// 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;
|
|
+const MSI_DEST_MODE_PHYSICAL: u64 = 0;
|
|
+
|
|
+#[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: 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 = 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, 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 {
|
|
+ MsiAddress::validate(self.address.raw)
|
|
+ && self.data.vector() >= 32
|
|
+ && self.data.vector() < 255
|
|
+ }
|
|
+}
|
|
+
|
|
+#[derive(Debug)]
|
|
+pub struct MsiCapability {
|
|
+ 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; 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 {
|
|
+ if msg_ctl & (1 << 7) != 0 { raw[4] } else { 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 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; 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,
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+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
|
|
+}
|
|
+
|
|
+#[cfg(test)]
|
|
+mod tests {
|
|
+ use super::*;
|
|
+
|
|
+ #[test]
|
|
+ fn test_compose_message() {
|
|
+ let msg = MsiMessage::compose(ApicId::new(0), 48, 0, 0);
|
|
+ assert!(msg.validate());
|
|
+ assert_eq!(msg.data.vector(), 48);
|
|
+ }
|
|
+
|
|
+ #[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);
|
|
+ }
|
|
+}
|