From de62d606fdce46a344529dad079372b421266538 Mon Sep 17 00:00:00 2001 From: Tim Trippel Date: Fri, 22 Nov 2024 22:57:15 -0800 Subject: [PATCH] [manuf] refactor CP init to read out wafer data and device ID When CP init runs, flash info page 0 will already be provisioned with wafer data from prior CP stages. This updates the CP init and subsequent FT provisioning stages to assume that is the case and pull appropriate data out of this flash info page accordingly. This fixes #24600. Signed-off-by: Tim Trippel --- .../lib/testing/json/provisioning_data.h | 29 ++- sw/device/silicon_creator/manuf/base/BUILD | 3 +- .../manuf/base/provisioning_inputs.bzl | 9 +- .../manuf/base/sram_cp_provision.c | 189 ++++++++++-------- .../manuf/base/sram_cp_provision_functest.c | 119 ++++++----- .../manuf/base/sram_ft_individualize.c | 15 +- sw/device/silicon_creator/manuf/lib/BUILD | 2 + .../manuf/lib/flash_info_fields.c | 54 +++-- .../manuf/lib/flash_info_fields.h | 61 +++++- .../silicon_creator/manuf/lib/individualize.c | 50 ++--- .../manuf/lib/individualize_functest.c | 53 ++++- .../silicon_creator/manuf/lib/personalize.c | 8 +- .../flash_device_info_flash_wr_functest.c | 9 +- .../sram_device_info_flash_wr_functest.c | 2 +- .../manuf/tests/test_wafer_auth_secret.h | 2 +- sw/host/opentitanlib/src/debug/openocd.rs | 1 - sw/host/provisioning/cp/BUILD | 1 + sw/host/provisioning/cp/src/main.rs | 10 +- sw/host/provisioning/cp_lib/src/lib.rs | 35 ++-- .../tests/manuf/cp_provision_functest/BUILD | 1 + .../manuf/cp_provision_functest/src/main.rs | 117 ++++++++--- 21 files changed, 513 insertions(+), 257 deletions(-) diff --git a/sw/device/lib/testing/json/provisioning_data.h b/sw/device/lib/testing/json/provisioning_data.h index 530cad56a8e28..cb6fa41b13c3c 100644 --- a/sw/device/lib/testing/json/provisioning_data.h +++ b/sw/device/lib/testing/json/provisioning_data.h @@ -14,12 +14,10 @@ extern "C" { #define MODULE_ID MAKE_MODULE_ID('j', 'p', 'd') /** - * Provisioning data imported onto the device in CP. + * Provisioning data imported onto the device during CP. */ // clang-format off #define STRUCT_MANUF_CP_PROVISIONING_DATA(field, string) \ - field(device_id, uint32_t, 8) \ - field(manuf_state, uint32_t, 8) \ field(wafer_auth_secret, uint32_t, 8) \ field(test_unlock_token_hash, uint64_t, 2) \ field(test_exit_token_hash, uint64_t, 2) @@ -28,6 +26,31 @@ UJSON_SERDE_STRUCT(ManufCpProvisioningData, \ STRUCT_MANUF_CP_PROVISIONING_DATA); // clang-format on +/** + * Provisioning data exported off the device during CP. + */ +// clang-format off +#define STRUCT_MANUF_CP_PROVISIONING_DATA_OUT(field, string) \ + field(cp_device_id, uint32_t, 4) +UJSON_SERDE_STRUCT(ManufCpProvisioningDataOut, \ + manuf_cp_provisioning_data_out_t, \ + STRUCT_MANUF_CP_PROVISIONING_DATA_OUT); +// clang-format on + +/** + * Test factory data imported onto the device prior to CP initialize stage. + */ +// clang-format off +#define STRUCT_MANUF_CP_TEST_DATA(field, string) \ + field(lot_name, uint32_t) \ + field(wafer_number, uint32_t) \ + field(wafer_x_coord, uint32_t) \ + field(wafer_y_coord, uint32_t) +UJSON_SERDE_STRUCT(ManufCpTestData, \ + manuf_cp_test_data_t, \ + STRUCT_MANUF_CP_TEST_DATA); +// clang-format on + /** * Provisioning data imported onto the device in FT during individualization. */ diff --git a/sw/device/silicon_creator/manuf/base/BUILD b/sw/device/silicon_creator/manuf/base/BUILD index c5b3d5c826513..26ad9bd506c62 100644 --- a/sw/device/silicon_creator/manuf/base/BUILD +++ b/sw/device/silicon_creator/manuf/base/BUILD @@ -72,7 +72,6 @@ opentitan_binary( "//sw/device/lib/testing/test_framework:ottf_test_config", "//sw/device/lib/testing/test_framework:status", "//sw/device/lib/testing/test_framework:ujson_ottf", - "//sw/device/silicon_creator/manuf/data/ast:fake", "//sw/device/silicon_creator/manuf/lib:flash_info_fields", "//sw/device/silicon_creator/manuf/lib:individualize", "//sw/device/silicon_creator/manuf/lib:otp_fields", @@ -169,7 +168,7 @@ opentitan_test( test_cmd = """ --provisioning-sram-elf={sram_cp_provision} --test-sram-elf={sram_cp_provision_functest} - """ + CP_PROVISIONING_INPUTS, + """, test_harness = "//sw/host/tests/manuf/cp_provision_functest", ), ) diff --git a/sw/device/silicon_creator/manuf/base/provisioning_inputs.bzl b/sw/device/silicon_creator/manuf/base/provisioning_inputs.bzl index 6b43499dec677..0d63cc58a3d2e 100644 --- a/sw/device/silicon_creator/manuf/base/provisioning_inputs.bzl +++ b/sw/device/silicon_creator/manuf/base/provisioning_inputs.bzl @@ -58,18 +58,17 @@ EARLGREY_SKUS = { }, } | EXT_EARLGREY_SKUS -_DEVICE_ID_AND_TEST_TOKENS = """ - --device-id="0x11111111_22222222_33333333_44444444_55555555_66666666_77777777_88888888" +_TEST_TOKENS = """ --test-unlock-token="0x11111111_11111111_11111111_11111111" --test-exit-token="0x11111111_11111111_11111111_11111111" """ -CP_PROVISIONING_INPUTS = _DEVICE_ID_AND_TEST_TOKENS + """ - --manuf-state="0x00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000" +CP_PROVISIONING_INPUTS = _TEST_TOKENS + """ --wafer-auth-secret="0x00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000" """ -FT_PROVISIONING_INPUTS = _DEVICE_ID_AND_TEST_TOKENS + """ +FT_PROVISIONING_INPUTS = _TEST_TOKENS + """ + --device-id="0x11111111_22222222_33333333_44444444_55555555_66666666_77777777_88888888" --target-mission-mode-lc-state="prod" --rma-unlock-token="0x01234567_89abcdef_01234567_89abcdef" --rom-ext-measurement="0x11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111" diff --git a/sw/device/silicon_creator/manuf/base/sram_cp_provision.c b/sw/device/silicon_creator/manuf/base/sram_cp_provision.c index ce5cb203a3057..7fd698bf1926e 100644 --- a/sw/device/silicon_creator/manuf/base/sram_cp_provision.c +++ b/sw/device/silicon_creator/manuf/base/sram_cp_provision.c @@ -21,7 +21,6 @@ #include "sw/device/lib/testing/test_framework/ottf_test_config.h" #include "sw/device/lib/testing/test_framework/ujson_ottf.h" #include "sw/device/silicon_creator/manuf/base/flash_info_permissions.h" -#include "sw/device/silicon_creator/manuf/data/ast/calibration_values.h" #include "sw/device/silicon_creator/manuf/lib/flash_info_fields.h" #include "sw/device/silicon_creator/manuf/lib/individualize.h" #include "sw/device/silicon_creator/manuf/lib/otp_fields.h" @@ -38,6 +37,8 @@ static dif_pinmux_t pinmux; static dif_flash_ctrl_state_t flash_ctrl_state; static dif_lc_ctrl_t lc_ctrl; +static uint32_t ast_cfg_data[kFlashInfoAstCalibrationDataSizeIn32BitWords]; + /** * Initializes all DIF handles used in this SRAM program. */ @@ -61,99 +62,106 @@ static void manually_init_ast(uint32_t *data) { } } -static status_t flash_info_page_0_erase(void) { - uint32_t byte_address = 0; - // DeviceId and ManufState are located on the same flash info page. - TRY(flash_ctrl_testutils_info_region_setup_properties( - &flash_ctrl_state, kFlashInfoFieldDeviceId.page, - kFlashInfoFieldDeviceId.bank, kFlashInfoFieldDeviceId.partition, - kFlashInfoPage0Permissions, &byte_address)); - TRY(flash_ctrl_testutils_erase_page(&flash_ctrl_state, byte_address, - kFlashInfoFieldDeviceId.partition, - kDifFlashCtrlPartitionTypeInfo)); - return OK_STATUS(); -} - -static status_t flash_info_page_0_write( - manuf_cp_provisioning_data_t *provisioning_data) { - uint32_t byte_address = 0; +static status_t flash_info_page_0_read_and_validate( + manuf_cp_provisioning_data_out_t *console_out) { TRY(flash_ctrl_testutils_info_region_setup_properties( - &flash_ctrl_state, kFlashInfoFieldDeviceId.page, - kFlashInfoFieldDeviceId.bank, kFlashInfoFieldDeviceId.partition, - kFlashInfoPage0Permissions, &byte_address)); - - // Write DeviceId. - TRY(flash_ctrl_testutils_write( - &flash_ctrl_state, byte_address, kFlashInfoFieldDeviceId.partition, - provisioning_data->device_id, kDifFlashCtrlPartitionTypeInfo, - kHwCfgDeviceIdSizeIn32BitWords)); - - // Write ManufState (on same page as DeviceId). - TRY(flash_ctrl_testutils_write( - &flash_ctrl_state, byte_address + kFlashInfoFieldManufState.byte_offset, - kFlashInfoFieldManufState.partition, provisioning_data->manuf_state, - kDifFlashCtrlPartitionTypeInfo, kHwCfgManufStateSizeIn32BitWords)); - - // Write AST calibration values (on same page as DeviceId). - TRY(flash_ctrl_testutils_write( - &flash_ctrl_state, - byte_address + kFlashInfoFieldAstCalibrationData.byte_offset, - kFlashInfoFieldAstCalibrationData.partition, ast_cfg_data, - kDifFlashCtrlPartitionTypeInfo, + &flash_ctrl_state, kFlashInfoFieldCpDeviceId.page, + kFlashInfoFieldCpDeviceId.bank, kFlashInfoFieldCpDeviceId.partition, + kFlashInfoPage0Permissions, /*offset=*/NULL)); + + // Read (wafer) lot name. + uint32_t lot_name = 0; + static_assert(kFlashInfoFieldLotNameSizeIn32BitWords == 1, + "Lot name should fit in <32bits."); + TRY(manuf_flash_info_field_read(&flash_ctrl_state, kFlashInfoFieldLotName, + &lot_name, + kFlashInfoFieldLotNameSizeIn32BitWords)); + + // Read wafer number. + uint32_t wafer_number = 0; + static_assert(kFlashInfoFieldWaferNumberSizeIn32BitWords == 1, + "Wafer number should fit in <32bits."); + TRY(manuf_flash_info_field_read(&flash_ctrl_state, kFlashInfoFieldWaferNumber, + &wafer_number, + kFlashInfoFieldWaferNumberSizeIn32BitWords)); + + // Read wafer X coord. + uint32_t wafer_x_coord = 0; + static_assert(kFlashInfoFieldWaferXCoordSizeIn32BitWords == 1, + "Wafer X coordinate value should fit in <32bits."); + TRY(manuf_flash_info_field_read(&flash_ctrl_state, kFlashInfoFieldWaferXCoord, + &wafer_x_coord, + kFlashInfoFieldWaferXCoordSizeIn32BitWords)); + + // Read wafer Y coord. + uint32_t wafer_y_coord = 0; + static_assert(kFlashInfoFieldWaferYCoordSizeIn32BitWords == 1, + "Wafer Y coordinate value should fit in <32bits."); + TRY(manuf_flash_info_field_read(&flash_ctrl_state, kFlashInfoFieldWaferYCoord, + &wafer_y_coord, + kFlashInfoFieldWaferYCoordSizeIn32BitWords)); + + // Read AST calibration values into RAM. + TRY(manuf_flash_info_field_read( + &flash_ctrl_state, kFlashInfoFieldAstCalibrationData, ast_cfg_data, kFlashInfoAstCalibrationDataSizeIn32BitWords)); - return OK_STATUS(); -} + // Encode CP device ID. + // HW origin portion of CP device. + // "0x00024001" encodes: + // - a SiliconCreator ID of "0x4001" for "Nuvoton", and + // - a Product ID of "0x0002" for Earlgrey A1 silicon. + console_out->cp_device_id[0] = 0x00024001u; + // Device Identification Number portion of CP device ID. + uint32_t year = (lot_name >> 24) & 0xf; + uint32_t week = (lot_name >> 16) & 0xff; + uint32_t lot_number = lot_name & 0xfff; + console_out->cp_device_id[1] = + (wafer_number << 24) | (lot_number << 12) | (week << 4) | year; + console_out->cp_device_id[2] = (wafer_y_coord << 12) | wafer_x_coord; + // Reserved word; set to 0. + console_out->cp_device_id[3] = 0; + + // Write CP device ID. + TRY(manuf_flash_info_field_write(&flash_ctrl_state, kFlashInfoFieldCpDeviceId, + console_out->cp_device_id, + kFlashInfoFieldCpDeviceIdSizeIn32BitWords, + /*erase_page_before_write=*/false)); -static status_t wafer_auth_secret_flash_info_page_erase(void) { - uint32_t byte_address = 0; - TRY(flash_ctrl_testutils_info_region_setup_properties( - &flash_ctrl_state, kFlashInfoFieldWaferAuthSecret.page, - kFlashInfoFieldWaferAuthSecret.bank, - kFlashInfoFieldWaferAuthSecret.partition, kFlashInfoPage3WritePermissions, - &byte_address)); - TRY(flash_ctrl_testutils_erase_page(&flash_ctrl_state, byte_address, - kFlashInfoFieldWaferAuthSecret.partition, - kDifFlashCtrlPartitionTypeInfo)); return OK_STATUS(); } static status_t wafer_auth_secret_flash_info_page_write( - manuf_cp_provisioning_data_t *provisioning_data) { + manuf_cp_provisioning_data_t *console_in) { uint32_t byte_address = 0; TRY(flash_ctrl_testutils_info_region_setup_properties( &flash_ctrl_state, kFlashInfoFieldWaferAuthSecret.page, kFlashInfoFieldWaferAuthSecret.bank, kFlashInfoFieldWaferAuthSecret.partition, kFlashInfoPage3WritePermissions, &byte_address)); - TRY(flash_ctrl_testutils_write( - &flash_ctrl_state, byte_address, kFlashInfoFieldWaferAuthSecret.partition, - provisioning_data->manuf_state, kDifFlashCtrlPartitionTypeInfo, - kFlashInfoWaferAuthSecretSizeIn32BitWords)); + TRY(manuf_flash_info_field_write( + &flash_ctrl_state, kFlashInfoFieldWaferAuthSecret, + console_in->wafer_auth_secret, + kFlashInfoFieldWaferAuthSecretSizeIn32BitWords, + /*erase_page_before_write=*/true)); return OK_STATUS(); } static status_t print_inputs_to_console( - manuf_cp_provisioning_data_t *provisioning_data) { + manuf_cp_provisioning_data_t *console_in) { uint32_t high; uint32_t low; - LOG_INFO("Device ID:"); - for (size_t i = 0; i < kHwCfgDeviceIdSizeIn32BitWords; ++i) { - LOG_INFO("0x%08x", provisioning_data->device_id[i]); - } LOG_INFO("Test Unlock Token Hash:"); - for (size_t i = 0; i < ARRAYSIZE(provisioning_data->test_unlock_token_hash); - ++i) { - high = provisioning_data->test_unlock_token_hash[i] >> 32; - low = provisioning_data->test_unlock_token_hash[i] & 0xffffffff; + for (size_t i = 0; i < ARRAYSIZE(console_in->test_unlock_token_hash); ++i) { + high = console_in->test_unlock_token_hash[i] >> 32; + low = console_in->test_unlock_token_hash[i] & 0xffffffff; LOG_INFO("0x%08x%08x", high, low); } LOG_INFO("Test Exit Token Hash:"); - for (size_t i = 0; i < ARRAYSIZE(provisioning_data->test_exit_token_hash); - ++i) { - high = provisioning_data->test_exit_token_hash[i] >> 32; - low = provisioning_data->test_exit_token_hash[i] & 0xffffffff; + for (size_t i = 0; i < ARRAYSIZE(console_in->test_exit_token_hash); ++i) { + high = console_in->test_exit_token_hash[i] >> 32; + low = console_in->test_exit_token_hash[i] & 0xffffffff; LOG_INFO("0x%08x%08x", high, low); } return OK_STATUS(); @@ -162,33 +170,46 @@ static status_t print_inputs_to_console( /** * Provision flash info pages 0 and 3, and OTP Secret0 partition. */ -static status_t provision(ujson_t *uj) { +static status_t provision(ujson_t *uj, + manuf_cp_provisioning_data_out_t *console_out) { + // Wait for input console data. LOG_INFO("Waiting for CP provisioning data ..."); - manuf_cp_provisioning_data_t provisioning_data; - TRY(ujson_deserialize_manuf_cp_provisioning_data_t(uj, &provisioning_data)); - TRY(print_inputs_to_console(&provisioning_data)); - TRY(flash_ctrl_testutils_wait_for_init(&flash_ctrl_state)); - TRY(flash_info_page_0_erase()); - TRY(wafer_auth_secret_flash_info_page_erase()); - TRY(flash_info_page_0_write(&provisioning_data)); - TRY(wafer_auth_secret_flash_info_page_write(&provisioning_data)); - TRY(manuf_individualize_device_secret0(&lc_ctrl, &otp_ctrl, - &provisioning_data)); - LOG_INFO("CP provisioning done."); + manuf_cp_provisioning_data_t console_in; + TRY(ujson_deserialize_manuf_cp_provisioning_data_t(uj, &console_in)); + TRY(print_inputs_to_console(&console_in)); + + // Provision flash info page 3 (wafer authentication secret). + TRY(wafer_auth_secret_flash_info_page_write(&console_in)); + + // Burn test tokens into OTP. + TRY(manuf_individualize_device_secret0(&lc_ctrl, &otp_ctrl, &console_in)); + + // Send data back to host. + LOG_INFO("Exporting CP device ID ..."); + RESP_OK(ujson_serialize_manuf_cp_provisioning_data_out_t, uj, console_out); + return OK_STATUS(); } bool test_main(void) { - // Initialize AST, DIF handles, pinmux, and UART. - manually_init_ast(ast_cfg_data); + // Initialize DIF handles, pinmux, and console. CHECK_STATUS_OK(peripheral_handles_init()); pinmux_testutils_init(&pinmux); ottf_console_init(); ujson_t uj = ujson_ottf_console(); + + // Extract factory data from flash info page 0. + manuf_cp_provisioning_data_out_t console_out; + CHECK_STATUS_OK(flash_ctrl_testutils_wait_for_init(&flash_ctrl_state)); + CHECK_STATUS_OK(flash_info_page_0_read_and_validate(&console_out)); + + // Initialize AST. + manually_init_ast(ast_cfg_data); LOG_INFO("AST manually configured."); // Perform CP provisioning operations. - CHECK_STATUS_OK(provision(&uj)); + CHECK_STATUS_OK(provision(&uj, &console_out)); + LOG_INFO("CP provisioning done."); return true; } diff --git a/sw/device/silicon_creator/manuf/base/sram_cp_provision_functest.c b/sw/device/silicon_creator/manuf/base/sram_cp_provision_functest.c index 2a1e13fdc08cc..24f6ea19b9510 100644 --- a/sw/device/silicon_creator/manuf/base/sram_cp_provision_functest.c +++ b/sw/device/silicon_creator/manuf/base/sram_cp_provision_functest.c @@ -52,66 +52,93 @@ static status_t peripheral_handles_init(void) { return OK_STATUS(); } -static status_t check_device_id_and_manuf_state( - manuf_cp_provisioning_data_t *expected_data) { - LOG_INFO("Checking expected DeviceId and ManufState data ..."); - // Configure flash info page 0 permissions. +/** + * Writes test data to flash info page 0 so the sram_cp_provision.c program can + * read it out. + */ +static status_t prep_flash_info_page_0(manuf_cp_test_data_t *test_data) { + // Setup page permissions on flash info page 0. uint32_t byte_address = 0; - uint32_t actual_device_id[kHwCfgDeviceIdSizeIn32BitWords] = {0}; - uint32_t actual_manuf_state[kHwCfgManufStateSizeIn32BitWords] = {0}; TRY(flash_ctrl_testutils_info_region_setup_properties( - &flash_ctrl_state, kFlashInfoFieldDeviceId.page, - kFlashInfoFieldDeviceId.bank, kFlashInfoFieldDeviceId.partition, + &flash_ctrl_state, kFlashInfoFieldCpDeviceId.page, + kFlashInfoFieldCpDeviceId.bank, kFlashInfoFieldCpDeviceId.partition, kFlashInfoPage0Permissions, &byte_address)); - // Read and check device_id. - TRY(flash_ctrl_testutils_read( - &flash_ctrl_state, byte_address, kFlashInfoFieldDeviceId.partition, - actual_device_id, kDifFlashCtrlPartitionTypeInfo, - kHwCfgDeviceIdSizeIn32BitWords, - /*delay_micros=*/0)); - CHECK_ARRAYS_EQ(actual_device_id, expected_data->device_id, - kHwCfgDeviceIdSizeIn32BitWords); - - // Read and check manuf_state (on same page as device_id). - TRY(flash_ctrl_testutils_read( - &flash_ctrl_state, byte_address + kFlashInfoFieldManufState.byte_offset, - kFlashInfoFieldManufState.partition, actual_manuf_state, - kDifFlashCtrlPartitionTypeInfo, kHwCfgManufStateSizeIn32BitWords, - /*delay_micros=*/0)); - CHECK_ARRAYS_EQ(actual_manuf_state, expected_data->manuf_state, - kHwCfgManufStateSizeIn32BitWords); + // Lot name. + TRY(manuf_flash_info_field_write(&flash_ctrl_state, kFlashInfoFieldLotName, + &test_data->lot_name, + kFlashInfoFieldLotNameSizeIn32BitWords, + /*erase_page_before_write=*/true)); + + // Wafer number. + TRY(manuf_flash_info_field_write( + &flash_ctrl_state, kFlashInfoFieldWaferNumber, &test_data->wafer_number, + kFlashInfoFieldWaferNumberSizeIn32BitWords, + /*erase_page_before_write=*/false)); + + // Wafer X coord. + TRY(manuf_flash_info_field_write( + &flash_ctrl_state, kFlashInfoFieldWaferXCoord, &test_data->wafer_x_coord, + kFlashInfoFieldWaferXCoordSizeIn32BitWords, + /*erase_page_before_write=*/false)); + + // Wafer Y coord. + TRY(manuf_flash_info_field_write( + &flash_ctrl_state, kFlashInfoFieldWaferYCoord, &test_data->wafer_y_coord, + kFlashInfoFieldWaferYCoordSizeIn32BitWords, + /*erase_page_before_write=*/false)); return OK_STATUS(); } bool test_main(void) { + // Initialize peripherals, pinmux, and console. CHECK_STATUS_OK(peripheral_handles_init()); pinmux_testutils_init(&pinmux); ottf_console_init(); ujson_t uj = ujson_ottf_console(); - // Check we are in in TEST_UNLOCKED1. - CHECK_STATUS_OK( - lc_ctrl_testutils_check_lc_state(&lc_ctrl, kDifLcCtrlStateTestUnlocked1)); - - LOG_INFO("Waiting for expected CP provisioning data ..."); - - // Get expected provisioning data over console. - manuf_cp_provisioning_data_t expected_data; - CHECK_STATUS_OK( - ujson_deserialize_manuf_cp_provisioning_data_t(&uj, &expected_data)); - - // Read and check device_id and manuf_state fields from flash info page 0. - CHECK_STATUS_OK(check_device_id_and_manuf_state(&expected_data)); - - // Note: we cannot read/check the wafer_auth_secret field in flash info page - // 3, as this page is not readable in the TEST_UNLOCKED* states. - - // Check the secret0 partition has been provisioned / locked. - CHECK_STATUS_OK(manuf_individualize_device_secret0_check(&otp_ctrl)); - - LOG_INFO("Checks complete. Success"); + // Get LC state. + dif_lc_ctrl_state_t lc_state; + CHECK_DIF_OK(dif_lc_ctrl_get_state(&lc_ctrl, &lc_state)); + + // Get CP test data over console. + LOG_INFO("Waiting for CP test data ..."); + manuf_cp_test_data_t test_data; + CHECK_STATUS_OK(ujson_deserialize_manuf_cp_test_data_t(&uj, &test_data)); + + if (lc_state == kDifLcCtrlStateTestUnlocked0) { + // Write test data to flash info page 0. + CHECK_STATUS_OK(prep_flash_info_page_0(&test_data)); + LOG_INFO("Flash info page 0 programmed."); + } else if (lc_state == kDifLcCtrlStateTestUnlocked1) { + // Read and validate CP device ID. + uint32_t cp_device_id[kFlashInfoFieldCpDeviceIdSizeIn32BitWords] = {0}; + static_assert(kFlashInfoFieldCpDeviceIdSizeIn32BitWords == 4, + "CP device ID should fit in four 32bit words."); + CHECK_STATUS_OK(manuf_flash_info_field_read( + &flash_ctrl_state, kFlashInfoFieldCpDeviceId, cp_device_id, + kFlashInfoFieldCpDeviceIdSizeIn32BitWords)); + uint32_t year = (test_data.lot_name >> 24) & 0xf; + uint32_t week = (test_data.lot_name >> 16) & 0xff; + uint32_t lot_number = test_data.lot_name & 0xfff; + CHECK(cp_device_id[0] == 0x00024001u); + CHECK(cp_device_id[1] == ((test_data.wafer_number << 24) | + (lot_number << 12) | (week << 4) | year)); + CHECK(cp_device_id[2] == + ((test_data.wafer_y_coord << 12) | test_data.wafer_x_coord)); + CHECK(cp_device_id[3] == 0); + + // Note: we cannot read/check the wafer_auth_secret field in flash info page + // 3, as this page is not readable in the TEST_UNLOCKED* states. + + // Check the secret0 partition has been provisioned / locked. + CHECK_STATUS_OK(manuf_individualize_device_secret0_check(&otp_ctrl)); + LOG_INFO("Checks complete. Success"); + } else { + LOG_INFO("Bad LC state."); + return false; + } return true; } diff --git a/sw/device/silicon_creator/manuf/base/sram_ft_individualize.c b/sw/device/silicon_creator/manuf/base/sram_ft_individualize.c index 9100138e4f1d6..7a49acd1877b9 100644 --- a/sw/device/silicon_creator/manuf/base/sram_ft_individualize.c +++ b/sw/device/silicon_creator/manuf/base/sram_ft_individualize.c @@ -34,7 +34,7 @@ static dif_otp_ctrl_t otp_ctrl; static dif_pinmux_t pinmux; static manuf_ft_individualize_data_t in_data; -static uint32_t device_id[kHwCfgDeviceIdSizeIn32BitWords]; +static uint32_t cp_device_id[kFlashInfoFieldCpDeviceIdSizeIn32BitWords]; static uint32_t ast_cfg_data[kFlashInfoAstCalibrationDataSizeIn32BitWords]; /** @@ -58,15 +58,16 @@ static status_t peripheral_handles_init(void) { static status_t print_flash_info_0_data_to_console(void) { uint32_t byte_address = 0; TRY(flash_ctrl_testutils_info_region_setup_properties( - &flash_ctrl_state, kFlashInfoFieldDeviceId.page, - kFlashInfoFieldDeviceId.bank, kFlashInfoFieldDeviceId.partition, + &flash_ctrl_state, kFlashInfoFieldCpDeviceId.page, + kFlashInfoFieldCpDeviceId.bank, kFlashInfoFieldCpDeviceId.partition, kFlashInfoPage0Permissions, &byte_address)); - LOG_INFO("Device ID:"); - TRY(manuf_flash_info_field_read(&flash_ctrl_state, kFlashInfoFieldDeviceId, - device_id, kHwCfgDeviceIdSizeIn32BitWords)); + LOG_INFO("CP Device ID:"); + TRY(manuf_flash_info_field_read(&flash_ctrl_state, kFlashInfoFieldCpDeviceId, + cp_device_id, + kFlashInfoFieldCpDeviceIdSizeIn32BitWords)); for (size_t i = 0; i < kHwCfgDeviceIdSizeIn32BitWords; ++i) { - LOG_INFO("0x%08x", device_id[i]); + LOG_INFO("0x%08x", cp_device_id[i]); } LOG_INFO("AST Calibration Values:"); diff --git a/sw/device/silicon_creator/manuf/lib/BUILD b/sw/device/silicon_creator/manuf/lib/BUILD index 3fe3a079ba05e..89c4d3a412eb6 100644 --- a/sw/device/silicon_creator/manuf/lib/BUILD +++ b/sw/device/silicon_creator/manuf/lib/BUILD @@ -150,6 +150,7 @@ opentitan_test( tags = ["manuf"], ), deps = [ + ":flash_info_fields", ":individualize", ":otp_fields", "//hw/top_earlgrey/sw/autogen:top_earlgrey", @@ -158,6 +159,7 @@ opentitan_test( "//sw/device/lib/dif:lc_ctrl", "//sw/device/lib/dif:otp_ctrl", "//sw/device/lib/dif:rstmgr", + "//sw/device/lib/testing:flash_ctrl_testutils", "//sw/device/lib/testing:lc_ctrl_testutils", "//sw/device/lib/testing:rstmgr_testutils", "//sw/device/lib/testing/json:provisioning_data", diff --git a/sw/device/silicon_creator/manuf/lib/flash_info_fields.c b/sw/device/silicon_creator/manuf/lib/flash_info_fields.c index 1e3ae477c0341..c1d9c366aa84c 100644 --- a/sw/device/silicon_creator/manuf/lib/flash_info_fields.c +++ b/sw/device/silicon_creator/manuf/lib/flash_info_fields.c @@ -15,41 +15,60 @@ #include "otp_ctrl_regs.h" // Generated. /** - * Partition 0 pages and fields. - * Refer to sw/device/silicon_creator/lib/drivers/flash_ctrl.h for what - * information ROM and ROM_EXT expect to find on various pages. + * Partition 0, page 0 fields. */ -const flash_info_field_t kFlashInfoFieldDeviceId = { +const flash_info_field_t kFlashInfoFieldLotName = { .partition = 0, .bank = 0, .page = 0, - .byte_offset = 0, + .byte_offset = kFlashInfoFieldLotNameStartOffset, +}; + +const flash_info_field_t kFlashInfoFieldWaferNumber = { + .partition = 0, + .bank = 0, + .page = 0, + .byte_offset = kFlashInfoFieldWaferNumberStartOffset, +}; + +const flash_info_field_t kFlashInfoFieldWaferXCoord = { + .partition = 0, + .bank = 0, + .page = 0, + .byte_offset = kFlashInfoFieldWaferXCoordStartOffset, +}; + +const flash_info_field_t kFlashInfoFieldWaferYCoord = { + .partition = 0, + .bank = 0, + .page = 0, + .byte_offset = kFlashInfoFieldWaferYCoordStartOffset, }; -const flash_info_field_t kFlashInfoFieldManufState = { +const flash_info_field_t kFlashInfoFieldProcessData = { .partition = 0, .bank = 0, .page = 0, - .byte_offset = OTP_CTRL_PARAM_DEVICE_ID_SIZE, + .byte_offset = kFlashInfoFieldProcessDataStartOffset, }; const flash_info_field_t kFlashInfoFieldAstCalibrationData = { .partition = 0, .bank = 0, .page = 0, - .byte_offset = - OTP_CTRL_PARAM_DEVICE_ID_SIZE + OTP_CTRL_PARAM_MANUF_STATE_SIZE, + .byte_offset = kFlashInfoFieldAstCalibrationDataStartOffset, }; -const flash_info_field_t kFlashInfoFieldCharacterizationData = { +const flash_info_field_t kFlashInfoFieldCpDeviceId = { .partition = 0, .bank = 0, .page = 0, - .byte_offset = OTP_CTRL_PARAM_DEVICE_ID_SIZE + - OTP_CTRL_PARAM_MANUF_STATE_SIZE + - kFlashInfoAstCalibrationDataSizeIn32BitWords, + .byte_offset = kFlashInfoFieldCpDeviceIdStartOffset, }; +/** + * Partition 0, page 1 fields. + */ const flash_info_field_t kFlashInfoFieldCreatorSeed = { .partition = 0, .bank = 0, @@ -57,6 +76,9 @@ const flash_info_field_t kFlashInfoFieldCreatorSeed = { .byte_offset = 0, }; +/** + * Partition 0, page 2 fields. + */ const flash_info_field_t kFlashInfoFieldOwnerSeed = { .partition = 0, .bank = 0, @@ -64,6 +86,9 @@ const flash_info_field_t kFlashInfoFieldOwnerSeed = { .byte_offset = 0, }; +/** + * Partition 0, page 3 fields. + */ const flash_info_field_t kFlashInfoFieldWaferAuthSecret = { .partition = 0, .bank = 0, @@ -71,6 +96,9 @@ const flash_info_field_t kFlashInfoFieldWaferAuthSecret = { .byte_offset = 0, }; +/** + * Partition 0, page 4 fields. + */ const flash_info_field_t kFlashInfoFieldUdsAttestationKeySeed = { .partition = 0, .bank = 0, diff --git a/sw/device/silicon_creator/manuf/lib/flash_info_fields.h b/sw/device/silicon_creator/manuf/lib/flash_info_fields.h index affb37f6dcbd9..43d5d51ef56e2 100644 --- a/sw/device/silicon_creator/manuf/lib/flash_info_fields.h +++ b/sw/device/silicon_creator/manuf/lib/flash_info_fields.h @@ -21,20 +21,57 @@ typedef struct flash_info_field { enum { /** - * AST Calibration Data Size - Bank 0, Page 0 + * Lot Name Data Start / Size - Bank 0, Page 0 + */ + kFlashInfoFieldLotNameStartOffset = 80, + kFlashInfoFieldLotNameSizeIn32BitWords = 1, + + /** + * Wafer Number Data Start / Size - Bank 0, Page 0 + */ + kFlashInfoFieldWaferNumberStartOffset = 88, + kFlashInfoFieldWaferNumberSizeIn32BitWords = 1, + + /** + * Wafer X Coord Start / Size - Bank 0, Page 0 + */ + kFlashInfoFieldWaferXCoordStartOffset = 96, + kFlashInfoFieldWaferXCoordSizeIn32BitWords = 1, + + /** + * Wafer Y Coord Start / Size - Bank 0, Page 0 + */ + kFlashInfoFieldWaferYCoordStartOffset = 104, + kFlashInfoFieldWaferYCoordSizeIn32BitWords = 1, + + /** + * Process Data Start / Size - Bank 0, Page 0 + */ + kFlashInfoFieldProcessDataStartOffset = 112, + kFlashInfoFieldProcessDataSizeIn32BitWords = 2, + + /** + * AST Calibration Data Start / Size - Bank 0, Page 0 * * Number of AST calibration words that will be stored in flash / OTP. */ + kFlashInfoFieldAstCalibrationDataStartOffset = 128, kFlashInfoAstCalibrationDataSizeInBytes = AST_REGAL_REG_OFFSET + sizeof(uint32_t), kFlashInfoAstCalibrationDataSizeIn32BitWords = kFlashInfoAstCalibrationDataSizeInBytes / sizeof(uint32_t), + /** + * CP Device ID Start / Size - Bank 0, Page 0 + */ + kFlashInfoFieldCpDeviceIdStartOffset = 384, + kFlashInfoFieldCpDeviceIdSizeIn32BitWords = 4, + // Creator/Owner Seeds - Bank 0, Pages 1 and 2 - kFlashInfoKeySeedSizeIn32BitWords = 32 / sizeof(uint32_t), + kFlashInfoFieldKeySeedSizeIn32BitWords = 32 / sizeof(uint32_t), // Wafer Authentication Secret - Bank 0, Page 3 - kFlashInfoWaferAuthSecretSizeIn32BitWords = 32 / sizeof(uint32_t), + kFlashInfoFieldWaferAuthSecretSizeIn32BitWords = 32 / sizeof(uint32_t), // Attestation key gen seed indices kFlashInfoFieldUdsKeySeedIdx = 0, @@ -43,13 +80,25 @@ enum { kFlashInfoFieldTpmEkKeySeedIdx = 3, }; -extern const flash_info_field_t kFlashInfoFieldDeviceId; -extern const flash_info_field_t kFlashInfoFieldManufState; +// Info Page 0 fields. +extern const flash_info_field_t kFlashInfoFieldLotName; +extern const flash_info_field_t kFlashInfoFieldWaferNumber; +extern const flash_info_field_t kFlashInfoFieldWaferXCoord; +extern const flash_info_field_t kFlashInfoFieldWaferYCoord; +extern const flash_info_field_t kFlashInfoFieldProcessData; extern const flash_info_field_t kFlashInfoFieldAstCalibrationData; -extern const flash_info_field_t kFlashInfoFieldCharacterizationData; +extern const flash_info_field_t kFlashInfoFieldCpDeviceId; + +// Info Page 1 fields. extern const flash_info_field_t kFlashInfoFieldCreatorSeed; + +// Info Page 2 fields. extern const flash_info_field_t kFlashInfoFieldOwnerSeed; + +// Info Page 3 fields. extern const flash_info_field_t kFlashInfoFieldWaferAuthSecret; + +// Info Page 4 fields. extern const flash_info_field_t kFlashInfoFieldUdsAttestationKeySeed; extern const flash_info_field_t kFlashInfoFieldCdi0AttestationKeySeed; extern const flash_info_field_t kFlashInfoFieldCdi1AttestationKeySeed; diff --git a/sw/device/silicon_creator/manuf/lib/individualize.c b/sw/device/silicon_creator/manuf/lib/individualize.c index c9340ad6a70ef..d5c61bcc7418a 100644 --- a/sw/device/silicon_creator/manuf/lib/individualize.c +++ b/sw/device/silicon_creator/manuf/lib/individualize.c @@ -85,42 +85,42 @@ status_t manuf_individualize_device_hw_cfg( // 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. TRY(flash_ctrl_testutils_info_region_setup_properties( - flash_state, kFlashInfoFieldDeviceId.page, kFlashInfoFieldDeviceId.bank, - kFlashInfoFieldDeviceId.partition, flash_info_page_0_permissions, + flash_state, kFlashInfoFieldCpDeviceId.page, + kFlashInfoFieldCpDeviceId.bank, kFlashInfoFieldCpDeviceId.partition, + flash_info_page_0_permissions, /*offset=*/NULL)); // Configure DeviceID - uint32_t device_id_from_flash[kHwCfgDeviceIdSizeIn32BitWords]; - uint32_t empty_device_id[kHwCfgDeviceIdSizeIn32BitWords] = {0}; - TRY(manuf_flash_info_field_read(flash_state, kFlashInfoFieldDeviceId, - device_id_from_flash, - kHwCfgDeviceIdSizeIn32BitWords)); - bool flash_device_id_empty = true; - for (size_t i = 0; - flash_device_id_empty && i < kHwCfgDeviceIdSizeIn32BitWords; ++i) { - flash_device_id_empty &= device_id_from_flash[i] == 0; + uint32_t cp_device_id_from_flash[kFlashInfoFieldCpDeviceIdSizeIn32BitWords]; + uint32_t empty_cp_device_id[kFlashInfoFieldCpDeviceIdSizeIn32BitWords] = { + 0}; + TRY(manuf_flash_info_field_read(flash_state, kFlashInfoFieldCpDeviceId, + cp_device_id_from_flash, + kFlashInfoFieldCpDeviceIdSizeIn32BitWords)); + 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; } - // If the device ID read from flash is non-empty, then it must match the - // device ID provided. If the device ID read from flash is empty, we check - // to ensure the device ID provided is also not empty. An empty (all zero) - // device ID will prevent the keymgr from advancing. - if (!flash_device_id_empty) { - TRY_CHECK_ARRAYS_EQ(device_id_from_flash, device_id, - kHwCfgDeviceIdSizeIn32BitWords); + // If the CP device ID read from flash is non-empty, then it must match the + // first 128-bits of device ID provided. If the device ID read from flash is + // empty, we check to ensure the device ID provided is also not empty. An + // empty (all zero) device ID will prevent the keymgr from advancing. + if (!flash_cp_device_id_empty) { + TRY_CHECK_ARRAYS_EQ(cp_device_id_from_flash, device_id, + kFlashInfoFieldCpDeviceIdSizeIn32BitWords); } else { - TRY_CHECK_ARRAYS_NE(device_id, empty_device_id, - kHwCfgDeviceIdSizeIn32BitWords); + TRY_CHECK_ARRAYS_NE(device_id, empty_cp_device_id, + kFlashInfoFieldCpDeviceIdSizeIn32BitWords); } TRY(otp_ctrl_testutils_dai_write32(otp_ctrl, kDifOtpCtrlPartitionHwCfg0, kHwCfgDeviceIdOffset, device_id, kHwCfgDeviceIdSizeIn32BitWords)); - // Configure ManufState - uint32_t manuf_state[kHwCfgManufStateSizeIn32BitWords]; - TRY(manuf_flash_info_field_read(flash_state, kFlashInfoFieldManufState, - manuf_state, - kHwCfgManufStateSizeIn32BitWords)); + // Configure ManufState as all 0s. It is unused. + uint32_t manuf_state[kHwCfgManufStateSizeIn32BitWords] = {0}; TRY(otp_ctrl_testutils_dai_write32(otp_ctrl, kDifOtpCtrlPartitionHwCfg0, kHwCfgManufStateOffset, manuf_state, kHwCfgManufStateSizeIn32BitWords)); diff --git a/sw/device/silicon_creator/manuf/lib/individualize_functest.c b/sw/device/silicon_creator/manuf/lib/individualize_functest.c index 4b7759af8c3a2..9af74f0d3cd51 100644 --- a/sw/device/silicon_creator/manuf/lib/individualize_functest.c +++ b/sw/device/silicon_creator/manuf/lib/individualize_functest.c @@ -7,10 +7,12 @@ #include "sw/device/lib/dif/dif_lc_ctrl.h" #include "sw/device/lib/dif/dif_otp_ctrl.h" #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/rstmgr_testutils.h" #include "sw/device/lib/testing/test_framework/check.h" #include "sw/device/lib/testing/test_framework/ottf_main.h" +#include "sw/device/silicon_creator/manuf/lib/flash_info_fields.h" #include "sw/device/silicon_creator/manuf/lib/individualize.h" #include "sw/device/silicon_creator/manuf/lib/otp_fields.h" @@ -28,6 +30,18 @@ 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, + 0xAAAAAAAA, 0xBBBBBBBB, 0xAAAAAAAA, 0xBBBBBBBB}; + +static dif_flash_ctrl_region_properties_t kFlashInfoPage0Permissions = { + .ecc_en = kMultiBitBool4True, + .high_endurance_en = kMultiBitBool4False, + .erase_en = kMultiBitBool4True, + .prog_en = kMultiBitBool4True, + .rd_en = kMultiBitBool4True, + .scramble_en = kMultiBitBool4False}; + /** * Initializes all DIF handles used in this module. */ @@ -59,18 +73,37 @@ bool test_main(void) { lc_ctrl_testutils_check_lc_state(&lc_ctrl, kDifLcCtrlStateTestUnlocked1)); if (!status_ok(manuf_individualize_device_hw_cfg_check(&otp_ctrl))) { - dif_flash_ctrl_region_properties_t kFlashInfoPage0Permissions = { - .ecc_en = kMultiBitBool4True, - .high_endurance_en = kMultiBitBool4False, - .erase_en = kMultiBitBool4True, - .prog_en = kMultiBitBool4True, - .rd_en = kMultiBitBool4True, - .scramble_en = kMultiBitBool4False}; - uint32_t device_id[kHwCfgDeviceIdSizeIn32BitWords] = { - 0xAAAAAAAA, 0xBBBBBBBB, 0xAAAAAAAA, 0xBBBBBBBB, + // Setup page permissions on flash info page 0. + uint32_t byte_address = 0; + CHECK_STATUS_OK(flash_ctrl_testutils_info_region_setup_properties( + &flash_state, kFlashInfoFieldCpDeviceId.page, + 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] = { 0xAAAAAAAA, 0xBBBBBBBB, 0xAAAAAAAA, 0xBBBBBBBB}; + CHECK_STATUS_OK(manuf_flash_info_field_write( + &flash_state, kFlashInfoFieldCpDeviceId, kGoodCpDeviceId, + kFlashInfoFieldCpDeviceIdSizeIn32BitWords, + /*erase_page_before_write=*/true)); CHECK_STATUS_OK(manuf_individualize_device_hw_cfg( - &flash_state, &otp_ctrl, kFlashInfoPage0Permissions, device_id)); + &flash_state, &otp_ctrl, kFlashInfoPage0Permissions, + kDeviceIdFromHost)); + sw_reset(); } diff --git a/sw/device/silicon_creator/manuf/lib/personalize.c b/sw/device/silicon_creator/manuf/lib/personalize.c index 825cf171f090b..cbc8195e1b233 100644 --- a/sw/device/silicon_creator/manuf/lib/personalize.c +++ b/sw/device/silicon_creator/manuf/lib/personalize.c @@ -110,7 +110,7 @@ static status_t flash_keymgr_secret_seed_write( TRY(entropy_csrng_instantiate(/*disable_trng_input=*/kHardenedBoolFalse, /*seed_material=*/NULL)); - uint32_t seed[kFlashInfoKeySeedSizeIn32BitWords]; + uint32_t seed[kFlashInfoFieldKeySeedSizeIn32BitWords]; TRY(entropy_csrng_generate(/*seed_material=*/NULL, seed, len, /*fips_check*/ kHardenedBoolTrue)); TRY(entropy_csrng_uninstantiate()); @@ -123,7 +123,7 @@ static status_t flash_keymgr_secret_seed_write( flash_state, address, field.partition, seed, kDifFlashCtrlPartitionTypeInfo, len)); - uint32_t seed_result[kFlashInfoKeySeedSizeIn32BitWords]; + uint32_t seed_result[kFlashInfoFieldKeySeedSizeIn32BitWords]; TRY(flash_ctrl_testutils_read(flash_state, address, field.partition, seed_result, kDifFlashCtrlPartitionTypeInfo, len, @@ -224,12 +224,12 @@ status_t manuf_personalize_device_secrets( // Provision secret Creator / Owner key seeds in flash. // Provision CreatorSeed into target flash info page. TRY(flash_keymgr_secret_seed_write(flash_state, kFlashInfoFieldCreatorSeed, - kFlashInfoKeySeedSizeIn32BitWords)); + kFlashInfoFieldKeySeedSizeIn32BitWords)); // Provision preliminary OwnerSeed into target flash info page (with // expectation that SiliconOwner will rotate this value during ownership // transfer). TRY(flash_keymgr_secret_seed_write(flash_state, kFlashInfoFieldOwnerSeed, - kFlashInfoKeySeedSizeIn32BitWords)); + kFlashInfoFieldKeySeedSizeIn32BitWords)); // Provision the OTP SECRET2 partition. TRY(otp_partition_secret2_configure(otp_ctrl, rma_unlock_token_hash)); diff --git a/sw/device/silicon_creator/manuf/tests/flash_device_info_flash_wr_functest.c b/sw/device/silicon_creator/manuf/tests/flash_device_info_flash_wr_functest.c index f301b14647b83..cd7a4b5bf1595 100644 --- a/sw/device/silicon_creator/manuf/tests/flash_device_info_flash_wr_functest.c +++ b/sw/device/silicon_creator/manuf/tests/flash_device_info_flash_wr_functest.c @@ -47,9 +47,8 @@ bool test_main(void) { case kDifLcCtrlStateProdEnd: LOG_INFO("Reading the isolated flash partition."); uint32_t byte_address = 0; - uint32_t - actual_wafer_auth_secret[kFlashInfoWaferAuthSecretSizeIn32BitWords] = - {0}; + uint32_t actual_wafer_auth_secret + [kFlashInfoFieldWaferAuthSecretSizeIn32BitWords] = {0}; CHECK_STATUS_OK(flash_ctrl_testutils_info_region_setup( &flash_ctrl_state, kFlashInfoFieldWaferAuthSecret.page, kFlashInfoFieldWaferAuthSecret.bank, @@ -58,10 +57,10 @@ bool test_main(void) { &flash_ctrl_state, byte_address, kFlashInfoFieldWaferAuthSecret.partition, actual_wafer_auth_secret, kDifFlashCtrlPartitionTypeInfo, - kFlashInfoWaferAuthSecretSizeIn32BitWords, + kFlashInfoFieldWaferAuthSecretSizeIn32BitWords, /*delay_micros=*/0)); CHECK_ARRAYS_EQ(actual_wafer_auth_secret, kExpectedWaferAuthSecret, - kFlashInfoWaferAuthSecretSizeIn32BitWords); + kFlashInfoFieldWaferAuthSecretSizeIn32BitWords); LOG_INFO("Done."); break; default: diff --git a/sw/device/silicon_creator/manuf/tests/sram_device_info_flash_wr_functest.c b/sw/device/silicon_creator/manuf/tests/sram_device_info_flash_wr_functest.c index fbec533d03578..d7dcc080ea33b 100644 --- a/sw/device/silicon_creator/manuf/tests/sram_device_info_flash_wr_functest.c +++ b/sw/device/silicon_creator/manuf/tests/sram_device_info_flash_wr_functest.c @@ -94,7 +94,7 @@ bool test_main(void) { &flash_ctrl_state, byte_address, kFlashInfoFieldWaferAuthSecret.partition, kExpectedWaferAuthSecret, kDifFlashCtrlPartitionTypeInfo, - kFlashInfoWaferAuthSecretSizeIn32BitWords)); + kFlashInfoFieldWaferAuthSecretSizeIn32BitWords)); LOG_INFO("Enabling ROM execution to enable bootstrap after reset."); CHECK_STATUS_OK(manuf_individualize_device_creator_sw_cfg( &otp_ctrl, &flash_ctrl_state)); diff --git a/sw/device/silicon_creator/manuf/tests/test_wafer_auth_secret.h b/sw/device/silicon_creator/manuf/tests/test_wafer_auth_secret.h index 4e3bdde7bb1ad..45b939611df75 100644 --- a/sw/device/silicon_creator/manuf/tests/test_wafer_auth_secret.h +++ b/sw/device/silicon_creator/manuf/tests/test_wafer_auth_secret.h @@ -9,7 +9,7 @@ // Expected wafer authentication secret to write to the flash const uint32_t - kExpectedWaferAuthSecret[kFlashInfoWaferAuthSecretSizeIn32BitWords] = { + kExpectedWaferAuthSecret[kFlashInfoFieldWaferAuthSecretSizeIn32BitWords] = { 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef, }; diff --git a/sw/host/opentitanlib/src/debug/openocd.rs b/sw/host/opentitanlib/src/debug/openocd.rs index 656425558bf42..6112b33c36eed 100644 --- a/sw/host/opentitanlib/src/debug/openocd.rs +++ b/sw/host/opentitanlib/src/debug/openocd.rs @@ -87,7 +87,6 @@ impl OpenOcd { cmd.arg("-c") .arg("tcl_port 0; telnet_port disabled; gdb_port disabled; noinit;"); - log::info!("CWD: {:?}", std::env::current_dir()); log::info!("Spawning OpenOCD: {cmd:?}"); cmd.stdin(Stdio::null()) diff --git a/sw/host/provisioning/cp/BUILD b/sw/host/provisioning/cp/BUILD index db25121a5ca17..8fcf05540c338 100644 --- a/sw/host/provisioning/cp/BUILD +++ b/sw/host/provisioning/cp/BUILD @@ -19,6 +19,7 @@ rust_binary( "@crate_index//:clap", "@crate_index//:humantime", "@crate_index//:log", + "@crate_index//:serde_json", "@crate_index//:zerocopy", ], ) diff --git a/sw/host/provisioning/cp/src/main.rs b/sw/host/provisioning/cp/src/main.rs index c8c5b67ab08cc..b2a6b52f577c4 100644 --- a/sw/host/provisioning/cp/src/main.rs +++ b/sw/host/provisioning/cp/src/main.rs @@ -8,7 +8,7 @@ use anyhow::Result; use clap::Parser; use zerocopy::IntoBytes; -use cp_lib::{reset_and_lock, run_sram_cp_provision, ManufCpProvisioningDataInput}; +use cp_lib::{reset_and_lock, run_sram_cp_provision, CpResponse, ManufCpProvisioningDataInput}; use opentitanlib::console::spi::SpiConsoleDevice; use opentitanlib::dif::lc_ctrl::DifLcCtrlState; use opentitanlib::test_utils::init::InitializeTest; @@ -45,8 +45,6 @@ fn main() -> Result<()> { let spi_console_device = SpiConsoleDevice::new(&*spi)?; let provisioning_data = ManufCpProvisioningData { - device_id: hex_string_to_u32_arrayvec::<8>(opts.provisioning_data.device_id.as_str())?, - manuf_state: hex_string_to_u32_arrayvec::<8>(opts.provisioning_data.manuf_state.as_str())?, wafer_auth_secret: hex_string_to_u32_arrayvec::<8>( opts.provisioning_data.wafer_auth_secret.as_str(), )?, @@ -60,6 +58,8 @@ fn main() -> Result<()> { )?, }; + let mut response = CpResponse::default(); + // Only run CP provisioning if requested in any of the TestUnlocked states, except the last // state (TestUnlocked7), as this state requires special handling of the wafer authentication // secret, which is not yet implemented. @@ -84,6 +84,7 @@ fn main() -> Result<()> { &opts.sram_program, &provisioning_data, &spi_console_device, + &mut response, opts.timeout, )?; // Only perform lock if we are in TEST_UNLOCKED0, otherwise we are running from a later @@ -103,5 +104,8 @@ fn main() -> Result<()> { } }; + let doc = serde_json::to_string(&response)?; + println!("CHIP_PROBE_DATA: {doc}"); + Ok(()) } diff --git a/sw/host/provisioning/cp_lib/src/lib.rs b/sw/host/provisioning/cp_lib/src/lib.rs index 2ab792d0b3509..d57d9d5d49406 100644 --- a/sw/host/provisioning/cp_lib/src/lib.rs +++ b/sw/host/provisioning/cp_lib/src/lib.rs @@ -6,6 +6,7 @@ use std::time::Duration; use anyhow::{Context, Result}; use clap::Args; +use serde::Serialize; use opentitanlib::app::TransportWrapper; use opentitanlib::console::spi::SpiConsoleDevice; @@ -15,9 +16,9 @@ use opentitanlib::test_utils::lc_transition::trigger_lc_transition; use opentitanlib::test_utils::load_sram_program::{ ExecutionMode, ExecutionResult, SramProgramParams, }; -use opentitanlib::test_utils::rpc::ConsoleSend; +use opentitanlib::test_utils::rpc::{ConsoleRecv, ConsoleSend}; use opentitanlib::uart::console::UartConsole; -use ujson_lib::provisioning_data::ManufCpProvisioningData; +use ujson_lib::provisioning_data::{ManufCpProvisioningData, ManufCpProvisioningDataOut}; // Generated by the `lc_raw_unlock_token` Bazel rule from `//rules/lc.bzl`. mod lc_raw_unlock_token; @@ -25,15 +26,6 @@ mod lc_raw_unlock_token; /// Provisioning data command-line parameters. #[derive(Debug, Args, Clone)] pub struct ManufCpProvisioningDataInput { - // TODO(#19456): construct device ID from building blocks - /// Device ID to provision. - #[arg(long)] - pub device_id: String, - - /// Manufacturing State information to provision. - #[arg(long)] - pub manuf_state: String, - /// Wafer Authentication Secret to provision. #[arg(long)] pub wafer_auth_secret: String, @@ -47,6 +39,11 @@ pub struct ManufCpProvisioningDataInput { pub test_exit_token: String, } +#[derive(Debug, Clone, Default, Serialize)] +pub struct CpResponse { + pub cp_device_id: String, +} + pub fn unlock_raw( transport: &TransportWrapper, jtag_params: &JtagParams, @@ -96,13 +93,15 @@ pub fn unlock_raw( Ok(()) } +#[allow(clippy::too_many_arguments)] pub fn run_sram_cp_provision( transport: &TransportWrapper, jtag_params: &JtagParams, reset_delay: Duration, sram_program: &SramProgramParams, - provisioning_data: &ManufCpProvisioningData, + data_in: &ManufCpProvisioningData, spi_console: &SpiConsoleDevice, + response: &mut CpResponse, timeout: Duration, ) -> Result<()> { // Set CPU TAP straps, reset, and connect to the JTAG interface. @@ -129,7 +128,17 @@ pub fn run_sram_cp_provision( )?; // Inject provisioning data into the device. - provisioning_data.send(spi_console)?; + data_in.send(spi_console)?; + + // Wait to receive CP device ID, and encode in big-endian in response. + let _ = UartConsole::wait_for(spi_console, r"Exporting CP device ID ...", timeout)?; + response.cp_device_id = ManufCpProvisioningDataOut::recv(spi_console, timeout, true)? + .cp_device_id + .iter() + .rev() + .map(|v| format!("{v:08X}")) + .collect::>() + .join(""); // Wait for provisioning operations to complete. let _ = UartConsole::wait_for(spi_console, r"CP provisioning done.", timeout)?; diff --git a/sw/host/tests/manuf/cp_provision_functest/BUILD b/sw/host/tests/manuf/cp_provision_functest/BUILD index e6e3911aff6b8..ea1d9edb5fa0c 100644 --- a/sw/host/tests/manuf/cp_provision_functest/BUILD +++ b/sw/host/tests/manuf/cp_provision_functest/BUILD @@ -20,6 +20,7 @@ rust_binary( "@crate_index//:humantime", "@crate_index//:log", "@crate_index//:rand", + "@crate_index//:serde_json", "@crate_index//:zerocopy", ], ) diff --git a/sw/host/tests/manuf/cp_provision_functest/src/main.rs b/sw/host/tests/manuf/cp_provision_functest/src/main.rs index 05a006730e3ed..0a5daac90aa2d 100644 --- a/sw/host/tests/manuf/cp_provision_functest/src/main.rs +++ b/sw/host/tests/manuf/cp_provision_functest/src/main.rs @@ -11,7 +11,7 @@ use clap::Parser; use rand::RngCore; use zerocopy::IntoBytes; -use cp_lib::{reset_and_lock, run_sram_cp_provision, unlock_raw, ManufCpProvisioningDataInput}; +use cp_lib::{reset_and_lock, run_sram_cp_provision, unlock_raw, CpResponse}; use opentitanlib::app::TransportWrapper; use opentitanlib::console::spi::SpiConsoleDevice; use opentitanlib::dif::lc_ctrl::{DifLcCtrlState, LcCtrlReg}; @@ -23,7 +23,7 @@ use opentitanlib::test_utils::load_sram_program::{ }; use opentitanlib::test_utils::rpc::ConsoleSend; use opentitanlib::uart::console::UartConsole; -use ujson_lib::provisioning_data::ManufCpProvisioningData; +use ujson_lib::provisioning_data::{ManufCpProvisioningData, ManufCpTestData}; use util_lib::hash_lc_token; #[derive(Debug, Parser)] @@ -37,9 +37,6 @@ pub struct Opts { #[arg(long)] pub test_sram_elf: Option, - #[command(flatten)] - pub provisioning_data: ManufCpProvisioningDataInput, - /// Console receive timeout. #[arg(long, value_parser = humantime::parse_duration, default_value = "600s")] pub timeout: Duration, @@ -53,17 +50,13 @@ fn cp_provision( opts: &Opts, transport: &TransportWrapper, provisioning_data: &ManufCpProvisioningData, + response: &mut CpResponse, spi_console: &SpiConsoleDevice, ) -> Result<()> { let provisioning_sram_program: SramProgramParams = SramProgramParams { elf: opts.provisioning_sram_elf.clone(), ..Default::default() }; - unlock_raw( - transport, - &opts.init.jtag_params, - opts.init.bootstrap.options.reset_delay, - )?; run_sram_cp_provision( transport, &opts.init.jtag_params, @@ -71,6 +64,7 @@ fn cp_provision( &provisioning_sram_program, provisioning_data, spi_console, + response, opts.timeout, )?; reset_and_lock( @@ -127,10 +121,57 @@ fn test_unlock( Ok(()) } +fn prep_flash_for_cp_init( + opts: &Opts, + transport: &TransportWrapper, + test_data: &ManufCpTestData, + spi_console: &SpiConsoleDevice, +) -> Result<()> { + let test_sram_program: SramProgramParams = SramProgramParams { + elf: opts.test_sram_elf.clone(), + ..Default::default() + }; + + // Set the TAP straps for the CPU and reset. + transport.pin_strapping("PINMUX_TAP_RISCV")?.apply()?; + transport.reset_target(opts.init.bootstrap.options.reset_delay, true)?; + + // Connect to the RISCV TAP via JTAG. + let mut jtag = opts + .init + .jtag_params + .create(transport)? + .connect(JtagTap::RiscvTap)?; + + // Reset and halt the CPU to ensure we are in a known state. + jtag.reset(/*run=*/ false)?; + + // Load and execute the SRAM program that contains the provisioning code. + let result = test_sram_program.load_and_execute(&mut *jtag, ExecutionMode::Jump)?; + match result { + ExecutionResult::Executing => log::info!("SRAM program loaded and is executing."), + _ => panic!("SRAM program load/execution failed: {:?}.", result), + } + + // Wait for test to start running. + let _ = UartConsole::wait_for(spi_console, r"Waiting for CP test data ...", opts.timeout)?; + + // Inject ground truth provisioning data into the device. + test_data.send(spi_console)?; + + // Wait for test complete. + let _ = UartConsole::wait_for(spi_console, r"Flash info page 0 programmed.", opts.timeout)?; + + jtag.disconnect()?; + transport.pin_strapping("PINMUX_TAP_RISCV")?.remove()?; + + Ok(()) +} + fn check_cp_provisioning( opts: &Opts, transport: &TransportWrapper, - provisioning_data: &ManufCpProvisioningData, + test_data: &ManufCpTestData, spi_console: &SpiConsoleDevice, ) -> Result<()> { let test_sram_program: SramProgramParams = SramProgramParams { @@ -161,14 +202,10 @@ fn check_cp_provisioning( } // Wait for test to start running. - let _ = UartConsole::wait_for( - spi_console, - r"Waiting for expected CP provisioning data ...", - opts.timeout, - )?; + let _ = UartConsole::wait_for(spi_console, r"Waiting for CP test data ...", opts.timeout)?; // Inject ground truth provisioning data into the device. - provisioning_data.send(spi_console)?; + test_data.send(spi_console)?; // Wait for test complete. let _ = UartConsole::wait_for(spi_console, r"Checks complete. Success.", opts.timeout)?; @@ -186,9 +223,28 @@ fn main() -> Result<()> { let spi = transport.spi(&opts.console_spi)?; let spi_console_device = SpiConsoleDevice::new(&*spi)?; - // Generate random provisioning values for testing. - let mut device_id = ArrayVec::new(); - let mut manuf_state = ArrayVec::new(); + // Transition from RAW to TEST_UNLOCKED0. + unlock_raw( + &transport, + &opts.init.jtag_params, + opts.init.bootstrap.options.reset_delay, + )?; + + // Generate random test wafer data. + let test_data = ManufCpTestData { + lot_name: rand::thread_rng().next_u32(), + wafer_number: rand::thread_rng().next_u32(), + wafer_x_coord: rand::thread_rng().next_u32(), + wafer_y_coord: rand::thread_rng().next_u32(), + }; + + // CP response to log to console in JSON format. + let mut response = CpResponse::default(); + + // Prep flash info page 0 with wafer data, CP device ID, and AST configs. + prep_flash_for_cp_init(&opts, &transport, &test_data, &spi_console_device)?; + + // Generate random CP inputs for testing. let mut wafer_auth_secret = ArrayVec::new(); let mut test_exit_token: ArrayVec = ArrayVec::new(); let mut test_unlock_token: ArrayVec = ArrayVec::new(); @@ -197,28 +253,33 @@ fn main() -> Result<()> { test_exit_token.push(rand::thread_rng().next_u32()); test_unlock_token.push(rand::thread_rng().next_u32()); } - device_id.push(rand::thread_rng().next_u32()); - manuf_state.push(rand::thread_rng().next_u32()); wafer_auth_secret.push(rand::thread_rng().next_u32()); } - // Provision values into the chip. + // Provision test tokens, WAS, and extract CP device ID. let provisioning_data = ManufCpProvisioningData { - device_id, - manuf_state, wafer_auth_secret, test_unlock_token_hash: hash_lc_token(test_unlock_token.as_bytes())?, test_exit_token_hash: hash_lc_token(test_exit_token.as_bytes())?, }; - cp_provision(&opts, &transport, &provisioning_data, &spi_console_device)?; + cp_provision( + &opts, + &transport, + &provisioning_data, + &mut response, + &spi_console_device, + )?; - // Transition to TEST_UNLOCKED1 and check provisioning operations over JTAG. + // Transition to TEST_UNLOCKED1 and check provisioning operations. test_unlock( &opts, &transport, Some(test_unlock_token.into_inner().unwrap()), )?; - check_cp_provisioning(&opts, &transport, &provisioning_data, &spi_console_device)?; + check_cp_provisioning(&opts, &transport, &test_data, &spi_console_device)?; + + let doc = serde_json::to_string(&response)?; + println!("CHIP_PROBE_DATA: {doc}"); Ok(()) }