base: bump submodule — acpid thermal zone methods (94d1b92d)
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/<zone>/{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.
This commit is contained in:
@@ -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/<zone>/{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 |
|
||||
|
||||
|
||||
@@ -120,6 +120,109 @@ pub struct FirmwareFragment {
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
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<HciCommand> {
|
||||
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<HciCommand> {
|
||||
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<u32> {
|
||||
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<IntelVersion>,
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
Submodule local/sources/base updated: 7071c4529e...94d1b92d91
Reference in New Issue
Block a user