[sherlock] 9.20221010.3.176 u-boot source
GitOrigin-RevId: a6d3993ddd37fe5c304ac8201a8d9ebc4c6ce96d
Change-Id: Ia900dabbc2a7edca14776d46bf9550e58b7a037e
Reviewed-on: https://turquoise-internal-review.googlesource.com/c/third_party/u-boot/+/655994
Reviewed-by: David Pursell <dpursell@google.com>
diff --git a/arb_version.txt b/arb_version.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/arb_version.txt
@@ -0,0 +1 @@
+1
diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
index 92b4267..30e5cdb 100644
--- a/arch/arm/lib/bootm.c
+++ b/arch/arm/lib/bootm.c
@@ -85,12 +85,12 @@
}
#ifndef CONFIG_TA_VX
-static inline void vx_finalize(void) {}
+static inline void vx_finalize_or_panic(void) {}
#else
-static void vx_finalize(void)
+static void vx_finalize_or_panic(void)
{
printf("VX: finalizing policies and configurations...\n");
- ta_vx_exit_bootloader(); // Panics on error.
+ ta_vx_exit_bootloader_or_panic(); // Panics on error.
}
#endif /* CONFIG_TA_VX */
@@ -116,7 +116,7 @@
#endif
/* Finalize Verified Execution policies and configurations. */
- vx_finalize();
+ vx_finalize_or_panic();
board_quiesce_devices();
diff --git a/board/amlogic/g12b_newman_bx/zircon_partition_map.c b/board/amlogic/g12b_newman_bx/zircon_partition_map.c
index 65a449a..5a2f164 100644
--- a/board/amlogic/g12b_newman_bx/zircon_partition_map.c
+++ b/board/amlogic/g12b_newman_bx/zircon_partition_map.c
@@ -5,6 +5,7 @@
*/
#include <common.h>
+#include <emmc_partitions.h>
#include <mmc.h>
#include <zircon_uboot/partition_internal.h>
@@ -193,7 +194,14 @@
.name = "fvm",
.fastboot_locked_access = ZIRCON_PARTITION_ACCESS_FLAG_WRITE,
.gpt_name = "fuchsia-fvm",
- }
+ },
+ {
+ .name = MMC_SECURE_STORAGE_NAME,
+ .fastboot_locked_access = ZIRCON_PARTITION_ACCESS_DEV_ONLY,
+ .gpt_name = "reserved",
+ .gpt_offset = MMC_SECURE_STORAGE_OFFSET,
+ .size = MMC_SECURE_STORAGE_SIZE,
+ },
};
const size_t zircon_partition_map_count = ARRAY_SIZE(zircon_partition_map);
diff --git a/common/Kconfig b/common/Kconfig
index 4f90eae..f07b201 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -641,14 +641,6 @@
bool "Support Verified Execution Trusted App"
default n
-config TA_VX_AUTO_PROVISION_RPMB
- bool "Automatically provision RPMB in the VX TA"
- help
- Configure the VX TA such that it will automatically provision the
- RPMB if the RPMB authentication key is not already programmed.
- depends on TA_VX
- default n
-
config TA_VX_TESTS
bool "Enable `fastboot oem vx-test` and `vx test` commands."
help
diff --git a/common/ta_vx_helper.c b/common/ta_vx_helper.c
index b6d0412..2406b3e 100644
--- a/common/ta_vx_helper.c
+++ b/common/ta_vx_helper.c
@@ -9,47 +9,13 @@
#include <tee/ta_helper.h>
#include <tee/ta_vx.h>
#include <tee/ta_vx_helper.h>
+#include <zircon_uboot/boot_args.h>
#ifdef CONFIG_TA_VX
#define VX_PERM_ATTR_HASH_SIZE 32
static struct tee_optee_ta_uuid vx_uuid = TA_VX_UUID;
-static int ta_vx_setup(void)
-{
- uint32_t options = 0;
- static bool setup_done = false;
- static int setup_result = 0;
-
- if (setup_done) {
- return setup_result;
- }
-
-#ifdef CONFIG_TA_VX_AUTO_PROVISION_RPMB
- options |= VX_OPTION_AUTO_PROVISION_RPMB;
-#endif
-
- if (options) {
- struct tee_param params[1] = { 0 };
- params[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
- params[0].u.value.a = options;
- setup_result = ta_call(&vx_uuid, TA_VX_CMD_SET_OPTIONS,
- ARRAY_SIZE(params), params);
- }
-
- setup_done = true;
- return setup_result;
-}
-
-#define SETUP_OR_FAIL() \
- do { \
- int rc = ta_vx_setup(); \
- if (rc) { \
- printf("ta_vx_setup() failed, rc = %d.", rc); \
- return rc; \
- } \
- } while (0)
-
static int ta_vx_read_lock_state(enum vx_lock_state *lock_state)
{
int rc;
@@ -57,8 +23,6 @@
struct tee_param param = { 0 };
param.attr = TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT;
- SETUP_OR_FAIL();
-
rc = ta_call(&vx_uuid, TA_VX_CMD_READ_LOCK_STATE, 1, ¶m);
if (!rc) {
*lock_state = param.u.value.a;
@@ -73,16 +37,55 @@
param.attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
param.u.value.a = lock_state;
- SETUP_OR_FAIL();
-
return ta_call(&vx_uuid, TA_VX_CMD_WRITE_LOCK_STATE, 1, ¶m);
}
int ta_vx_lock(void)
{
+ int rc = zircon_clear_stored_cmdline();
+ if (rc) {
+ printf("Failed to clear stored boot args\n");
+ return rc;
+ }
+
return ta_vx_write_lock_state(VX_LOCKED);
}
+int ta_vx_lock_if_ephemerally_unlocked(void)
+{
+ int rc;
+ uint32_t vars;
+
+ rc = ta_vx_getvar_all(&vars);
+ if (rc) {
+ return rc;
+ }
+
+ if (!(vars & VX_VAR_EPHEMERALLY_UNLOCKED)) {
+ return 0;
+ }
+
+ printf("Locking up an ephemerally unlocked device\n");
+ rc = ta_vx_lock();
+ if (!rc) {
+ printf("ta_vx_lock() failed\n");
+ return rc;
+ }
+
+ rc = ta_vx_getvar_all(&vars);
+ if (rc) {
+ return rc;
+ }
+
+ if (vars & VX_VAR_EPHEMERALLY_UNLOCKED) {
+ printf("SHOCKED: device is still ephemerally unlocked after "
+ "successful locking\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
int ta_vx_unlock(void)
{
return ta_vx_write_lock_state(VX_UNLOCKED);
@@ -103,8 +106,6 @@
int rc;
struct tee_param params[2] = { 0 };
- SETUP_OR_FAIL();
-
params[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
params[0].u.value.a = slot;
@@ -124,8 +125,6 @@
{
struct tee_param params[2] = { 0 };
- SETUP_OR_FAIL();
-
params[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
params[0].u.value.a = slot;
@@ -149,8 +148,6 @@
size_t key_len = strlen(name) + 1;
- SETUP_OR_FAIL();
-
/* Connect to TA. */
rc = ta_open(&vx_uuid, &context);
if (rc)
@@ -206,8 +203,6 @@
size_t key_len = strlen(name) + 1;
- SETUP_OR_FAIL();
-
/* Connect to TA. */
rc = ta_open(&vx_uuid, &context);
if (rc)
@@ -254,8 +249,6 @@
struct tee_shm *shm_key = NULL;
size_t key_len = strlen(name) + 1;
- SETUP_OR_FAIL();
-
/* Connect to TA. */
rc = ta_open(&vx_uuid, &context);
if (rc)
@@ -287,8 +280,6 @@
struct tee_param params[1] = { 0 };
struct tee_shm *shm_buf = NULL;
- SETUP_OR_FAIL();
-
if (!(buf && buf_len))
return -EINVAL;
@@ -318,26 +309,16 @@
return rc;
}
-void ta_vx_exit_bootloader(void)
+void ta_vx_exit_bootloader_or_panic(void)
{
- /* Exiting bootloader should panic on failure so call ta_vx_setup()
- directly rather than using SETUP_OR_FAIL. */
- int rc = ta_vx_setup();
- if (rc) {
- printf("ta_vx_setup() failed, rc = %d.", rc);
- panic("VX setup failed!");
- }
+ uint32_t vars;
if (ta_call(&vx_uuid, TA_VX_CMD_EXIT_BOOTLOADER, 0, NULL)) {
panic("VX finalization failed!");
}
/* Make sure we are indeed beyond the bootloader security domain. */
- struct tee_param params[1] = { 0 };
- params[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_INPUT;
- params[0].u.value.a = VX_OPTION_FOR_TESTING;
- if (!ta_call(&vx_uuid, TA_VX_CMD_SET_OPTIONS, ARRAY_SIZE(params),
- params)) {
+ if (ta_vx_getvar_all(&vars) || !(vars & VX_VAR_OUT_OF_BOOTLOADER)) {
panic("VX finalization verification failed.");
}
@@ -352,8 +333,6 @@
struct tee_shm *shm_buf = NULL;
- SETUP_OR_FAIL();
-
if (!(buf && buf_len)) {
return -EINVAL;
}
@@ -400,8 +379,6 @@
struct tee_shm *shm_buf = NULL;
- SETUP_OR_FAIL();
-
if (!(buf && buf_len))
return -EINVAL;
@@ -438,8 +415,6 @@
int rc;
struct tee_param params[1] = { 0 };
- SETUP_OR_FAIL();
-
params[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT;
rc = ta_call(&vx_uuid, TA_VX_CMD_GET_RPMB_STATUS, ARRAY_SIZE(params),
params);
@@ -459,15 +434,26 @@
int ta_vx_provision_rpmb(void)
{
- SETUP_OR_FAIL();
-
return ta_call(&vx_uuid, TA_VX_CMD_PROVISION_RPMB, 0, NULL);
}
+int ta_vx_reroute_rpmb_till_reboot(void)
+{
+ return ta_call(&vx_uuid, TA_VX_CMD_REROUTE_RPMB_TILL_REBOOT, 0, NULL);
+}
+
+int ta_vx_reroute_rpmb_to_software(void)
+{
+ return ta_call(&vx_uuid, TA_VX_CMD_REROUTE_RPMB_TO_SOFTWARE, 0, NULL);
+}
+
+int ta_vx_reroute_rpmb_to_hardware(void)
+{
+ return ta_call(&vx_uuid, TA_VX_CMD_REROUTE_RPMB_TO_HARDWARE, 0, NULL);
+}
+
int ta_vx_delete_perm_attr(void)
{
- SETUP_OR_FAIL();
-
return ta_call(&vx_uuid, TA_VX_CMD_DELETE_PERM_ATTR, 0, NULL);
}
@@ -479,8 +465,6 @@
struct tee_shm *shm_buf = NULL;
- SETUP_OR_FAIL();
-
if (!buf || (buf_len < VX_PERM_ATTR_HASH_SIZE))
return -EINVAL;
@@ -523,8 +507,6 @@
struct tee_param param = { 0 };
param.attr = TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT;
- SETUP_OR_FAIL();
-
rc = ta_call(&vx_uuid, TA_VX_CMD_GET_PERM_ATTR_STATUS, 1, ¶m);
if (!rc) {
if (status) {
@@ -537,15 +519,11 @@
int ta_vx_lock_perm_attr(void)
{
- SETUP_OR_FAIL();
-
return ta_call(&vx_uuid, TA_VX_CMD_LOCK_PERM_ATTR, 0, NULL);
}
int ta_vx_provision_usb_hash(void)
{
- SETUP_OR_FAIL();
-
return ta_call(&vx_uuid, TA_VX_CMD_PROVISION_USBBOOT_PWD_HASH, 0, NULL);
}
@@ -556,8 +534,6 @@
struct tee_param param = { 0 };
param.attr = TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT;
- SETUP_OR_FAIL();
-
rc = ta_call(&vx_uuid, TA_VX_CMD_GET_USBBOOT_STATUS, 1, ¶m);
if (!rc) {
if (status) {
@@ -568,6 +544,26 @@
return rc;
}
+int ta_vx_getvar_all(uint32_t *out_vars)
+{
+ int rc;
+ struct tee_param params[1] = { 0 };
+
+ if (!out_vars) {
+ return -EINVAL;
+ }
+
+ params[0].attr = TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT;
+ rc = ta_call(&vx_uuid, TA_VX_CMD_GETVAR_ALL, ARRAY_SIZE(params),
+ params);
+ if (rc) {
+ return rc;
+ }
+
+ *out_vars = params[0].u.value.a;
+ return 0;
+}
+
#ifdef CONFIG_TA_VX_TESTS
int ta_vx_run_tests(const char *name)
{
@@ -577,8 +573,6 @@
size_t name_len = strlen(name) + 1;
struct tee_shm *shm_buf = NULL;
- SETUP_OR_FAIL();
-
rc = ta_open(&vx_uuid, &context);
if (rc)
return rc;
@@ -616,6 +610,11 @@
return ta_vx_fail(__func__);
}
+int ta_vx_lock_if_ephemerally_unlocked()
+{
+ return ta_vx_fail(__func__);
+}
+
int ta_vx_unlock()
{
return ta_vx_fail(__func__);
@@ -658,7 +657,7 @@
return ta_vx_fail(__func__);
}
-void ta_vx_exit_bootloader()
+void ta_vx_exit_bootloader_or_panic()
{
/* Unlike other VX stubs, this one succeeds by default as a no-op if
the VX TA is disabled. */
@@ -704,6 +703,21 @@
return ta_vx_fail(__func__);
}
+int ta_vx_reroute_rpmb_till_reboot(void)
+{
+ return ta_vx_fail(__func__);
+}
+
+int ta_vx_reroute_rpmb_to_software(void)
+{
+ return ta_vx_fail(__func__);
+}
+
+int ta_vx_reroute_rpmb_to_hardware(void)
+{
+ return ta_vx_fail(__func__);
+}
+
int ta_vx_provision_usb_hash(void)
{
return ta_vx_fail(__func__);
@@ -714,4 +728,9 @@
return ta_vx_fail(__func__);
}
+int ta_vx_getvar_all(uint32_t *out_vars)
+{
+ return ta_vx_fail(__func__);
+}
+
#endif // CONFIG_TA_VX
diff --git a/common/zircon_partition.c b/common/zircon_partition.c
index 9960d0b..20a61cc 100644
--- a/common/zircon_partition.c
+++ b/common/zircon_partition.c
@@ -20,7 +20,7 @@
/* Temporary buffer when we need to cache data locally. Only valid for use
within a single call, do not expect the contents to be consistent across
multiple calls since other functions may have modified it. */
-static uint8_t temp_buffer[ERASE_GROUP_SIZE] = { 0 };
+static uint8_t temp_buffer[ERASE_GROUP_SIZE] __aligned(ARCH_DMA_MINALIGN);
static int store_call_setup(const zircon_partition *part, uint64_t offset,
size_t length)
@@ -107,6 +107,49 @@
return -1;
}
+ // store_write() offset must be at a block boundary. If our |offset| is
+ // not, read the first partial block, modify and write back manually.
+ // Compute the unaligned write offset within the first block.
+ size_t first_block_write_offset =
+ offset % part->data->mmc->write_bl_len;
+ if (first_block_write_offset) {
+ static uint8_t scratch_buffer[512] __aligned(ARCH_DMA_MINALIGN);
+ assert(sizeof(scratch_buffer) == part->data->mmc->write_bl_len);
+ // The aligned offset of the first block.
+ size_t first_block_offset = offset - first_block_write_offset;
+
+ // Read the block
+ int res = gpt_part_read(part, first_block_offset,
+ scratch_buffer, sizeof(scratch_buffer));
+ if (res) {
+ return res;
+ }
+
+ // The amount of data to write for the first block. It's the smaller
+ // of the total length and the remaining part in the block.
+ size_t first_block_write_length =
+ min(length,
+ sizeof(scratch_buffer) - first_block_write_offset);
+
+ // Modify
+ memcpy(scratch_buffer + first_block_write_offset, buffer,
+ first_block_write_length);
+
+ // Write back the modified data.
+ res = gpt_part_write(part, first_block_offset, scratch_buffer,
+ sizeof(scratch_buffer));
+ if (res) {
+ return res;
+ }
+
+ offset += first_block_write_length;
+ length -= first_block_write_length;
+ buffer = (const uint8_t *)(buffer) + first_block_write_length;
+ if (length == 0) {
+ return 0;
+ }
+ }
+
return store_write(part->data->gpt_name,
part->data->gpt_offset + offset, length, buffer);
}
@@ -860,6 +903,16 @@
return NULL;
}
+ // If we are not in dev build, check if access is dev only.
+#if !defined(DEV_BUILD_CONFIG)
+ if (part->data->fastboot_locked_access &
+ ZIRCON_PARTITION_ACCESS_DEV_ONLY) {
+ part->write = NULL;
+ part->erase = NULL;
+ return part;
+ }
+#endif
+
if (unlocked) {
return part;
}
diff --git a/common/zircon_vboot.c b/common/zircon_vboot.c
index 1635e4c..9248ed5 100644
--- a/common/zircon_vboot.c
+++ b/common/zircon_vboot.c
@@ -376,6 +376,11 @@
NULL
};
+ int ret = ta_vx_lock_if_ephemerally_unlocked();
+ if (ret) {
+ return ret;
+ }
+
AvbSlotVerifyData *verify_data = NULL;
AvbSlotVerifyResult result =
@@ -383,7 +388,7 @@
AVB_SLOT_VERIFY_FLAGS_NONE,
AVB_HASHTREE_ERROR_MODE_EIO, &verify_data);
- int ret = process_verify_data(&ops, result, verify_data, &context, zbi,
+ ret = process_verify_data(&ops, result, verify_data, &context, zbi,
capacity, has_successfully_booted);
if (verify_data) {
avb_slot_verify_data_free(verify_data);
@@ -521,6 +526,11 @@
ramboot_ops.user_data = (void *)&context;
+ int ret = ta_vx_lock_if_ephemerally_unlocked();
+ if (ret) {
+ return ret;
+ }
+
AvbSlotVerifyData *verify_data = NULL;
AvbSlotVerifyResult result =
@@ -528,7 +538,7 @@
AVB_SLOT_VERIFY_FLAGS_NONE,
AVB_HASHTREE_ERROR_MODE_EIO, &verify_data);
- int ret = process_verify_data(&ramboot_ops, result, verify_data, NULL,
+ ret = process_verify_data(&ramboot_ops, result, verify_data, NULL,
zbi, capacity, false);
if (verify_data) {
avb_slot_verify_data_free(verify_data);
diff --git a/configs/g12b_newman_bx_zircon_defconfig b/configs/g12b_newman_bx_zircon_defconfig
index d76e341..5df275e 100644
--- a/configs/g12b_newman_bx_zircon_defconfig
+++ b/configs/g12b_newman_bx_zircon_defconfig
@@ -12,7 +12,6 @@
CONFIG_TEE=y
CONFIG_OPTEE=y
CONFIG_TA_VX=y
-CONFIG_TA_VX_AUTO_PROVISION_RPMB=y
CONFIG_SUPPORT_EMMC_RPMB=y
CONFIG_CMD_TEE=y
CONFIG_DM_GPIO=y
@@ -225,3 +224,4 @@
CONFIG_LZ4=y
CONFIG_NET=n
CONFIG_AML_GPT_SYNC_ENTIRE_ENTRY=y
+CONFIG_OPTEE_RAW_PARTITION_IO=y
diff --git a/drivers/mmc/aml_emmc_partition.c b/drivers/mmc/aml_emmc_partition.c
index 0aa40c3..0e19001 100644
--- a/drivers/mmc/aml_emmc_partition.c
+++ b/drivers/mmc/aml_emmc_partition.c
@@ -119,25 +119,36 @@
};
struct virtual_partition virtual_partition_table[] = {
- /* partition for name idx, off & size will not be used! */
+/* partition for name idx, off & size will not be used! */
#if (CONFIG_PTBL_MBR)
- VIRTUAL_PARTITION_ELEMENT(MMC_MBR_NAME, MMC_MBR_OFFSET, MMC_MBR_SIZE),
+ VIRTUAL_PARTITION_ELEMENT(MMC_MBR_NAME, MMC_MBR_OFFSET, MMC_MBR_SIZE),
#endif
- VIRTUAL_PARTITION_ELEMENT(MMC_BOOT_NAME0, 0, 0),
- VIRTUAL_PARTITION_ELEMENT(MMC_BOOT_NAME1, 0, 0),
+ VIRTUAL_PARTITION_ELEMENT(MMC_BOOT_NAME0, 0, 0),
+ VIRTUAL_PARTITION_ELEMENT(MMC_BOOT_NAME1, 0, 0),
/* virtual partition in reserved partition, take care off and size */
#ifdef CONFIG_AML_PARTITION
- VIRTUAL_PARTITION_ELEMENT(MMC_TABLE_NAME, MMC_TABLE_OFFSET, MMC_TABLE_SIZE),
+ VIRTUAL_PARTITION_ELEMENT(MMC_TABLE_NAME, MMC_TABLE_OFFSET,
+ MMC_TABLE_SIZE),
#endif
- VIRTUAL_PARTITION_ELEMENT(MMC_KEY_NAME, EMMCKEY_RESERVE_OFFSET, MMC_KEY_SIZE),
- VIRTUAL_PARTITION_ELEMENT(MMC_PATTERN_NAME, CALI_PATTERN_OFFSET, CALI_PATTERN_SIZE),
+ VIRTUAL_PARTITION_ELEMENT(MMC_KEY_NAME, EMMCKEY_RESERVE_OFFSET,
+ MMC_KEY_SIZE),
+ VIRTUAL_PARTITION_ELEMENT(MMC_PATTERN_NAME, CALI_PATTERN_OFFSET,
+ CALI_PATTERN_SIZE),
#ifndef DTB_BIND_KERNEL
VIRTUAL_PARTITION_ELEMENT(MMC_DTB_NAME, DTB_OFFSET, DTB_SIZE),
#endif
VIRTUAL_PARTITION_ELEMENT(MMC_FASTBOOT_CONTEXT_NAME,
- FASTBOOT_CONTEXT_OFFSET, FASTBOOT_CONTEXT_SIZE),
- VIRTUAL_PARTITION_ELEMENT(MMC_DDR_PARAMETER_NAME,DDR_PARAMETER_OFFSET, DDR_PARAMETER_SIZE),
+ FASTBOOT_CONTEXT_OFFSET,
+ FASTBOOT_CONTEXT_SIZE),
+ VIRTUAL_PARTITION_ELEMENT(MMC_DDR_PARAMETER_NAME, DDR_PARAMETER_OFFSET,
+ DDR_PARAMETER_SIZE),
+ // Partition for storing secure storage data.
+ // Rerserve the entry here so that merging of any upstream code change
+ // on the table will be made aware of this local change.
+ VIRTUAL_PARTITION_ELEMENT(MMC_SECURE_STORAGE_NAME,
+ MMC_SECURE_STORAGE_OFFSET,
+ MMC_SECURE_STORAGE_SIZE),
};
int get_emmc_partition_arraysize(void)
diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c
index c53a624..82ade52 100644
--- a/drivers/mmc/mmc_write.c
+++ b/drivers/mmc/mmc_write.c
@@ -134,8 +134,20 @@
return 0;
}
-static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start,
- lbaint_t blkcnt, const void *src)
+static int mmc_set_blockcount(struct mmc *mmc, unsigned int blockcount)
+{
+ struct mmc_cmd cmd = { 0 };
+
+ cmd.cmdidx = MMC_CMD_SET_BLOCK_COUNT;
+ cmd.cmdarg = min(blockcount, (unsigned int)MMC_BLOCK_COUNT_MAX);
+ cmd.cmdarg |= MMC_RELIABLE_WRITE_ARG;
+ cmd.resp_type = MMC_RSP_R1;
+
+ return mmc_send_cmd(mmc, &cmd, NULL);
+}
+
+static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start, lbaint_t blkcnt,
+ const void *src)
{
struct mmc_cmd cmd;
struct mmc_data data;
@@ -146,13 +158,20 @@
return 0;
}
+ if (mmc->ext_csd[EXT_CSD_DATA_SECTOR_SIZE] !=
+ EXT_CSD_DATA_SECTOR_SIZE_512) {
+ printf("MMC: mmc is not operating in 512 bytes sector size.\n");
+ return 0;
+ }
+
if (blkcnt == 0)
return 0;
- else if (blkcnt == 1)
- cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK;
- else
- cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
+ // Set block count and activate reliable write.
+ if (mmc_set_blockcount(mmc, blkcnt))
+ return 0;
+
+ cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
if (mmc->high_capacity)
cmd.cmdarg = start;
else
@@ -170,18 +189,7 @@
return 0;
}
- /* SPI multiblock writes terminate using a special
- * token, not a STOP_TRANSMISSION request.
- */
- if (!mmc_host_is_spi(mmc) && blkcnt > 1) {
- cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
- cmd.cmdarg = 0;
- cmd.resp_type = MMC_RSP_R1b;
- if (mmc_send_cmd(mmc, &cmd, NULL)) {
- printf("mmc fail to send stop cmd\n");
- return 0;
- }
- }
+ // Pre-defined block count. No need for stop command.
/* Waiting for the ready status */
if (mmc_send_status(mmc, timeout))
@@ -220,9 +228,10 @@
return 0;
do {
- cur = (blocks_todo > mmc->cfg->b_max) ?
- mmc->cfg->b_max : blocks_todo;
-
+ cur = min(blocks_todo, (lbaint_t)mmc->cfg->b_max);
+ // Reliable write requires to set block count, which is only 2 bytes.
+ // Thus limit the write size to no more than 0xffff blocks.
+ cur = min((lbaint_t)MMC_BLOCK_COUNT_MAX, cur);
if (mmc_write_blocks(mmc, start, cur, src) != cur)
return 0;
diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig
index d489834..e7ca2ec 100644
--- a/drivers/tee/optee/Kconfig
+++ b/drivers/tee/optee/Kconfig
@@ -22,6 +22,13 @@
The TA can support the "avb" subcommands "read_rb", "write"rb"
and "is_unlocked".
+config OPTEE_RAW_PARTITION_IO
+ bool "Enable secure storage backed by a raw partition"
+ help
+ Enables supplicant support for routing raw IO requests to a designated
+ partition.
+ default n
+
endmenu
endif
diff --git a/drivers/tee/optee/Makefile b/drivers/tee/optee/Makefile
index 928d3f8..fb4b79e 100644
--- a/drivers/tee/optee/Makefile
+++ b/drivers/tee/optee/Makefile
@@ -3,3 +3,4 @@
obj-y += core.o
obj-y += supplicant.o
obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
+obj-$(CONFIG_OPTEE_RAW_PARTITION_IO) += raw_io.o
diff --git a/drivers/tee/optee/optee_msg_supplicant.h b/drivers/tee/optee/optee_msg_supplicant.h
index a0fb806..9891c2b 100644
--- a/drivers/tee/optee/optee_msg_supplicant.h
+++ b/drivers/tee/optee/optee_msg_supplicant.h
@@ -237,4 +237,37 @@
* End of definitions for messages with .cmd == OPTEE_MSG_RPC_CMD_SOCKET
*/
+/*
+ * Raw partition IO
+ *
+ * Starting with 0x100 to avoid conflicts with the upstream:
+ * https://github.com/OP-TEE/optee_client/blob/master/tee-supplicant/src/optee_msg_supplicant.h
+ */
+#define OPTEE_MSG_RPC_CMD_RAW 0x100
+
+
+/*
+ * Definitions for messages with .cmd == OPTEE_MSG_RPC_CMD_RAW
+ */
+
+/*
+ * Read bytes from a RAW partition
+ *
+ * [in] param[0].u.value.a OPTEE_MRC_RAW_READ
+ * [in] param[0].u.value.b offset into the partition
+ * [in] param[0].u.value.c length in bytes
+ * [in] param[1].u.tmem buffer to receive the bytes
+ */
+#define OPTEE_MRC_RAW_READ 0
+
+/*
+ * Write bytes to a RAW partition
+ *
+ * [in] param[0].u.value.a OPTEE_MRC_RAW_WRITE
+ * [in] param[0].u.value.b offset into the partition
+ * [in] param[0].u.value.c length in bytes
+ * [in] param[1].u.tmem buffer containing the bytes
+ */
+#define OPTEE_MRC_RAW_WRITE 1
+
#endif /* __OPTEE_MSG_SUPPLICANT_H */
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h
index 1db953a..ba9e04a 100644
--- a/drivers/tee/optee/optee_private.h
+++ b/drivers/tee/optee/optee_private.h
@@ -62,4 +62,21 @@
}
#endif
+#ifdef CONFIG_OPTEE_RAW_PARTITION_IO
+
+/**
+ * optee_suppl_cmd_raw_io() - basic IO to a designated raw partition
+ * @arg: OP-TEE message holding the request details.
+ */
+void optee_suppl_cmd_raw_io(struct optee_msg_arg *arg);
+
+#else
+
+static inline void optee_suppl_cmd_raw_io(struct optee_msg_arg *arg)
+{
+ arg->ret = TEE_ERROR_NOT_IMPLEMENTED;
+}
+
+#endif /* CONFIG_OPTEE_RAW_PARTITION_IO */
+
#endif /* __OPTEE_PRIVATE_H */
diff --git a/drivers/tee/optee/raw_io.c b/drivers/tee/optee/raw_io.c
new file mode 100644
index 0000000..dfb8baa
--- /dev/null
+++ b/drivers/tee/optee/raw_io.c
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2022 Google
+ */
+
+#include <common.h>
+#include <emmc_partitions.h>
+#include <tee.h>
+#include <tee/optee.h>
+#include <zircon_uboot/partition.h>
+
+#include "optee_msg.h"
+#include "optee_msg_supplicant.h"
+#include "optee_private.h"
+
+/*
+ * Read `length` bytes from `offset` of a designated raw partition into
+ * `buffer`. Buffer size is guaranteed to be >= `length`.
+ */
+static u32 do_read(u64 offset, u64 length, void *buffer)
+{
+ zircon_partition *part = zircon_get_partition(MMC_SECURE_STORAGE_NAME);
+ if (!part) {
+ return TEE_ERROR_ITEM_NOT_FOUND;
+ }
+
+ if (!part->read) {
+ printf("Optee raw IO: no read implementation\n");
+ zircon_free_partition(part);
+ return TEE_ERROR_NOT_SUPPORTED;
+ }
+
+ // Boundary check will be performed in read(). The API supports unaligned
+ // read.
+ int res = part->read(part, offset, buffer, length);
+ if (res) {
+ printf("Optee raw IO: read failed. %d\n", res);
+ zircon_free_partition(part);
+ return TEE_ERROR_GENERIC;
+ }
+
+ zircon_free_partition(part);
+ return TEE_SUCCESS;
+}
+
+/*
+ * Write `length` bytes from `buffer` into a designated raw partition at
+ * `offset`. Buffer size is guaranteed to be >= `length`.
+ */
+static u32 do_write(u64 offset, u64 length, const void *buffer)
+{
+ zircon_partition *part = zircon_get_partition(MMC_SECURE_STORAGE_NAME);
+ if (!part) {
+ return TEE_ERROR_ITEM_NOT_FOUND;
+ }
+
+ if (!part->write) {
+ printf("Optee raw IO: no write implementation\n");
+ zircon_free_partition(part);
+ return TEE_ERROR_NOT_SUPPORTED;
+ }
+
+ // Boundary check will be performed in write(). The API supports unaligned
+ // write.
+ int res = part->write(part, offset, buffer, length);
+ if (res) {
+ printf("Optee raw IO: write failed. %d\n", res);
+ zircon_free_partition(part);
+ return TEE_ERROR_GENERIC;
+ }
+
+ zircon_free_partition(part);
+ return TEE_SUCCESS;
+}
+
+void optee_suppl_cmd_raw_io(struct optee_msg_arg *arg)
+{
+ u64 offset;
+ u64 length;
+ void *buffer;
+ u64 buffer_size;
+
+ /* The supplicant is part of the REE<>TEE communications stack. */
+ arg->ret_origin = TEE_ORIGIN_COMMS;
+
+ if (!(arg->num_params == 2 &&
+ arg->params[0].attr == OPTEE_MSG_ATTR_TYPE_VALUE_INPUT)) {
+ arg->ret = TEE_ERROR_BAD_PARAMETERS;
+ return;
+ }
+
+ offset = arg->params[0].u.value.b;
+ length = arg->params[0].u.value.c;
+ buffer = (u8 *)arg->params[1].u.tmem.buf_ptr;
+ buffer_size = arg->params[1].u.tmem.size;
+ if (!(buffer && buffer_size > 0 && buffer_size >= length)) {
+ arg->ret = TEE_ERROR_BAD_PARAMETERS;
+ return;
+ }
+
+ switch (arg->params[0].u.value.a) {
+ case OPTEE_MRC_RAW_READ:
+ if (arg->params[1].attr != OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT) {
+ arg->ret = TEE_ERROR_BAD_PARAMETERS;
+ return;
+ }
+
+ arg->ret = do_read(offset, length, buffer);
+ break;
+ case OPTEE_MRC_RAW_WRITE:
+ if (arg->params[1].attr != OPTEE_MSG_ATTR_TYPE_TMEM_INPUT) {
+ arg->ret = TEE_ERROR_BAD_PARAMETERS;
+ return;
+ }
+
+ arg->ret = do_write(offset, length, buffer);
+ break;
+ default:
+ arg->ret = TEE_ERROR_BAD_PARAMETERS;
+ break;
+ }
+
+ return;
+}
+
+#if defined(DEV_BUILD_CONFIG)
+int optee_suppl_cmd_raw_io_wrapper(enum optee_suppl_cmd_raw_io_op op,
+ void *buffer, size_t offset, size_t length)
+{
+ struct optee_suppl_cmd_raw_io_test_param {
+ struct optee_msg_arg arg;
+ struct optee_msg_param params[2];
+ } test_arg = {
+ .arg = {
+ .num_params = 2,
+ },
+ .params[0] = {
+ .attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT,
+ .u.value.b = offset,
+ .u.value.c = length,
+ },
+ .params[1] = {
+ .u.tmem.buf_ptr = (u64)buffer,
+ .u.tmem.size = length,
+ },
+ };
+ switch (op) {
+ case optee_suppl_cmd_raw_io_read:
+ test_arg.arg.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT;
+ test_arg.arg.params[0].u.value.a = OPTEE_MRC_RAW_READ;
+ break;
+ case optee_suppl_cmd_raw_io_write:
+ test_arg.arg.params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
+ test_arg.arg.params[0].u.value.a = OPTEE_MRC_RAW_WRITE;
+ break;
+ default:
+ return -1;
+ }
+
+ optee_suppl_cmd_raw_io(&test_arg.arg);
+ return test_arg.arg.ret == TEE_SUCCESS ? 0 : -1;
+}
+#endif
\ No newline at end of file
diff --git a/drivers/tee/optee/supplicant.c b/drivers/tee/optee/supplicant.c
index d5338b2..03351aa 100644
--- a/drivers/tee/optee/supplicant.c
+++ b/drivers/tee/optee/supplicant.c
@@ -75,6 +75,10 @@
case OPTEE_MSG_RPC_CMD_RPMB:
optee_suppl_cmd_rpmb(dev, arg);
break;
+ case OPTEE_MSG_RPC_CMD_RAW:
+ /* Raw partition IO */
+ optee_suppl_cmd_raw_io(arg);
+ break;
default:
arg->ret = TEE_ERROR_NOT_IMPLEMENTED;
}
diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c
index 3e5f057..1d62557 100644
--- a/drivers/usb/gadget/f_fastboot.c
+++ b/drivers/usb/gadget/f_fastboot.c
@@ -32,6 +32,7 @@
#include <mmc.h>
#include <stdalign.h>
#include <tee/ta_vx.h>
+#include <tee/optee.h>
#include <version.h>
#include <zircon_uboot/boot_args.h>
#include <zircon_uboot/bootimg.h>
@@ -550,6 +551,23 @@
return false;
}
+#if defined(DEV_BUILD_CONFIG)
+static bool fb_run_again_to_confirm_or_fail(void)
+{
+ static uint32_t nth_run = 0;
+
+ nth_run++;
+
+ if (nth_run % 2) {
+ fastboot_fail("RERUN COMMAND TO CONFIRM YOU KNOW WHAT YOU ARE "
+ "DOING!");
+ return true;
+ }
+
+ return false;
+}
+#endif // DEV_BUILD_CONFIG
+
static void cb_reboot(struct usb_ep *ep, struct usb_request *req)
{
char *cmd = req->buf;
@@ -861,6 +879,17 @@
return unlocked ? "no" : "yes";
}
+static const char *get_dev_key_enabled(const char *arg)
+{
+ uint32_t vars = 0;
+
+ if (ta_vx_getvar_all(&vars)) {
+ return "error";
+ }
+
+ return !!(vars & VX_VAR_DEV_KEY_ENABLED)? "yes" : "no";
+}
+
static const char *get_rpmb_key_programmed(const char *arg)
{
uint32_t flags = 0;
@@ -894,6 +923,17 @@
return (flags & VX_RPMB_PROVISIONING_ALLOWED) ? "yes": "no";
}
+static const char *get_rpmb_protection_level(const char *arg)
+{
+ uint32_t flags = 0;
+
+ if (ta_vx_get_rpmb_status(&flags, /* out_write_count= */NULL)) {
+ return "error";
+ }
+
+ return (flags & VX_RPMB_REROUTING_TRAFFIC) ? "100": "1000";
+}
+
static const char *get_rpmb_total_bytes(const char *arg)
{
uint8_t rpmb_size_mult;
@@ -961,6 +1001,10 @@
.func = get_current_slot,
},
{
+ .name = "dev-key-enabled",
+ .func = get_dev_key_enabled,
+ },
+ {
.name = "emmc-firmware-revision",
.func = get_emmc_firmware_revision,
},
@@ -1001,6 +1045,10 @@
.func = get_rpmb_key_verified,
},
{
+ .name = "rpmb-protection-level",
+ .func = get_rpmb_protection_level,
+ },
+ {
.name = "rpmb-provisioning-allowed",
.func = get_rpmb_provisioning_allowed,
},
@@ -1526,6 +1574,102 @@
fastboot_okay(NULL);
}
+#if defined(DEV_BUILD_CONFIG)
+static void cb_kill_rpmb_till_reboot(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ int rc;
+ uint32_t flags = 0;
+
+ rc = ta_vx_reroute_rpmb_till_reboot();
+ if (rc) {
+ fastboot_fail("Request somehow got rejected.");
+ return;
+ }
+
+ rc = ta_vx_get_rpmb_status(&flags, /* out_write_count= */NULL);
+ if (rc) {
+ fastboot_fail("Failed to query RPMB status.");
+ return;
+ }
+
+ if (!(flags & VX_RPMB_REROUTING_TRAFFIC)) {
+ fastboot_fail("Request went through but didn't take effect.");
+ return;
+ }
+
+ fastboot_okay(NULL);
+}
+
+static void cb_kill_rpmb(struct usb_ep *ep, struct usb_request *req)
+{
+ int rc;
+ uint32_t flags = 0;
+
+ if (fb_run_again_to_confirm_or_fail()) {
+ return;
+ }
+
+ rc = ta_vx_reroute_rpmb_to_software();
+ if (rc) {
+ fastboot_fail("Rejected. Have you killed RPMB before?");
+ return;
+ }
+
+ rc = ta_vx_get_rpmb_status(&flags, /* out_write_count= */NULL);
+ if (rc) {
+ fastboot_fail("Failed to query RPMB status.");
+ return;
+ }
+
+ if (!(flags & VX_RPMB_REROUTING_TRAFFIC)) {
+ fastboot_fail("Request went through but didn't take effect!");
+ return;
+ }
+
+ fastboot_okay(NULL);
+}
+
+static void cb_unkill_rpmb(struct usb_ep *ep, struct usb_request *req)
+{
+ int rc;
+ uint32_t flags = 0;
+ static bool just_need_fastboot_okay = false;
+
+ if (just_need_fastboot_okay) {
+ just_need_fastboot_okay = false;
+ fastboot_okay(NULL);
+ return;
+ }
+
+ rc = ta_vx_get_rpmb_status(&flags, /* out_write_count= */NULL);
+ if (rc) {
+ fastboot_fail("Failed to query RPMB status.");
+ return;
+ }
+
+ if (!(flags & VX_RPMB_REROUTING_TRAFFIC)) {
+ fastboot_fail("Your RPMB is alive, maybe kill it first?");
+ return;
+ }
+
+ if (fb_run_again_to_confirm_or_fail()) {
+ return;
+ }
+
+ rc = ta_vx_reroute_rpmb_to_hardware();
+ if (rc) {
+ fastboot_fail("Request somehow got rejected.");
+ return;
+ }
+
+ /* Reboot is required to take effect because it is not safe or reliable
+ * for TEE to revert rerouting. */
+ just_need_fastboot_okay = true;
+ fastboot_info("Please reboot device to take effect.");
+}
+#endif /* defined(DEV_BUILD_CONFIG) */
+
static void cb_provision_rpmb(struct usb_ep *ep,
struct usb_request *req)
{
@@ -1621,12 +1765,7 @@
static void cb_vx_lock(struct usb_ep *ep, struct usb_request *req)
{
- if (zircon_clear_stored_cmdline()) {
- FB_ERR("Failed to clear stored boot args\n");
- fastboot_fail("Failed to clear boot args");
- return;
- }
-
+ // ta_vx_lock() will clear any stored boot args.
if (ta_vx_lock()) {
FB_ERR("Failed to lock\n");
fastboot_fail("Failed to lock");
@@ -1842,6 +1981,57 @@
fastboot_okay(NULL);
}
+#if defined(DEV_BUILD_CONFIG)
+static void cb_optee_suppl_cmd_raw_io(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ // usage: oem optee-supl-cmd-raw-io <"read"|"write"> <off> <len>
+ const char usage[] = "Usage: optee-supl-cmd-raw-io <read|write> <off> <len>";
+
+ char *name = req->buf;
+
+ // skip past "oem optee-supl-cmd-raw-io"
+ if (!(strsep(&name, " ") && strsep(&name, " ") && name)) {
+ fastboot_fail(usage);
+ return;
+ }
+
+ enum optee_suppl_cmd_raw_io_op op = optee_suppl_cmd_raw_io_write;
+ if (strncmp(name, "read", strlen("read")) == 0) {
+ op = optee_suppl_cmd_raw_io_read;
+ } else if (strncmp(name, "write", strlen("write") - 1)) {
+ fastboot_fail(usage);
+ return;
+ }
+
+ // offset
+ if (!strsep(&name, " ")) {
+ fastboot_fail(usage);
+ return;
+ }
+ uint64_t offset = simple_strtoul(name, NULL, 16);
+
+ // length
+ if (!strsep(&name, " ")) {
+ fastboot_fail(usage);
+ return;
+ }
+ uint64_t length = simple_strtoul(name, NULL, 16);
+
+ int res = optee_suppl_cmd_raw_io_wrapper(
+ op, (void *)CONFIG_FASTBOOT_BUF_ADDR, offset, length);
+ if (res) {
+ fastboot_fail("IO failed");
+ return;
+ }
+
+ if (op == optee_suppl_cmd_raw_io_read)
+ upload_size = length;
+
+ fastboot_okay("");
+}
+#endif
+
static void cb_staged_bootloader_file(struct usb_ep *ep,
struct usb_request *req)
{
@@ -2056,6 +2246,20 @@
.cb = cb_erase,
},
#endif
+#if defined(DEV_BUILD_CONFIG)
+ {
+ .cmd = "oem kill-rpmb-till-reboot",
+ .cb = cb_kill_rpmb_till_reboot,
+ },
+ {
+ .cmd = "oem kill-rpmb",
+ .cb = cb_kill_rpmb,
+ },
+ {
+ .cmd = "oem unkill-rpmb",
+ .cb = cb_unkill_rpmb,
+ },
+#endif
{
.cmd = "oem stage-partition",
.cb = cb_stage_partition,
@@ -2102,6 +2306,12 @@
.cmd = "oem gpt-update",
.cb = cb_gpt_update,
},
+#if defined(DEV_BUILD_CONFIG)
+ {
+ .cmd = "oem optee-supl-cmd-raw-io",
+ .cb = cb_optee_suppl_cmd_raw_io,
+ },
+#endif
#ifdef CONFIG_FACTORY_BOOT_KVS
{
.cmd = "oem factory-boot-kvs-get",
diff --git a/include/emmc_partitions.h b/include/emmc_partitions.h
index e8f4bc5..d964586 100644
--- a/include/emmc_partitions.h
+++ b/include/emmc_partitions.h
@@ -114,6 +114,10 @@
#define GPT_LBA_COUNT 34
#define GPT_TOTAL_SIZE (GPT_LBA_COUNT * 512)
+#define MMC_SECURE_STORAGE_NAME "secure-storage"
+#define MMC_SECURE_STORAGE_OFFSET (SZ_1M * 32)
+#define MMC_SECURE_STORAGE_SIZE (SZ_1M * 32)
+
struct virtual_partition {
char name[MAX_MMC_PART_NAME_LEN];
uint64_t offset;
diff --git a/include/mmc.h b/include/mmc.h
index 8c5ffa7..90a6803 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -165,6 +165,8 @@
#define MMC_DISCARD_ARG 0x00000003
#define MMC_SECURE_TRIM1_ARG 0x80000001
#define MMC_SECURE_TRIM2_ARG 0x80008000
+#define MMC_RELIABLE_WRITE_ARG (1 << 31)
+#define MMC_BLOCK_COUNT_MAX (0xFFFF)
#define MMC_STATUS_MASK (~0x0206BF7F)
#define MMC_STATUS_SWITCH_ERROR (1 << 7)
@@ -208,6 +210,7 @@
* EXT_CSD fields
*/
#define EXT_CSD_CLASS_6_CTRL 59 /*R/W/E_P*/
+#define EXT_CSD_DATA_SECTOR_SIZE 61
#define EXT_CSD_ENH_START_ADDR 136 /* R/W */
#define EXT_CSD_ENH_SIZE_MULT 140 /* R/W */
#define EXT_CSD_GP_SIZE_MULT 143 /* R/W */
@@ -301,6 +304,8 @@
#define EXT_CSD_WR_DATA_REL_USR (1 << 0) /* user data area WR_REL */
#define EXT_CSD_WR_DATA_REL_GP(x) (1 << ((x)+1)) /* GP part (x+1) WR_REL */
+#define EXT_CSD_DATA_SECTOR_SIZE_512 0
+
#define R1_ILLEGAL_COMMAND (1 << 22)
#define R1_APP_CMD (1 << 5)
diff --git a/include/tee/optee.h b/include/tee/optee.h
index 9446928..b4a35d1 100644
--- a/include/tee/optee.h
+++ b/include/tee/optee.h
@@ -67,4 +67,18 @@
}
#endif
+#if defined(DEV_BUILD_CONFIG)
+enum optee_suppl_cmd_raw_io_op {
+ optee_suppl_cmd_raw_io_read,
+ optee_suppl_cmd_raw_io_write,
+};
+
+// A helper based on `optee_suppl_cmd_raw_io()` for writing/reading data
+// to/from the reserved partition. The helper is mainly for firmware testing by
+// fastboot oem command
+// `fastboot oem optee-supl-cmd-raw-io <"read"|"write"> <off> <len>`
+int optee_suppl_cmd_raw_io_wrapper(enum optee_suppl_cmd_raw_io_op op,
+ void *buffer, size_t offset, size_t length);
+#endif
+
#endif /* _OPTEE_H */
diff --git a/include/tee/ta_vx.h b/include/tee/ta_vx.h
index fe2e589..6744ceb 100644
--- a/include/tee/ta_vx.h
+++ b/include/tee/ta_vx.h
@@ -16,6 +16,14 @@
VX_UNLOCKED = 1,
} vx_lock_state_t;
+/* VX variables. */
+typedef enum vx_variable {
+ VX_VAR_NONE = 0x0,
+ VX_VAR_DEV_KEY_ENABLED = 0x01,
+ VX_VAR_OUT_OF_BOOTLOADER = 0x02,
+ VX_VAR_EPHEMERALLY_UNLOCKED = 0x04,
+} vx_variable_t;
+
/*
* Gets the rollback index corresponding to the given rollback index slot.
*
@@ -142,9 +150,17 @@
#define TA_VX_CMD_READ_PERM_ATTR 13
enum vx_rpmb_status {
+ /* eMMC claims the RPMB key has been programmed. */
VX_RPMB_AUTH_KEY_PROGRAMMED = 0x01,
+
+ /* RPMB key has been verified by the firmware. */
VX_RPMB_AUTH_KEY_VERIFIED = 0x02,
+
+ /* RPMB provisioning is no longer allowed (mitigates key phishing). */
VX_RPMB_PROVISIONING_ALLOWED = 0x04,
+
+ /* Reroute RPMB traffic (to REE controlled storage). */
+ VX_RPMB_REROUTING_TRAFFIC = 0x08,
};
/* Reads the RPMB provisioning status.
@@ -210,8 +226,13 @@
#define TA_VX_CMD_LOCK_PERM_ATTR 17
typedef enum {
+ /* Programmed to RPMB. */
VX_PERM_ATTR_PROGRAMMED = (1 << 0),
+
+ /* SHA256 digest stored in OTP. */
VX_PERM_ATTR_LOCKED = (1 << 1),
+
+ /* Hardcoded. */
VX_PERM_ATTR_HARDCODED = (1 << 2),
} perm_attr_status_t;
@@ -235,40 +256,8 @@
*/
#define TA_VX_CMD_DELETE_PERM_ATTR 19
-typedef enum vx_option {
- /* If set, automatically provisions RPMB if RPMB is not already
- * provisioned. Default unset. */
- VX_OPTION_AUTO_PROVISION_RPMB = (1 << 1),
- /* For testing use. e.g. The Bootloader uses this to make sure options
- * CAN NOT be set after issuing CMD_EXIT_BOOTLOADER. */
- VX_OPTION_FOR_TESTING = (1 << 3),
-} vx_option_t;
-
-/*
- * Sets certain options for the VX TA.
- *
- * This command is only available to the Bootloader.
- *
- * in params[0].value.a: Options flags to set (VX_OPTION_*).
- *
- * Returns
- * TEE_SUCCESS on success,
- * TEE_ERROR_* otherwise.
- */
-#define TA_VX_CMD_SET_OPTIONS 20
-
-/*
- * Unsets certain options for the VX TA.
- *
- * This command is only available to the Bootloader.
- *
- * in params[0].value.a: Options flags to unset (VX_OPTION_*).
- *
- * Returns
- * TEE_SUCCESS on success,
- * TEE_ERROR_* otherwise.
- */
-#define TA_VX_CMD_UNSET_OPTIONS 21
+#define TA_VX_CMD_SET_OPTIONS_DEPRECATED 20
+#define TA_VX_CMD_UNSET_OPTIONS_DEPRECATED 21
/* Provisions the USBBOOT password hash.
*
@@ -303,6 +292,76 @@
*/
#define TA_VX_CMD_GET_USBBOOT_STATUS 23
+/* Sets the OTA Config option.
+ *
+ * Args:
+ * in params[0].value.a: config option.
+ *
+ * Returns:
+ * TEE_SUCCESS if the option value was set successfully.
+ * Otherwise TEE_ERROR_*.
+ */
+#define TA_VX_CMD_OTA_CONFIG_SET 24
+
+/* Reads the OTA Config option.
+ *
+ * Args:
+ * in params[0].value.a: default value for option, which will be returned if
+ * there is no stored value in secure storage.
+ * out params[1].value.a: config option
+ *
+ * Returns:
+ * TEE_SUCCESS if the option value was read successfully.
+ * Otherwise TEE_ERROR_*.
+ */
+#define TA_VX_CMD_OTA_CONFIG_GET 25
+
+/*
+ * Delete the OTA Config.
+ *
+ * Returns:
+ * TEE_SUCCESS if the config was deleted successfully.
+ * Otherwise TEE_ERROR_*.
+ */
+#define TA_VX_CMD_OTA_CONFIG_DELETE 26
+
+/*
+ * Query VX variables.
+ *
+ * out params[0].value.a: or'ed VX_VAR_*
+ */
+#define TA_VX_CMD_GETVAR_ALL 27
+
+/*
+ * Force reroute RPMB until reboot.
+ *
+ * For testing on dev-key hardware only.
+ *
+ * Returns:
+ * TEE_SUCCESS if successful. Otherwise TEE_ERROR_*.
+ */
+#define TA_VX_CMD_REROUTE_RPMB_TILL_REBOOT 28
+
+/*
+ * Force reroute RPMB to REE-controlled secure storage.
+ *
+ * Works on dev-key hardware only.
+ *
+ * Returns:
+ * TEE_SUCCESS if successful. Otherwise TEE_ERROR_*.
+ */
+#define TA_VX_CMD_REROUTE_RPMB_TO_SOFTWARE 29
+
+/*
+ * Force route RPMB to hardware (eMMC).
+ *
+ * Works on dev-key hardware only.
+ *
+ * Returns:
+ * TEE_SUCCESS if successful. Otherwise TEE_ERROR_*.
+ */
+#define TA_VX_CMD_REROUTE_RPMB_TO_HARDWARE 30
+
/**
* Persistent Nonces Management.
*/
diff --git a/include/tee/ta_vx_helper.h b/include/tee/ta_vx_helper.h
index 2b78f3d..d2bf2f3 100644
--- a/include/tee/ta_vx_helper.h
+++ b/include/tee/ta_vx_helper.h
@@ -27,6 +27,13 @@
int ta_vx_lock(void);
/**
+ * ta_vx_lock_if_ephemerally_unlocked()
+ *
+ * Return: 0 if successful, non-zero error code on failure.
+ */
+int ta_vx_lock_if_ephemerally_unlocked(void);
+
+/**
* ta_vx_unlock() - Unlocks the device.
*
* Return: 0 if successful, non-zero error code on failure.
@@ -101,10 +108,10 @@
int ta_vx_cprng_draw(void *buf, size_t buf_len);
/**
- * ta_vx_exit_bootloader() - Finalize verified execution policies and
+ * ta_vx_exit_bootloader_or_panic() - Finalize verified execution policies and
* configurations. Panics on any error.
*/
-void ta_vx_exit_bootloader(void);
+void ta_vx_exit_bootloader_or_panic(void);
/**
* ta_vx_read_perm_attr() - Read permanent attributes
@@ -149,6 +156,28 @@
int ta_vx_provision_rpmb(void);
/**
+ * ta_vx_reroute_rpmb_till_reboot() - Reroute RPMB traffic till reboot for
+ * testing.
+ *
+ * Return: 0 if successful, non-zero code otherwise.
+ */
+int ta_vx_reroute_rpmb_till_reboot(void);
+
+/**
+ * ta_vx_reroute_rpmb_to_software() - Persistently reroute RPMB traffic.
+ *
+ * Return: 0 if successful, non-zero code otherwise.
+ */
+int ta_vx_reroute_rpmb_to_software(void);
+
+/**
+ * ta_vx_reroute_rpmb_to_hardware() - Permanently restore RPMB traffic.
+ *
+ * Return: 0 if successful, non-zero code otherwise.
+ */
+int ta_vx_reroute_rpmb_to_hardware(void);
+
+/**
* ta_vx_read_perm_attr_hash() - Read permanent attributes hash
* @buf: Buffer to write value into.
* @buf_len: Length of buf.
@@ -197,6 +226,15 @@
*/
int ta_vx_get_usbboot_status(uint32_t *status);
+/**
+ * ta_vx_getvar_all() - Query hardware capabilities
+ *
+ * @out_caps: Receives VX_HARDWARE_* flags as defined in tee/ta_vx.h
+ *
+ * Return: 0 if successful, non-zero error code otherwise.
+ */
+int ta_vx_getvar_all(uint32_t *out_caps);
+
#ifdef CONFIG_TA_VX_TESTS
/**
* ta_vx_run_tests() - Run tests defined in the VX TA.
diff --git a/include/zircon_uboot/partition_internal.h b/include/zircon_uboot/partition_internal.h
index 55286e2..76fbe32 100644
--- a/include/zircon_uboot/partition_internal.h
+++ b/include/zircon_uboot/partition_internal.h
@@ -18,6 +18,9 @@
// erase if the user can write anyway.
#define ZIRCON_PARTITION_ACCESS_FLAG_ERASE (1 << 0)
#define ZIRCON_PARTITION_ACCESS_FLAG_WRITE (1 << 1)
+// write/erase access is only allowed when variant is dev, regardless of
+// lock/unlock status.
+#define ZIRCON_PARTITION_ACCESS_DEV_ONLY (1 << 2)
typedef enum {
// Alias for partition within GPT on eMMC USER hardware partition.