| // Copyright 2024 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #![cfg_attr(target_os = "uefi", no_main)] |
| #![cfg_attr(target_os = "uefi", no_std)] |
| |
| extern crate alloc; |
| |
| mod launch; |
| mod operation; |
| mod tpm_v1; |
| |
| use core::mem; |
| use core::sync::atomic::{AtomicU32, Ordering}; |
| use log::info; |
| use operation::Operation; |
| use uefi::table::boot::BootServices; |
| use uefi::table::{Boot, SystemTable}; |
| use uefi::{cstr16, entry, fs, Handle, Status}; |
| |
| #[cfg(not(target_os = "uefi"))] |
| use libcrdy::uefi_services; |
| |
| static OPERATION: AtomicU32 = AtomicU32::new(Operation::Unset as u32); |
| |
| impl Operation { |
| /// Read the operation from a file on the ESP. |
| /// |
| /// Panics if the file can't be read, or if the contents are |
| /// invalid. |
| /// |
| /// The operation is stored in the global `OPERATION`. |
| fn init(boot_services: &BootServices) { |
| let sfs = boot_services |
| .get_image_file_system(boot_services.image_handle()) |
| .expect("failed to open SimpleFileSystem"); |
| let mut fs = fs::FileSystem::new(sfs); |
| |
| let content = fs |
| .read_to_string(cstr16!(r"\efi\boot\crdy_test_control")) |
| .expect("failed to read control file"); |
| let content = content.trim(); |
| |
| let op: Operation = match content.parse() { |
| Ok(op) => op, |
| Err(_) => panic!("invalid control file: {content}"), |
| }; |
| |
| info!("operation: {op}"); |
| |
| OPERATION.store(op as u32, Ordering::Release); |
| } |
| |
| /// Load the operation from the global `OPERATION`. |
| fn get() -> Self { |
| let op: u32 = OPERATION.load(Ordering::Acquire); |
| // SAFETY: `Operation` is a `u32`, so the underlying |
| // representation matches. The value of `OPERATION` is only |
| // written by `Operation::init`, which always writes a valid |
| // variant of `Operation`. |
| unsafe { mem::transmute(op) } |
| } |
| } |
| |
| #[entry] |
| fn efi_main(image: Handle, mut st: SystemTable<Boot>) -> Status { |
| uefi_services::init(&mut st).expect("failed to initialize uefi_services"); |
| |
| Operation::init(st.boot_services()); |
| |
| match Operation::get() { |
| Operation::Unset => unreachable!(), |
| Operation::Tpm1Deactivated | Operation::Tpm1ExtendFail => { |
| tpm_v1::create_tpm1(st.boot_services()) |
| } |
| } |
| |
| launch::launch_crdyshim(st.boot_services()); |
| |
| Status::SUCCESS |
| } |