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

[orchestrator] fix bugs in orchestrator.py script #25873

Merged
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sw/device/lib/testing/json/provisioning_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ UJSON_SERDE_STRUCT(ManufCpTestData, \
// clang-format off
#define STRUCT_MANUF_FT_INDIVIDUALIZE_DATA(field, string) \
field(use_ext_clk, bool) \
field(device_id, uint32_t, 8)
field(ft_device_id, uint32_t, 4)
UJSON_SERDE_STRUCT(ManufFtIndividualizeData, \
manuf_ft_individualize_data_t, \
STRUCT_MANUF_FT_INDIVIDUALIZE_DATA);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ CP_PROVISIONING_INPUTS = _TEST_TOKENS + """
"""

FT_PROVISIONING_INPUTS = _TEST_TOKENS + """
--device-id="0x11111111_22222222_33333333_44444444_55555555_66666666_77777777_88888888"
--ft-device-id="0x11111111_22222222_33333333_44444444"
--target-mission-mode-lc-state="prod"
--rma-unlock-token="0x01234567_89abcdef_01234567_89abcdef"
--token-encrypt-key-der-file="sw/device/silicon_creator/manuf/keys/fake/rma_unlock_enc_rsa3072.pub.der"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ static status_t provision(ujson_t *uj) {
LOG_INFO("Writing HW_CFG* OTP partitions ...");
TRY(manuf_individualize_device_hw_cfg(&flash_ctrl_state, &otp_ctrl,
kFlashInfoPage0Permissions,
in_data.device_id));
in_data.ft_device_id));
LOG_INFO("Writing ROT_CREATOR_AUTH_CODESIGN OTP partition ...");
TRY(manuf_individualize_device_rot_creator_auth_codesign(&otp_ctrl));
LOG_INFO("Writing ROT_CREATOR_AUTH_STATE OTP partition ...");
Expand Down
1 change: 1 addition & 0 deletions sw/device/silicon_creator/manuf/lib/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ opentitan_test(
"//sw/device/lib/dif:rstmgr",
"//sw/device/lib/testing:flash_ctrl_testutils",
"//sw/device/lib/testing:lc_ctrl_testutils",
"//sw/device/lib/testing:otp_ctrl_testutils",
"//sw/device/lib/testing:rstmgr_testutils",
"//sw/device/lib/testing/json:provisioning_data",
"//sw/device/lib/testing/test_framework:ottf_main",
Expand Down
2 changes: 2 additions & 0 deletions sw/device/silicon_creator/manuf/lib/flash_info_fields.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ enum {
*/
kFlashInfoFieldCpDeviceIdStartOffset = 384,
kFlashInfoFieldCpDeviceIdSizeIn32BitWords = 4,
kFlashInfoFieldCpDeviceIdSizeInBytes =
kFlashInfoFieldCpDeviceIdSizeIn32BitWords * sizeof(uint32_t),

// Creator/Owner Seeds - Bank 0, Pages 1 and 2
kFlashInfoFieldKeySeedSizeIn32BitWords = 32 / sizeof(uint32_t),
Expand Down
67 changes: 26 additions & 41 deletions sw/device/silicon_creator/manuf/lib/individualize.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,71 +75,56 @@ static status_t hw_cfg1_enable_knobs_set(const dif_otp_ctrl_t *otp_ctrl) {
status_t manuf_individualize_device_hw_cfg(
dif_flash_ctrl_state_t *flash_state, const dif_otp_ctrl_t *otp_ctrl,
dif_flash_ctrl_region_properties_t flash_info_page_0_permissions,
uint32_t *device_id) {
uint32_t *ft_device_id) {
bool is_locked;

// Provision HW_CFG0 if it is not locked.
TRY(dif_otp_ctrl_is_digest_computed(otp_ctrl, kDifOtpCtrlPartitionHwCfg0,
&is_locked));
if (!is_locked) {
// Configure flash info page permissions in case we started from a cold
// boot. Note: device_id and manuf_state are on the same flash info page.
// boot. Note: cp_device_id and manuf_state are on the same flash info page.
TRY(flash_ctrl_testutils_info_region_setup_properties(
flash_state, kFlashInfoFieldCpDeviceId.page,
kFlashInfoFieldCpDeviceId.bank, kFlashInfoFieldCpDeviceId.partition,
flash_info_page_0_permissions,
/*offset=*/NULL));

// Read CpDeviceId from flash info page 0.
uint32_t cp_device_id_from_flash[kFlashInfoFieldCpDeviceIdSizeIn32BitWords];
uint32_t empty_cp_device_id[kFlashInfoFieldCpDeviceIdSizeIn32BitWords] = {
0};
uint32_t cp_device_id[kFlashInfoFieldCpDeviceIdSizeIn32BitWords];
TRY(manuf_flash_info_field_read(flash_state, kFlashInfoFieldCpDeviceId,
cp_device_id_from_flash,
cp_device_id,
kFlashInfoFieldCpDeviceIdSizeIn32BitWords));

// Check if CP device ID from flash is empty.
bool flash_cp_device_id_empty = true;
for (size_t i = 0; flash_cp_device_id_empty &&
i < kFlashInfoFieldCpDeviceIdSizeIn32BitWords;
++i) {
flash_cp_device_id_empty &= cp_device_id_from_flash[i] == 0;
}

// Check if CP device ID provided is empty (i.e., all ones). This means CP
// stage was skipped or already run in the past.
bool provided_din_empty = true;
for (size_t i = 1;
provided_din_empty && i < kFlashInfoFieldCpDeviceIdSizeIn32BitWords;
++i) {
provided_din_empty &= device_id[i] == 0;
for (size_t i = 0; i < kFlashInfoFieldCpDeviceIdSizeIn32BitWords; ++i) {
if (cp_device_id[i] != 0) {
flash_cp_device_id_empty = false;
break;
}
}

// If the CP device ID read from flash is non-empty, then it must match the
// first 128-bits of device ID provided, unless the first 128-bits are all
// ones (in which case we use the CP device ID in flash).
//
// If the device ID read from flash is empty, we check to ensure the device
// ID provided is also not empty, and the CP portion is not all ones. An
// empty (all zero) device ID will prevent the keymgr from advancing.
if (!flash_cp_device_id_empty) {
if (!provided_din_empty) {
TRY_CHECK_ARRAYS_EQ(cp_device_id_from_flash, device_id,
kFlashInfoFieldCpDeviceIdSizeIn32BitWords);
// On non-silicon targets, we expect the CP device ID from flash to be
// empty. In this case we set the HW origin portion of the CP device ID.
// Otherwise, we expect the CP device ID to be present and non-zero.
if (flash_cp_device_id_empty) {
if (kDeviceType != kDeviceSilicon) {
memset(&cp_device_id, 0, sizeof(cp_device_id));
cp_device_id[0] = 0x00024001u;
} else {
// Extract CP device ID from flash again.
memcpy(device_id, cp_device_id_from_flash,
kFlashInfoFieldCpDeviceIdSizeIn32BitWords * sizeof(uint32_t));
return NOT_FOUND();
}
} else {
// On FPGA, we expect the provided DIN to be empty and CP device ID from
// flash to be empty.
if (kDeviceType == kDeviceSilicon) {
TRY_CHECK(!provided_din_empty);
}
TRY_CHECK_ARRAYS_NE(device_id, empty_cp_device_id,
kFlashInfoFieldCpDeviceIdSizeIn32BitWords);
}

// Construct the complete device ID.
uint32_t device_id[kHwCfgDeviceIdSizeIn32BitWords];
memcpy(device_id, cp_device_id, kFlashInfoFieldCpDeviceIdSizeInBytes);
// CP and FT device IDs are the same length (128 bit words).
memcpy(&device_id[kFlashInfoFieldCpDeviceIdSizeIn32BitWords], ft_device_id,
kFlashInfoFieldCpDeviceIdSizeInBytes);

// Write the complete device ID to OTP.
TRY(otp_ctrl_testutils_dai_write32(otp_ctrl, kDifOtpCtrlPartitionHwCfg0,
kHwCfgDeviceIdOffset, device_id,
kHwCfgDeviceIdSizeIn32BitWords));
Expand Down
38 changes: 18 additions & 20 deletions sw/device/silicon_creator/manuf/lib/individualize_functest.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "sw/device/lib/dif/dif_rstmgr.h"
#include "sw/device/lib/testing/flash_ctrl_testutils.h"
#include "sw/device/lib/testing/lc_ctrl_testutils.h"
#include "sw/device/lib/testing/otp_ctrl_testutils.h"
#include "sw/device/lib/testing/rstmgr_testutils.h"
#include "sw/device/lib/testing/test_framework/check.h"
#include "sw/device/lib/testing/test_framework/ottf_main.h"
Expand All @@ -30,8 +31,8 @@ static dif_lc_ctrl_t lc_ctrl;
static dif_otp_ctrl_t otp_ctrl;
static dif_rstmgr_t rstmgr;

static uint32_t kDeviceIdFromHost[kHwCfgDeviceIdSizeIn32BitWords] = {
0xAAAAAAAA, 0xBBBBBBBB, 0xAAAAAAAA, 0xBBBBBBBB,
// CP and FT portions of the device ID are the same size.
static uint32_t kFtDeviceId[kFlashInfoFieldCpDeviceIdSizeIn32BitWords] = {
0xAAAAAAAA, 0xBBBBBBBB, 0xAAAAAAAA, 0xBBBBBBBB};

static dif_flash_ctrl_region_properties_t kFlashInfoPage0Permissions = {
Expand Down Expand Up @@ -80,29 +81,26 @@ bool test_main(void) {
kFlashInfoFieldCpDeviceId.bank, kFlashInfoFieldCpDeviceId.partition,
kFlashInfoPage0Permissions, &byte_address));

// Write a bad CP device ID to flash info page 0 and try to program HW_CFG0
// partition, expecting a failure.
uint32_t kBadCpDeviceId[kFlashInfoFieldCpDeviceIdSizeIn32BitWords] = {
0xAAAAAAAA, 0xBBBBBBBB, 0xAAAA0AAA, 0xBBBBBBBB};
CHECK_STATUS_OK(manuf_flash_info_field_write(
&flash_state, kFlashInfoFieldCpDeviceId, kBadCpDeviceId,
kFlashInfoFieldCpDeviceIdSizeIn32BitWords,
/*erase_page_before_write=*/true));
CHECK_STATUS_NOT_OK(manuf_individualize_device_hw_cfg(
&flash_state, &otp_ctrl, kFlashInfoPage0Permissions,
kDeviceIdFromHost));

// Write a good CP device ID to flash info page 0 and try to program HW_CFG0
// partition, expecting success.
uint32_t kGoodCpDeviceId[kFlashInfoFieldCpDeviceIdSizeIn32BitWords] = {
// Write the CP device ID to flash info page 0 and try to program HW_CFG0
// partition.
uint32_t kCpDeviceId[kFlashInfoFieldCpDeviceIdSizeIn32BitWords] = {
0xAAAAAAAA, 0xBBBBBBBB, 0xAAAAAAAA, 0xBBBBBBBB};
CHECK_STATUS_OK(manuf_flash_info_field_write(
&flash_state, kFlashInfoFieldCpDeviceId, kGoodCpDeviceId,
&flash_state, kFlashInfoFieldCpDeviceId, kCpDeviceId,
kFlashInfoFieldCpDeviceIdSizeIn32BitWords,
/*erase_page_before_write=*/true));
CHECK_STATUS_OK(manuf_individualize_device_hw_cfg(
&flash_state, &otp_ctrl, kFlashInfoPage0Permissions,
kDeviceIdFromHost));
&flash_state, &otp_ctrl, kFlashInfoPage0Permissions, kFtDeviceId));

// Check the value of the DeviceId in the HW_CFG0 partition.
uint32_t device_id[kHwCfgDeviceIdSizeIn32BitWords];
CHECK_STATUS_OK(otp_ctrl_testutils_dai_read32_array(
&otp_ctrl, kDifOtpCtrlPartitionHwCfg0, 0, device_id,
kHwCfgDeviceIdSizeIn32BitWords));
CHECK_ARRAYS_EQ(device_id, kCpDeviceId,
kFlashInfoFieldCpDeviceIdSizeIn32BitWords);
CHECK_ARRAYS_EQ(&device_id[kFlashInfoFieldCpDeviceIdSizeIn32BitWords],
kFtDeviceId, kFlashInfoFieldCpDeviceIdSizeIn32BitWords);

sw_reset();
}
Expand Down
31 changes: 14 additions & 17 deletions sw/host/provisioning/ft/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ use util_lib::{
/// Provisioning data command-line parameters.
#[derive(Debug, Args, Clone)]
pub struct ManufFtProvisioningDataInput {
/// Device ID to provision.
/// FT Device ID to provision.
///
/// Must match the device ID provisioned in to flash during CP, if one was provisioned then.
/// Contains the SKU-specific portion of the device ID.
#[arg(long)]
pub device_id: String,
pub ft_device_id: String,

#[arg(long)]
pub use_ext_clk_during_individualize: bool,
Expand Down Expand Up @@ -151,17 +151,13 @@ fn main() -> Result<()> {
log::info!("Encrypted rma_unlock_token = {}", response.rma_unlock_token);

// Parse and prepare individualization ujson data payload.
let mut device_id = hex_string_to_u32_arrayvec::<8>(opts.provisioning_data.device_id.as_str())?;
response.device_id = device_id
.iter()
.map(|v| format!("{v:08X}"))
.collect::<Vec<String>>()
.join("");
// We feed the device ID to the DUT in little endian order.
device_id.reverse();
let mut ft_device_id =
hex_string_to_u32_arrayvec::<4>(opts.provisioning_data.ft_device_id.as_str())?;
// The FT device ID is sent to the DUT in little endian order.
ft_device_id.reverse();
let ft_individualize_data_in = ManufFtIndividualizeData {
use_ext_clk: opts.provisioning_data.use_ext_clk_during_individualize,
device_id,
ft_device_id,
};

// Parse and prepare CA key.
Expand Down Expand Up @@ -317,11 +313,6 @@ fn main() -> Result<()> {
opts.owner_success_text,
)?;
log::info!("Provisioning Done");
let doc = if opts.provisioning_data.pretty {
serde_json::to_string_pretty(&response)?
} else {
serde_json::to_string(&response)?
};

// Extract final device ID.
let mut final_device_id = read_device_id(
Expand All @@ -338,6 +329,12 @@ fn main() -> Result<()> {
.collect::<Vec<String>>()
.join("");

// Log JSON data to console.
let doc = if opts.provisioning_data.pretty {
serde_json::to_string_pretty(&response)?
} else {
serde_json::to_string(&response)?
};
println!("PROVISIONING_DATA: {doc}");

Ok(())
Expand Down
16 changes: 7 additions & 9 deletions sw/host/provisioning/orchestrator/src/device_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import struct
from dataclasses import dataclass
from typing import Optional

import util
from sku_config import SkuConfig
Expand Down Expand Up @@ -93,8 +92,7 @@ class DeviceId():
sku_id: A 32-bit string indicating the SKU the chip was provisioned for.
"""

def __init__(self, sku_config: SkuConfig,
din: Optional[DeviceIdentificationNumber]):
def __init__(self, sku_config: SkuConfig, din: DeviceIdentificationNumber):
# Save string keys for easier printing.
self._product = sku_config.product
self._si_creator = sku_config.si_creator
Expand All @@ -117,16 +115,13 @@ def __init__(self, sku_config: SkuConfig,
# - Wafer X coord.
# - Wafer Y coord.
self.din = din
din_as_int = self.din.to_int()

din_as_int = 0
if self.din is not None:
din_as_int = self.din.to_int()

# Build base unique ID.
# Build base unique ID (i.e., CP device ID).
self._base_uid = util.bytes_to_int(
struct.pack("<IQI", self._hw_origin, din_as_int, 0))

# Build SKU specific field.
# Build SKU specific field (i.e., FT device ID).
self.package_id = sku_config.package_id
self.sku_id = util.bytes_to_int(
self.sku.upper()[:4].encode("utf-8")[::-1])
Expand Down Expand Up @@ -226,3 +221,6 @@ def pretty_print(self):

def __str__(self):
return self.to_hexstr()

def __eq__(self, other):
return self.device_id == other.device_id
21 changes: 17 additions & 4 deletions sw/host/provisioning/orchestrator/src/orchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import hjson

import db
from device_id import DeviceId
from device_id import DeviceId, DeviceIdentificationNumber
from ot_dut import OtDut
from sku_config import SkuConfig
from util import confirm, parse_hexstring_to_int, resolve_runfile
Expand Down Expand Up @@ -100,6 +100,11 @@ def main(args_in):
choices=["hyper310", "cw340"],
help="Run flow on FPGA (instead of silicon).",
)
parser.add_argument(
"--fpga-dont-clear-bitstream",
action="store_true",
help="If set, the FPGA bitsream will not be cleared before CP.",
)
parser.add_argument(
"--use-ext-clk",
action="store_true",
Expand Down Expand Up @@ -142,10 +147,10 @@ def main(args_in):

# The device identification number is determined during CP by extracting data
# from the device.
din = None
din = DeviceIdentificationNumber(0)
device_id = DeviceId(sku_config, din)

# TODO: Setup remote and/or local DV connections.
# TODO: Setup remote and/or local DB connections.
# TODO: Check if the device ID is present in the DB.

# Generate commit hash of current provisioning run.
Expand All @@ -161,19 +166,27 @@ def main(args_in):
test_unlock_token=args.test_unlock_token,
test_exit_token=args.test_exit_token,
fpga=args.fpga,
fpga_dont_clear_bitstream=args.fpga_dont_clear_bitstream,
use_ext_clk=args.use_ext_clk,
require_confirmation=not args.non_interactive)
dut.run_cp()
if args.cp_only:
logging.info("FT skipped since --cp-only was provided")
return

dut.run_ft()

# Open the local SQLite registry database.
db_path = Path(args.db_path)
db_handle = db.DB(db.DBConfig(db_path=db_path))
db.DeviceRecord.create_table(db_handle)

# Check device ID exists in the database.
if db.DeviceRecord.query(db_handle, dut.device_id.to_hexstr()) is not None:
logging.warning(
"DeviceId already exists in database. Overwrite record?")
confirm()

# Register the DUT in the database.
device_record = db.DeviceRecord.from_dut(dut)
device_record.upsert(db_handle)
logging.info(f"Added DeviceRecord to database: {device_record}")
Expand Down
Loading
Loading