From d123df0b29eaae5735fd5763290fa787b5d46c0b Mon Sep 17 00:00:00 2001 From: Dan McArdle Date: Thu, 20 Apr 2023 16:23:37 -0400 Subject: [PATCH] [sw/silicon_creator] Add structured kChipInfo to ROM This commit adds a new `chip_info_t` struct that contains info about the ROM's provenance. The ROM now prints the Git commit hash on shutdown after the "VER:" prefix. The ROM linker script was already configured to place the .chip_info section at the top of ROM, but I'm not confident that it worked as expected. The autogenerated header contained a static constant, so I think a copy would be inlined at some arbitrary location into any compilation unit that used it, rather than being placed by the linker script. To verify that the ROM prints the Git commit hash on shutdown: ./bazelisk.sh test --test_output=streamed \ //sw/device/silicon_creator/rom/e2e:shutdown_output_dev_fpga_cw310_rom To verify that the .chip_info section contains data from chip_info.o: ./bazelisk.sh build-then 'less %s' --config riscv32 \ //sw/device/silicon_creator/rom:rom_with_fake_keys_fpga_cw310_map To see the value of `kChipInfo` at the end of ROM: ./bazelisk.sh build-then 'xxd %s | less' --config riscv32 \ //sw/device/silicon_creator/rom:rom_with_fake_keys_fpga_cw310_bin For example, here's the end of the ROM from the previous command. Note that it contains 32 bits of a git commit hash starting at 0x7f80, followed by a human-readable timestamp. ... 00007f70: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00007f80: e3fe 72cd 3230 3233 2d30 342d 3230 2031 ..r.2023-04-20 1 00007f90: 363a 3533 3a34 3800 6:53:48. Issue #14892 Signed-off-by: Dan McArdle --- rules/autogen.bzl | 41 +++++++++++++------ sw/device/lib/testing/test_rom/BUILD | 7 +--- sw/device/lib/testing/test_rom/test_rom.c | 5 ++- sw/device/silicon_creator/lib/BUILD | 4 ++ sw/device/silicon_creator/lib/chip_info.h | 26 ++++++++++++ sw/device/silicon_creator/lib/shutdown.c | 8 +++- sw/device/silicon_creator/lib/shutdown.h | 1 + util/BUILD | 7 ++++ util/rom_chip_info.py | 49 ++++++++++++++++------- 9 files changed, 112 insertions(+), 36 deletions(-) create mode 100644 sw/device/silicon_creator/lib/chip_info.h diff --git a/rules/autogen.bzl b/rules/autogen.bzl index 2ada4eefd1ec6..0bcf2644cb8ad 100644 --- a/rules/autogen.bzl +++ b/rules/autogen.bzl @@ -65,35 +65,34 @@ autogen_hjson_header = rule( }, ) -def _chip_info(ctx): - header = ctx.actions.declare_file("chip_info.h") +def _chip_info_src(ctx): + out_source = ctx.actions.declare_file("chip_info.c") ctx.actions.run( - outputs = [header], + outputs = [ + out_source, + ], inputs = [ ctx.file.version, ctx.executable._tool, ], arguments = [ "-o", - header.dirname, + out_source.dirname, "--ot_version_file", ctx.file.version.path, ], executable = ctx.executable._tool, ) + return [ - CcInfo(compilation_context = cc_common.create_compilation_context( - includes = depset([header.dirname]), - headers = depset([header]), - )), - DefaultInfo(files = depset([header])), + DefaultInfo(files = depset([out_source])), ] -autogen_chip_info = rule( - implementation = _chip_info, +autogen_chip_info_src = rule( + implementation = _chip_info_src, attrs = { "version": attr.label( - default = "//util:ot_version_file", + default = "//util:scm_revision_file", allow_single_file = True, ), "_tool": attr.label( @@ -104,6 +103,24 @@ autogen_chip_info = rule( }, ) +def autogen_chip_info(name): + """Generates a cc_library named `name` that defines chip info.""" + + # Generate a C source file that defines the chip info struct. This is an + # implementation detail and should not be depended on externally. + chip_info_src_target = name + "_gen_src" + autogen_chip_info_src(name = chip_info_src_target) + + # Package up the generated source file with its corresponding header file + # and dependencies. Any target that wants access to the chip info should + # depend on this. + native.cc_library( + name = name, + srcs = [chip_info_src_target], + hdrs = ["//sw/device/silicon_creator/lib:chip_info.h"], + deps = ["//hw/ip/lc_ctrl/data:lc_ctrl_regs"], + ) + def _cryptotest_hjson_external(ctx): """ Implementation of the Bazel rule for parsing externally-sourced test vectors. diff --git a/sw/device/lib/testing/test_rom/BUILD b/sw/device/lib/testing/test_rom/BUILD index 09cc886f049a0..b14041763c72d 100644 --- a/sw/device/lib/testing/test_rom/BUILD +++ b/sw/device/lib/testing/test_rom/BUILD @@ -5,16 +5,11 @@ load("//rules:opentitan.bzl", "OPENTITAN_CPU", "opentitan_rom_binary") load("//rules:opentitan_test.bzl", "opentitan_functest") load("//rules:exclude_files.bzl", "exclude_files") -load("//rules:autogen.bzl", "autogen_chip_info") load("//rules:linker.bzl", "ld_library") load("@rules_pkg//pkg:mappings.bzl", "pkg_files") package(default_visibility = ["//visibility:public"]) -autogen_chip_info( - name = "chip_info", -) - ld_library( name = "linker_script", script = "test_rom.ld", @@ -120,7 +115,6 @@ cc_library( ], target_compatible_with = [OPENTITAN_CPU], deps = [ - ":chip_info", ":target_test_rom_lib", ":test_rom_manifest", "//hw/ip/csrng/data:csrng_regs", @@ -153,6 +147,7 @@ cc_library( "//sw/device/lib/testing:pinmux_testutils", "//sw/device/lib/testing/test_framework:check", "//sw/device/lib/testing/test_framework:status", + "//sw/device/silicon_creator/lib:chip_info", "//sw/device/silicon_creator/lib/base:sec_mmio", "//sw/device/silicon_creator/lib/base:static_critical_boot_measurements", "//sw/device/silicon_creator/lib/base:static_critical_epmp_state", diff --git a/sw/device/lib/testing/test_rom/test_rom.c b/sw/device/lib/testing/test_rom/test_rom.c index cbb9fbf7d68b2..12a45ab5cb10b 100644 --- a/sw/device/lib/testing/test_rom/test_rom.c +++ b/sw/device/lib/testing/test_rom/test_rom.c @@ -22,8 +22,8 @@ #include "sw/device/lib/testing/pinmux_testutils.h" #include "sw/device/lib/testing/test_framework/check.h" #include "sw/device/lib/testing/test_framework/status.h" -#include "sw/device/lib/testing/test_rom/chip_info.h" // Generated. #include "sw/device/silicon_creator/lib/base/sec_mmio.h" +#include "sw/device/silicon_creator/lib/chip_info.h" // Generated. #include "sw/device/silicon_creator/lib/drivers/flash_ctrl.h" #include "sw/device/silicon_creator/lib/drivers/retention_sram.h" #include "sw/device/silicon_creator/lib/manifest.h" @@ -152,7 +152,8 @@ bool rom_test_main(void) { } // Print the chip version information - LOG_INFO("%s", chip_info); + LOG_INFO("kChipInfo: scm_revision=%x, build_date_str=%s", + kChipInfo.scm_revision, kChipInfo.build_date_str); // Skip sram_init for test_rom dif_rstmgr_reset_info_bitfield_t reset_reasons; diff --git a/sw/device/silicon_creator/lib/BUILD b/sw/device/silicon_creator/lib/BUILD index 518e43a5555a7..078859116c6cc 100644 --- a/sw/device/silicon_creator/lib/BUILD +++ b/sw/device/silicon_creator/lib/BUILD @@ -3,6 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 load("//rules:opentitan.bzl", "OPENTITAN_CPU") +load("//rules:autogen.bzl", "autogen_chip_info") load("//rules:opentitan_test.bzl", "cw310_params", "opentitan_functest", "verilator_params") load("//rules:cross_platform.bzl", "dual_cc_device_library_of", "dual_cc_library", "dual_inputs") @@ -272,6 +273,8 @@ filegroup( ], ) +autogen_chip_info(name = "chip_info") + dual_cc_library( name = "shutdown", srcs = dual_inputs( @@ -289,6 +292,7 @@ dual_cc_library( "@googletest//:gtest", ], shared = [ + ":chip_info", ":error", ":epmp_defs", "//sw/device/lib/base:hardened", diff --git a/sw/device/silicon_creator/lib/chip_info.h b/sw/device/silicon_creator/lib/chip_info.h new file mode 100644 index 0000000000000..fa8d566b13e04 --- /dev/null +++ b/sw/device/silicon_creator/lib/chip_info.h @@ -0,0 +1,26 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#ifndef OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_CHIP_INFO_H_ +#define OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_CHIP_INFO_H_ + +#include +#include + +typedef struct chip_info { + uint32_t hw_rev; + uint64_t scm_revision; + char build_date_str[20]; +} chip_info_t; + +// This struct contains information about the ROM's provenance, and critically, +// it can be manually decoded from a hexdump. The linker script should place +// this at the top of the ROM. +extern const chip_info_t kChipInfo __attribute__((section(".chip_info"))); + +// Set an arbitrary upper bound on the size of `kChipInfo` to prevent future +// additions from wasting space in the ROM. +static_assert(sizeof(kChipInfo) <= 64u, "Size of kChipInfo exceeds budget."); + +#endif // OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_CHIP_INFO_H_ diff --git a/sw/device/silicon_creator/lib/shutdown.c b/sw/device/silicon_creator/lib/shutdown.c index c5a77ae4416bd..f3dbb7f827a4c 100644 --- a/sw/device/silicon_creator/lib/shutdown.c +++ b/sw/device/silicon_creator/lib/shutdown.c @@ -15,6 +15,7 @@ #include "sw/device/lib/base/memory.h" #include "sw/device/lib/base/multibits.h" #include "sw/device/lib/base/stdasm.h" +#include "sw/device/silicon_creator/lib/chip_info.h" // Generated. #include "sw/device/silicon_creator/lib/drivers/alert.h" #include "sw/device/silicon_creator/lib/drivers/lifecycle.h" #include "sw/device/silicon_creator/lib/drivers/otp.h" @@ -379,14 +380,19 @@ SHUTDOWN_FUNC(NO_MODIFIERS, shutdown_report_error(rom_error_t reason)) { uart_ctrl_reg = bitfield_bit32_write(uart_ctrl_reg, UART_CTRL_TX_BIT, true); abs_mmio_write32(kUartBase + UART_CTRL_REG_OFFSET, uart_ctrl_reg); + // Extract the commit hash from the `chip_info` at the top of ROM. + uint64_t chip_info_version = kChipInfo.scm_revision; + uint32_t chip_info_version_truncated = chip_info_version >> 32; + // Print the error message and the raw life cycle state as reported by the // hardware. shutdown_print(kShutdownLogPrefixBootFault, redacted_error); shutdown_print(kShutdownLogPrefixLifecycle, raw_state); + shutdown_print(kShutdownLogPrefixVersion, chip_info_version_truncated); #ifdef OT_PLATFORM_RV32 // Wait until UART TX is complete. - static_assert(2 * kErrorMsgLen <= kUartFifoSize, + static_assert(3 * kErrorMsgLen <= kUartFifoSize, "Total message length must be less than TX FIFO size."); CSR_WRITE(CSR_REG_MCYCLE, 0); uint32_t mcycle; diff --git a/sw/device/silicon_creator/lib/shutdown.h b/sw/device/silicon_creator/lib/shutdown.h index ab8ee4452026c..8e5d33e5c5474 100644 --- a/sw/device/silicon_creator/lib/shutdown.h +++ b/sw/device/silicon_creator/lib/shutdown.h @@ -87,6 +87,7 @@ typedef enum shutdown_error_redact { typedef enum shutdown_log_prefix { kShutdownLogPrefixBootFault = LOG_PREFIX_('B', 'F', 'V'), kShutdownLogPrefixLifecycle = LOG_PREFIX_('L', 'C', 'V'), + kShutdownLogPrefixVersion = LOG_PREFIX_('V', 'E', 'R'), } shutdown_log_prefix_t; /** diff --git a/util/BUILD b/util/BUILD index 606c2c7a555ed..794bda24cf857 100644 --- a/util/BUILD +++ b/util/BUILD @@ -16,6 +16,13 @@ genrule( stamp = 1, # this provides volatile-status.txt ) +genrule( + name = "scm_revision_file", + outs = ["scm_revision.txt"], + cmd = """awk '/BUILD_SCM_REVISION/ { print $$2 }' bazel-out/volatile-status.txt > $@""", + stamp = 1, # this provides volatile-status.txt +) + genrule( name = "full_version_file", outs = ["full_version.txt"], diff --git a/util/rom_chip_info.py b/util/rom_chip_info.py index baa1b69111cb0..55199ccbe1e94 100755 --- a/util/rom_chip_info.py +++ b/util/rom_chip_info.py @@ -11,21 +11,41 @@ from datetime import datetime from pathlib import Path -header_template = r""" + +def generate_chip_info_c_source(scm_revision: int, wall_time: str) -> str: + """Return the contents of a C source file that defines `kChipInfo`. + + Args: + scm_revision: SHA1 sum identifying the current SCM revision. + wall_time: A human-readable string containing the build timestamp. + """ + + SHA1_SUM_SIZE_BYTES = 20 + SHA1_SUM_SIZE_BITS = SHA1_SUM_SIZE_BYTES * 8 + + assert scm_revision.bit_length() <= SHA1_SUM_SIZE_BITS + + # Truncate the SCM revision to the top N bits. + SCM_REVISION_SIZE_BITS = 64 + scm_revision = scm_revision >> (SHA1_SUM_SIZE_BITS - SCM_REVISION_SIZE_BITS) + + return f""" // Copyright lowRISC contributors. // Licensed under the Apache License, Version 2.0, see LICENSE for details. // SPDX-License-Identifier: Apache-2.0 // // --------- W A R N I N G: A U T O - G E N E R A T E D C O D E !! ---------// -#ifndef _F_CHIPINFO_H__ -#define _F_CHIPINFO_H__ - -static const char chip_info[128] __attribute__((section(".chip_info"))) = - "Version: {%version%}, Build Date: {%build_date%}"; - -#endif // _F_CHIPINFO_H__ +#include "sw/device/silicon_creator/lib/chip_info.h" +#include "hw/ip/lc_ctrl/data/lc_ctrl_regs.h" +const chip_info_t kChipInfo __attribute__((section(".chip_info"))) = {{ + // Use lc_ctrl.HW_REV's reset value, a compile-time constant that identifies + // the hardware revision. + .hw_rev = (uint64_t)LC_CTRL_HW_REV_REG_RESVAL, + .scm_revision = {scm_revision:#0x}, + .build_date_str = "{wall_time}", +}}; """ @@ -57,24 +77,23 @@ def main(): log.error( "Missing ot_version, provide --ot_version or --ot_version_file.") raise SystemExit(sys.exc_info()[1]) + version = int(version, base=16) outdir = Path(args.outdir) outdir.mkdir(parents=True, exist_ok=True) - out_path = outdir / "chip_info.h" + source_out_path = outdir / "chip_info.c" now = datetime.now() wall_time = now.strftime("%Y-%m-%d %H:%M:%S") - log.info("Version: %s" % (version, )) + log.info("Version: %x" % (version, )) log.info("Build Date: %s" % (wall_time, )) - output = header_template - output = output.replace('{%version%}', version, 1) - output = output.replace('{%build_date%}', wall_time, 1) + output = generate_chip_info_c_source(version, wall_time) - with out_path.open(mode='w', encoding='UTF-8') as fout: - fout.write(output + "\n") + with source_out_path.open(mode='w', encoding='UTF-8') as fout: + fout.write(output) if __name__ == "__main__":