From df7475bd404782598d7332e1c80a161d0256ae1e Mon Sep 17 00:00:00 2001 From: Alphan Ulusoy Date: Tue, 19 Oct 2021 14:48:11 -0400 Subject: [PATCH] [sw/silicon_creator] Add initial files for ROM_EXT boot policy This change adds skeleton code for ROM_EXT boot policy by mostly copying the corresponding files from `sw/device/silicon_creato/mask_rom` to unblock booting the first owner boot stage. Signed-off-by: Alphan Ulusoy --- .../silicon_creator/mask_rom/meson.build | 2 +- .../silicon_creator/rom_exts/meson.build | 27 +++++ .../rom_exts/mock_rom_ext_boot_policy_ptrs.h | 41 +++++++ .../rom_exts/rom_ext_boot_policy.c | 37 ++++++ .../rom_exts/rom_ext_boot_policy.h | 71 ++++++++++++ .../rom_exts/rom_ext_boot_policy_ptrs.h | 57 ++++++++++ .../rom_exts/rom_ext_boot_policy_unittest.cc | 107 ++++++++++++++++++ 7 files changed, 341 insertions(+), 1 deletion(-) create mode 100644 sw/device/silicon_creator/rom_exts/mock_rom_ext_boot_policy_ptrs.h create mode 100644 sw/device/silicon_creator/rom_exts/rom_ext_boot_policy.c create mode 100644 sw/device/silicon_creator/rom_exts/rom_ext_boot_policy.h create mode 100644 sw/device/silicon_creator/rom_exts/rom_ext_boot_policy_ptrs.h create mode 100644 sw/device/silicon_creator/rom_exts/rom_ext_boot_policy_unittest.cc diff --git a/sw/device/silicon_creator/mask_rom/meson.build b/sw/device/silicon_creator/mask_rom/meson.build index a8fa2ae865f6f..90542f403e7ab 100644 --- a/sw/device/silicon_creator/mask_rom/meson.build +++ b/sw/device/silicon_creator/mask_rom/meson.build @@ -30,7 +30,7 @@ sw_silicon_creator_mask_rom_sigverify = declare_dependency( ), ) -# ROM_EXT image. +# Mask ROM boot policy. sw_silicon_creator_mask_rom_boot_policy = declare_dependency( link_with: static_library( 'sw_silicon_creator_mask_rom_boot_policy', diff --git a/sw/device/silicon_creator/rom_exts/meson.build b/sw/device/silicon_creator/rom_exts/meson.build index 57426987e7d14..028963ea49016 100644 --- a/sw/device/silicon_creator/rom_exts/meson.build +++ b/sw/device/silicon_creator/rom_exts/meson.build @@ -7,6 +7,32 @@ # See sw/device/exts/common/flash_link.ld for additional info about these # parameters. +# ROM_EXT boot policy. +sw_silicon_creator_rom_ext_boot_policy = declare_dependency( + link_with: static_library( + 'sw_silicon_creator_rom_ext_boot_policy', + sources: [ + 'rom_ext_boot_policy.c', + ], + ), +) + +test('sw_silicon_creator_rom_ext_boot_policy_unittest', executable( + 'sw_silicon_creator_rom_ext_boot_policy_unittest', + sources: [ + 'rom_ext_boot_policy_unittest.cc', + 'rom_ext_boot_policy.c', + ], + dependencies: [ + sw_vendor_gtest, + ], + native: true, + c_args: ['-DOT_OFF_TARGET_TEST'], + cpp_args: ['-DOT_OFF_TARGET_TEST'], + ), + suite: 'rom_ext', +) + rom_ext_linkfile_slot_a = files(['rom_ext_slot_a.ld']) rom_ext_linkfile_slot_b = files(['rom_ext_slot_b.ld']) @@ -53,6 +79,7 @@ foreach slot, slot_link_args : rom_ext_link_info sw_lib_runtime_print, sw_silicon_creator_lib_base_sec_mmio, sw_silicon_creator_lib_manifest_section, + sw_silicon_creator_rom_ext_boot_policy, # TODO: ePMP test status dependency should be removed from # production ROM_EXT. Tests should unlock the test status diff --git a/sw/device/silicon_creator/rom_exts/mock_rom_ext_boot_policy_ptrs.h b/sw/device/silicon_creator/rom_exts/mock_rom_ext_boot_policy_ptrs.h new file mode 100644 index 0000000000000..37223dc7c4f20 --- /dev/null +++ b/sw/device/silicon_creator/rom_exts/mock_rom_ext_boot_policy_ptrs.h @@ -0,0 +1,41 @@ +// 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_ROM_EXTS_MOCK_ROM_EXT_BOOT_POLICY_PTRS_H_ +#define OPENTITAN_SW_DEVICE_SILICON_CREATOR_ROM_EXTS_MOCK_ROM_EXT_BOOT_POLICY_PTRS_H_ + +#include "sw/device/silicon_creator/rom_exts/rom_ext_boot_policy_ptrs.h" +#include "sw/device/silicon_creator/testing/mask_rom_test.h" + +namespace mask_rom_test { +namespace internal { + +/** + * Mock class for rom_ext_boot_policy_ptrs.h + */ +class MockRomExtBootPolicyPtrs : public GlobalMock { + public: + MOCK_METHOD(const manifest_t *, ManifestA, ()); + MOCK_METHOD(const manifest_t *, ManifestB, ()); +}; + +} // namespace internal + +using MockRomExtBootPolicyPtrs = + testing::StrictMock; + +extern "C" { + +const manifest_t *rom_ext_boot_policy_manifest_a_get() { + return MockRomExtBootPolicyPtrs::Instance().ManifestA(); +} + +const manifest_t *rom_ext_boot_policy_manifest_b_get() { + return MockRomExtBootPolicyPtrs::Instance().ManifestB(); +} + +} // extern "C" +} // namespace mask_rom_test + +#endif // OPENTITAN_SW_DEVICE_SILICON_CREATOR_ROM_EXTS_MOCK_ROM_EXT_BOOT_POLICY_PTRS_H_ diff --git a/sw/device/silicon_creator/rom_exts/rom_ext_boot_policy.c b/sw/device/silicon_creator/rom_exts/rom_ext_boot_policy.c new file mode 100644 index 0000000000000..6b98a5bfed807 --- /dev/null +++ b/sw/device/silicon_creator/rom_exts/rom_ext_boot_policy.c @@ -0,0 +1,37 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "sw/device/silicon_creator/rom_exts/rom_ext_boot_policy.h" + +#include "sw/device/silicon_creator/lib/error.h" +#include "sw/device/silicon_creator/rom_exts/rom_ext_boot_policy_ptrs.h" + +rom_ext_boot_policy_manifests_t rom_ext_boot_policy_manifests_get(void) { + const manifest_t *slot_a = rom_ext_boot_policy_manifest_a_get(); + const manifest_t *slot_b = rom_ext_boot_policy_manifest_b_get(); + if (slot_a->security_version >= slot_b->security_version) { + return (rom_ext_boot_policy_manifests_t){ + .ordered = {slot_a, slot_b}, + }; + } + return (rom_ext_boot_policy_manifests_t){ + .ordered = {slot_b, slot_a}, + }; +} + +rom_error_t rom_ext_boot_policy_manifest_check(const manifest_t *manifest) { + RETURN_IF_ERROR(manifest_check(manifest)); + if (manifest->identifier != kRomExtBootPolicyOwnerStageIdentifier) { + return kErrorBootPolicyBadIdentifier; + } + // TODO(#7879): Implement anti-rollback. + uint32_t min_security_version = 0; + if (manifest->security_version < min_security_version) { + return kErrorBootPolicyRollback; + } + return kErrorOk; +} + +extern const manifest_t *rom_ext_boot_policy_manifest_a_get(void); +extern const manifest_t *rom_ext_boot_policy_manifest_b_get(void); diff --git a/sw/device/silicon_creator/rom_exts/rom_ext_boot_policy.h b/sw/device/silicon_creator/rom_exts/rom_ext_boot_policy.h new file mode 100644 index 0000000000000..907df1efa20c4 --- /dev/null +++ b/sw/device/silicon_creator/rom_exts/rom_ext_boot_policy.h @@ -0,0 +1,71 @@ +// 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_ROM_EXTS_ROM_EXT_BOOT_POLICY_H_ +#define OPENTITAN_SW_DEVICE_SILICON_CREATOR_ROM_EXTS_ROM_EXT_BOOT_POLICY_H_ + +#include "sw/device/silicon_creator/lib/error.h" +#include "sw/device/silicon_creator/lib/manifest.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +enum { + /** + * First owner boot stage manifest identifier (ASCII "OTSO"). + */ + kRomExtBootPolicyOwnerStageIdentifier = 0x4f53544f, +}; + +/** + * Type alias for the first owner boot stage entry point. + * + * The entry point address obtained from the first owner boot stage manifest + * must be cast to a pointer to this type before being called. + */ +typedef void owner_stage_entry_point(void); + +/** + * Manifests of first boot owner boot stages in descending order according to + * their security versions. + * + * These boot stages must be verified prior to handing over execution. + */ +typedef struct rom_ext_boot_policy_manifests { + /** + * First owner boot stage manifests in descending order according to + * their security versions. + */ + const manifest_t *ordered[2]; +} rom_ext_boot_policy_manifests_t; + +/** + * Returns the manifests of first owner boot stages that should be attempted to + * boot in descending order according to their security versions. + * + * These boot stages must be verified prior to handing over execution. + * + * @return Manifests of first owner boot stages in descending order according to + * their security versions. + */ +rom_ext_boot_policy_manifests_t rom_ext_boot_policy_manifests_get(void); + +/** + * Checks the fields of a first owner boot stage manifest. + * + * This function performs bounds checks on the fields of the manifest, checks + * that its `identifier` is correct, and its `security_version` is greater than + * or equal to the minimum required security version. + * + * @param manifest A first boot owner boot stage manifest. + * @return Result of the operation. + */ +rom_error_t rom_ext_boot_policy_manifest_check(const manifest_t *manifest); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // OPENTITAN_SW_DEVICE_SILICON_CREATOR_ROM_EXTS_ROM_EXT_BOOT_POLICY_H_ diff --git a/sw/device/silicon_creator/rom_exts/rom_ext_boot_policy_ptrs.h b/sw/device/silicon_creator/rom_exts/rom_ext_boot_policy_ptrs.h new file mode 100644 index 0000000000000..b1e7d0315d535 --- /dev/null +++ b/sw/device/silicon_creator/rom_exts/rom_ext_boot_policy_ptrs.h @@ -0,0 +1,57 @@ +// 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_ROM_EXTS_ROM_EXT_BOOT_POLICY_PTRS_H_ +#define OPENTITAN_SW_DEVICE_SILICON_CREATOR_ROM_EXTS_ROM_EXT_BOOT_POLICY_PTRS_H_ + +#include "sw/device/silicon_creator/lib/manifest.h" + +#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +static_assert((TOP_EARLGREY_EFLASH_SIZE_BYTES % 2) == 0, + "Flash size is not divisible by 2"); + +#ifndef OT_OFF_TARGET_TEST +/** + * Returns a pointer to the manifest of the first owner boot stage image stored + * in flash slot A. + * + * @return Pointer to the manifest of the first owner boot stage image in slot + * A. + */ +// TODO(#7893): Should these be volatile? +inline const manifest_t *rom_ext_boot_policy_manifest_a_get(void) { + return (const manifest_t *)(TOP_EARLGREY_EFLASH_BASE_ADDR + + MANIFEST_LENGTH_FIELD_MAX); +} + +/** + * Returns a pointer to the manifest of the first owner boot stage image stored + * in flash slot B. + * + * @return Pointer to the manifest of the first owner boot stage image in slot + * B. + */ +inline const manifest_t *rom_ext_boot_policy_manifest_b_get(void) { + return (const manifest_t *)(TOP_EARLGREY_EFLASH_BASE_ADDR + + (TOP_EARLGREY_EFLASH_SIZE_BYTES / 2) + + MANIFEST_LENGTH_FIELD_MAX); +} +#else +/** + * Declarations for the functions above that should be defined in tests. + */ +const manifest_t *rom_ext_boot_policy_manifest_a_get(void); +const manifest_t *rom_ext_boot_policy_manifest_b_get(void); +#endif + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // OPENTITAN_SW_DEVICE_SILICON_CREATOR_ROM_EXTS_ROM_EXT_BOOT_POLICY_PTRS_H_ diff --git a/sw/device/silicon_creator/rom_exts/rom_ext_boot_policy_unittest.cc b/sw/device/silicon_creator/rom_exts/rom_ext_boot_policy_unittest.cc new file mode 100644 index 0000000000000..3fa97ad720e70 --- /dev/null +++ b/sw/device/silicon_creator/rom_exts/rom_ext_boot_policy_unittest.cc @@ -0,0 +1,107 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "sw/device/silicon_creator/rom_exts/rom_ext_boot_policy.h" + +#include "gtest/gtest.h" +#include "sw/device/silicon_creator/lib/mock_manifest.h" +#include "sw/device/silicon_creator/rom_exts/mock_rom_ext_boot_policy_ptrs.h" +#include "sw/device/silicon_creator/testing/mask_rom_test.h" + +namespace manifest_unittest { +namespace { +using ::testing::Return; + +class RomExtBootPolicyTest : public mask_rom_test::MaskRomTest { + protected: + mask_rom_test::MockRomExtBootPolicyPtrs rom_ext_boot_policy_ptrs_; + mask_rom_test::MockManifest mock_manifest_; +}; + +TEST_F(RomExtBootPolicyTest, ManifestCheck) { + manifest_t manifest{}; + manifest.identifier = kRomExtBootPolicyOwnerStageIdentifier; + + EXPECT_CALL(mock_manifest_, Check(&manifest)).WillOnce(Return(kErrorOk)); + + EXPECT_EQ(rom_ext_boot_policy_manifest_check(&manifest), kErrorOk); +} + +TEST_F(RomExtBootPolicyTest, ManifestCheckOutOfBounds) { + manifest_t manifest{}; + + EXPECT_CALL(mock_manifest_, Check(&manifest)) + .WillOnce(Return(kErrorManifestBadLength)); + + EXPECT_EQ(rom_ext_boot_policy_manifest_check(&manifest), + kErrorManifestBadLength); +} + +TEST_F(RomExtBootPolicyTest, ManifestCheckBadIdentifier) { + manifest_t manifest{}; + + EXPECT_CALL(mock_manifest_, Check(&manifest)).WillOnce(Return(kErrorOk)); + + EXPECT_EQ(rom_ext_boot_policy_manifest_check(&manifest), + kErrorBootPolicyBadIdentifier); +} + +struct ManifestOrderTestCase { + uint32_t version_a; + uint32_t version_b; + bool is_a_first; +}; + +class ManifestOrderTest + : public RomExtBootPolicyTest, + public testing::WithParamInterface {}; + +TEST_P(ManifestOrderTest, ManifestsGet) { + manifest_t manifest_a{}; + manifest_t manifest_b{}; + manifest_a.security_version = GetParam().version_a; + manifest_b.security_version = GetParam().version_b; + + EXPECT_CALL(rom_ext_boot_policy_ptrs_, ManifestA) + .WillOnce(Return(&manifest_a)); + EXPECT_CALL(rom_ext_boot_policy_ptrs_, ManifestB) + .WillOnce(Return(&manifest_b)); + + rom_ext_boot_policy_manifests_t res = rom_ext_boot_policy_manifests_get(); + if (GetParam().is_a_first) { + EXPECT_EQ(res.ordered[0], &manifest_a); + EXPECT_EQ(res.ordered[1], &manifest_b); + } else { + EXPECT_EQ(res.ordered[0], &manifest_b); + EXPECT_EQ(res.ordered[1], &manifest_a); + } +} + +INSTANTIATE_TEST_SUITE_P( + SecurityVersionCases, ManifestOrderTest, + testing::Values( + ManifestOrderTestCase{ + .version_a = 0, + .version_b = 0, + .is_a_first = true, + }, + ManifestOrderTestCase{ + .version_a = 1, + .version_b = 0, + .is_a_first = true, + }, + ManifestOrderTestCase{ + .version_a = 0, + .version_b = 1, + .is_a_first = false, + }, + ManifestOrderTestCase{ + .version_a = std::numeric_limits::max(), + .version_b = + static_cast(std::numeric_limits::max()) + 1, + .is_a_first = false, + })); + +} // namespace +} // namespace manifest_unittest