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(()) }