diff --git a/BUILD b/BUILD index d0048cb..1ce7d8d 100644 --- a/BUILD +++ b/BUILD @@ -7,6 +7,14 @@ cc_library( hdrs = [":gen_version_header"], ) +cc_library( + name = "libhoth_status", + hdrs = ["include/libhoth/status.h"], + strip_include_prefix = "include", + visibility = ["//visibility:public"], +) + + genrule( name = "gen_version_header", outs = ["git_version.h"], diff --git a/examples/BUILD b/examples/BUILD index be17dd9..49565b8 100644 --- a/examples/BUILD +++ b/examples/BUILD @@ -161,6 +161,7 @@ cc_test( ":htool_security_version", "//examples/test:test_util", "//protocol/test:libhoth_device_mock", + "//:libhoth_status", "@googletest//:gtest", "@googletest//:gtest_main", ], @@ -265,6 +266,7 @@ cc_binary( "//transports:libhoth_spi", "//transports:libhoth_usb", "//transports:libhoth_usb_device", + "//:libhoth_status", "@libusb", ] + select({ ":dbus_backend": ["//transports:libhoth_dbus"], diff --git a/examples/htool.c b/examples/htool.c index 3df934c..4a24d0f 100644 --- a/examples/htool.c +++ b/examples/htool.c @@ -769,11 +769,13 @@ static int command_hello(const struct htool_invocation* inv) { } uint32_t output = 0; - const int rv = libhoth_hello(dev, input, &output); + const libhoth_error rv = libhoth_hello(dev, input, &output); if (rv) { return rv; } + printf("Rv: %ld\n", rv); + printf("output: 0x%08x\n", output); return 0; } diff --git a/examples/htool_provisioning_test.cc b/examples/htool_provisioning_test.cc index 5178b46..9c22201 100644 --- a/examples/htool_provisioning_test.cc +++ b/examples/htool_provisioning_test.cc @@ -297,7 +297,10 @@ TEST_F(HtoolProvisioningTest, GetProvisioningLogUnexpectedErrorFromDevice) { .WillOnce(DoAll(CopyResp(&response, sizeof(header) + header.size), Return(LIBHOTH_ERR_INTERFACE_NOT_FOUND))); - ASSERT_EQ(htool_get_provisioning_log(&inv), -1); + ASSERT_EQ( + htool_get_provisioning_log(&inv), + (int)LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_RECEIVE_ERROR)); // Verify output file is empty FILE* fp = fopen(tmp_output_file.c_str(), "rb"); @@ -548,7 +551,10 @@ TEST_F(HtoolProvisioningTest, ValidateAndSignUnexpectedErrorFromDevice) { .WillOnce(DoAll(CopyResp(signed_log_data.data(), signed_log_data.size()), Return(LIBHOTH_ERR_INTERFACE_NOT_FOUND))); - ASSERT_EQ(htool_validate_and_sign(&inv), -1); + ASSERT_EQ( + htool_validate_and_sign(&inv), + (int)LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_RECEIVE_ERROR)); // Verify output file is empty FILE* fp = fopen(tmp_output_file.c_str(), "rb"); @@ -712,7 +718,10 @@ TEST_F(HtoolProvisioningTest, ValidateAndSignTooLargeResponse) { .WillOnce(DoAll(CopyResp(signed_log_data.data(), signed_log_data.size()), Return(LIBHOTH_OK))); - ASSERT_EQ(htool_validate_and_sign(&inv), -1); + ASSERT_EQ( + htool_validate_and_sign(&inv), + (int)LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_RESPONSE_TOO_BIG)); // Verify output file size is 0 FILE* fp = fopen(tmp_output_file.c_str(), "rb"); diff --git a/examples/htool_security_v2_test.cc b/examples/htool_security_v2_test.cc index 798f98e..594a322 100644 --- a/examples/htool_security_v2_test.cc +++ b/examples/htool_security_v2_test.cc @@ -9,6 +9,7 @@ #include "examples/host_commands.h" #include "examples/test/test_util.h" +#include "libhoth/status.h" #include "protocol/test/libhoth_device_mock.h" using ::testing::_; @@ -21,10 +22,11 @@ using ::testing::SetArrayArgument; struct libhoth_device* mock_dev = nullptr; struct libhoth_device* htool_libhoth_device() { return mock_dev; } -int libhoth_hostcmd_exec(struct libhoth_device* dev, uint16_t command, - uint8_t version, const void* request, - size_t request_size, void* response, - size_t max_response_size, size_t* bytes_read) { +libhoth_error libhoth_hostcmd_exec(struct libhoth_device* dev, uint16_t command, + uint8_t version, const void* request, + size_t request_size, void* response, + size_t max_response_size, + size_t* bytes_read) { LibHothDeviceMock* mock = (LibHothDeviceMock*)dev->user_ctx; return mock->hostcmd_exec(dev, command, version, request, request_size, response, max_response_size, bytes_read); @@ -92,13 +94,18 @@ TEST_F(HtoolSecurityV2Test, ExecCmdHostCmdFailure) { struct security_v2_buffer response_buffer = { .data = response_storage, .size = sizeof(response_storage)}; - EXPECT_CALL(mock_, hostcmd_exec(_, _, _, _, _, _, _, _)).WillOnce(Return(-1)); + EXPECT_CALL(mock_, hostcmd_exec(_, _, _, _, _, _, _, _)) + .WillOnce(Return(LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, + HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_SEND_ERROR))); int status = htool_exec_security_v2_cmd(mock_dev, 1, 2, 3, &request_buffer, nullptr, 0, &response_buffer, nullptr, 0); - ASSERT_EQ(status, -1); + ASSERT_EQ(status, (int)LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, + HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_SEND_ERROR)); } TEST_F(HtoolSecurityV2Test, SerializedCmdSuccess) { @@ -167,7 +174,10 @@ TEST_F(HtoolSecurityV2Test, SerializedCmdExecFailure) { struct security_v2_buffer response_buffer = { .data = response_storage, .size = sizeof(response_storage)}; - EXPECT_CALL(mock_, hostcmd_exec(_, _, _, _, _, _, _, _)).WillOnce(Return(-1)); + EXPECT_CALL(mock_, hostcmd_exec(_, _, _, _, _, _, _, _)) + .WillOnce(Return(LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, + HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_SEND_ERROR))); const struct security_v2_serialized_param* param_out1 = nullptr; const struct security_v2_serialized_param** response_params[] = {¶m_out1}; diff --git a/examples/htool_target_control.c b/examples/htool_target_control.c index 72e402b..18e7c71 100644 --- a/examples/htool_target_control.c +++ b/examples/htool_target_control.c @@ -39,32 +39,39 @@ int target_control_perform_action( }; size_t response_length = 0; - int ret = libhoth_hostcmd_exec( + libhoth_error ret = libhoth_hostcmd_exec( dev, HOTH_CMD_BOARD_SPECIFIC_BASE + HOTH_PRV_CMD_HOTH_TARGET_CONTROL, /*version=*/0, &request, sizeof(request), response, sizeof(*response), &response_length); if (ret != 0) { - fprintf(stderr, "HOTH_TARGET_CONTROL error code: %d\n", ret); + fprintf(stderr, "HOTH_TARGET_CONTROL error code: %ld\n", ret); switch (ret) { - case (HTOOL_ERROR_HOST_COMMAND_START + HOTH_RES_INVALID_COMMAND): + case (LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_FW, + HOTH_RES_FW_INVALID_COMMAND)): fprintf(stderr, "Command not supported, or requested action is forbidden on " "function. Please confirm if the RoT FW version supports this " "command, and requested action is allowed on the function\n"); break; - case (HTOOL_ERROR_HOST_COMMAND_START + HOTH_RES_INVALID_PARAM): + case (LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_FW, + HOTH_RES_FW_INVALID_PARAM)): fprintf(stderr, "Invalid function or action. Please confirm if the RoT " "firmware version supports the given function, and action on " "that function is correct\n"); break; - case (HTOOL_ERROR_HOST_COMMAND_START + HOTH_RES_ACCESS_DENIED): + case (LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_FW, + HOTH_RES_FW_ACCESS_DENIED)): fprintf(stderr, "Not authorized to perform requested action on function. " "Please use `authz_host_command` commands to authorize RoT to " "perform requested action on function\n"); break; + default: + fprintf(stderr, + "Unexpected error. Please check the transport layer and " + "RoT firmware are working correctly\n"); } return -1; } diff --git a/examples/htool_target_control.h b/examples/htool_target_control.h index 7a04575..838c3a8 100644 --- a/examples/htool_target_control.h +++ b/examples/htool_target_control.h @@ -17,6 +17,8 @@ #define LIBHOTH_EXAMPLES_HTOOL_TARGET_CONTROL_H_ #include "host_commands.h" +#include "libhoth/status.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/examples/meson.build b/examples/meson.build index 889f715..3766041 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -6,7 +6,7 @@ git_version_h = vcs_tag( replace_string: '@GIT_COMMIT@', ) -incdir = include_directories('..') +incdir = libhoth_include_dirs link_with = [libhoth.get_static_lib()] c_args = [] diff --git a/include/libhoth/status.h b/include/libhoth/status.h new file mode 100644 index 0000000..ff489fd --- /dev/null +++ b/include/libhoth/status.h @@ -0,0 +1,102 @@ + +// 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_INCLUDE_LIBHOTH_STATUS_H_ +#define LIBHOTH_INCLUDE_LIBHOTH_STATUS_H_ + +#include + +// Represents success +#define HOTH_SUCCESS 0x0ULL + +// Typedef for the error code +typedef uint64_t libhoth_error; + +#define LIBHOTH_ERR_CONSTRUCT(ctx, space, code) \ + ((((uint64_t)(ctx) & 0xFFFFFFFFULL) << 32) | \ + (((uint64_t)(space) & 0xFFFFULL) << 16) | ((uint64_t)(code) & 0xFFFFULL)) + +// hoth_context_id: High 32 bits of the error code. +// Uniquely identifies the libhoth operation or subsystem. +enum hoth_context_id { + HOTH_CTX_NONE = 0, + + // Initialization / General + HOTH_CTX_INIT = 1, + + // Transport layers + HOTH_CTX_USB = 10, + HOTH_CTX_SPI = 20, + + // Command Execution + HOTH_CTX_CMD_EXEC = 30, +}; + +// hoth_host_space: Top 16 bits of the low 32-bit Base Error Code. +// Indicates the domain of host-side errors. +enum hoth_host_space { + HOTH_HOST_SPACE_FW = 0x0000, // Firmware errors directly + HOTH_HOST_SPACE_POSIX = 0x0001, // errno values + HOTH_HOST_SPACE_LIBUSB = 0x0002, // libusb_error values + HOTH_HOST_SPACE_HTOOL = 0x0003, // htool error codes + HOTH_HOST_SPACE_LIBHOTH = 0x0005, // libhoth internal errors +}; + +#ifndef __packed +#define __packed __attribute__((packed)) +#endif + +// Hoth error code: Low 16 bits of the 32-bit Base Error Code +// Firmware Error +enum hoth_fw_error_status { + HOTH_RES_FW_SUCCESS = 0, + HOTH_RES_FW_INVALID_COMMAND = 1, + HOTH_RES_FW_ERROR = 2, + HOTH_RES_FW_INVALID_PARAM = 3, + HOTH_RES_FW_ACCESS_DENIED = 4, + HOTH_RES_FW_INVALID_RESPONSE = 5, + HOTH_RES_FW_INVALID_VERSION = 6, + HOTH_RES_FW_INVALID_CHECKSUM = 7, + HOTH_RES_FW_IN_PROGRESS = 8, + HOTH_RES_FW_UNAVAILABLE = 9, + HOTH_RES_FW_TIMEOUT = 10, + HOTH_RES_FW_OVERFLOW = 11, + HOTH_RES_FW_INVALID_HEADER = 12, + HOTH_RES_FW_REQUEST_TRUNCATED = 13, + HOTH_RES_FW_RESPONSE_TOO_BIG = 14, + HOTH_RES_FW_BUS_ERROR = 15, + HOTH_RES_FW_BUSY = 16, + HOTH_RES_FW_INVALID_HEADER_VERSION = 17, + HOTH_RES_FW_INVALID_HEADER_CRC = 18, + HOTH_RES_FW_INVALID_DATA_CRC = 19, + HOTH_RES_FW_DUP_UNAVAILABLE = 20, + HOTH_RES_FW_MAX = UINT16_MAX +} __packed; + +// Hoth error code: Low 16 bits of the 32-bit Base Error Code +// Libhoth Error +enum hoth_libhoth_error_status { + HOTH_LIBHOTH_SUCCESS = 0, + HOTH_LIBHOTH_ERROR = 1, + HOTH_LIBHOTH_REQUEST_TOO_BIG = 2, + HOTH_LIBHOTH_EC_ERROR = 3, + HOTH_LIBHOTH_SEND_ERROR = 4, + HOTH_LIBHOTH_RECEIVE_ERROR = 5, + HOTH_LIBHOTH_VALIDATE_ERROR = 6, + HOTH_LIBHOTH_RESPONSE_TOO_BIG = 7, + HOTH_LIBHOTH_MAX = UINT16_MAX +} __packed; + +#endif // LIBHOTH_INCLUDE_LIBHOTH_STATUS_H_ diff --git a/meson.build b/meson.build index 0cd1e43..424b7a5 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,9 @@ project('libhoth', 'c', 'cpp', license: 'Apache-2.0', version: '0.0.0') +install_headers('include/libhoth/status.h', subdir: 'libhoth') + +libhoth_include_dirs = include_directories('include', '.') + header_subdirs = ['libhoth'] libhoth_objs = [] libhoth_deps = [] diff --git a/protocol/BUILD b/protocol/BUILD index 564598f..f876481 100644 --- a/protocol/BUILD +++ b/protocol/BUILD @@ -8,6 +8,7 @@ cc_library( srcs = ["host_cmd.c"], hdrs = ["host_cmd.h"], deps = [ + "//:libhoth_status", "//transports:libhoth_device", ], ) @@ -17,6 +18,7 @@ cc_test( srcs = ["host_cmd_test.cc"], deps = [ ":host_cmd", + "//:libhoth_status", "//protocol/test:libhoth_device_mock", "//transports:libhoth_device", "@googletest//:gtest", @@ -390,6 +392,7 @@ cc_library( hdrs = ["hello.h"], deps = [ ":host_cmd", + "//:libhoth_status", "//transports:libhoth_device", ], ) diff --git a/protocol/authz_record.c b/protocol/authz_record.c index 78205eb..cca0380 100644 --- a/protocol/authz_record.c +++ b/protocol/authz_record.c @@ -19,7 +19,7 @@ #include "chipinfo.h" -int libhoth_authz_record_erase(struct libhoth_device* dev) { +libhoth_error libhoth_authz_record_erase(struct libhoth_device* dev) { struct hoth_authz_record_set_request request = { .index = 0, .erase = 1, @@ -29,17 +29,17 @@ int libhoth_authz_record_erase(struct libhoth_device* dev) { /*version=*/0, &request, sizeof(request), NULL, 0, NULL); } -int libhoth_authz_record_read(struct libhoth_device* dev, - struct hoth_authz_record_get_response* resp) { +libhoth_error libhoth_authz_record_read( + struct libhoth_device* dev, struct hoth_authz_record_get_response* resp) { struct hoth_authz_record_get_request request = {.index = 0}; return libhoth_hostcmd_exec( dev, HOTH_CMD_BOARD_SPECIFIC_BASE + HOTH_PRV_CMD_HOTH_GET_AUTHZ_RECORD, /*version=*/0, &request, sizeof(request), resp, sizeof(*resp), NULL); } -int libhoth_authz_record_build(struct libhoth_device* dev, - uint32_t capabilities, - struct authorization_record* record) { +libhoth_error libhoth_authz_record_build(struct libhoth_device* dev, + uint32_t capabilities, + struct authorization_record* record) { memset(record, 0, sizeof(*record)); memcpy(&record->magic, AUTHORIZATION_RECORD_MAGIC, sizeof(record->magic)); record->version = 1; @@ -49,9 +49,9 @@ int libhoth_authz_record_build(struct libhoth_device* dev, *(uint32_t*)record->capabilities = capabilities; struct hoth_response_chip_info chipinfo_resp; - int status = libhoth_chipinfo(dev, &chipinfo_resp); + libhoth_error status = libhoth_chipinfo(dev, &chipinfo_resp); if (status != 0) { - return -1; + return status; } record->dev_id_0 = chipinfo_resp.hardware_identity & 0xfffffffful; record->dev_id_1 = (chipinfo_resp.hardware_identity >> 32); @@ -67,14 +67,16 @@ int libhoth_authz_record_build(struct libhoth_device* dev, if (nonce_resp.ro_supported_key_id == 0) { fprintf(stderr, "ro_supported_key_id = 0. Please reset the chip and retry\n"); - return -1; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_ERROR); } if (nonce_resp.ro_supported_key_id != nonce_resp.rw_supported_key_id) { fprintf( stderr, "RO and RW supported key_ids do not match: (RO) 0x%x != (RW) 0x%x\n", nonce_resp.ro_supported_key_id, nonce_resp.rw_supported_key_id); - return -1; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_ERROR); } record->key_id = nonce_resp.ro_supported_key_id; if (sizeof(record->authorization_nonce) != @@ -82,7 +84,8 @@ int libhoth_authz_record_build(struct libhoth_device* dev, fprintf(stderr, "Nonce size does not match. Expecting %ld, got %ld", sizeof(nonce_resp.authorization_nonce), sizeof(record->authorization_nonce)); - return -1; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_ERROR); } memcpy(record->authorization_nonce, nonce_resp.authorization_nonce, sizeof(record->authorization_nonce)); @@ -90,8 +93,8 @@ int libhoth_authz_record_build(struct libhoth_device* dev, return 0; } -int libhoth_authz_record_set(struct libhoth_device* dev, - const struct authorization_record* record) { +libhoth_error libhoth_authz_record_set( + struct libhoth_device* dev, const struct authorization_record* record) { struct hoth_authz_record_set_request request = { .index = 0, .erase = 0, diff --git a/protocol/authz_record.h b/protocol/authz_record.h index 747e1f7..b9831d9 100644 --- a/protocol/authz_record.h +++ b/protocol/authz_record.h @@ -107,17 +107,21 @@ struct hoth_authz_record_get_nonce_response { uint32_t rw_supported_key_id; } __attribute__((packed)); -int libhoth_authz_record_erase(struct libhoth_device* dev); -int libhoth_authz_record_read(struct libhoth_device* dev, - struct hoth_authz_record_get_response* resp); -int libhoth_authz_record_build(struct libhoth_device* dev, - uint32_t capabilities, - struct authorization_record* record); -int libhoth_authz_record_set(struct libhoth_device* dev, - const struct authorization_record* record); +libhoth_error libhoth_authz_record_erase(struct libhoth_device* dev); + +libhoth_error libhoth_authz_record_read( + struct libhoth_device* dev, struct hoth_authz_record_get_response* resp); + +libhoth_error libhoth_authz_record_build(struct libhoth_device* dev, + uint32_t capabilities, + struct authorization_record* record); + +libhoth_error libhoth_authz_record_set( + struct libhoth_device* dev, const struct authorization_record* record); int libhoth_authorization_record_print_hex_string( const struct authorization_record* record); + int libhoth_authorization_record_from_hex_string( struct authorization_record* record, const char* buf, size_t length); diff --git a/protocol/authz_record_test.cc b/protocol/authz_record_test.cc index 1416e73..6a279b1 100644 --- a/protocol/authz_record_test.cc +++ b/protocol/authz_record_test.cc @@ -47,7 +47,9 @@ TEST_F(LibHothTest, authz_erase_test) { EXPECT_CALL(mock_, receive).WillOnce(DoAll(CopyResp(&dummy, 0), Return(-1))); - EXPECT_EQ(libhoth_authz_record_erase(&hoth_dev_), -1); + EXPECT_EQ(libhoth_authz_record_erase(&hoth_dev_), + LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_RECEIVE_ERROR)); } TEST_F(LibHothTest, authz_read_test) { @@ -147,7 +149,9 @@ TEST_F(LibHothTest, authz_build_fail_test) { uint32_t cap = 123; struct authorization_record record = {}; - EXPECT_EQ(libhoth_authz_record_build(&hoth_dev_, cap, &record), -1); + EXPECT_EQ(libhoth_authz_record_build(&hoth_dev_, cap, &record), + LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_ERROR)); } TEST_F(LibHothTest, authz_mismatch_key_id_test) { @@ -183,7 +187,9 @@ TEST_F(LibHothTest, authz_mismatch_key_id_test) { uint32_t cap = 123; struct authorization_record record = {}; - EXPECT_EQ(libhoth_authz_record_build(&hoth_dev_, cap, &record), -1); + EXPECT_EQ(libhoth_authz_record_build(&hoth_dev_, cap, &record), + LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_ERROR)); } TEST_F(LibHothTest, authz_nonce_fail_test) { @@ -215,7 +221,9 @@ TEST_F(LibHothTest, authz_nonce_fail_test) { uint32_t cap = 123; struct authorization_record record; - EXPECT_EQ(libhoth_authz_record_build(&hoth_dev_, cap, &record), -1); + EXPECT_EQ(libhoth_authz_record_build(&hoth_dev_, cap, &record), + LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_ERROR)); } TEST_F(LibHothTest, authz_set_test) { diff --git a/protocol/controlled_storage.c b/protocol/controlled_storage.c index ed6a41e..7ed7952 100644 --- a/protocol/controlled_storage.c +++ b/protocol/controlled_storage.c @@ -18,7 +18,7 @@ #include "controlled_storage.h" -int libhoth_controlled_storage_read( +libhoth_error libhoth_controlled_storage_read( struct libhoth_device* dev, uint32_t slot, struct hoth_payload_controlled_storage* payload, size_t* payload_len) { struct hoth_request_controlled_storage req = {}; @@ -30,11 +30,14 @@ int libhoth_controlled_storage_read( /*version=*/0, &req, sizeof(req), payload, sizeof(*payload), payload_len); } -int libhoth_controlled_storage_write(struct libhoth_device* dev, uint32_t slot, - const uint8_t* data, size_t len) { +libhoth_error libhoth_controlled_storage_write(struct libhoth_device* dev, + uint32_t slot, + const uint8_t* data, + size_t len) { struct hoth_request_controlled_storage req = {}; if (len > sizeof(req.payload.data)) { - return -1; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_REQUEST_TOO_BIG); } req.operation = CONTROLLED_STORAGE_WRITE; @@ -47,8 +50,8 @@ int libhoth_controlled_storage_write(struct libhoth_device* dev, uint32_t slot, 0, NULL); } -int libhoth_controlled_storage_delete(struct libhoth_device* dev, - uint32_t slot) { +libhoth_error libhoth_controlled_storage_delete(struct libhoth_device* dev, + uint32_t slot) { struct hoth_request_controlled_storage req = {}; req.operation = CONTROLLED_STORAGE_DELETE; diff --git a/protocol/controlled_storage.h b/protocol/controlled_storage.h index e842cf6..a4b0bda 100644 --- a/protocol/controlled_storage.h +++ b/protocol/controlled_storage.h @@ -48,13 +48,14 @@ struct hoth_request_controlled_storage { struct hoth_payload_controlled_storage payload; } __attribute__((packed)); -int libhoth_controlled_storage_read( +libhoth_error libhoth_controlled_storage_read( struct libhoth_device* dev, uint32_t slot, struct hoth_payload_controlled_storage* payload, size_t* payload_len); -int libhoth_controlled_storage_write(struct libhoth_device* dev, uint32_t slot, - const uint8_t* data, size_t len); -int libhoth_controlled_storage_delete(struct libhoth_device* dev, - uint32_t slot); +libhoth_error libhoth_controlled_storage_write(struct libhoth_device* dev, + uint32_t slot, + const uint8_t* data, size_t len); +libhoth_error libhoth_controlled_storage_delete(struct libhoth_device* dev, + uint32_t slot); #ifdef __cplusplus } diff --git a/protocol/controlled_storage_test.cc b/protocol/controlled_storage_test.cc index 7651584..b574df0 100644 --- a/protocol/controlled_storage_test.cc +++ b/protocol/controlled_storage_test.cc @@ -73,7 +73,8 @@ TEST_F(LibHothTest, controlled_storage_write_test) { LIBHOTH_OK); EXPECT_EQ( libhoth_controlled_storage_write(&hoth_dev_, 0, payload, sizeof(payload)), - -1); + LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_SEND_ERROR)); } TEST_F(LibHothTest, controlled_storage_delete_test) { @@ -89,5 +90,7 @@ TEST_F(LibHothTest, controlled_storage_delete_test) { .WillOnce(DoAll(CopyResp(&dummy, 0), Return(LIBHOTH_OK))); EXPECT_EQ(libhoth_controlled_storage_delete(&hoth_dev_, 0), LIBHOTH_OK); - EXPECT_EQ(libhoth_controlled_storage_delete(&hoth_dev_, 0), -1); + EXPECT_EQ(libhoth_controlled_storage_delete(&hoth_dev_, 0), + LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_SEND_ERROR)); } diff --git a/protocol/firmware_update.c b/protocol/firmware_update.c index e7f2700..4796317 100644 --- a/protocol/firmware_update.c +++ b/protocol/firmware_update.c @@ -20,14 +20,14 @@ #include "protocol/host_cmd.h" #include "transports/libhoth_device.h" -int libhoth_firmware_update_from_flash_and_reset(struct libhoth_device* dev, - uint32_t offset) { +libhoth_error libhoth_firmware_update_from_flash_and_reset( + struct libhoth_device* dev, uint32_t offset) { const struct hoth_request_firmware_update request = { .operation = HOTH_FIRMWARE_UPDATE_OP_UPDATE_AND_RESET, .flags = 0, .offset = offset, }; - const int rv = + const libhoth_error rv = libhoth_hostcmd_exec(dev, HOTH_CMD_FIRMWARE_UPDATE, /*version=*/0, &request, sizeof(request), NULL, 0, NULL); if (rv == 0) { @@ -37,17 +37,21 @@ int libhoth_firmware_update_from_flash_and_reset(struct libhoth_device* dev, offset); return 0; } - if (rv > HTOOL_ERROR_HOST_COMMAND_START) { + if (rv != 0 && (rv >> 32) == HOTH_CTX_CMD_EXEC && + ((rv >> 16) & 0xFFFF) == HOTH_HOST_SPACE_FW) { fprintf(stderr, "Firmware update from flash offset 0x%x failed with error code: " - "%d. Aborting.\n", + "%ld. Aborting.\n", offset, rv); return rv; } - fprintf(stderr, - "Lost connection after firmware update command (error code %d). " - "This is expected if the device reset. Attempting to reconnect...\n", - rv); - return libhoth_device_reconnect(dev); + if (rv != 0) { + fprintf( + stderr, + "Lost connection after firmware update command (error code %ld). " + "This is expected if the device reset. Attempting to reconnect...\n", + rv); + } + return (libhoth_error)libhoth_device_reconnect(dev); } diff --git a/protocol/firmware_update.h b/protocol/firmware_update.h index 2a404d9..2657b6c 100644 --- a/protocol/firmware_update.h +++ b/protocol/firmware_update.h @@ -17,6 +17,7 @@ #include +#include "libhoth/status.h" #include "protocol/host_cmd.h" #ifdef __cplusplus @@ -37,8 +38,8 @@ struct hoth_request_firmware_update { uint32_t offset; // Bundle offset in the active side of flash. } __attribute__((packed, aligned(4))); -int libhoth_firmware_update_from_flash_and_reset(struct libhoth_device* dev, - uint32_t offset); +libhoth_error libhoth_firmware_update_from_flash_and_reset( + struct libhoth_device* dev, uint32_t offset); #ifdef __cplusplus } diff --git a/protocol/firmware_update_test.cc b/protocol/firmware_update_test.cc index e0c22f8..17cf0ee 100644 --- a/protocol/firmware_update_test.cc +++ b/protocol/firmware_update_test.cc @@ -64,5 +64,6 @@ TEST_F(LibHothTest, firmware_update_test_failed_without_rebooting) { EXPECT_CALL(mock_, reconnect).Times(0); EXPECT_EQ( libhoth_firmware_update_from_flash_and_reset(&hoth_dev_, /*offset=*/0), - HTOOL_ERROR_HOST_COMMAND_START + HOTH_RES_UNAVAILABLE); + LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_FW, + HOTH_RES_FW_UNAVAILABLE)); } diff --git a/protocol/hello.c b/protocol/hello.c index 9a05779..9ac2bde 100644 --- a/protocol/hello.c +++ b/protocol/hello.c @@ -16,13 +16,13 @@ #include -int libhoth_hello(struct libhoth_device* const dev, const uint32_t input, - uint32_t* const output) { +libhoth_error libhoth_hello(struct libhoth_device* const dev, + const uint32_t input, uint32_t* const output) { const struct hoth_request_hello request = { .input = input, }; - struct hoth_response_hello response; - const int rv = + struct hoth_response_hello response = {0}; + const libhoth_error rv = libhoth_hostcmd_exec(dev, HOTH_CMD_HELLO, /*version=*/0, &request, sizeof(request), &response, sizeof(response), NULL); *output = response.output; diff --git a/protocol/hello.h b/protocol/hello.h index 88804d2..1a73c0c 100644 --- a/protocol/hello.h +++ b/protocol/hello.h @@ -17,6 +17,7 @@ #include +#include "libhoth/status.h" #include "protocol/host_cmd.h" #ifdef __cplusplus @@ -35,7 +36,8 @@ struct hoth_response_hello { uint32_t output; } __hoth_align4; -int libhoth_hello(struct libhoth_device* dev, uint32_t input, uint32_t* output); +libhoth_error libhoth_hello(struct libhoth_device* dev, uint32_t input, + uint32_t* output); #ifdef __cplusplus } diff --git a/protocol/host_cmd.c b/protocol/host_cmd.c index 95cea32..3dad689 100644 --- a/protocol/host_cmd.c +++ b/protocol/host_cmd.c @@ -162,19 +162,21 @@ static int validate_ec_response_header( return 0; } -int libhoth_hostcmd_exec(struct libhoth_device* dev, uint16_t command, - uint8_t version, const void* req_payload, - size_t req_payload_size, void* resp_buf, - size_t resp_buf_size, size_t* out_resp_size) { +libhoth_error libhoth_hostcmd_exec(struct libhoth_device* dev, uint16_t command, + uint8_t version, const void* req_payload, + size_t req_payload_size, void* resp_buf, + size_t resp_buf_size, + size_t* out_resp_size) { struct { struct hoth_host_request hdr; uint8_t payload_buf[LIBHOTH_MAILBOX_SIZE - sizeof(struct hoth_host_request)]; - } req; + } req = {0}; if (req_payload_size > sizeof(req.payload_buf)) { fprintf(stderr, "req_payload_size too large: %d > %d\n", (int)req_payload_size, (int)sizeof(req.payload_buf)); - return -1; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_REQUEST_TOO_BIG); } if (req_payload) { memcpy(req.payload_buf, req_payload, req_payload_size); @@ -183,40 +185,47 @@ int libhoth_hostcmd_exec(struct libhoth_device* dev, uint16_t command, req_payload_size, &req.hdr); if (status != 0) { fprintf(stderr, "populate_ec_request_header() failed: %d\n", status); - return -1; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_EC_ERROR); } status = libhoth_send_request(dev, &req, sizeof(req.hdr) + req_payload_size); if (status != LIBHOTH_OK) { fprintf(stderr, "libhoth_send_request() failed: %d\n", status); - return -1; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_SEND_ERROR); } struct { struct hoth_host_response hdr; uint8_t payload_buf[LIBHOTH_MAILBOX_SIZE - sizeof(struct hoth_host_response)]; - } resp; + } resp = {0}; size_t resp_size = 0; status = libhoth_receive_response(dev, &resp, sizeof(resp), &resp_size, HOTH_CMD_TIMEOUT_MS_DEFAULT); if (status != LIBHOTH_OK) { fprintf(stderr, "libhoth_receive_response() failed: %d\n", status); - return -1; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_RECEIVE_ERROR); } status = validate_ec_response_header(&resp.hdr, resp.payload_buf, resp_size); if (status != 0) { fprintf(stderr, "EC response header invalid: %d\n", status); - return -1; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_VALIDATE_ERROR); } if (resp.hdr.result != HOTH_RES_SUCCESS) { fprintf(stderr, "EC response contained error: %d", resp.hdr.result); if (resp.hdr.data_len >= 4) { - uint32_t error_code; + uint32_t error_code = 0; memcpy(&error_code, resp.payload_buf, sizeof(error_code)); fprintf(stderr, " (extended: 0x%08x)\n", error_code); + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_FW, + error_code); } else { fprintf(stderr, "\n"); + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_FW, + resp.hdr.result); } - return HTOOL_ERROR_HOST_COMMAND_START + resp.hdr.result; } size_t resp_payload_size = resp_size - sizeof(struct hoth_host_response); @@ -226,14 +235,16 @@ int libhoth_hostcmd_exec(struct libhoth_device* dev, uint16_t command, stderr, "Response payload too large to fit in supplied buffer: %zu > %zu\n", resp_payload_size, resp_buf_size); - return -1; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_RESPONSE_TOO_BIG); } } else { if (resp_payload_size != resp_buf_size) { fprintf(stderr, "Unexpected response payload size: got %zu expected %zu\n", resp_payload_size, resp_buf_size); - return -1; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, + HOTH_LIBHOTH_RESPONSE_TOO_BIG); } } if (resp_buf) { diff --git a/protocol/host_cmd.h b/protocol/host_cmd.h index 17e8100..e2f7474 100644 --- a/protocol/host_cmd.h +++ b/protocol/host_cmd.h @@ -18,6 +18,7 @@ #include #include +#include "libhoth/status.h" #include "transports/libhoth_device.h" #ifdef __cplusplus @@ -101,10 +102,10 @@ struct hoth_host_response { uint16_t reserved; } __hoth_align4; -int libhoth_hostcmd_exec(struct libhoth_device* dev, uint16_t command, - uint8_t version, const void* req_payload, - size_t req_payload_size, void* resp_buf, - size_t resp_buf_size, size_t* out_resp_size); +libhoth_error libhoth_hostcmd_exec(struct libhoth_device* dev, uint16_t command, + uint8_t version, const void* req_payload, + size_t req_payload_size, void* resp_buf, + size_t resp_buf_size, size_t* out_resp_size); uint8_t libhoth_calculate_checksum(const void* header, size_t header_size, const void* data, size_t data_size); diff --git a/protocol/host_cmd_test.cc b/protocol/host_cmd_test.cc index 79ed151..6cbf0c4 100644 --- a/protocol/host_cmd_test.cc +++ b/protocol/host_cmd_test.cc @@ -17,7 +17,7 @@ #include #include -#include "protocol/host_cmd.h" +#include "libhoth/status.h" #include "test/libhoth_device_mock.h" #include "transports/libhoth_device.h" @@ -47,7 +47,7 @@ TEST_F(LibHothTest, response_failure_legacy) { size_t out_resp_size; EXPECT_EQ(libhoth_hostcmd_exec(&hoth_dev_, kCmd, 0, nullptr, 0, resp_buf, sizeof(resp_buf), &out_resp_size), - HTOOL_ERROR_HOST_COMMAND_START + 2); + LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_FW, 2)); } TEST_F(LibHothTest, response_failure_extended) { @@ -60,7 +60,9 @@ TEST_F(LibHothTest, response_failure_extended) { uint8_t resp_buf[1024]; size_t out_resp_size; + // Payload is 0x05, 0x00, 0xc7, 0x89 -> 0x89c70005. The code is the low 16 + // bits: 5. EXPECT_EQ(libhoth_hostcmd_exec(&hoth_dev_, kCmd, 0, nullptr, 0, resp_buf, sizeof(resp_buf), &out_resp_size), - HTOOL_ERROR_HOST_COMMAND_START + 2); + LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_FW, 5)); } diff --git a/protocol/meson.build b/protocol/meson.build index 8681075..3900512 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -26,12 +26,12 @@ protocol_srcs = [ 'console.c' ] -incdir = include_directories('..') +incdir = libhoth_include_dirs libhoth_protocol = static_library( 'hoth_protocols', protocol_srcs, - include_directories: incdir, + include_directories: libhoth_include_dirs, link_with: [libhoth_transport], ) libhoth_objs += [libhoth_protocol.extract_all_objects(recursive: false)] diff --git a/transports/meson.build b/transports/meson.build index e9f30d4..8bd107c 100644 --- a/transports/meson.build +++ b/transports/meson.build @@ -7,7 +7,7 @@ transport_srcs = [ 'libhoth_usb_mailbox.c', ] -incdir = include_directories('..') +incdir = libhoth_include_dirs libusb = dependency('libusb-1.0') libsystemd = dependency('libsystemd') libcap = dependency('libcap') @@ -16,7 +16,7 @@ if get_option('dbus_backend') libhoth_dbus = static_library( 'hoth_dbus', 'libhoth_dbus.c', - include_directories: incdir, + include_directories: libhoth_include_dirs, dependencies: [libsystemd], ) libhoth_objs += [libhoth_dbus.extract_all_objects(recursive: false)] @@ -27,7 +27,7 @@ endif libhoth_transport = static_library( 'hoth_transports', transport_srcs, - include_directories: incdir, + include_directories: libhoth_include_dirs, dependencies: [libusb], )