This implements more ELE operations useful for AHAB secure boot. Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> --- arch/arm/mach-imx/ele.c | 345 +++++++++++++++++++++++++++++++++++++++- include/mach/imx/ele.h | 18 +++ 2 files changed, 362 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/ele.c b/arch/arm/mach-imx/ele.c index eaae784c94..18161428c6 100644 --- a/arch/arm/mach-imx/ele.c +++ b/arch/arm/mach-imx/ele.c @@ -2,7 +2,7 @@ /* * Copyright 2020-2022 NXP */ -#define pr_fmt(fmt) "s4mu: " fmt +#define pr_fmt(fmt) "ele: " fmt #include <common.h> #include <io.h> @@ -253,6 +253,130 @@ int ele_read_shadow_fuse(u16 fuse_id, u32 *fuse_word, u32 *response) return ret; } +/* + * ele_write_fuse - write a fuse + * @fuse_id: The fuse to write to + * @fuse_val: The value to write to the fuse + * @lock: lock fuse after writing + * @response: on return contains the response from ELE + * + * This writes the 32bit given in @fuse_val to the fuses at @fuse_id. This is + * a permanent change, be careful. + * + * Return: 0 when the ELE call succeeds, negative error code otherwise + */ +int ele_write_fuse(u16 fuse_id, u32 fuse_val, bool lock, u32 *response) +{ + struct ele_msg msg; + int ret; + + msg.version = ELE_VERSION; + msg.tag = ELE_CMD_TAG; + msg.size = 3; + msg.command = ELE_WRITE_FUSE_REQ; + msg.data[0] = (32 << 16) | (fuse_id << 5); + + if (lock) + msg.data[0] |= (1 << 31); + + msg.data[1] = fuse_val; + + ret = imx9_s3mua_call(&msg, true); + + if (response) + *response = msg.data[0]; + + return ret; +} + +/* + * ele_forward_lifecycle - forward lifecycle + * @lc: The lifecycle value to forward to + * @response: on return contains the response from ELE + * + * This changes the chip's lifecycle value. Mainly useful to forward to + * from ELE_LIFECYCLE_OEM_OPEN to ELE_LIFECYCLE_OEM_CLOSED. When doing + * this the SoC will only boot authenticated images. Make sure the correct + * SRK has been fused beforehand, otherwise you brick your board. + * + * Return: 0 when the ELE call succeeds, negative error code otherwise + */ +int ele_forward_lifecycle(enum ele_lifecycle lc, u32 *response) +{ + struct ele_msg msg; + int ret; + + msg.version = ELE_VERSION; + msg.tag = ELE_CMD_TAG; + msg.size = 2; + msg.command = ELE_FWD_LIFECYCLE_UP_REQ; + msg.data[0] = lc; + + ret = imx9_s3mua_call(&msg, true); + + if (response) + *response = msg.data[0]; + + return ret; +} + +/* + * ele_authenticate_container - authenticate a container image + * @addr: the address of the container + * @response: on return contains the response from ELE + * + * This authenticates a container with the ELE. On return the result + * of the authentication will be encoded in @response + * + * Return: 0 when the ELE call succeeds, negative error code otherwise + */ +int ele_authenticate_container(unsigned long addr, u32 *response) +{ + struct ele_msg msg; + int ret; + + msg.version = ELE_VERSION; + msg.tag = ELE_CMD_TAG; + msg.size = 3; + msg.command = ELE_OEM_CNTN_AUTH_REQ; + msg.data[0] = upper_32_bits(addr); + msg.data[1] = lower_32_bits(addr); + + ret = imx9_s3mua_call(&msg, true); + + if (response) + *response = msg.data[0]; + + return ret; +} + +/* + * ele_release_container - release a container image + * @response: on return contains the response from ELE + * + * This releases a container image. Must be called when done with an + * image previously authenticated with ele_authenticate_container() + * + * Return: 0 when the ELE call succeeds, negative error code otherwise + */ +int ele_release_container(u32 *response) +{ + struct ele_msg msg; + int ret; + + msg.version = ELE_VERSION; + msg.tag = ELE_CMD_TAG; + msg.size = 1; + msg.command = ELE_RELEASE_CONTAINER_REQ; + + ret = imx9_s3mua_call(&msg, true); + + if (response) + *response = msg.data[0]; + + return ret; +} + int ele_release_rdc(u8 core_id, u8 xrdc, u32 *response) { struct ele_msg msg; @@ -290,3 +414,222 @@ int ele_release_rdc(u8 core_id, u8 xrdc, u32 *response) return ret; } + +struct ele_str { + u8 id; + const char *str; +}; + +static struct ele_str ele_ind[] = { + { .id = ELE_ROM_PING_FAILURE_IND, .str = "ELE_ROM_PING_FAILURE" }, + { .id = ELE_FW_PING_FAILURE_IND, .str = "ELE_FW_PING_FAILURE" }, + { .id = ELE_BAD_SIGNATURE_FAILURE_IND, .str = "ELE_BAD_SIGNATURE_FAILURE" }, + { .id = ELE_BAD_HASH_FAILURE_IND, .str = "ELE_BAD_HASH_FAILURE" }, + { .id = ELE_INVALID_LIFECYCLE_IND, .str = "ELE_INVALID_LIFECYCLE" }, + { .id = ELE_PERMISSION_DENIED_FAILURE_IND, .str = "ELE_PERMISSION_DENIED_FAILURE" }, + { .id = ELE_INVALID_MESSAGE_FAILURE_IND, .str = "ELE_INVALID_MESSAGE_FAILURE" }, + { .id = ELE_BAD_VALUE_FAILURE_IND, .str = "ELE_BAD_VALUE_FAILURE" }, + { .id = ELE_BAD_FUSE_ID_FAILURE_IND, .str = "ELE_BAD_FUSE_ID_FAILURE" }, + { .id = ELE_BAD_CONTAINER_FAILURE_IND, .str = "ELE_BAD_CONTAINER_FAILURE" }, + { .id = ELE_BAD_VERSION_FAILURE_IND, .str = "ELE_BAD_VERSION_FAILURE" }, + { .id = ELE_INVALID_KEY_FAILURE_IND, .str = "ELE_INVALID_KEY_FAILURE" }, + { .id = ELE_BAD_KEY_HASH_FAILURE_IND, .str = "ELE_BAD_KEY_HASH_FAILURE" }, + { .id = ELE_NO_VALID_CONTAINER_FAILURE_IND, .str = "ELE_NO_VALID_CONTAINER_FAILURE" }, + { .id = ELE_BAD_CERTIFICATE_FAILURE_IND, .str = "ELE_BAD_CERTIFICATE_FAILURE" }, + { .id = ELE_BAD_UID_FAILURE_IND, .str = "ELE_BAD_UID_FAILURE" }, + { .id = ELE_BAD_MONOTONIC_COUNTER_FAILURE_IND, .str = "ELE_BAD_MONOTONIC_COUNTER_FAILURE" }, + { .id = ELE_MUST_SIGNED_FAILURE_IND, .str = "ELE_MUST_SIGNED_FAILURE" }, + { .id = ELE_NO_AUTHENTICATION_FAILURE_IND, .str = "ELE_NO_AUTHENTICATION_FAILURE" }, + { .id = ELE_BAD_SRK_SET_FAILURE_IND, .str = "ELE_BAD_SRK_SET_FAILURE" }, + { .id = ELE_UNALIGNED_PAYLOAD_FAILURE_IND, .str = "ELE_UNALIGNED_PAYLOAD_FAILURE" }, + { .id = ELE_WRONG_SIZE_FAILURE_IND, .str = "ELE_WRONG_SIZE_FAILURE" }, + { .id = ELE_ENCRYPTION_FAILURE_IND, .str = "ELE_ENCRYPTION_FAILURE" }, + { .id = ELE_DECRYPTION_FAILURE_IND, .str = "ELE_DECRYPTION_FAILURE" }, + { .id = ELE_OTP_PROGFAIL_FAILURE_IND, .str = "ELE_OTP_PROGFAIL_FAILURE" }, + { .id = ELE_OTP_LOCKED_FAILURE_IND, .str = "ELE_OTP_LOCKED_FAILURE" }, + { .id = ELE_OTP_INVALID_IDX_FAILURE_IND, .str = "ELE_OTP_INVALID_IDX_FAILURE" }, + { .id = ELE_TIME_OUT_FAILURE_IND, .str = "ELE_TIME_OUT_FAILURE" }, + { .id = ELE_BAD_PAYLOAD_FAILURE_IND, .str = "ELE_BAD_PAYLOAD_FAILURE" }, + { .id = ELE_WRONG_ADDRESS_FAILURE_IND, .str = "ELE_WRONG_ADDRESS_FAILURE" }, + { .id = ELE_DMA_FAILURE_IND, .str = "ELE_DMA_FAILURE" }, + { .id = ELE_DISABLED_FEATURE_FAILURE_IND, .str = "ELE_DISABLED_FEATURE_FAILURE" }, + { .id = ELE_MUST_ATTEST_FAILURE_IND, .str = "ELE_MUST_ATTEST_FAILURE" }, + { .id = ELE_RNG_NOT_STARTED_FAILURE_IND, .str = "ELE_RNG_NOT_STARTED_FAILURE" }, + { .id = ELE_CRC_ERROR_IND, .str = "ELE_CRC_ERROR" }, + { .id = ELE_AUTH_SKIPPED_OR_FAILED_FAILURE_IND, .str = "ELE_AUTH_SKIPPED_OR_FAILED_FAILURE" }, + { .id = ELE_INCONSISTENT_PAR_FAILURE_IND, .str = "ELE_INCONSISTENT_PAR_FAILURE" }, + { .id = ELE_RNG_INST_FAILURE_FAILURE_IND, .str = "ELE_RNG_INST_FAILURE_FAILURE" }, + { .id = ELE_LOCKED_REG_FAILURE_IND, .str = "ELE_LOCKED_REG_FAILURE" }, + { .id = ELE_BAD_ID_FAILURE_IND, .str = "ELE_BAD_ID_FAILURE" }, + { .id = ELE_INVALID_OPERATION_FAILURE_IND, .str = "ELE_INVALID_OPERATION_FAILURE" }, + { .id = ELE_NON_SECURE_STATE_FAILURE_IND, .str = "ELE_NON_SECURE_STATE_FAILURE" }, + { .id = ELE_MSG_TRUNCATED_IND, .str = "ELE_MSG_TRUNCATED" }, + { .id = ELE_BAD_IMAGE_NUM_FAILURE_IND, .str = "ELE_BAD_IMAGE_NUM_FAILURE" }, + { .id = ELE_BAD_IMAGE_ADDR_FAILURE_IND, .str = "ELE_BAD_IMAGE_ADDR_FAILURE" }, + { .id = ELE_BAD_IMAGE_PARAM_FAILURE_IND, .str = "ELE_BAD_IMAGE_PARAM_FAILURE" }, + { .id = ELE_BAD_IMAGE_TYPE_FAILURE_IND, .str = "ELE_BAD_IMAGE_TYPE_FAILURE" }, + { .id = ELE_CORRUPTED_SRK_FAILURE_IND, .str = "ELE_CORRUPTED_SRK_FAILURE" }, + { .id = ELE_OUT_OF_MEMORY_IND, .str = "ELE_OUT_OF_MEMORY" }, + { .id = ELE_CSTM_FAILURE_IND, .str = "ELE_CSTM_FAILURE" }, + { .id = ELE_OLD_VERSION_FAILURE_IND, .str = "ELE_OLD_VERSION_FAILURE" }, + { .id = ELE_WRONG_BOOT_MODE_FAILURE_IND, .str = "ELE_WRONG_BOOT_MODE_FAILURE" }, + { .id = ELE_APC_ALREADY_ENABLED_FAILURE_IND, .str = "ELE_APC_ALREADY_ENABLED_FAILURE" }, + { .id = ELE_RTC_ALREADY_ENABLED_FAILURE_IND, .str = "ELE_RTC_ALREADY_ENABLED_FAILURE" }, + { .id = ELE_ABORT_IND, .str = "ELE_ABORT" }, +}; + +static struct ele_str ele_ipc[] = { + { .id = ELE_IPC_MU_RTD, .str = "MU RTD" }, + { .id = ELE_IPC_MU_APD, .str = "MU APD" }, +}; + +static struct ele_str ele_command[] = { + { .id = ELE_PING_REQ, .str = "ELE_PING" }, + { .id = ELE_FW_AUTH_REQ, .str = "ELE_FW_AUTH" }, + { .id = ELE_RESTART_RST_TIMER_REQ, .str = "ELE_RESTART_RST_TIMER" }, + { .id = ELE_DUMP_DEBUG_BUFFER_REQ, .str = "ELE_DUMP_DEBUG_BUFFER" }, + { .id = ELE_OEM_CNTN_AUTH_REQ, .str = "ELE_OEM_CNTN_AUTH" }, + { .id = ELE_VERIFY_IMAGE_REQ, .str = "ELE_VERIFY_IMAGE" }, + { .id = ELE_RELEASE_CONTAINER_REQ, .str = "ELE_RELEASE_CONTAINER" }, + { .id = ELE_WRITE_SECURE_FUSE_REQ, .str = "ELE_WRITE_SECURE_FUSE" }, + { .id = ELE_FWD_LIFECYCLE_UP_REQ, .str = "ELE_FWD_LIFECYCLE_UP" }, + { .id = ELE_READ_FUSE_REQ, .str = "ELE_READ_FUSE" }, + { .id = ELE_GET_FW_VERSION_REQ, .str = "ELE_GET_FW_VERSION" }, + { .id = ELE_RET_LIFECYCLE_UP_REQ, .str = "ELE_RET_LIFECYCLE_UP" }, + { .id = ELE_GET_EVENTS_REQ, .str = "ELE_GET_EVENTS" }, + { .id = ELE_ENABLE_PATCH_REQ, .str = "ELE_ENABLE_PATCH" }, + { .id = ELE_RELEASE_RDC_REQ, .str = "ELE_RELEASE_RDC" }, + { .id = ELE_GET_FW_STATUS_REQ, .str = "ELE_GET_FW_STATUS" }, + { .id = ELE_ENABLE_OTFAD_REQ, .str = "ELE_ENABLE_OTFAD" }, + { .id = ELE_RESET_REQ, .str = "ELE_RESET" }, + { .id = ELE_UPDATE_OTP_CLKDIV_REQ, .str = "ELE_UPDATE_OTP_CLKDIV" }, + { .id = ELE_POWER_DOWN_REQ, .str = "ELE_POWER_DOWN" }, + { .id = ELE_ENABLE_APC_REQ, .str = "ELE_ENABLE_APC" }, + { .id = ELE_ENABLE_RTC_REQ, .str = "ELE_ENABLE_RTC" }, + { .id = ELE_DEEP_POWER_DOWN_REQ, .str = "ELE_DEEP_POWER_DOWN" }, + { .id = ELE_STOP_RST_TIMER_REQ, .str = "ELE_STOP_RST_TIMER" }, + { .id = ELE_WRITE_FUSE_REQ, .str = "ELE_WRITE_FUSE" }, + { .id = ELE_RELEASE_CAAM_REQ, .str = "ELE_RELEASE_CAAM" }, + { .id = ELE_RESET_A35_CTX_REQ, .str = "ELE_RESET_A35_CTX" }, + { .id = ELE_MOVE_TO_UNSECURED_REQ, .str = "ELE_MOVE_TO_UNSECURED" }, + { .id = ELE_GET_INFO_REQ, .str = "ELE_GET_INFO" }, + { .id = ELE_ATTEST_REQ, .str = "ELE_ATTEST" }, + { .id = ELE_RELEASE_PATCH_REQ, .str = "ELE_RELEASE_PATCH" }, + { .id = ELE_OTP_SEQ_SWITH_REQ, .str = "ELE_OTP_SEQ_SWITH" }, +}; + +static struct ele_str ele_status[] = { + { .id = ELE_SUCCESS_IND, .str = "ELE_SUCCESS" }, + { .id = ELE_FAILURE_IND, .str = "ELE_FAILURE" }, +}; + +static const struct ele_str *get_idx(struct ele_str *str, int size, int id) +{ + u32 i; + + for (i = 0; i < size; i++) { + if (str[i].id == id) + return &str[i]; + } + + return NULL; +} + +#define ELE_EVENT_IPC GENMASK(31, 24) +#define ELE_EVENT_COMMAND GENMASK(23, 16) +#define ELE_EVENT_IND GENMASK(15, 8) +#define ELE_EVENT_STATUS GENMASK(7, 0) + +static void display_event(u32 event) +{ + int ipc = FIELD_GET(ELE_EVENT_IPC, event); + int command = FIELD_GET(ELE_EVENT_COMMAND, event); + int ind = FIELD_GET(ELE_EVENT_IND, event); + int status = FIELD_GET(ELE_EVENT_STATUS, event); + const struct ele_str *ipc_str = get_idx(ARRAY_AND_SIZE(ele_ipc), ipc); + const struct ele_str *command_str = get_idx(ARRAY_AND_SIZE(ele_command), command); + const struct ele_str *ind_str = get_idx(ARRAY_AND_SIZE(ele_ind), ind); + const struct ele_str *status_str = get_idx(ARRAY_AND_SIZE(ele_status), status); + + pr_info("Event 0x%08x:\n", event); + pr_info(" IPC = %s (0x%02x)\n", ipc_str ? ipc_str->str : "INVALID", ipc); + pr_info(" CMD = %s (0x%02x)\n", command_str ? command_str->str : "INVALID", command); + pr_info(" IND = %s (0x%02x)\n", ind_str ? ind_str->str : "INVALID", ind); + pr_info(" STA = %s (0x%02x)\n", status_str ? status_str->str : "INVALID", status); +} + +#define AHAB_MAX_EVENTS 8 + +static int ahab_get_events(u32 *events) +{ + struct ele_msg msg; + int ret, i = 0; + u32 n_events; + + msg.version = ELE_VERSION; + msg.tag = ELE_CMD_TAG; + msg.size = 1; + msg.command = ELE_GET_EVENTS_REQ; + + ret = imx9_s3mua_call(&msg, true); + if (ret) { + pr_err("%s: ret %d, response 0x%x\n", __func__, ret, msg.data[0]); + + return ret; + } + + n_events = msg.data[1] & 0xffff; + + if (n_events > AHAB_MAX_EVENTS) + n_events = AHAB_MAX_EVENTS; + + for (; i < n_events; i++) + events[i] = msg.data[i + 2]; + + return n_events; +} + +unsigned int imx93_ahab_read_lifecycle(void) +{ + return readl(MX9_OCOTP_BASE_ADDR + 0x41c) & 0x3ff; +} + +static const char *ele_life_cycle(u32 lc) +{ + switch (lc) { + case ELE_LIFECYCLE_BLANK: return "BLANK"; + case ELE_LIFECYCLE_FAB: return "FAB"; + case ELE_LIFECYCLE_NXP_PROVISIONED: return "NXP Provisioned"; + case ELE_LIFECYCLE_OEM_OPEN: return "OEM Open"; + case ELE_LIFECYCLE_OEM_CLOSED: return "OEM closed"; + case ELE_LIFECYCLE_FIELD_RETURN_OEM: return "Field Return OEM"; + case ELE_LIFECYCLE_FIELD_RETURN_NXP: return "Field Return NXP"; + case ELE_LIFECYCLE_OEM_LOCKED: return "OEM Locked"; + case ELE_LIFECYCLE_BRICKED: return "BRICKED"; + default: return "Unknown"; + } +} + +int ele_print_events(void) +{ + unsigned int lc; + u32 events[AHAB_MAX_EVENTS]; + int i, ret; + + lc = imx93_ahab_read_lifecycle(); + pr_info("Current lifecycle: %s\n", ele_life_cycle(lc)); + + ret = ahab_get_events(events); + if (ret < 0) + return ret; + + if (!ret) { + pr_info("No Events Found!\n"); + return 0; + } + + for (i = 0; i < ret; i++) + display_event(events[i]); + + return 0; +} diff --git a/include/mach/imx/ele.h b/include/mach/imx/ele.h index 7e6896be3c..018e8345aa 100644 --- a/include/mach/imx/ele.h +++ b/include/mach/imx/ele.h @@ -132,6 +132,18 @@ struct ele_get_info_data { u32 state; }; +enum ele_lifecycle { + ELE_LIFECYCLE_BLANK = 0x1, + ELE_LIFECYCLE_FAB = 0x2, + ELE_LIFECYCLE_NXP_PROVISIONED = 0x4, + ELE_LIFECYCLE_OEM_OPEN = 0x8, + ELE_LIFECYCLE_OEM_CLOSED = 0x20, + ELE_LIFECYCLE_FIELD_RETURN_OEM = 0x40, + ELE_LIFECYCLE_FIELD_RETURN_NXP = 0x80, + ELE_LIFECYCLE_OEM_LOCKED = 0x100, + ELE_LIFECYCLE_BRICKED = 0x200, +}; + #define ELE_INFO_SOC_REV GENMASK(31, 24) int ele_call(struct ele_msg *msg, bool get_response); @@ -140,7 +152,13 @@ int ele_read_common_fuse(u16 fuse_id, u32 *fuse_word, u32 *response); int ele_release_rdc(u8 core_id, u8 xrdc, u32 *response); int ele_read_shadow_fuse(u16 fuse_id, u32 *fuse_word, u32 *response); int ele_get_info(struct ele_get_info_data *info); +int ele_write_fuse(u16 fuse_id, u32 fuse_val, bool lock, u32 *response); +int ele_authenticate_container(unsigned long addr, u32 *response); +int ele_release_container(u32 *response); +int ele_forward_lifecycle(enum ele_lifecycle lc, u32 *response); +int ele_print_events(void); int imx93_ele_load_fw(void *bl33); +unsigned int imx93_ahab_read_lifecycle(void); #endif -- 2.39.2