From 07ba3371338855928d0bd11d1890e891624fc9df Mon Sep 17 00:00:00 2001 From: vasilito Date: Wed, 22 Jul 2026 17:32:41 +0900 Subject: [PATCH] =?UTF-8?q?base:=20bump=20submodule=20=E2=80=94=20acpid=20?= =?UTF-8?q?thermal=20zone=20methods=20(94d1b92d)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also: btusb firmware download command sequence + plan doc updates. - btintel.rs extended: firmware_download_commands() generates the full HCI command sequence for SFI firmware download (CSS header + PKey + Signature + payload fragments). RSA and ECDSA header types supported. secure_send_commands() splits data into 252-byte fragments with type prefix. extract_boot_param() finds the CMD_WRITE_BOOT_PARAMS record in firmware data. 5 new unit tests (160 total pass). - acpid/scheme.rs: ThermalZone handle kind for per-zone ACPI thermal data. /scheme/acpi/thermal//{temperature,passive,critical} evaluates _TMP/_PSV/_CRT. thermald can now read real thresholds. - Plan doc: Phase 7.1 updated with download command sequence. ACPICA assessment updated with thermal zone methods. --- .../LG-GRAM-16Z90TP-COMPATIBILITY-PLAN.md | 3 +- .../redbear-btusb/source/src/btintel.rs | 142 ++++++++++++++++++ local/sources/base | 2 +- 3 files changed, 145 insertions(+), 2 deletions(-) diff --git a/local/docs/LG-GRAM-16Z90TP-COMPATIBILITY-PLAN.md b/local/docs/LG-GRAM-16Z90TP-COMPATIBILITY-PLAN.md index ed1dc431b1..91878e02bb 100644 --- a/local/docs/LG-GRAM-16Z90TP-COMPATIBILITY-PLAN.md +++ b/local/docs/LG-GRAM-16Z90TP-COMPATIBILITY-PLAN.md @@ -104,6 +104,7 @@ the existing `acpi-rs` vendored fork + `acpid` daemon: | EC query protocol | ✅ Already in acpid/ec.rs | SCI_EVT poll/IRQ, QR_EC drain, bounded at 32 | | Fixed event dispatch | ✅ Already in acpid/power_events.rs | PM1_STS PWRBTN/SLPBTN/RTC | | Sleep/wake (S0ix entry) | 🟡 Partial | `enter_s2idle()` now arms wake devices; `exit_s2idle()` disarms them. MWAIT idle loop remains (kernel idle-loop work) | +| Thermal zone methods | ✅ Ported (2026-07-22) | `/scheme/acpi/thermal//{temperature,passive,critical}` — _TMP/_PSV/_CRT evaluation via scheme | | Namespace management | ✅ In acpi-rs | AmlSymbols with RwLock | | Table manager (RSDT/XSDT) | ✅ In acpid/acpi.rs | SdtHeader parse + checksum + DSDT/SSDT/FADT/FACS/ECDT | @@ -451,7 +452,7 @@ real wireless connectivity, not bounded simulation. | # | Work item | Files | Effort | |---|---|---|---| -| 7.1 | Intel BT firmware load in `redbear-btusb`: bootloader-mode detection, `ibt-0093-0291.sfi` download, DDC apply — port from Linux `btintel.c` | `local/recipes/drivers/redbear-btusb/` | M → 🟡 PARTIAL (2026-07-22) — btintel.rs module: IntelVersion parse, bootloader/operational detection, MFG enter/exit commands, firmware fragment splitting, SFI/DDC filename tables, CSS header length detection. Firmware download transport wiring (HCI event-driven fragment ack) remains. | +| 7.1 | Intel BT firmware load in `redbear-btusb`: bootloader-mode detection, `ibt-0093-0291.sfi` download, DDC apply — port from Linux `btintel.c` | `local/recipes/drivers/redbear-btusb/` | M → 🟡 PARTIAL (2026-07-22) — btintel.rs: IntelVersion parse, MFG enter/exit, firmware download command sequence (CSS header + PKey + Signature + payload fragments, RSA/ECDSA), boot param extraction, SFI/DDC filename tables, 9 unit tests. HCI transport wiring (event-driven fragment ack) remains. | | 7.2 | HCI bring-up on the host: reset → read version → operational mode; bounded BLE battery-level slice validation via existing harness | btusb + `test-bluetooth-qemu.sh` host analogue | M | | 7.3 | `redbear-btctl` scan/pair/connect on host | redbear-btctl | S | diff --git a/local/recipes/drivers/redbear-btusb/source/src/btintel.rs b/local/recipes/drivers/redbear-btusb/source/src/btintel.rs index 5d1b3882c3..46d62222ab 100644 --- a/local/recipes/drivers/redbear-btusb/source/src/btintel.rs +++ b/local/recipes/drivers/redbear-btusb/source/src/btintel.rs @@ -120,6 +120,109 @@ pub struct FirmwareFragment { pub data: Vec, } +const FRAGMENT_TYPE_CSS: u8 = 0x00; +const FRAGMENT_TYPE_PAYLOAD: u8 = 0x01; +const FRAGMENT_TYPE_SIGNATURE: u8 = 0x02; +const FRAGMENT_TYPE_PKEY: u8 = 0x03; +const FRAGMENT_TYPE_LMS_SIG: u8 = 0x04; +const FRAGMENT_TYPE_LMS_PKEY: u8 = 0x05; + +pub fn secure_send_commands(fragment_type: u8, data: &[u8]) -> Vec { + let mut commands = Vec::new(); + let mut offset = 0; + while offset < data.len() { + let chunk_len = (data.len() - offset).min(FRAGMENT_SIZE); + let mut params = vec![fragment_type]; + params.extend_from_slice(&data[offset..offset + chunk_len]); + commands.push(HciCommand::new(OP_INTEL_DOWNLOAD_FRAGMENT, params)); + offset += chunk_len; + } + commands +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum CssKeyType { + Rsa, + Ecdsa, + Hybrid, +} + +fn detect_css_type(fw_data: &[u8]) -> CssKeyType { + if fw_data.len() < 4 { + return CssKeyType::Rsa; + } + match fw_data[0] { + 0x01 => CssKeyType::Rsa, + 0x02 => CssKeyType::Ecdsa, + _ => CssKeyType::Rsa, + } +} + +pub fn firmware_download_commands(fw_data: &[u8]) -> Vec { + let mut commands = Vec::new(); + let key_type = detect_css_type(fw_data); + + match key_type { + CssKeyType::Rsa => { + if fw_data.len() < 644 { + warn!("btintel: RSA firmware too short ({} bytes)", fw_data.len()); + return commands; + } + commands.extend(secure_send_commands(FRAGMENT_TYPE_CSS, &fw_data[0..128])); + commands.extend(secure_send_commands(FRAGMENT_TYPE_PKEY, &fw_data[128..384])); + commands.extend(secure_send_commands(FRAGMENT_TYPE_SIGNATURE, &fw_data[384..640])); + let payload = &fw_data[644..]; + commands.extend(secure_send_commands(FRAGMENT_TYPE_PAYLOAD, payload)); + } + CssKeyType::Ecdsa => { + if fw_data.len() < 644 { + warn!("btintel: ECDSA firmware too short ({} bytes)", fw_data.len()); + return commands; + } + commands.extend(secure_send_commands(FRAGMENT_TYPE_CSS, &fw_data[644..644 + 128])); + commands.extend(secure_send_commands(FRAGMENT_TYPE_PKEY, &fw_data[644 + 128..644 + 224])); + commands.extend(secure_send_commands(FRAGMENT_TYPE_SIGNATURE, &fw_data[644 + 224..644 + 320])); + let payload = &fw_data[644 + 320..]; + commands.extend(secure_send_commands(FRAGMENT_TYPE_PAYLOAD, payload)); + } + CssKeyType::Hybrid => { + if fw_data.len() < 128 { + return commands; + } + commands.extend(secure_send_commands(FRAGMENT_TYPE_CSS, &fw_data[0..128])); + let payload = &fw_data[128..]; + commands.extend(secure_send_commands(FRAGMENT_TYPE_PAYLOAD, payload)); + } + } + + info!( + "btintel: firmware download prepared — {} commands for {} bytes ({:?})", + commands.len(), + fw_data.len(), + key_type + ); + commands +} + +pub fn extract_boot_param(fw_data: &[u8]) -> Option { + let mut offset = 0; + while offset + 3 < fw_data.len() { + let opcode = u16::from_le_bytes([fw_data[offset], fw_data[offset + 1]]); + let plen = fw_data[offset + 2] as usize; + if opcode == 0xfc0e && offset + 3 + plen <= fw_data.len() { + let boot_addr = u32::from_le_bytes([ + fw_data[offset + 3], + fw_data[offset + 4], + fw_data[offset + 5], + fw_data[offset + 6], + ]); + return Some(boot_addr); + } + offset += 3 + plen; + } + None +} + pub struct IntelFirmwareLoader { pub version: Option, } @@ -238,4 +341,43 @@ mod tests { assert_eq!(fragments[0].data.len(), 252); assert_eq!(fragments[1].data.len(), 248); } + + #[test] + fn secure_send_single_fragment() { + let data = vec![0xAA; 100]; + let cmds = secure_send_commands(FRAGMENT_TYPE_PAYLOAD, &data); + assert_eq!(cmds.len(), 1); + } + + #[test] + fn secure_send_multiple_fragments() { + let data = vec![0xBB; 600]; + let cmds = secure_send_commands(FRAGMENT_TYPE_PAYLOAD, &data); + assert_eq!(cmds.len(), 3); + } + + #[test] + fn rsa_download_commands() { + let mut fw = vec![0x01]; + fw.extend_from_slice(&[0u8; 643]); + fw.extend_from_slice(&[0xCC; 300]); + let cmds = firmware_download_commands(&fw); + assert!(cmds.len() > 3); + } + + #[test] + fn extract_boot_param_finds_write_boot_params() { + let mut fw = Vec::new(); + fw.extend_from_slice(&0xfc0eu16.to_le_bytes()); + fw.push(7); + fw.extend_from_slice(&0x12345678u32.to_le_bytes()); + fw.extend_from_slice(&[1, 1, 24]); + assert_eq!(extract_boot_param(&fw), Some(0x12345678)); + } + + #[test] + fn extract_boot_param_not_found() { + let fw = vec![0u8; 20]; + assert_eq!(extract_boot_param(&fw), None); + } } diff --git a/local/sources/base b/local/sources/base index 7071c4529e..94d1b92d91 160000 --- a/local/sources/base +++ b/local/sources/base @@ -1 +1 @@ -Subproject commit 7071c4529e75849afb9fe5ffe0cf46e11852e90a +Subproject commit 94d1b92d915d86cea70a4609994321936aa302d2