From: Simon Glass <simon.glass@canonical.com> One useful feature a the TKey is the ability to set up its app with an key modified by a user-supplied secret. Add support for this. Take this opportunity to make the API more expo-friendly by allowing loading of the TKey to take place iteratively. The TKey runs fairly slowly (about 60Kbaud) and loading an app takes 6 seconds or so. Signed-off-by: Simon Glass <simon.glass@canonical.com> --- drivers/misc/tkey-uclass.c | 149 +++++++++++++++++++++---------------- include/tkey.h | 49 ++++++++++++ 2 files changed, 132 insertions(+), 66 deletions(-) diff --git a/drivers/misc/tkey-uclass.c b/drivers/misc/tkey-uclass.c index 4696f9c8d83..d2c4b8351fd 100644 --- a/drivers/misc/tkey-uclass.c +++ b/drivers/misc/tkey-uclass.c @@ -502,27 +502,80 @@ static int tkey_load_app_header(struct udevice *dev, int app_size, return 0; } -static int tkey_load_app_data(struct udevice *dev, const void *data, int size) +int tkey_load_app_with_uss(struct udevice *dev, const void *app_data, + int app_size, const void *uss, int uss_size) { - struct tkey_frame cmd_frame, rsp_frame; - int offset = 0; + struct tkey_load_ctx ctx; int ret; - log_debug("Loading app data, %u bytes\n", size); + /* Start loading */ + ret = tkey_load_start(&ctx, dev, app_data, app_size, uss, + uss_size); + if (ret) + return ret; + + /* Send all remaining blocks */ + do { + ret = tkey_load_next(&ctx, 0); + } while (ret == -EAGAIN); + + return ret; +} + +int tkey_load_app(struct udevice *dev, const void *app_data, int app_size) +{ + return tkey_load_app_with_uss(dev, app_data, app_size, NULL, 0); +} + +int tkey_load_start(struct tkey_load_ctx *ctx, struct udevice *dev, + const void *app_data, int app_size, + const void *uss, int uss_size) +{ + int ret; + + /* Initialize context */ + ctx->dev = dev; + ctx->app_data = app_data; + ctx->app_size = app_size; + ctx->offset = 0; + + /* Check if we're in firmware mode first */ + ret = tkey_in_app_mode(dev); + if (ret < 0) { + log_debug("Failed to check device mode (error %d)\n", ret); + return ret; + } + + if (ret) { + log_debug("Device must be in firmware mode to load app\n"); + return -ENOTSUPP; + } + + log_debug("Starting iterative app load (%u bytes)...\n", app_size); + + /* Send app header with size and USS (if provided) */ + ret = tkey_load_app_header(dev, app_size, uss, uss_size); + if (ret) { + log_debug("Failed to send app header (error %d)\n", ret); + return ret; + } + + return 0; +} + +int tkey_load_next(struct tkey_load_ctx *ctx, int max_blocks) +{ + struct tkey_frame cmd_frame, rsp_frame; + int blocks_sent = 0; + int ret; - while (offset < size) { - int todo = min(size - offset, TKEY_MAX_DATA_SIZE - 1); - u8 len_code; + /* If max_blocks is 0, send all remaining blocks */ + if (max_blocks == 0) + max_blocks = INT_MAX; - /* Determine length code for chunk */ - if (todo <= 1) - len_code = TKEY_LEN_1_BYTE; - else if (todo <= 4) - len_code = TKEY_LEN_4_BYTES; - else if (todo <= 32) - len_code = TKEY_LEN_32_BYTES; - else - len_code = TKEY_LEN_128_BYTES; + while (ctx->offset < ctx->app_size && blocks_sent < max_blocks) { + int todo = min(ctx->app_size - ctx->offset, + TKEY_MAX_DATA_SIZE - 1); /* * Build LOAD_APP_DATA command (always use 128-byte frames @@ -533,7 +586,7 @@ static int tkey_load_app_data(struct udevice *dev, const void *data, int size) TKEY_STATUS_OK, TKEY_LEN_128_BYTES); cmd_frame.data[0] = TKEY_FW_CMD_LOAD_APP_DATA; - memcpy(&cmd_frame.data[1], data + offset, todo); + memcpy(&cmd_frame.data[1], ctx->app_data + ctx->offset, todo); /* Pad remaining bytes with zeros */ if (todo + 1 < 128) @@ -541,73 +594,37 @@ static int tkey_load_app_data(struct udevice *dev, const void *data, int size) 128 - (todo + 1)); /* Send chunk (always 128 bytes like Go app) */ - ret = tkey_send_frame(dev, &cmd_frame, 128); + ret = tkey_send_frame(ctx->dev, &cmd_frame, 128); if (ret < 0) return ret; /* Receive response */ - ret = tkey_recv_frame(dev, &rsp_frame, TKEY_LOAD_TIMEOUT_MS); + ret = tkey_recv_frame(ctx->dev, &rsp_frame, + TKEY_LOAD_TIMEOUT_MS); if (ret < 0) return ret; /* Check response status */ if (rsp_frame.header & TKEY_STATUS_ERROR) { log_debug("Load app data failed at offset %u\n", - offset); + ctx->offset); return -EIO; } - offset += todo; - log_debug("Loaded chunk: %u/%u bytes\n", offset, size); + ctx->offset += todo; + blocks_sent++; + log_debug("Loaded chunk: %u/%u bytes (%d blocks sent)\n", + ctx->offset, ctx->app_size, blocks_sent); schedule(); } - log_debug("App data loaded successfully\n"); - - return 0; -} - -int tkey_load_app_with_uss(struct udevice *dev, const void *app_data, - int app_size, const void *uss, int uss_size) -{ - int ret; - - /* Check if we're in firmware mode first */ - ret = tkey_in_app_mode(dev); - if (ret < 0) { - log_debug("Failed to check device mode (error %d)\n", ret); - return ret; + /* Check if we're done */ + if (ctx->offset >= ctx->app_size) { + log_debug("App data loaded successfully\n"); + return 0; /* Done */ } - if (ret) { - log_debug("Device must be in firmware mode to load app\n"); - return -ENOTSUPP; - } - - log_debug("Loading app (%u bytes)...\n", app_size); - - /* Send app header with size and USS (if provided) */ - ret = tkey_load_app_header(dev, app_size, uss, uss_size); - if (ret) { - log_debug("Failed to send app header (error %d)\n", ret); - return ret; - } - - /* Send app data */ - ret = tkey_load_app_data(dev, app_data, app_size); - if (ret) { - log_debug("Failed to send app data (error %d)\n", ret); - return ret; - } - - log_debug("App loaded successfully\n"); - - return 0; -} - -int tkey_load_app(struct udevice *dev, const void *app_data, int app_size) -{ - return tkey_load_app_with_uss(dev, app_data, app_size, NULL, 0); + return -EAGAIN; /* More blocks remain */ } int tkey_get_pubkey(struct udevice *dev, void *pubkey) diff --git a/include/tkey.h b/include/tkey.h index 14ad3ebc9e9..1c66dab8484 100644 --- a/include/tkey.h +++ b/include/tkey.h @@ -13,6 +13,21 @@ struct tkey_frame; struct udevice; +/** + * struct tkey_load_ctx - Context for iterative app loading + * + * @dev: TKey device + * @app_data: Complete app binary data + * @app_size: Size of app data + * @offset: Current offset in app data + */ +struct tkey_load_ctx { + struct udevice *dev; + const void *app_data; + int app_size; + int offset; +}; + /* TKey constants */ #define TKEY_NAME_SIZE 5 #define TKEY_CDI_SIZE 32 @@ -182,6 +197,40 @@ int tkey_load_app(struct udevice *dev, const void *app_data, int app_size); int tkey_load_app_with_uss(struct udevice *dev, const void *app_data, int app_size, const void *uss, int uss_size); +/** + * tkey_load_start() - Start iterative app loading + * + * @ctx: Context structure to initialize + * @dev: TKey device + * @app_data: Complete app binary data + * @app_size: Size of app data + * @uss: User-Supplied Secret (password/passphrase) - can be NULL + * @uss_size: Size of USS data (max 32 bytes) + * + * This function initializes the context and sends the app header. + * Call tkey_load_next() repeatedly to send the data blocks. + * + * Return: 0 on success, -ve error on failure (-ENOTSUPP if not in + * firmware mode) + */ +int tkey_load_start(struct tkey_load_ctx *ctx, struct udevice *dev, + const void *app_data, int app_size, + const void *uss, int uss_size); + +/** + * tkey_load_next() - Send next block(s) of app data + * + * @ctx: Context structure from tkey_load_start() + * @max_blocks: Maximum number of blocks to send (0 = send all remaining) + * + * This function sends the next n blocks of app data. Call repeatedly + * until it returns 0 (done) instead of -EAGAIN (more blocks remain). + * + * Return: 0 if loading is complete, -EAGAIN if more blocks remain, + * -ve error on failure + */ +int tkey_load_next(struct tkey_load_ctx *ctx, int max_blocks); + /** * tkey_get_pubkey() - Get public key from signer app * -- 2.43.0