Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions EXAMPLES_ADVANCED.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,66 @@ ESRT Entry 0
Last Attempt Status: Success
```

## Intel ME Information

Show Intel Management Engine status, including firmware version, bootguard
configuration, and security status. This information is read from SMBIOS tables.

On Linux, additional information is available from sysfs.

```
> sudo framework_tool --meinfo
Intel ME Information (from sysfs)
Enabled: true
Firmware Version: 0:18.0.15.2518
Recovery Version: 0:18.0.15.2518
FITC Version: 0:18.0.5.2141
ME Family: CSME 18+
Intel ME Status (SMBIOS Type 0xDB)
Working State: Normal
Operation Mode: Normal
Bootguard:
Enabled: Yes
ACM Active: Yes
ACM Done: Yes
FPF SOC Lock: No
```

Use `-v` for verbose output including raw HFSTS registers and SMBIOS handle information:

```
> sudo framework_tool --meinfo -v
Intel ME Information (from sysfs)
Enabled: true
Firmware Version: 0:18.0.15.2518
Recovery Version: 0:18.0.15.2518
FITC Version: 0:18.0.5.2141
ME Family: CSME 18+
ME Handles (from SMBIOS Type 14):
Handle: 0x002D
Handle: 0x002E
Handle: 0x002F
Handle: 0x0030
Handle: 0x0031
Handle: 0x0032
Handle: 0x0033
Intel ME Status (SMBIOS Type 0xDB)
Working State: Normal
Operation Mode: Normal
Bootguard:
Enabled: Yes
ACM Active: Yes
ACM Done: Yes
FPF SOC Lock: No
HFSTS Registers:
HFSTS1: 0xA0000255
HFSTS2: 0x82108908
HFSTS3: 0x00000030
HFSTS4: 0x00000000
HFSTS5: 0x02F41F03
HFSTS6: 0x00000000
```

## Manually overriding tablet mode status

If you have a suspicion that the embedded controller does not control tablet
Expand Down
6 changes: 5 additions & 1 deletion completions/bash/framework_tool
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ _framework_tool() {

case "${cmd}" in
framework_tool)
opts="-v -q -t -f -h --flash-gpu-descriptor --verbose --quiet --versions --version --features --esrt --device --compare-version --power --thermal --sensors --fansetduty --fansetrpm --autofanctrl --pdports --info --pd-info --pd-reset --pd-disable --pd-enable --dp-hdmi-info --dp-hdmi-update --audio-card-info --privacy --pd-bin --ec-bin --capsule --dump --h2o-capsule --dump-ec-flash --flash-ec --flash-ro-ec --flash-rw-ec --intrusion --inputdeck --inputdeck-mode --expansion-bay --charge-limit --charge-current-limit --charge-rate-limit --get-gpio --fp-led-level --fp-brightness --kblight --remap-key --rgbkbd --ps2-enable --tablet-mode --touchscreen-enable --stylus-battery --console --reboot-ec --ec-hib-delay --uptimeinfo --s0ix-counter --hash --driver --pd-addrs --pd-ports --test --test-retimer --boardid --force --dry-run --flash-gpu-descriptor-file --dump-gpu-descriptor-file --nvidia --generate-completions --help"
opts="-v -q -t -f -h --flash-gpu-descriptor --verbose --quiet --versions --version --features --esrt --device --compare-version --power --thermal --sensors --fansetduty --fansetrpm --autofanctrl --pdports --info --meinfo --pd-info --pd-reset --pd-disable --pd-enable --dp-hdmi-info --dp-hdmi-update --audio-card-info --privacy --pd-bin --ec-bin --capsule --dump --h2o-capsule --dump-ec-flash --flash-ec --flash-ro-ec --flash-rw-ec --intrusion --inputdeck --inputdeck-mode --expansion-bay --charge-limit --charge-current-limit --charge-rate-limit --get-gpio --fp-led-level --fp-brightness --kblight --remap-key --rgbkbd --ps2-enable --tablet-mode --touchscreen-enable --stylus-battery --console --reboot-ec --ec-hib-delay --uptimeinfo --s0ix-counter --hash --driver --pd-addrs --pd-ports --test --test-retimer --boardid --force --dry-run --flash-gpu-descriptor-file --dump-gpu-descriptor-file --nvidia --generate-completions --help"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
Expand Down Expand Up @@ -53,6 +53,10 @@ _framework_tool() {
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--meinfo)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--pd-reset)
COMPREPLY=($(compgen -f "${cur}"))
return 0
Expand Down
1 change: 1 addition & 0 deletions completions/fish/framework_tool.fish
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ complete -c framework_tool -l compare-version -r
complete -c framework_tool -l fansetduty -d 'Set fan duty cycle (0-100%)' -r
complete -c framework_tool -l fansetrpm -d 'Set fan RPM (limited by EC fan table max RPM)' -r
complete -c framework_tool -l autofanctrl -d 'Turn on automatic fan speed control' -r
complete -c framework_tool -l meinfo -d 'Show Intel ME information (from SMBIOS type 0xDB). Optionally provide a dmidecode binary dump file path' -r
complete -c framework_tool -l pd-reset -d 'Reset a specific PD controller (for debugging only)' -r
complete -c framework_tool -l pd-disable -d 'Disable all ports on a specific PD controller (for debugging only)' -r
complete -c framework_tool -l pd-enable -d 'Enable all ports on a specific PD controller (for debugging only)' -r
Expand Down
1 change: 1 addition & 0 deletions completions/zsh/_framework_tool
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ _framework_tool() {
'*--fansetduty=[Set fan duty cycle (0-100%)]::FANSETDUTY:_default' \
'*--fansetrpm=[Set fan RPM (limited by EC fan table max RPM)]::FANSETRPM:_default' \
'--autofanctrl=[Turn on automatic fan speed control]::AUTOFANCTRL:_default' \
'--meinfo=[Show Intel ME information (from SMBIOS type 0xDB). Optionally provide a dmidecode binary dump file path]::MEINFO:_default' \
'--pd-reset=[Reset a specific PD controller (for debugging only)]:PD_RESET:_default' \
'--pd-disable=[Disable all ports on a specific PD controller (for debugging only)]:PD_DISABLE:_default' \
'--pd-enable=[Enable all ports on a specific PD controller (for debugging only)]:PD_ENABLE:_default' \
Expand Down
6 changes: 6 additions & 0 deletions framework_lib/src/commandline/clap_std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ struct ClapCli {
#[arg(long)]
info: bool,

/// Show Intel ME information (from SMBIOS type 0xDB).
/// Optionally provide a dmidecode binary dump file path.
#[arg(long)]
meinfo: Option<Option<String>>,

/// Show details about the PD controllers
#[arg(long)]
pd_info: bool,
Expand Down Expand Up @@ -503,6 +508,7 @@ pub fn parse(args: &[String]) -> Cli {
// UEFI only - every command needs to implement a parameter to enable the pager
paginate: false,
info: args.info,
meinfo: args.meinfo,
flash_gpu_descriptor,
flash_gpu_descriptor_file: args
.flash_gpu_descriptor_file
Expand Down
132 changes: 131 additions & 1 deletion framework_lib/src/commandline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ use crate::chromium_ec::commands::TabletModeOverride;
use crate::chromium_ec::EcResponseStatus;
use crate::chromium_ec::{print_err, EcFlashType};
use crate::chromium_ec::{EcError, EcResult};
#[cfg(target_os = "linux")]
use crate::csme;
use crate::ec_binary;
use crate::esrt::{self, ResourceType};
Expand Down Expand Up @@ -223,6 +222,7 @@ pub struct Cli {
pub pd_ports: Option<(u8, u8, u8)>,
pub help: bool,
pub info: bool,
pub meinfo: Option<Option<String>>,
pub flash_gpu_descriptor: Option<(u8, String)>,
pub flash_gpu_descriptor_file: Option<String>,
pub dump_gpu_descriptor_file: Option<String>,
Expand Down Expand Up @@ -1531,6 +1531,9 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
power::get_and_print_pd_info(&ec);
} else if args.info {
smbios_info();
} else if let Some(dump_path) = &args.meinfo {
let verbose = args.verbosity.0 >= log::LevelFilter::Warn;
me_info(verbose, dump_path.as_deref());
} else if args.pd_info {
print_pd_details(&ec);
} else if let Some(pd) = args.pd_reset {
Expand Down Expand Up @@ -2133,6 +2136,133 @@ fn smbios_info() {
}
}

fn me_info(verbose: bool, dump_path: Option<&str>) {
let smbios = if let Some(path) = dump_path {
#[cfg(feature = "uefi")]
let data: Option<Vec<u8>> = crate::uefi::fs::shell_read_file(path);
#[cfg(not(feature = "uefi"))]
let data = match std::fs::read(path) {
Ok(data) => Some(data),
Err(e) => {
error!("Failed to read SMBIOS dump file '{}': {}", path, e);
None
}
};
data.map(|d| smbioslib::SMBiosData::from_vec_and_version(d, None))
} else {
get_smbios()
};
if smbios.is_none() {
error!("Failed to get SMBIOS data");
return;
}
let smbios = smbios.unwrap();

// Track ME family for bootguard parsing
let mut me_family: Option<csme::MeFamily> = None;

// Try to get ME version from sysfs first (Linux only, live system only)
#[cfg(target_os = "linux")]
if dump_path.is_none() {
if let Ok(csme_info) = csme::csme_from_sysfs() {
println!("Intel ME Information (from sysfs)");
println!(" Enabled: {}", csme_info.enabled);
println!(" Firmware Version: {}", csme_info.main_ver);
if csme_info.main_ver != csme_info.recovery_ver
|| csme_info.main_ver != csme_info.fitc_ver
{
println!(" Recovery Version: {}", csme_info.recovery_ver);
println!(" FITC Version: {}", csme_info.fitc_ver);
}
let family = csme::MeFamily::from_version(csme_info.main_ver.major);
println!(" ME Family: {}", family);
me_family = Some(family);
}
}

// Get ME version from SMBIOS type 0xDD (FVI)
let smbios_version = csme::me_version_from_smbios(&smbios);
if let Some(ref fvi_version) = smbios_version {
// If sysfs wasn't available, use SMBIOS version as primary
if me_family.is_none() {
println!("Intel ME Version (from SMBIOS Type 0xDD)");
println!(" Firmware Version: {}", fvi_version);
let family = csme::MeFamily::from_version(fvi_version.major as u32);
println!(" ME Family: {}", family);
me_family = Some(family);
} else if verbose {
// In verbose mode, also show SMBIOS version for comparison
println!("Intel ME Version (from SMBIOS Type 0xDD)");
println!(" Firmware Version: {}", fvi_version);
}
}

// Show handles found via Type 14 (Group Associations) - verbose only
if verbose {
let me_handles = csme::find_me_handles_from_type14(&smbios);
if !me_handles.is_empty() {
println!("ME Handles (from SMBIOS Type 14):");
for handle in &me_handles {
println!(" Handle: 0x{:04X}", handle);
}
}
}

// Parse SMBIOS type 0xDB for HFSTS registers
if let Some(me_fwsts) = csme::me_fwsts_from_smbios(&smbios) {
println!("Intel ME Status (SMBIOS Type 0xDB)");

if let Some(record) = me_fwsts.mei1() {
println!(" Working State: {}", record.hfsts.working_state());
println!(" Operation Mode: {}", record.hfsts.operation_mode());

// Parse bootguard status if we know the ME family
if let Some(family) = me_family {
if let Some(bootguard) = me_fwsts.bootguard_status(family) {
println!(" Bootguard:");
println!(
" Enabled: {}",
if bootguard.enabled { "Yes" } else { "No" }
);
if let Some(verified) = bootguard.verified_boot {
println!(
" Verified Boot: {}",
if verified { "Yes" } else { "No" }
);
}
println!(
" ACM Active: {}",
if bootguard.acm_active { "Yes" } else { "No" }
);
if let Some(done) = bootguard.acm_done {
println!(" ACM Done: {}", if done { "Yes" } else { "No" });
}
if let Some(ref policy) = bootguard.policy {
println!(" Policy: {}", policy);
}
println!(
" FPF SOC Lock: {}",
if bootguard.fpf_soc_lock { "Yes" } else { "No" }
);
}
}

// Show raw HFSTS registers - verbose only
if verbose {
println!(" HFSTS Registers:");
println!(" HFSTS1: 0x{:08X}", record.hfsts.hfsts1);
println!(" HFSTS2: 0x{:08X}", record.hfsts.hfsts2);
println!(" HFSTS3: 0x{:08X}", record.hfsts.hfsts3);
println!(" HFSTS4: 0x{:08X}", record.hfsts.hfsts4);
println!(" HFSTS5: 0x{:08X}", record.hfsts.hfsts5);
println!(" HFSTS6: 0x{:08X}", record.hfsts.hfsts6);
}
}
} else {
error!("No Intel ME FWSTS table found in SMBIOS (type 0xDB)");
}
}

fn analyze_ccgx_pd_fw(data: &[u8]) {
if let Some(versions) = ccgx::binary::read_versions(data, Ccg3) {
println!("Detected CCG3 firmware");
Expand Down
8 changes: 8 additions & 0 deletions framework_lib/src/commandline/uefi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ pub fn parse(args: &[String]) -> Cli {
dump_gpu_descriptor_file: None,
allupdate: false,
info: false,
meinfo: None,
nvidia: false,
raw_command: vec![],
};
Expand Down Expand Up @@ -223,6 +224,13 @@ pub fn parse(args: &[String]) -> Cli {
} else if arg == "--info" {
cli.info = true;
found_an_option = true;
} else if arg == "--meinfo" {
cli.meinfo = if args.len() > i + 1 {
Some(Some(args[i + 1].clone()))
} else {
Some(None)
};
found_an_option = true;
} else if arg == "--intrusion" {
cli.intrusion = true;
found_an_option = true;
Expand Down
Loading