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. At
0x7f80, there are 64 bits of a Git commit hash (e20871e1cf102bf6).

    00007f70: 0000 0000 0000 0000 0000 0000 0000 0000  ................
    00007f80: f62b 10cf e171 08e2                      .+...q..

Issue #14892
Signed-off-by: Dan McArdle <dmcardle@opentitan.org>
  • Loading branch information
dmcardle committed May 1, 2023
1 parent 54ab27b commit 2ecf53b
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 42 deletions.
43 changes: 31 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,26 @@ 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 = [
"//sw/device/lib/base:macros",
],
)

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
4 changes: 2 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"
#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,7 @@ bool rom_test_main(void) {
}

// Print the chip version information
LOG_INFO("%s", chip_info);
LOG_INFO("kChipInfo: scm_revision=%x", kChipInfo.scm_revision);

// 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
27 changes: 27 additions & 0 deletions sw/device/silicon_creator/lib/chip_info.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 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 <stdint.h>

#include "sw/device/lib/base/macros.h"

typedef struct chip_info {
// A truncated commit hash from the open-source OpenTitan repo that can be
// used to reproduce the ROM binary.
uint64_t scm_revision;
} 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.
OT_ASSERT_SIZE(chip_info_t, 8);

#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"
#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 @@ -23,6 +23,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
)

py_binary(
name = "otbn_build",
srcs = ["otbn_build.py"],
Expand Down
49 changes: 28 additions & 21 deletions util/rom_chip_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,39 @@
"""

import argparse
import hashlib
import logging as log
import sys
from datetime import datetime
from pathlib import Path

header_template = r"""

def generate_chip_info_c_source(scm_revision: int) -> str:
"""Return the contents of a C source file that defines `kChipInfo`.
Args:
scm_revision: SHA1 sum identifying the current SCM revision.
"""

SHA1_DIGEST_SIZE_BITS = hashlib.sha1().digest_size * 8
assert scm_revision.bit_length() <= SHA1_DIGEST_SIZE_BITS

# Truncate the SCM revision to the top N bits.
SCM_REVISION_SIZE_BITS = 64
shift_amount = SHA1_DIGEST_SIZE_BITS - SCM_REVISION_SIZE_BITS
scm_revision >>= shift_amount

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"
const chip_info_t kChipInfo __attribute__((section(".chip_info"))) = {{
.scm_revision = (uint64_t){scm_revision:#0x},
}};
"""


Expand Down Expand Up @@ -57,24 +70,18 @@ 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)
log.info("Version: %x" % (version, ))

outdir = Path(args.outdir)

outdir.mkdir(parents=True, exist_ok=True)
out_path = outdir / "chip_info.h"

now = datetime.now()
wall_time = now.strftime("%Y-%m-%d %H:%M:%S")

log.info("Version: %s" % (version, ))
log.info("Build Date: %s" % (wall_time, ))
source_out_path = outdir / "chip_info.c"

output = header_template
output = output.replace('{%version%}', version, 1)
output = output.replace('{%build_date%}', wall_time, 1)
output = generate_chip_info_c_source(version)

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 2ecf53b

Please sign in to comment.