Skip to content

Commit

Permalink
[sw/silicon_creator] Add structured kChipInfo to ROM
Browse files Browse the repository at this point in the history
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: 633e 05dd e3fe 72cd 0000 0000 3230 3233  c>....r.....2023
    00007f90: 2d30 342d 3235 2031 353a 3133 3a32 3900  -04-25 15:13:29.

Issue #14892
Signed-off-by: Dan McArdle <dmcardle@opentitan.org>
  • Loading branch information
dmcardle committed Apr 25, 2023
1 parent 880e7e7 commit 910d28c
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 36 deletions.
41 changes: 29 additions & 12 deletions rules/autogen.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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.
Expand Down
7 changes: 1 addition & 6 deletions sw/device/lib/testing/test_rom/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
5 changes: 3 additions & 2 deletions sw/device/lib/testing/test_rom/test_rom.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions sw/device/silicon_creator/lib/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down Expand Up @@ -272,6 +273,8 @@ filegroup(
],
)

autogen_chip_info(name = "chip_info")

dual_cc_library(
name = "shutdown",
srcs = dual_inputs(
Expand All @@ -289,6 +292,7 @@ dual_cc_library(
"@googletest//:gtest",
],
shared = [
":chip_info",
":error",
":epmp_defs",
"//sw/device/lib/base:hardened",
Expand Down
28 changes: 28 additions & 0 deletions sw/device/silicon_creator/lib/chip_info.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// 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 <assert.h>
#include <stdint.h>

typedef struct chip_info {
uint64_t scm_revision;
// This field should be set to lc_ctrl.HW_REV's reset value, a compile-time
// constant that identifies the hardware revision.
uint32_t hw_rev;
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")));

// Track the size of `kChipInfo` so we can compute how much space is left in the
// `.chip_info` section. If it becomes too large, linking will fail.
static_assert(sizeof(kChipInfo) == 32, "Size of kChipInfo has changed.");

#endif // OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_CHIP_INFO_H_
8 changes: 7 additions & 1 deletion sw/device/silicon_creator/lib/shutdown.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions sw/device/silicon_creator/lib/shutdown.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down
7 changes: 7 additions & 0 deletions util/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
Expand Down
47 changes: 32 additions & 15 deletions util/rom_chip_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,39 @@
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"))) = {{
.scm_revision = {scm_revision:#0x},
.hw_rev = (uint64_t)LC_CTRL_HW_REV_REG_RESVAL,
.build_date_str = "{wall_time}",
}};
"""


Expand Down Expand Up @@ -57,24 +75,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__":
Expand Down

0 comments on commit 910d28c

Please sign in to comment.