Skip to content
Open
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
4 changes: 2 additions & 2 deletions sw/device/lib/testing/otp_ctrl_testutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
* OTP the Direct Access Interface (DAI) operation time-out in micro seconds.
*
* It is not possible to predict the specific cycle count that a DAI operation
* takes, thus arbitrary value of 100us is used.
* takes, thus arbitrary value of 10ms is used.
*/
const uint16_t kOtpDaiTimeoutUs = 5000;
const uint16_t kOtpDaiTimeoutUs = 10000;

/**
* Checks whether the DAI operation has finished.
Expand Down
2 changes: 1 addition & 1 deletion sw/device/silicon_creator/manuf/base/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ filegroup(
EXT_SIGNED_PERSO_BINS,
)

_DISQUALIFIED_FOR_SIGNING = ["emulation"]
_DISQUALIFIED_FOR_SIGNING = ["em00"]

[
offline_presigning_artifacts(
Expand Down
12 changes: 6 additions & 6 deletions sw/device/silicon_creator/manuf/base/provisioning_inputs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ load(
# individualization binaries that configure OTP with the constants defined in
# these bazel targets.
EARLGREY_OTP_CFGS = {
"sival": "//hw/top_earlgrey/data/otp/sival_skus:otp_consts",
"emulation": "//hw/top_earlgrey/data/otp/emulation:otp_consts",
"sv00": "//hw/top_earlgrey/data/otp/sival_skus:otp_consts",
"em00": "//hw/top_earlgrey/data/otp/emulation:otp_consts",
} | EXT_EARLGREY_OTP_CFGS

EXT_SIGNED_PERSO_BINS = []
Expand All @@ -24,7 +24,7 @@ EXT_SIGNED_PERSO_BINS = []
EARLGREY_SKUS = {
# OTP Config: Emulation; DICE Certs: X.509; Additional Certs: None
"emulation": {
"otp": "emulation",
"otp": "em00",
"ca_data": "@//sw/device/silicon_creator/manuf/keys/fake:ca_data",
"dice_libs": ["//sw/device/silicon_creator/lib/cert:dice"],
"host_ext_libs": ["@provisioning_exts//:default_ft_ext_lib"],
Expand All @@ -38,7 +38,7 @@ EARLGREY_SKUS = {
},
# OTP Config: Emulation; DICE Certs: CWT; Additional Certs: None
"emulation_dice_cwt": {
"otp": "emulation",
"otp": "em00",
"ca_data": "@//sw/device/silicon_creator/manuf/keys/fake:ca_data",
"dice_libs": ["//sw/device/silicon_creator/lib/cert:dice_cwt"],
"host_ext_libs": ["@provisioning_exts//:default_ft_ext_lib"],
Expand All @@ -54,7 +54,7 @@ EARLGREY_SKUS = {
},
# OTP Config: Emulation; DICE Certs: X.509; Additional Certs: TPM EK
"emulation_tpm": {
"otp": "emulation",
"otp": "em00",
"ca_data": "@//sw/device/silicon_creator/manuf/keys/fake:ca_data",
"dice_libs": ["//sw/device/silicon_creator/lib/cert:dice"],
"host_ext_libs": ["@provisioning_exts//:default_ft_ext_lib"],
Expand All @@ -74,7 +74,7 @@ EARLGREY_SKUS = {
# This configuration is not really usable in master but left here as an example until
# a more appropriate solution is found.
# "sival": {
# "otp": "sival",
# "otp": "sv00",
# "ca_data": "@//sw/device/silicon_creator/manuf/keys/sival:ca_data",
# "dice_libs": ["//sw/device/silicon_creator/lib/cert:dice"],
# "host_ext_libs": ["@provisioning_exts//:default_ft_ext_lib"],
Expand Down
2 changes: 1 addition & 1 deletion sw/device/silicon_creator/manuf/lib/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ opentitan_test(
deps = [
":flash_info_fields",
# Testing sival SKU only should be sufficient.
":individualize_sw_cfg_emulation",
":individualize_sw_cfg_em00",
"//hw/top:otp_ctrl_c_regs",
"//hw/top_earlgrey/sw/autogen:top_earlgrey",
"//sw/device/lib/base:status",
Expand Down
2 changes: 1 addition & 1 deletion sw/device/silicon_creator/manuf/tests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ opentitan_binary(
"//sw/device/lib/testing/test_framework:ottf_test_config",
"//sw/device/lib/testing/test_framework:status",
"//sw/device/silicon_creator/manuf/lib:flash_info_fields",
"//sw/device/silicon_creator/manuf/lib:individualize_sw_cfg_sival",
"//sw/device/silicon_creator/manuf/lib:individualize_sw_cfg_sv00",
"//sw/device/silicon_creator/manuf/lib:sram_start",
],
)
Expand Down
2 changes: 1 addition & 1 deletion sw/device/tests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -2517,7 +2517,7 @@ opentitan_binary(
"//sw/device/lib/testing/test_framework:ottf_test_config",
"//sw/device/lib/testing/test_framework:status",
"//sw/device/silicon_creator/manuf/lib:individualize",
"//sw/device/silicon_creator/manuf/lib:individualize_sw_cfg_sival",
"//sw/device/silicon_creator/manuf/lib:individualize_sw_cfg_sv00",
"//sw/device/silicon_creator/manuf/lib:otp_fields",
"//sw/device/silicon_creator/manuf/lib:sram_start",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
si_creator: "nuvoton",
package: "npcr10",
target_lc_state: "prod",
otp: "emulation",
otp: "em00",
perso_bin: "sw/device/silicon_creator/manuf/base/ft_personalize_{sku}_{target}.prod_key_0.prod_key_0.signed.bin",
owner_fw_boot_str: "Bare metal PASS!"
dice_ca: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
si_creator: "nuvoton",
package: "npcr10",
target_lc_state: "prod",
otp: "emulation",
otp: "em00",
perso_bin: "sw/device/silicon_creator/manuf/base/ft_personalize_{sku}_{target}.prod_key_0.prod_key_0.signed.bin",
owner_fw_boot_str: "Bare metal PASS!",
dice_ca: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
si_creator: "nuvoton",
package: "npcr10",
target_lc_state: "prod",
otp: "emulation",
otp: "em00",
perso_bin: "sw/device/silicon_creator/manuf/base/ft_personalize_{sku}_{target}.prod_key_0.prod_key_0.signed.bin",
owner_fw_boot_str: "Bare metal PASS!"
dice_ca: {
Expand Down
2 changes: 1 addition & 1 deletion sw/host/provisioning/orchestrator/configs/skus/sival.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
si_creator: "nuvoton",
package: "npcr10",
target_lc_state: "prod",
otp: "sival",
otp: "sv00",
perso_bin: "sw/device/silicon_creator/manuf/base/binaries/ft_personalize_{sku}_{target}.signed.bin",
# owner_fw_boot_str: "Bare metal PASS!"
dice_ca: {
Expand Down
83 changes: 60 additions & 23 deletions sw/host/provisioning/orchestrator/src/device_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@
import util
from sku_config import SkuConfig

_RESERVED_WORD = 0
_RESERVED_VALUE = 0

# This defines the format of the "sku_specific" portion of the device ID. This
# should be updated everytime the the "sku_specific" portion of the device ID is
# updated.
_SKU_SPECIFIC_FORMAT_VERSION = 1


@dataclass
Expand Down Expand Up @@ -123,15 +128,26 @@ def __init__(self, sku_config: SkuConfig, din: DeviceIdentificationNumber):

# Build SKU specific field (i.e., FT device ID).
self.package_id = sku_config.package_id
self.ast_cfg_version = sku_config.ast_cfg_version
self.otp_id = util.bytes_to_int(
sku_config.otp.upper()[0:2].encode("utf-8")[::-1])
self.otp_version = sku_config.otp_version
self.sku_id = util.bytes_to_int(
self.sku.upper()[:4].encode("utf-8")[::-1])
self.sku_specific_version = _SKU_SPECIFIC_FORMAT_VERSION
self.sku_specific = util.bytes_to_int(
struct.pack(
"<HHIQ",
"<BBHBBHIHBB",
self.package_id,
_RESERVED_WORD,
self.ast_cfg_version,
self.otp_id,
self.otp_version,
_RESERVED_VALUE,
_RESERVED_VALUE,
self.sku_id,
_RESERVED_WORD,
_RESERVED_VALUE,
_RESERVED_VALUE,
self.sku_specific_version,
))

# Build full device ID.
Expand Down Expand Up @@ -161,11 +177,6 @@ def from_hexstr(hexstr: str) -> "DeviceId":
@staticmethod
def from_int(device_id: int) -> "DeviceId":
"""Creates a DeviceId object from an int."""
# Extract SKU specific field.
sku_specific = device_id >> 128
package_id = sku_specific & 0xFFFF
sku_id = (sku_specific >> 32) & 0xFFFFFFFF

# Extract base unique ID.
mask = (1 << 128) - 1
base_uid = device_id & mask
Expand All @@ -174,9 +185,27 @@ def from_int(device_id: int) -> "DeviceId":
si_creator_id = hw_origin & 0xFFFF
product_id = (hw_origin >> 16) & 0xFFFF

# Extract SKU specific field.
sku_specific = device_id >> 128
package_id = sku_specific & 0xFF
ast_cfg_version = (sku_specific >> 8) & 0xFF
otp_id = (sku_specific >> 16) & 0xFFFF
otp_version = (sku_specific >> 32) & 0xFF
sku_id = (sku_specific >> 64) & 0xFFFFFFFF

# Unpack OTP name.
try:
otp = (struct.pack('>H', otp_id).decode('ascii') +
f"{otp_version:02x}")
except UnicodeDecodeError:
otp = "Invalid"
print("HERE", otp)

# Extract SKU config.
sku_config = SkuConfig.from_ids(product_id, si_creator_id, package_id)
sku_config = SkuConfig.from_ids(product_id, si_creator_id, package_id,
otp, ast_cfg_version)

# Unpack SKU name.
try:
sku_name = struct.pack('>I', sku_id).decode('ascii')
except UnicodeDecodeError:
Expand All @@ -198,26 +227,34 @@ def to_int(self) -> int:
return self.device_id

def pretty_print(self):
print("> Device ID: {}".format(self))
print("SiliconCreator ID: {} ({})".format(
print("> Device ID: {}".format(self))
print("SiliconCreator ID: {} ({})".format(
util.format_hex(self.si_creator_id, width=4), self._si_creator))
print("Product ID: {} ({})".format(
print("Product ID: {} ({})".format(
util.format_hex(self.product_id, width=4), self._product))
if self.din is not None:
print("DIN Year: {}".format(self.din.year))
print("DIN Week: {}".format(self.din.week))
print("DIN Lot: {}".format(self.din.lot))
print("DIN Wafer: {}".format(self.din.wafer))
print("DIN Wafer X Coord: {}".format(self.din.wafer_x_coord))
print("DIN Wafer Y Coord: {}".format(self.din.wafer_y_coord))
print("DIN Year: {}".format(self.din.year))
print("DIN Week: {}".format(self.din.week))
print("DIN Lot: {}".format(self.din.lot))
print("DIN Wafer: {}".format(self.din.wafer))
print("DIN Wafer X Coord: {}".format(self.din.wafer_x_coord))
print("DIN Wafer Y Coord: {}".format(self.din.wafer_y_coord))
else:
print("DIN: <unset>")
print("Reserved: {}".format(hex(0)))
print("SKU ID: {} ({})".format(
print("Reserved (40 bits): {}".format(hex(_RESERVED_VALUE)))
print("Package ID: {} ({})".format(self.package_id,
self._package))
print("AST Config Version: {}".format(self.ast_cfg_version))
print("OTP ID: {} ({})".format(
hex(self.otp_id),
self.otp_id.to_bytes(length=4, byteorder="big").decode("utf-8")))
print("OTP Version: {}".format(self.otp_version))
print("Reserved (24 bits): {}".format(hex(_RESERVED_VALUE)))
print("SKU ID: {} ({})".format(
util.format_hex(self.sku_id),
self.sku_id.to_bytes(length=4, byteorder="big").decode("utf-8")))
print("Package ID: {} ({})".format(self.package_id,
self._package))
print("Reserved (24 bits): {}".format(hex(_RESERVED_VALUE)))
print("SKU Specific Version: {}".format(self.sku_specific_version))

def __str__(self):
return self.to_hexstr()
Expand Down
20 changes: 19 additions & 1 deletion sw/host/provisioning/orchestrator/src/orchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ def main(args_in):
type=str,
help="SKU HJSON configuration file.",
)
parser.add_argument(
"--ast-cfg-version",
required=True,
type=int,
help="AST configuration version to be written to OTP.",
)
parser.add_argument(
"--package",
type=str,
help="Override of package string that is in the SKU config.",
)
parser.add_argument(
"--test-unlock-token",
required=True,
Expand Down Expand Up @@ -149,7 +160,14 @@ def main(args_in):
sku_config_args = {}
with open(sku_config_path, "r") as fp:
sku_config_args = hjson.load(fp)
sku_config = SkuConfig(**sku_config_args)
sku_config = SkuConfig(ast_cfg_version=args.ast_cfg_version,
**sku_config_args)

# Override package ID if requested.
if args.package:
sku_config.package = args.package
sku_config.validate()
sku_config.load_hw_ids()

# The device identification number is determined during CP by extracting data
# from the device.
Expand Down
51 changes: 37 additions & 14 deletions sw/host/provisioning/orchestrator/src/sku_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ class SkuConfig:
si_creator: Optional[str] # valid: any SiliconCreator that exists in product database
package: Optional[str] # valid: any package that exists in package database
target_lc_state: str # valid: must be in ["dev", "prod", "prod_end"]
otp: str # valid: any string
otp: str # valid: any 4 char string whose first char is alphabetic and last two are numeric
ast_cfg_version: int # valid: any positive integer < 256 (to fit in one byte)
perso_bin: str # valid: any string
token_encrypt_key: str
token_encrypt_key: str # valid: any file path that exists
dice_ca: Optional[OrderedDict] # valid: see CaConfig
ext_ca: Optional[OrderedDict] = None # valid: see CaConfig
owner_fw_boot_str: str = None # valid: any string
Expand All @@ -53,22 +54,17 @@ def __post_init__(self):
# Validate inputs.
self.validate()

# Set product, SiliconCreator, and package IDs.
self.si_creator_id = int(
self._product_ids["si_creator_ids"][self.si_creator], 16)
self.product_id = int(self._product_ids["product_ids"][self.product],
16)

if self.package in self._package_ids:
self.package_id = int(self._package_ids[self.package], 16)
# Load HW IDs.
self.load_hw_ids()

# Resolve LC token encryption key path.
if self.token_encrypt_key:
self.token_encrypt_key = resolve_runfile(self.token_encrypt_key)

@staticmethod
def from_ids(product_id: int, si_creator_id: int,
package_id: int) -> "SkuConfig":
"""Creates a SKU configuration object from product, SiliconCreator, and package IDs."""
def from_ids(product_id: int, si_creator_id: int, package_id: int,
otp: str, ast_cfg_version: int) -> "SkuConfig":
"""Creates a SKU configuration object from various subcomponent IDs."""
# Load product IDs database.
product_ids_hjson = resolve_runfile(_PRODUCT_IDS_HJSON)
product_ids = None
Expand Down Expand Up @@ -102,7 +98,8 @@ def from_ids(product_id: int, si_creator_id: int,
si_creator=si_creator,
package=package,
target_lc_state="dev",
otp="",
otp=otp,
ast_cfg_version=ast_cfg_version,
perso_bin="",
dice_ca=OrderedDict(),
ext_ca=OrderedDict(),
Expand Down Expand Up @@ -131,3 +128,29 @@ def validate(self) -> None:
raise ValueError(
"Target LC state ({}) must be in [\"dev\", \"prod\", \"prod_end\"]"
.format(self.target_lc_state))
# Validate AST configuration version.
if self.ast_cfg_version < 0 or self.ast_cfg_version > 255:
raise ValueError("AST config version should be in range [0, 256).")
# Validate OTP string.
if len(self.otp) != 4:
raise ValueError("OTP must be a non-empty 4 character string.")
# Validate OTP ID string.
if not self.otp[0].isalpha() or not self.otp[1].isalpha():
raise ValueError(
"First two chars of OTP string must be alphabetic.")
# Validate OTP version.
try:
_ = int(self.otp[2:], 16)
except ValueError:
raise ValueError("OTP version should two digit hexstring.")

def load_hw_ids(self) -> None:
"""Sets product, SiliconCreator, and package IDs."""
self.si_creator_id = int(
self._product_ids["si_creator_ids"][self.si_creator], 16)
self.product_id = int(self._product_ids["product_ids"][self.product],
16)
self.package_id = int(self._package_ids[self.package], 16)
# We process the OTP str into a two character ID and version number.
self.otp_id = self.otp[:2]
self.otp_version = int(self.otp[2:], 16)
Loading
Loading