Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion examples/htool.c
Original file line number Diff line number Diff line change
Expand Up @@ -973,17 +973,34 @@ static const struct htool_cmd CMDS[] = {
},
{
.verbs = (const char*[]){"payload", "update", NULL},
.desc = "Perform payload update protocol for Titan images.",
.desc = "Perform payload update protocol for Titan images. Optional "
"allows for payload confirmation.",
.params =
(const struct htool_param[]){
{HTOOL_POSITIONAL, .name = "source-file"},
{HTOOL_FLAG_BOOL, 's', "skip_erase", "false",
.desc = "Skip erasing the staging side."},
{HTOOL_FLAG_BOOL, 'b', "binary", "false",
.desc = "Update with generic binary file"},
{HTOOL_FLAG_BOOL, 'e', "enable", "false",
.desc = "Enable confirm mode"},
{HTOOL_FLAG_VALUE, 't', "timeout", "0",
.desc = "Timeout in seconds"},
{}},
.func = htool_payload_update,
},
{
.verbs = (const char*[]){"payload", "confirm", NULL},
.desc = "Finish a payload update confirmation.",
.params = (const struct htool_param[]){{}},
.func = htool_payload_update_confirm,
},
{
.verbs = (const char*[]){"payload", "get_timeout", NULL},
.desc = "Get the current payload update confirmation timeout.",
.params = (const struct htool_param[]){{}},
.func = htool_payload_update_confirm_get_timeout,
},
{
.verbs = (const char*[]){"payload", "read", NULL},
.desc = "Read content of staging flash for Titan images.",
Expand Down
56 changes: 56 additions & 0 deletions examples/htool_payload_update.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ int htool_payload_update(const struct htool_invocation* inv) {
return -1;
}

uint32_t timeout = 0;
if (htool_get_param_u32(inv, "timeout", &timeout)) {
return -1;
}

bool enable_confirm = false;
if (htool_get_param_bool(inv, "enable", &enable_confirm)) {
return -1;
}

int fd = open(image_file, O_RDONLY, 0);
if (fd == -1) {
fprintf(stderr, "Error opening file %s: %s\n", image_file, strerror(errno));
Expand Down Expand Up @@ -99,6 +109,15 @@ int htool_payload_update(const struct htool_invocation* inv) {
break;
}

if (enable_confirm) {
int ret =
libhoth_payload_update_confirm_enable(dev, enable_confirm, timeout);
if (ret != 0) {
fprintf(stderr, "Failed to confirm payload update\n");
goto cleanup;
}
}

int ret = munmap(image, statbuf.st_size);
if (ret != 0) {
fprintf(stderr, "munmap error: %d\n", ret);
Expand Down Expand Up @@ -207,3 +226,40 @@ int htool_payload_update_getstatus(const struct htool_invocation* inv) {

return 0;
}

int htool_payload_update_confirm(const struct htool_invocation* inv) {
struct libhoth_device* dev = htool_libhoth_device();
if (!dev) {
return -1;
}

int ret = 0;

ret = libhoth_payload_update_confirm(dev);
if (ret != 0) {
fprintf(stderr, "Failed to confirm payload update\n");
return -1;
}

return ret;
}

int htool_payload_update_confirm_get_timeout(
const struct htool_invocation* inv) {
struct libhoth_device* dev = htool_libhoth_device();
if (!dev) {
return -1;
}

payload_update_confirm_response_t response = {0};

int ret = libhoth_payload_update_confirm_get_timeout(dev, &response);
if (ret != 0) {
fprintf(stderr, "Failed to get payload update timeout\n");
return -1;
}

printf("Current timeout: %u seconds\n", response.timeouts.current);

return 0;
}
4 changes: 3 additions & 1 deletion examples/htool_payload_update.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ struct htool_invocation;
int htool_payload_update(const struct htool_invocation* inv);
int htool_payload_read(const struct htool_invocation* inv);
int htool_payload_update_getstatus(const struct htool_invocation* inv);

int htool_payload_update_confirm(const struct htool_invocation* inv);
int htool_payload_update_confirm_get_timeout(
const struct htool_invocation* inv);
#ifdef __cplusplus
}
#endif
Expand Down
113 changes: 113 additions & 0 deletions protocol/payload_update.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@
#include "transports/libhoth_device.h"
#include "util.h"

#define PAYLOAD_UPDATE_CONFIRM_OP_ENABLE 0
#define PAYLOAD_UPDATE_CONFIRM_OP_ENABLE_WITH_TIMEOUT 1
#define PAYLOAD_UPDATE_CONFIRM_OP_DISABLE 2
#define PAYLOAD_UPDATE_CONFIRM_OP_CONFIRM 3
#define PAYLOAD_UPDATE_CONFIRM_OP_GET_TIMEOUT_VALUES 4

static int send_payload_update_request_with_command(struct libhoth_device* dev,
uint8_t command) {
struct payload_update_packet request;
Expand Down Expand Up @@ -269,3 +275,110 @@ enum payload_update_err libhoth_payload_update_read_chunk(

return PAYLOAD_UPDATE_OK;
}

int libhoth_payload_update_confirm(struct libhoth_device* dev) {
payload_update_confirm_response_t confirm_response = {0};

// 1. Create the structures
payload_update_confirm_request_t confirm_request = {0};
confirm_request.op = PAYLOAD_UPDATE_CONFIRM_OP_CONFIRM;

struct payload_update_packet pkt_header = {
.type = PAYLOAD_UPDATE_CONFIRM,
.offset = 0,
.len = sizeof(confirm_request),
};

uint8_t send_buf[sizeof(pkt_header) + sizeof(confirm_request)] = {0};
memcpy(&send_buf[0], &pkt_header, sizeof(pkt_header));
memcpy(&send_buf[sizeof(pkt_header)], &confirm_request,
sizeof(confirm_request));

int ret = libhoth_hostcmd_exec(
dev, HOTH_CMD_BOARD_SPECIFIC_BASE + HOTH_PRV_CMD_HOTH_PAYLOAD_UPDATE, 0,
&send_buf, sizeof(send_buf), &confirm_response, sizeof(confirm_response),
NULL);
if (ret != 0) {
fprintf(stderr, "Payload update confirm failed, err code: %d\n", ret);
return -1;
}

return 0;
}

int libhoth_payload_update_confirm_enable(struct libhoth_device* dev,
bool enable,
uint32_t timeout_seconds) {
payload_update_confirm_response_t confirm_response = {0};

payload_update_confirm_request_t confirm_request = {0};
confirm_request.op = enable ? PAYLOAD_UPDATE_CONFIRM_OP_ENABLE_WITH_TIMEOUT
: PAYLOAD_UPDATE_CONFIRM_OP_DISABLE;
confirm_request.timeout = timeout_seconds;

struct payload_update_packet pkt_header = {
.type = PAYLOAD_UPDATE_CONFIRM,
.offset = 0,
.len = sizeof(confirm_request),
};

// timout_seconds of 0 is treated as a special value to use the default
// timeout value defined in the firmware.
if (timeout_seconds == 0) {
confirm_request.op = PAYLOAD_UPDATE_CONFIRM_OP_ENABLE;
confirm_request.timeout = PAYLOAD_UPDATE_CONFIRM_SECONDS_DEFAULT;
}

if (confirm_request.timeout < PAYLOAD_UPDATE_CONFIRM_SECONDS_MIN ||
confirm_request.timeout > PAYLOAD_UPDATE_CONFIRM_SECONDS_MAX) {
fprintf(stderr,
"Invalid timeout value: %u. Must be between %u and %u seconds.\n",
confirm_request.timeout, PAYLOAD_UPDATE_CONFIRM_SECONDS_MIN,
PAYLOAD_UPDATE_CONFIRM_SECONDS_MAX);
return -1;
}

uint8_t send_buf[sizeof(pkt_header) + sizeof(confirm_request)] = {0};
memcpy(&send_buf[0], &pkt_header, sizeof(pkt_header));
memcpy(&send_buf[sizeof(pkt_header)], &confirm_request,
sizeof(confirm_request));

int ret = libhoth_hostcmd_exec(
dev, HOTH_CMD_BOARD_SPECIFIC_BASE + HOTH_PRV_CMD_HOTH_PAYLOAD_UPDATE, 0,
&send_buf, sizeof(send_buf), &confirm_response, sizeof(confirm_response),
NULL);
if (ret != 0) {
fprintf(stderr, "Payload update confirm enable failed, err code: %d\n",
ret);
return -1;
}

return 0;
}

int libhoth_payload_update_confirm_get_timeout(
struct libhoth_device* dev, payload_update_confirm_response_t* response) {
payload_update_confirm_request_t confirm_request = {0};
confirm_request.op = PAYLOAD_UPDATE_CONFIRM_OP_GET_TIMEOUT_VALUES;

struct payload_update_packet pkt_header = {
.type = PAYLOAD_UPDATE_CONFIRM,
.offset = 0,
.len = sizeof(confirm_request),
};

uint8_t send_buf[sizeof(pkt_header) + sizeof(confirm_request)] = {0};
memcpy(&send_buf[0], &pkt_header, sizeof(pkt_header));
memcpy(&send_buf[sizeof(pkt_header)], &confirm_request,
sizeof(confirm_request));

int ret = libhoth_hostcmd_exec(
dev, HOTH_CMD_BOARD_SPECIFIC_BASE + HOTH_PRV_CMD_HOTH_PAYLOAD_UPDATE, 0,
&send_buf, sizeof(send_buf), response, sizeof(*response), NULL);
if (ret != 0) {
fprintf(stderr, "Payload update get timeout failed, err code: %d\n", ret);
return -1;
}

return 0;
}
82 changes: 82 additions & 0 deletions protocol/payload_update.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
extern "C" {
#endif

#include <assert.h>
#include <stdbool.h>
#include <stdint.h>

Expand All @@ -39,6 +40,60 @@ extern "C" {
#define PAYLOAD_UPDATE_CONFIRM 10
#define PAYLOAD_UPDATE_VERIFY_DESCRIPTOR 11

typedef uint32_t payload_update_confirm_seconds;
typedef uint8_t payload_update_confirm_op;

static const payload_update_confirm_seconds
PAYLOAD_UPDATE_CONFIRM_SECONDS_ZERO = 0;
static const payload_update_confirm_seconds PAYLOAD_UPDATE_CONFIRM_SECONDS_MIN =
30;
static const payload_update_confirm_seconds PAYLOAD_UPDATE_CONFIRM_SECONDS_MAX =
60 * 60;
static const payload_update_confirm_seconds
PAYLOAD_UPDATE_CONFIRM_SECONDS_DEFAULT = 15 * 60;

typedef struct {
payload_update_confirm_seconds min;
payload_update_confirm_seconds max;
payload_update_confirm_seconds default_val;
payload_update_confirm_seconds current;
} payload_update_confirm_timeouts_t;
static_assert(sizeof(payload_update_confirm_timeouts_t) == 16,
"Unexpected struct size for payload_update_confirm_timeouts_t");
static_assert(offsetof(payload_update_confirm_timeouts_t, min) == 0,
"Unexpected offset for min");
static_assert(offsetof(payload_update_confirm_timeouts_t, max) == 4,
"Unexpected offset for max");
static_assert(offsetof(payload_update_confirm_timeouts_t, default_val) == 8,
"Unexpected offset for default_val");
static_assert(offsetof(payload_update_confirm_timeouts_t, current) == 12,
"Unexpected offset for current");

typedef struct {
payload_update_confirm_op op;
uint8_t padding[3];
payload_update_confirm_seconds timeout;
uint64_t cookie;
} payload_update_confirm_request_t;
static_assert(offsetof(payload_update_confirm_request_t, op) == 0,
"Unexpected offset for op");
static_assert(offsetof(payload_update_confirm_request_t, padding) == 1,
"Unexpected offset for padding");
static_assert(offsetof(payload_update_confirm_request_t, timeout) == 4,
"Unexpected offset for timeout");
static_assert(offsetof(payload_update_confirm_request_t, cookie) == 8,
"Unexpected offset for cookie");
static_assert(sizeof(payload_update_confirm_request_t) == 16,
"Unexpected struct size for payload_update_confirm_request_t");

typedef struct {
payload_update_confirm_timeouts_t timeouts;
} payload_update_confirm_response_t;
static_assert(offsetof(payload_update_confirm_response_t, timeouts) == 0, "");
static_assert(sizeof(payload_update_confirm_response_t) ==
sizeof(payload_update_confirm_timeouts_t),
"");

struct payload_update_status {
uint8_t a_valid; /* 0 = invalid, 1 = unverified, 2 = valid, */
/* 3 = descriptor valid */
Expand All @@ -48,6 +103,18 @@ struct payload_update_status {
uint8_t next_half; /* 0, 1 */
uint8_t persistent_half; /* 0, 1 */
} __attribute__((packed));
static_assert(sizeof(struct payload_update_status) == 5,
"Unexpected struct size");
static_assert(offsetof(struct payload_update_status, a_valid) == 0,
"Unexpected offset for a_valid");
static_assert(offsetof(struct payload_update_status, b_valid) == 1,
"Unexpected offset for b_valid");
static_assert(offsetof(struct payload_update_status, active_half) == 2,
"Unexpected offset for active_half");
static_assert(offsetof(struct payload_update_status, next_half) == 3,
"Unexpected offset for next_half");
static_assert(offsetof(struct payload_update_status, persistent_half) == 4,
"Unexpected offset for persistent_half");

enum payload_update_err {
PAYLOAD_UPDATE_OK = 0,
Expand All @@ -66,6 +133,14 @@ struct payload_update_packet {
uint8_t type; /* One of PAYLOAD_UPDATE_* */
/* payload data immediately follows */
} __attribute__((packed));
static_assert(sizeof(struct payload_update_packet) == 9,
"Unexpected struct size");
static_assert(offsetof(struct payload_update_packet, offset) == 0,
"Unexpected offset for offset");
static_assert(offsetof(struct payload_update_packet, len) == 4,
"Unexpected offset for len");
static_assert(offsetof(struct payload_update_packet, type) == 8,
"Unexpected offset for type");

struct payload_update_finalize_response_v1 {
// Non-zero if configuration currently running on PLD needs to be
Expand All @@ -82,6 +157,13 @@ int libhoth_payload_update_getstatus(
struct libhoth_device* dev, struct payload_update_status* update_status);
enum payload_update_err libhoth_payload_update_read_chunk(
struct libhoth_device* dev, int fd, size_t len, size_t offset);
int libhoth_payload_update_confirm(struct libhoth_device* dev);
int libhoth_payload_update_confirm_enable(struct libhoth_device* dev,
bool enable,
uint32_t timeout_seconds);
int libhoth_payload_update_confirm_get_timeout(
struct libhoth_device* dev,
payload_update_confirm_response_t* timeout_seconds);

#ifdef __cplusplus
}
Expand Down
Loading