Skip to content

Commit

Permalink
Create an all zeros fw image
Browse files Browse the repository at this point in the history
Creates an image bundle with FMC and Runtime populated with zeros. 0 is
an ilegal opcode in risc-v, so the image will immediately NMI.

This is useful for testing production signing infrastructure. A
production key can be used to sign this image before an official
release is ready. The prod-signed zeros binary is benign but can
be used to ensure that the prod key was loaded into fuses correctly.
  • Loading branch information
jhand2 committed Jan 15, 2025
1 parent 6f0a823 commit def0910
Show file tree
Hide file tree
Showing 11 changed files with 233 additions and 13 deletions.
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ members = [
"test",
"test-harness",
"test-harness/types",
"zero_bin",
]

[workspace.dependencies]
Expand Down
42 changes: 29 additions & 13 deletions builder/bin/image_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ fn main() {
.arg(arg!(--"fake-fw" [FILE] "Fake FW bundle image").value_parser(value_parser!(PathBuf)))
.arg(
arg!(--"hashes" [FILE] "File path for output JSON file containing image bundle header hashes for external signing tools")
.value_parser(value_parser!(PathBuf)),
.value_parser(value_parser!(PathBuf))
)
.arg(arg!(--"zeros" "Build an image bundle with zero'd FMC and RT. This will NMI immediately."))
.get_matches();

if let Some(path) = args.get_one::<PathBuf>("rom-no-log") {
Expand Down Expand Up @@ -72,18 +73,33 @@ fn main() {

if let Some(path) = args.get_one::<PathBuf>("fw") {
// Generate Image Bundle
let image = caliptra_builder::build_and_sign_image(
&firmware::FMC_WITH_UART,
&firmware::APP_WITH_UART,
ImageOptions {
fmc_version: version::get_fmc_version(),
app_version: version::get_runtime_version(),
fmc_svn,
app_svn,
..Default::default()
},
)
.unwrap();
let image = if args.contains_id("zeros") {
caliptra_builder::build_and_sign_image(
&firmware::FMC_ZEROS,
&firmware::APP_ZEROS,
ImageOptions {
fmc_version: 0,
app_version: 0,
fmc_svn: 0,
app_svn: 0,
..Default::default()
},
)
.unwrap()
} else {
caliptra_builder::build_and_sign_image(
&firmware::FMC_WITH_UART,
&firmware::APP_WITH_UART,
ImageOptions {
fmc_version: version::get_fmc_version(),
app_version: version::get_runtime_version(),
fmc_svn,
app_svn,
..Default::default()
},
)
.unwrap()
};

let contents = image.to_bytes().unwrap();
std::fs::write(path, contents.clone()).unwrap();
Expand Down
14 changes: 14 additions & 0 deletions builder/src/firmware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,18 @@ pub const APP_WITH_UART_FPGA: FwId = FwId {
features: &["emu", "fips_self_test", "fpga_realtime"],
};

pub const APP_ZEROS: FwId = FwId {
crate_name: "caliptra-zeros",
bin_name: "caliptra-zeros",
features: &[],
};

pub const FMC_ZEROS: FwId = FwId {
crate_name: "caliptra-zeros",
bin_name: "caliptra-zeros",
features: &["fmc"],
};

pub mod caliptra_builder_tests {
use super::*;

Expand Down Expand Up @@ -387,6 +399,8 @@ pub const REGISTERED_FW: &[&FwId] = &[
&APP_WITH_UART,
&APP_WITH_UART_FIPS_TEST_HOOKS,
&APP_WITH_UART_FPGA,
&APP_ZEROS,
&FMC_ZEROS,
&caliptra_builder_tests::FWID,
&hw_model_tests::MAILBOX_RESPONDER,
&hw_model_tests::MAILBOX_SENDER,
Expand Down
30 changes: 30 additions & 0 deletions libcaliptra/src/caliptra_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,36 @@ bool caliptra_ready_for_firmware(void)
return true;
}

/**
* caliptra_ready_for_runtime
*
* Waits until Caliptra hardware is ready for runtime commands or until
* Caliptra reports an error
*
* @return int 0 if ready, Caliptra error otherwise
*/
uint32_t caliptra_ready_for_runtime(void)
{
uint32_t status;
bool ready = false;

do
{
status = caliptra_read_status();

if ((status & GENERIC_AND_FUSE_REG_CPTRA_FLOW_STATUS_READY_FOR_FW_MASK) == GENERIC_AND_FUSE_REG_CPTRA_FLOW_STATUS_READY_FOR_FW_MASK)
{
ready = true;
}
else
{
caliptra_wait();
}
} while (ready == false);

return true;
}

/*
* caliptra_is_csr_ready
*
Expand Down
23 changes: 23 additions & 0 deletions zero_bin/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Licensed under the Apache-2.0 license

[package]
name = "caliptra-zeros"
version = "0.1.0"
edition = "2021"

[build-dependencies]
caliptra_common = { workspace = true, default-features = false }
caliptra-gen-linker-scripts.workspace = true
cfg-if.workspace = true

[dev-dependencies]
caliptra-api.workspace = true
caliptra-builder.workspace = true
caliptra-error.workspace = true
caliptra-hw-model.workspace = true

[features]
default = ["std"]
std = ["caliptra_common/std"]
riscv = []
fmc = []
37 changes: 37 additions & 0 deletions zero_bin/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
fn main() {
cfg_if::cfg_if! {
if #[cfg(not(feature = "std"))] {
use std::env;
use std::fs;
use std::path::PathBuf;
use caliptra_gen_linker_scripts::gen_memory_x;

let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());

cfg_if::cfg_if! {
if #[cfg(feature = "fmc")] {
fs::write(out_dir.join("memory.x"),gen_memory_x(caliptra_common::FMC_ORG, caliptra_common::FMC_SIZE)
.as_bytes())
.expect("Unable to generate memory.x");
} else {
fs::write(out_dir.join("memory.x"),gen_memory_x(caliptra_common::RUNTIME_ORG, caliptra_common::RUNTIME_SIZE)
.as_bytes())
.expect("Unable to generate memory.x");
}
}

fs::write(out_dir.join("link.x"), include_bytes!("src/link.x")).unwrap();

let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());

println!("cargo:rustc-link-search={}", out_dir.display());

println!("cargo:rerun-if-changed=memory.x");
println!("cargo:rustc-link-arg=-Tmemory.x");

println!("cargo:rerun-if-changed=link.x");
println!("cargo:rustc-link-arg=-Tlink.x");
println!("cargo:rerun-if-changed=build.rs");
}
}
}
14 changes: 14 additions & 0 deletions zero_bin/src/link.x
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
SECTIONS
{
.text : ALIGN(4)
{
_stext = .;

KEEP(*(.init .init.*));
*(.text .text.*);
KEEP(*(.vectors))

. = ALIGN(4);
_etext = .;
} > REGION_TEXT
}
15 changes: 15 additions & 0 deletions zero_bin/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(not(feature = "std"), no_main)]

#[cfg(target_arch = "riscv32")]
core::arch::global_asm!(include_str!("zeros.S"));

#[cfg(feature = "std")]
pub fn main() {}

// Should not be linked
#[cfg(not(feature = "std"))]
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}
19 changes: 19 additions & 0 deletions zero_bin/src/zeros.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.section .init.text, "ax"
.global _start
_start:
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
38 changes: 38 additions & 0 deletions zero_bin/tests/test_zeros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Licensed under the Apache-2.0 license

use caliptra_api::soc_mgr::SocManager;
use caliptra_builder::{
firmware::{APP_ZEROS, FMC_ZEROS},
ImageOptions,
};
use caliptra_error::CaliptraError;
use caliptra_hw_model::{BootParams, HwModel, InitParams};

#[test]
fn test_zeros() {
let rom = caliptra_builder::rom_for_fw_integration_tests().unwrap();
let init_params = InitParams {
rom: &rom,
..Default::default()
};

let image =
caliptra_builder::build_and_sign_image(&FMC_ZEROS, &APP_ZEROS, ImageOptions::default())
.unwrap();

let mut model = caliptra_hw_model::new(
init_params,
BootParams {
fw_image: Some(&image.to_bytes().unwrap()),
..Default::default()
},
)
.unwrap();

// 0 is an ilegal instruction in risc-v. Image should immediately NMI.
model.step_until(|m| m.soc_ifc().cptra_fw_error_fatal().read() != 0);
assert_eq!(
model.soc_ifc().cptra_fw_error_fatal().read(),
u32::from(CaliptraError::ROM_GLOBAL_EXCEPTION)
);
}

0 comments on commit def0910

Please sign in to comment.