From af2655202a0371a70a7f6b8660f280f917e3eb17 Mon Sep 17 00:00:00 2001 From: hotline1337 Date: Wed, 30 Sep 2026 22:13:21 +0200 Subject: [PATCH 1/2] fix: parse and serialize blacklisted hardware IDs in profile parser --- src/data.rs | 32 +++++++++++++++++++ src/profile.rs | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) diff --git a/src/data.rs b/src/data.rs index 50cb114..83f86a3 100644 --- a/src/data.rs +++ b/src/data.rs @@ -1109,6 +1109,38 @@ mod tests { assert!(data::matches_cpu_filter(&profile, &cpu_info)); } + #[test] + fn blacklisted_device_id_rejects_matching_device() { + let devices = vec![crate::device::Device { + class_id: "0600".into(), + vendor_id: "8086".into(), + device_id: "4650".into(), + class_name: "Host bridge".into(), + device_name: "12th Gen Core Processor Host Bridge".into(), + vendor_name: "Intel Corporation".into(), + sysfs_busid: "0000:00:00.0".into(), + sysfs_id: "".into(), + available_profiles: vec![], + installed_profiles: vec![], + }]; + let mut profile = crate::profile::Profile { + hwd_ids: vec![crate::profile::HardwareID { + class_ids: vec!["0600".into()], + vendor_ids: vec!["8086".into()], + device_ids: vec!["*".into()], + blacklisted_device_ids: vec!["4650".into()], + ..Default::default() + }], + ..Default::default() + }; + + assert!(data::get_all_devices_of_profile(&devices, &profile).is_empty()); + + // Without blacklist, it matches + profile.hwd_ids[0].blacklisted_device_ids.clear(); + assert_eq!(data::get_all_devices_of_profile(&devices, &profile), vec![0]); + } + #[test] fn get_devices_from_gc_versions() { let devices = test_data(); diff --git a/src/profile.rs b/src/profile.rs index 5997770..17adaaa 100644 --- a/src/profile.rs +++ b/src/profile.rs @@ -274,6 +274,12 @@ fn parse_profile(node: &toml::Table, profile_name: &str) -> Result { let conf_devids = node.get("device_ids").and_then(|x| x.as_str()).unwrap_or(""); let conf_vendorids = node.get("vendor_ids").and_then(|x| x.as_str()).unwrap_or(""); let conf_classids = node.get("class_ids").and_then(|x| x.as_str()).unwrap_or(""); + let conf_blacklisted_devids = + node.get("blacklisted_device_ids").and_then(|x| x.as_str()).unwrap_or(""); + let conf_blacklisted_vendorids = + node.get("blacklisted_vendor_ids").and_then(|x| x.as_str()).unwrap_or(""); + let conf_blacklisted_classids = + node.get("blacklisted_class_ids").and_then(|x| x.as_str()).unwrap_or(""); // Read ids in extern file let devids_val = if !conf_devids.is_empty() && conf_devids.as_bytes()[0] == b'>' { @@ -281,6 +287,12 @@ fn parse_profile(node: &toml::Table, profile_name: &str) -> Result { } else { conf_devids.to_owned() }; + let blacklisted_devids_val = + if !conf_blacklisted_devids.is_empty() && conf_blacklisted_devids.as_bytes()[0] == b'>' { + parse_ids_file(&conf_blacklisted_devids[1..])? + } else { + conf_blacklisted_devids.to_owned() + }; // Add new HardwareIDs group to vector if vector is not empty if !profile.hwd_ids.last().unwrap().device_ids.is_empty() { @@ -312,6 +324,28 @@ fn parse_profile(node: &toml::Table, profile_name: &str) -> Result { .collect::>(); } + if !blacklisted_devids_val.is_empty() { + profile.hwd_ids.last_mut().unwrap().blacklisted_device_ids = blacklisted_devids_val + .split(' ') + .filter(|x| !x.is_empty()) + .map(std::borrow::ToOwned::to_owned) + .collect::>(); + } + if !conf_blacklisted_classids.is_empty() { + profile.hwd_ids.last_mut().unwrap().blacklisted_class_ids = conf_blacklisted_classids + .split(' ') + .filter(|x| !x.is_empty()) + .map(std::borrow::ToOwned::to_owned) + .collect::>(); + } + if !conf_blacklisted_vendorids.is_empty() { + profile.hwd_ids.last_mut().unwrap().blacklisted_vendor_ids = conf_blacklisted_vendorids + .split(' ') + .filter(|x| !x.is_empty()) + .map(std::borrow::ToOwned::to_owned) + .collect::>(); + } + let append_star = |vec: &mut Vec<_>| { if vec.is_empty() { vec.push("*".to_string()); @@ -487,6 +521,24 @@ fn profile_into_toml(profile: &Profile) -> toml::Table { table.insert("device_ids".to_owned(), device_ids.join(" ").into()); table.insert("vendor_ids".to_owned(), vendor_ids.join(" ").into()); table.insert("class_ids".to_owned(), class_ids.join(" ").into()); + if !last_hwd_id.blacklisted_device_ids.is_empty() { + table.insert( + "blacklisted_device_ids".to_owned(), + last_hwd_id.blacklisted_device_ids.join(" ").into(), + ); + } + if !last_hwd_id.blacklisted_class_ids.is_empty() { + table.insert( + "blacklisted_class_ids".to_owned(), + last_hwd_id.blacklisted_class_ids.join(" ").into(), + ); + } + if !last_hwd_id.blacklisted_vendor_ids.is_empty() { + table.insert( + "blacklisted_vendor_ids".to_owned(), + last_hwd_id.blacklisted_vendor_ids.join(" ").into(), + ); + } table } @@ -797,4 +849,36 @@ mod tests { // Should fail because cpu_models is set without cpu_family assert!(parsed_profiles.is_err() || parsed_profiles.unwrap().is_empty()); } + + #[test] + fn parse_and_serialize_blacklisted_ids() { + let toml_content = r#" +[test-profile] +desc = "Test profile" +class_ids = "0600" +vendor_ids = "8086" +device_ids = "*" +blacklisted_device_ids = "4650 4651" +blacklisted_class_ids = "0300" +blacklisted_vendor_ids = "10de" +packages = "test-pkg" +"#; + let table = toml_content.parse::().unwrap(); + let profile = super::parse_profile( + table.get("test-profile").unwrap().as_table().unwrap(), + "test-profile", + ) + .unwrap(); + assert_eq!(profile.hwd_ids[0].blacklisted_device_ids, vec!["4650", "4651"]); + assert_eq!(profile.hwd_ids[0].blacklisted_class_ids, vec!["0300"]); + assert_eq!(profile.hwd_ids[0].blacklisted_vendor_ids, vec!["10de"]); + + let serialized = super::profile_into_toml(&profile); + assert_eq!( + serialized.get("blacklisted_device_ids").unwrap().as_str().unwrap(), + "4650 4651" + ); + assert_eq!(serialized.get("blacklisted_class_ids").unwrap().as_str().unwrap(), "0300"); + assert_eq!(serialized.get("blacklisted_vendor_ids").unwrap().as_str().unwrap(), "10de"); + } } From e42f4e41341671d19e7aaef29d409e32c4362780 Mon Sep 17 00:00:00 2001 From: hotline1337 Date: Wed, 30 Sep 2026 22:13:55 +0200 Subject: [PATCH 2/2] profiles: blacklist non-hybrid Alder Lake CPUs from intel-lpmd --- profiles/pci/power_management/profiles.toml | 4 ++++ src/profile.rs | 1 + tests/profiles/cpu-profile-test.toml | 1 + 3 files changed, 6 insertions(+) diff --git a/profiles/pci/power_management/profiles.toml b/profiles/pci/power_management/profiles.toml index ab11114..5eef99e 100644 --- a/profiles/pci/power_management/profiles.toml +++ b/profiles/pci/power_management/profiles.toml @@ -3,6 +3,10 @@ desc = 'Intel Low Power Mode Daemon for supported hybrid Intel CPUs' class_ids = "0600" vendor_ids = "8086" device_ids = "*" +# Exclude Alder Lake-S desktop processors without E-Cores (Host Bridge 4650): +# i5-12600, i5-12600T, i5-12500, i5-12500T, i5-12490F, i5-12400, i5-12400F, i5-12400T, +# i3-12300, i3-12300T, i3-12100, i3-12100F, i3-12100T, Pentium Gold G7400/G7400T, Celeron G6900/G6900T +blacklisted_device_ids = "4650" cpu_family = "6" cpu_models = "151 154 183 186 191 170 172 189 204 213" priority = 5 diff --git a/src/profile.rs b/src/profile.rs index 17adaaa..586dc87 100644 --- a/src/profile.rs +++ b/src/profile.rs @@ -838,6 +838,7 @@ mod tests { "213".to_owned(), ]) ); + assert_eq!(parsed_profiles[0].hwd_ids[0].blacklisted_device_ids, vec!["4650".to_owned()]); assert!(!parsed_profiles[0].post_install.is_empty()); assert!(!parsed_profiles[0].post_remove.is_empty()); } diff --git a/tests/profiles/cpu-profile-test.toml b/tests/profiles/cpu-profile-test.toml index ab11114..da711d7 100644 --- a/tests/profiles/cpu-profile-test.toml +++ b/tests/profiles/cpu-profile-test.toml @@ -3,6 +3,7 @@ desc = 'Intel Low Power Mode Daemon for supported hybrid Intel CPUs' class_ids = "0600" vendor_ids = "8086" device_ids = "*" +blacklisted_device_ids = "4650" cpu_family = "6" cpu_models = "151 154 183 186 191 170 172 189 204 213" priority = 5