Skip to content

Commit

Permalink
[sw/silicon_creator] Add initial files for ROM_EXT boot policy
Browse files Browse the repository at this point in the history
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 <alphan@google.com>
  • Loading branch information
alphan committed Oct 21, 2021
1 parent 20c2a9d commit df7475b
Show file tree
Hide file tree
Showing 7 changed files with 341 additions and 1 deletion.
2 changes: 1 addition & 1 deletion sw/device/silicon_creator/mask_rom/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
27 changes: 27 additions & 0 deletions sw/device/silicon_creator/rom_exts/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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'])

Expand Down Expand Up @@ -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
Expand Down
41 changes: 41 additions & 0 deletions sw/device/silicon_creator/rom_exts/mock_rom_ext_boot_policy_ptrs.h
Original file line number Diff line number Diff line change
@@ -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<MockRomExtBootPolicyPtrs> {
public:
MOCK_METHOD(const manifest_t *, ManifestA, ());
MOCK_METHOD(const manifest_t *, ManifestB, ());
};

} // namespace internal

using MockRomExtBootPolicyPtrs =
testing::StrictMock<internal::MockRomExtBootPolicyPtrs>;

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_
37 changes: 37 additions & 0 deletions sw/device/silicon_creator/rom_exts/rom_ext_boot_policy.c
Original file line number Diff line number Diff line change
@@ -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);
71 changes: 71 additions & 0 deletions sw/device/silicon_creator/rom_exts/rom_ext_boot_policy.h
Original file line number Diff line number Diff line change
@@ -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_
57 changes: 57 additions & 0 deletions sw/device/silicon_creator/rom_exts/rom_ext_boot_policy_ptrs.h
Original file line number Diff line number Diff line change
@@ -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_
107 changes: 107 additions & 0 deletions sw/device/silicon_creator/rom_exts/rom_ext_boot_policy_unittest.cc
Original file line number Diff line number Diff line change
@@ -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<ManifestOrderTestCase> {};

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<int32_t>::max(),
.version_b =
static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) + 1,
.is_a_first = false,
}));

} // namespace
} // namespace manifest_unittest

0 comments on commit df7475b

Please sign in to comment.