| // Copyright 2022 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| use std::path::PathBuf; | |
| use log::info; | |
| use crate::context::Context; | |
| use crate::error::HwsecError; | |
| use crate::gsc::extract_board_id_from_gsctool_response; | |
| use crate::gsc::run_gsctool_cmd; | |
| use crate::gsc::GSCTOOL_CMD_NAME; | |
| use crate::gsc::GSC_IMAGE_BASE_NAME; | |
| use crate::tpm2::ERASED_BOARD_ID; | |
| pub fn gsc_get_name( | |
| ctx: &mut impl Context, | |
| gsctool_command_options: &[&str], | |
| ) -> Result<PathBuf, HwsecError> { | |
| const PRE_PVT_FLAG: u32 = 0x10; | |
| info!("updater is {}", GSCTOOL_CMD_NAME); | |
| let exe_result = run_gsctool_cmd(ctx, [gsctool_command_options, &["--board_id"]].concat())?; | |
| let exit_status = exe_result.status.code().unwrap(); | |
| let output = format!( | |
| "{}{}", | |
| std::str::from_utf8(&exe_result.stdout) | |
| .map_err(|_| HwsecError::Tpm2ResponseBadFormatError)?, | |
| std::str::from_utf8(&exe_result.stderr) | |
| .map_err(|_| HwsecError::Tpm2ResponseBadFormatError)? | |
| ); | |
| let mut ext = "prod"; | |
| let board_id = extract_board_id_from_gsctool_response(&output)?; | |
| let board_flags = format!("0x{:02x}", board_id.flag); | |
| if exit_status != 0 { | |
| info!("exit status: {}", exit_status); | |
| info!("output: {}", output); | |
| } else if board_id == ERASED_BOARD_ID { | |
| info!("board ID is erased using {} image", ext); | |
| } else if board_id.flag & PRE_PVT_FLAG != 0 { | |
| ext = "prepvt"; | |
| } | |
| info!( | |
| r"board_id: '{:02x}:{:02x}:{:02x}' board_flags: '{}', extension: '{}'", | |
| board_id.part_1, board_id.part_2, board_id.flag, board_flags, ext | |
| ); | |
| Ok(PathBuf::from(format!("{}.{}", GSC_IMAGE_BASE_NAME, ext))) | |
| } | |
| #[cfg(test)] | |
| mod tests { | |
| use super::*; | |
| use crate::context::mock::MockContext; | |
| use crate::gsc::GSC_IMAGE_BASE_NAME; | |
| #[test] | |
| fn test_gsc_get_name() { | |
| let mut mock_ctx = MockContext::new(); | |
| mock_ctx.cmd_runner().add_gsctool_interaction( | |
| vec!["--any", "--board_id"], | |
| 0, | |
| "finding_device 18d1:5014\n\ | |
| Found device.\n\ | |
| found interface 3 endpoint 4, chunk_len 64\n\ | |
| READY\n\ | |
| -------\n\ | |
| Board ID space: 43425559:bcbdaaa6:00007f80\n", | |
| "", | |
| ); | |
| let name = gsc_get_name(&mut mock_ctx, &["--any"]); | |
| assert_eq!( | |
| name, | |
| Ok(PathBuf::from(String::from(GSC_IMAGE_BASE_NAME) + ".prod")) | |
| ); | |
| } | |
| #[test] | |
| fn test_gsc_get_name_board_id_not_found() { | |
| let mut mock_ctx = MockContext::new(); | |
| mock_ctx.cmd_runner().add_gsctool_interaction( | |
| vec!["--any", "--board_id"], | |
| 0, | |
| "finding_device 18d1:5014\n\ | |
| Found device.\n\ | |
| found interface 3 endpoint 4, chunk_len 64\n\ | |
| READY\n\ | |
| -------\n\ | |
| Board ID space: 43425559:bxbdaaa6:00007f80\n", | |
| "", | |
| ); | |
| let name = gsc_get_name(&mut mock_ctx, &["--any"]); | |
| assert_eq!(name, Err(HwsecError::GsctoolResponseBadFormatError)); | |
| } | |
| #[test] | |
| fn test_gsc_get_name_different_ext() { | |
| let mut mock_ctx = MockContext::new(); | |
| mock_ctx.cmd_runner().add_gsctool_interaction( | |
| vec!["--any", "--board_id"], | |
| 0, | |
| "finding_device 18d1:5014\n\ | |
| Found device.\n\ | |
| found interface 3 endpoint 4, chunk_len 64\n\ | |
| READY\n\ | |
| -------\n\ | |
| Board ID space: 43425559:bcbdaaa6:00007f10\n", | |
| "", | |
| ); | |
| let name = gsc_get_name(&mut mock_ctx, &["--any"]); | |
| assert_eq!( | |
| name, | |
| Ok(PathBuf::from(String::from(GSC_IMAGE_BASE_NAME) + ".prepvt")) | |
| ); | |
| } | |
| } |