Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[sw/silicon_creator] Implement ROM_EXT bootstrap library #18929

Merged
merged 2 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 20 additions & 0 deletions sw/device/silicon_creator/lib/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,17 @@ cc_library(
],
)

cc_library(
name = "error_unittest_util",
hdrs = ["error_unittest_util.h"],
)

cc_test(
name = "error_unittest",
srcs = ["error_unittest.cc"],
deps = [
":error",
":error_unittest_util",
"@googletest//:gtest_main",
],
)
Expand Down Expand Up @@ -416,3 +422,17 @@ filegroup(
"bootstrap.h",
],
)

cc_library(
name = "bootstrap_unittest_util",
srcs = ["bootstrap_unittest_util.cc"],
hdrs = ["bootstrap_unittest_util.h"],
deps = [
":bootstrap",
"//hw/ip/gpio/data:gpio_regs",
"//hw/ip/otp_ctrl/data:otp_ctrl_regs",
"//hw/top_earlgrey/ip/flash_ctrl/data/autogen:flash_ctrl_regs",
"//hw/top_earlgrey/sw/autogen:top_earlgrey",
"//sw/device/silicon_creator/lib/base:chip",
],
)
37 changes: 8 additions & 29 deletions sw/device/silicon_creator/lib/bootstrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

#include "sw/device/silicon_creator/lib/bootstrap.h"

#include <assert.h>
#include <stdalign.h>
#include <stdint.h>

#include "sw/device/lib/base/abs_mmio.h"
#include "sw/device/lib/base/bitfield.h"
#include "sw/device/lib/base/hardened.h"
#include "sw/device/silicon_creator/lib/drivers/flash_ctrl.h"
Expand Down Expand Up @@ -59,23 +60,6 @@ typedef enum bootstrap_state {
kBootstrapStateProgram = 0xbdd8ca60,
} bootstrap_state_t;

/**
* Handles access permissions and erases both data banks of the embedded flash.
*
* @return Result of the operation.
*/
OT_WARN_UNUSED_RESULT
static rom_error_t bootstrap_chip_erase(void) {
flash_ctrl_bank_erase_perms_set(kHardenedBoolTrue);
rom_error_t err_0 = flash_ctrl_data_erase(0, kFlashCtrlEraseTypeBank);
rom_error_t err_1 = flash_ctrl_data_erase(FLASH_CTRL_PARAM_BYTES_PER_BANK,
kFlashCtrlEraseTypeBank);
flash_ctrl_bank_erase_perms_set(kHardenedBoolFalse);

HARDENED_RETURN_IF_ERROR(err_0);
return err_1;
}

/**
* Handles access permissions and erases a 4 KiB region in the data partition of
* the embedded flash.
Expand Down Expand Up @@ -262,15 +246,13 @@ OT_WARN_UNUSED_RESULT
static rom_error_t bootstrap_handle_erase_verify(bootstrap_state_t *state) {
HARDENED_CHECK_EQ(*state, kBootstrapStateEraseVerify);

rom_error_t err_0 = flash_ctrl_data_erase_verify(0, kFlashCtrlEraseTypeBank);
rom_error_t err_1 = flash_ctrl_data_erase_verify(
FLASH_CTRL_PARAM_BYTES_PER_BANK, kFlashCtrlEraseTypeBank);
HARDENED_RETURN_IF_ERROR(err_0);
HARDENED_RETURN_IF_ERROR(err_1);
const rom_error_t err = bootstrap_erase_verify();
HARDENED_RETURN_IF_ERROR(err);

*state = kBootstrapStateProgram;
spi_device_flash_status_clear();
return err_0;

*state = kBootstrapStateProgram;
return err;
}

/**
Expand Down Expand Up @@ -333,10 +315,7 @@ static rom_error_t bootstrap_handle_program(bootstrap_state_t *state) {
return error;
}

rom_error_t enter_bootstrap(hardened_bool_t protect_rom_ext) {
// TODO(lowRISC/opentitan#19151): Implement `protect_rom_ext` behavior.
HARDENED_CHECK_EQ(protect_rom_ext, kHardenedBoolFalse);

rom_error_t enter_bootstrap(void) {
spi_device_init();

// Bootstrap event loop.
Expand Down
45 changes: 38 additions & 7 deletions sw/device/silicon_creator/lib/bootstrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,62 @@
#ifndef OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_BOOTSTRAP_H_
#define OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_BOOTSTRAP_H_

#include "sw/device/lib/base/hardened.h"
#include "sw/device/silicon_creator/lib/drivers/spi_device.h"
#include "sw/device/silicon_creator/lib/error.h"

#ifdef __cplusplus
extern "C" {
#endif

#include "sw/device/lib/base/hardened.h"
#include "sw/device/silicon_creator/lib/error.h"

/**
* @public
* Enters flash programming mode. This function initializes the SPI device and
* uses incoming SPI commands to drive an internal state machine.
*
* Dependent code should use this function as the main entry point to bootstrap.
* The dependent code must provide implementations for the following functions:
* - `bootstrap_chip_erase()`
* - `bootstrap_erase_verify()`
*
* Bootstrapping uses the typical SPI flash EEPROM commands. A typical session
* involves:
* - Asserting bootstrap pins to enter bootstrap mode,
* - Erasing the chip (WREN, CHIP_ERASE, busy loop ...),
* - Programming the chip (WREN, PAGE_PROGRAM, busy loop ...), and
* - Resetting the chip (RESET).
*
* This function only returns on error since a successful session ends with a
* chip reset.
* This function only returns on error; a successful session ends with a chip
* reset.
*
* @param protect_rom_ext Whether to prevent changes to to ROM_EXT.
* @return The result of the flash loop.
*/
rom_error_t enter_bootstrap(hardened_bool_t protect_rom_ext);
OT_WARN_UNUSED_RESULT
rom_error_t enter_bootstrap(void);

/**
* @private @pure
* Handles access permissions and erases both data banks of the embedded flash.
*
* NOTE: This abstract function must be implemented by dependent code.
*
* @return Result of the operation.
*/
OT_WARN_UNUSED_RESULT
rom_error_t bootstrap_chip_erase(void);

/**
* @private @pure
* Verify that all data banks have been erased.
*
* This function also clears the WIP and WEN bits of the flash status register.
*
* NOTE: This abstract function must be implemented by dependent code.
*
* @return Result of the operation.
*/
OT_WARN_UNUSED_RESULT
rom_error_t bootstrap_erase_verify(void);

#ifdef __cplusplus
}
Expand Down
153 changes: 153 additions & 0 deletions sw/device/silicon_creator/lib/bootstrap_unittest_util.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
// 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/lib/bootstrap_unittest_util.h"

#include <stdint.h>
#include <string.h>

#include "sw/device/silicon_creator/lib/base/chip.h"

#include "flash_ctrl_regs.h"
#include "gpio_regs.h"
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
#include "otp_ctrl_regs.h"

bool operator==(flash_ctrl_perms_t lhs, flash_ctrl_perms_t rhs) {
return memcmp(&lhs, &rhs, sizeof(flash_ctrl_perms_t)) == 0;
}

namespace bootstrap_unittest_util {

namespace {
using ::testing::DoAll;
using ::testing::NotNull;
using ::testing::Return;
using ::testing::SetArgPointee;
} // namespace

void BootstrapTest::ExpectBootstrapRequestCheck(bool requested) {
EXPECT_CALL(otp_,
read32(OTP_CTRL_PARAM_OWNER_SW_CFG_ROM_BOOTSTRAP_DIS_OFFSET))
.WillOnce(Return(kHardenedBoolFalse));
uint32_t pins = SW_STRAP_BOOTSTRAP;
if (!requested) {
pins = ~pins;
}
EXPECT_ABS_READ32(TOP_EARLGREY_GPIO_BASE_ADDR + GPIO_DATA_IN_REG_OFFSET,
pins);
}

void BootstrapTest::ExpectSpiCmd(spi_device_cmd_t cmd) {
EXPECT_CALL(spi_device_, CmdGet(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(cmd), Return(kErrorOk)));
}

void BootstrapTest::ExpectSpiFlashStatusGet(bool wel) {
EXPECT_CALL(spi_device_, FlashStatusGet())
.WillOnce(Return(wel << kSpiDeviceWelBit));
}

void BootstrapTest::ExpectFlashCtrlWriteEnable() {
EXPECT_CALL(flash_ctrl_, DataDefaultPermsSet((flash_ctrl_perms_t){
.read = kMultiBitBool4False,
.write = kMultiBitBool4True,
.erase = kMultiBitBool4False,
}));
}

void BootstrapTest::ExpectFlashCtrlEraseEnable() {
EXPECT_CALL(flash_ctrl_, DataDefaultPermsSet((flash_ctrl_perms_t){
.read = kMultiBitBool4False,
.write = kMultiBitBool4False,
.erase = kMultiBitBool4True,
}));
}

void BootstrapTest::ExpectFlashCtrlAllDisable() {
EXPECT_CALL(flash_ctrl_, DataDefaultPermsSet((flash_ctrl_perms_t){
.read = kMultiBitBool4False,
.write = kMultiBitBool4False,
.erase = kMultiBitBool4False,
}));
}

void BootstrapTest::ExpectFlashCtrlChipErase(rom_error_t err0,
rom_error_t err1) {
EXPECT_CALL(flash_ctrl_, BankErasePermsSet(kHardenedBoolTrue));
EXPECT_CALL(flash_ctrl_, DataErase(0, kFlashCtrlEraseTypeBank))
.WillOnce(Return(err0));
EXPECT_CALL(flash_ctrl_, DataErase(FLASH_CTRL_PARAM_BYTES_PER_BANK,
kFlashCtrlEraseTypeBank))
.WillOnce(Return(err1));
EXPECT_CALL(flash_ctrl_, BankErasePermsSet(kHardenedBoolFalse));
}

void BootstrapTest::ExpectFlashCtrlSectorErase(rom_error_t err0,
rom_error_t err1,
uint32_t addr) {
EXPECT_CALL(flash_ctrl_, DataDefaultPermsSet((flash_ctrl_perms_t){
.read = kMultiBitBool4False,
.write = kMultiBitBool4False,
.erase = kMultiBitBool4True,
}));
EXPECT_CALL(flash_ctrl_, DataErase(addr, kFlashCtrlEraseTypePage))
.WillOnce(Return(err0));
EXPECT_CALL(flash_ctrl_, DataErase(addr + FLASH_CTRL_PARAM_BYTES_PER_PAGE,
kFlashCtrlEraseTypePage))
.WillOnce(Return(err1));
ExpectFlashCtrlAllDisable();
}

void BootstrapTest::ExpectFlashCtrlEraseVerify(rom_error_t err0,
rom_error_t err1) {
EXPECT_CALL(flash_ctrl_, DataEraseVerify(0, kFlashCtrlEraseTypeBank))
.WillOnce(Return(err0));
EXPECT_CALL(flash_ctrl_, DataEraseVerify(FLASH_CTRL_PARAM_BYTES_PER_BANK,
kFlashCtrlEraseTypeBank))
.WillOnce(Return(err1));
}

spi_device_cmd_t ChipEraseCmd() {
return {
.opcode = kSpiDeviceOpcodeChipErase,
.address = kSpiDeviceNoAddress,
.payload_byte_count = 0,
.payload = {},
};
}

spi_device_cmd_t SectorEraseCmd(uint32_t address) {
return {
.opcode = kSpiDeviceOpcodeSectorErase,
.address = address,
.payload_byte_count = 0,
.payload = {},
};
}

spi_device_cmd_t PageProgramCmd(uint32_t address, size_t payload_byte_count) {
spi_device_cmd_t cmd{
.opcode = kSpiDeviceOpcodePageProgram,
.address = address,
.payload_byte_count = payload_byte_count,
};
EXPECT_LE(payload_byte_count, kSpiDevicePayloadAreaNumBytes);
for (size_t i = 0; i < payload_byte_count; ++i) {
cmd.payload[i] = static_cast<uint8_t>(i);
}

return cmd;
}

spi_device_cmd_t ResetCmd() {
return {
.opcode = kSpiDeviceOpcodeReset,
.address = kSpiDeviceNoAddress,
.payload_byte_count = 0,
.payload = {},
};
}

} // namespace bootstrap_unittest_util