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
3 changes: 3 additions & 0 deletions examples/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@ cc_binary(
"htool_tpm.c",
"htool_tpm.h",
"htool_update_failure_reasons.h",
"htool_update_session.c",
"htool_update_session.h",
"htool_usb.c",
"htool_usb.h",
],
Expand Down Expand Up @@ -270,6 +272,7 @@ cc_binary(
"//protocol:secure_boot",
"//protocol:spi_proxy",
"//protocol:statistics",
"//protocol:update_session",
"//protocol:util",
"//transports:libhoth_device",
"//transports:libhoth_mtd",
Expand Down
30 changes: 30 additions & 0 deletions examples/htool.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include "htool_statistics.h"
#include "htool_target_control.h"
#include "htool_tpm.h"
#include "htool_update_session.h"
#include "htool_usb.h"
#include "protocol/authz_record.h"
#include "protocol/chipinfo.h"
Expand Down Expand Up @@ -2176,6 +2177,35 @@ static const struct htool_cmd CMDS[] = {
.params = (const struct htool_param[]){{}},
.func = htool_set_tpm_mode,
},
{
.verbs = (const char*[]){"update_session", "start", NULL},
.desc = "Start a RoT update session.",
.params =
(const struct htool_param
[]){{HTOOL_FLAG_VALUE, 't', "timeout", "",
.desc = "Requested timeout in seconds for the update "
"session."},
{HTOOL_POSITIONAL, .name = "timeout_seconds",
.default_value = "",
.desc = "Requested timeout in seconds for the update "
"session."},
{}},
.func = htool_update_session_start,
},
{
.verbs = (const char*[]){"update_session", "finalize", NULL},
.alias = (const char*[]){"update_session", "end", NULL},
.desc = "Finalize the active RoT update session.",
.params = (const struct htool_param[]){{}},
.func = htool_update_session_finalize,
},
{
.verbs = (const char*[]){"update_session", "status", NULL},
.alias = (const char*[]){"update_session", "get_status", NULL},
.desc = "Get the current status of the RoT update session.",
.params = (const struct htool_param[]){{}},
.func = htool_update_session_status,
},
{},
};

Expand Down
114 changes: 114 additions & 0 deletions examples/htool_update_session.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "htool_update_session.h"

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "htool.h"
#include "htool_cmd.h"
#include "protocol/update_session.h"

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

const char* timeout_str = NULL;
if (htool_has_param(inv, "timeout")) {
htool_get_param_string(inv, "timeout", &timeout_str);
}
if ((!timeout_str || timeout_str[0] == '\0') &&
htool_has_param(inv, "timeout_seconds")) {
htool_get_param_string(inv, "timeout_seconds", &timeout_str);
}
if (!timeout_str || timeout_str[0] == '\0') {
fprintf(
stderr,
"Missing required timeout (use --timeout=<seconds> or <seconds>)\n");
return -1;
}

char* endptr = NULL;
unsigned long val = strtoul(timeout_str, &endptr, 0);
uint32_t timeout_seconds = 0;
if (endptr != timeout_str && *endptr == '\0') {
timeout_seconds = (uint32_t)val;
} else {
int64_t time_us = parse_time_string_us(timeout_str);
if (time_us > 0 && time_us % 1000000 == 0) {
timeout_seconds = (uint32_t)(time_us / 1000000);
}
}

if (timeout_seconds == 0) {
fprintf(stderr, "Invalid or zero timeout: %s\n", timeout_str);
return -1;
}

libhoth_error err = libhoth_update_session_start(dev, timeout_seconds);
if (err != HOTH_SUCCESS) {
htool_report_error("update_session_start", err);
return -1;
}

printf("Update session started (timeout: %u seconds)\n", timeout_seconds);
return 0;
}

int htool_update_session_finalize(const struct htool_invocation* inv) {
(void)inv;
struct libhoth_device* dev = htool_libhoth_device();
if (dev == NULL) {
return -1;
}

libhoth_error err = libhoth_update_session_finalize(dev);
if (err != HOTH_SUCCESS) {
htool_report_error("update_session_finalize", err);
return -1;
}

printf("Update session finalized\n");
return 0;
}

int htool_update_session_status(const struct htool_invocation* inv) {
(void)inv;
struct libhoth_device* dev = htool_libhoth_device();
if (dev == NULL) {
return -1;
}

struct update_session_status_response status;
memset(&status, 0, sizeof(status));

libhoth_error err = libhoth_update_session_get_status(dev, &status);
if (err != HOTH_SUCCESS) {
htool_report_error("update_session_get_status", err);
return -1;
}

printf("Update session status:\n");
printf(" State: %s (%u)\n",
libhoth_update_session_state_string(
(enum update_session_state)status.current_state),
status.current_state);
printf(" Timeout seconds left: %u\n", status.timeout_seconds_left);
return 0;
}
32 changes: 32 additions & 0 deletions examples/htool_update_session.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef LIBHOTH_EXAMPLES_HTOOL_UPDATE_SESSION_H_
#define LIBHOTH_EXAMPLES_HTOOL_UPDATE_SESSION_H_

#include "htool_cmd.h"

#ifdef __cplusplus
extern "C" {
#endif

int htool_update_session_start(const struct htool_invocation* inv);
int htool_update_session_finalize(const struct htool_invocation* inv);
int htool_update_session_status(const struct htool_invocation* inv);

#ifdef __cplusplus
}
#endif

#endif // LIBHOTH_EXAMPLES_HTOOL_UPDATE_SESSION_H_
2 changes: 2 additions & 0 deletions examples/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ executable(
'htool_security_tokens.c',
'htool_tpm.h',
'htool_tpm.c',
'htool_update_session.h',
'htool_update_session.c',
git_version_h,
],
dependencies: [libusb],
Expand Down
25 changes: 25 additions & 0 deletions protocol/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -620,3 +620,28 @@ cc_test(
"@googletest//:gtest_main",
],
)

cc_library(
name = "update_session",
srcs = ["update_session.c"],
hdrs = ["update_session.h"],
deps = [
":host_cmd",
":libhoth_status",
"//transports:libhoth_device",
],
)

cc_test(
name = "update_session_test",
srcs = ["update_session_test.cc"],
deps = [
":host_cmd",
":libhoth_status",
":update_session",
"//protocol/test:libhoth_device_mock",
"//transports:libhoth_device",
"@googletest//:gtest",
"@googletest//:gtest_main",
],
)
1 change: 1 addition & 0 deletions protocol/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ protocol_srcs = [
'util.c',
'console.c',
'gpio_drive_strength.c',
'update_session.c',
'status.c'
]

Expand Down
95 changes: 95 additions & 0 deletions protocol/update_session.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "protocol/update_session.h"

#include <stddef.h>
#include <stdint.h>

#include "protocol/host_cmd.h"
#include "protocol/status.h"
#include "transports/libhoth_device.h"

libhoth_error libhoth_update_session_start(struct libhoth_device* dev,
uint32_t timeout_seconds) {
if (dev == NULL || timeout_seconds == 0) {
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH,
LIBHOTH_ERR_INVALID_PARAMETER);
}

struct update_session_start_request req = {
.timeout_seconds = timeout_seconds,
};
size_t rlen = 0;
return libhoth_hostcmd_exec_v2(
dev,
HOTH_CMD_BOARD_SPECIFIC_BASE + HOTH_PRV_CMD_HOTH_UPDATE_SESSION_START, 0,
&req, sizeof(req), NULL, 0, &rlen);
}

libhoth_error libhoth_update_session_finalize(struct libhoth_device* dev) {
if (dev == NULL) {
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH,
LIBHOTH_ERR_INVALID_PARAMETER);
}

size_t rlen = 0;
return libhoth_hostcmd_exec_v2(
dev,
HOTH_CMD_BOARD_SPECIFIC_BASE + HOTH_PRV_CMD_HOTH_UPDATE_SESSION_FINALIZE,
0, NULL, 0, NULL, 0, &rlen);
}

libhoth_error libhoth_update_session_get_status(
struct libhoth_device* dev, struct update_session_status_response* status) {
if (dev == NULL || status == NULL) {
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH,
LIBHOTH_ERR_INVALID_PARAMETER);
}

size_t rlen = 0;
libhoth_error err =
libhoth_hostcmd_exec_v2(dev,
HOTH_CMD_BOARD_SPECIFIC_BASE +
HOTH_PRV_CMD_HOTH_UPDATE_SESSION_GET_STATUS,
0, NULL, 0, status, sizeof(*status), &rlen);
if (err != HOTH_SUCCESS) {
return err;
}
if (rlen != sizeof(*status)) {
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH,
LIBHOTH_ERR_FAIL);
}
return HOTH_SUCCESS;
}

const char* libhoth_update_session_state_string(
enum update_session_state state) {
switch (state) {
case UPDATE_SESSION_NONE:
return "NONE";
case UPDATE_SESSION_PENDING_START:
return "PENDING_START";
case UPDATE_SESSION_UPDATING:
return "UPDATING";
case UPDATE_SESSION_FINALIZED:
return "FINALIZED";
case UPDATE_SESSION_START_TIMEOUT:
return "START_TIMEOUT";
case UPDATE_SESSION_UPDATE_TIMEOUT:
return "UPDATE_TIMEOUT";
default:
return "UNKNOWN";
}
}
Loading
Loading