Files
RedBear-OS/local/patches/kernel/P8-msi-foundation.patch
T
vasilito 091f19167b kwin: plugin path fix + KF6Svg stub + QmlPlugins cleanup
- 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
2026-05-04 16:42:19 +01:00

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);
+ }
+}