From d2c49d450b4cce7c3680821bf31d95f5bbe11bd4 Mon Sep 17 00:00:00 2001 From: Ellis Sarza-Nguyen Date: Mon, 22 Jun 2026 18:06:11 -0700 Subject: [PATCH] Refactor transports to use libhoth_error Migrates the transport layer in dev/libhoth from legacy 'int' return codes to the new rich 64-bit 'libhoth_error' format. This allows propagating detailed error information (like libusb or POSIX errno) all the way to callers. Includes: - Core libhoth_device interface and wrapper updates - USB, SPI, MTD, and DBUS transport migrations with rich error mapping - host_cmd.c updates to propagate rich errors directly - htool_usb and htool_console updates to handle libhoth_error --- examples/htool_console.c | 14 ++- examples/htool_usb.c | 7 +- protocol/authz_record_test.cc | 10 +- protocol/dfu_hostcmd.c | 7 +- protocol/firmware_update.c | 7 +- protocol/host_cmd.c | 39 +++---- protocol/test/libhoth_device_mock.cc | 12 +- protocol/test/libhoth_device_mock.h | 6 +- transports/BUILD | 11 +- transports/libhoth_dbus.c | 80 ++++++++----- transports/libhoth_dbus.h | 7 +- transports/libhoth_device.c | 60 +++++++--- transports/libhoth_device.h | 38 +++--- transports/libhoth_mtd.c | 88 ++++++++------ transports/libhoth_mtd.h | 23 ++-- transports/libhoth_spi.c | 150 ++++++++++++++---------- transports/libhoth_spi.h | 47 ++++---- transports/libhoth_usb.c | 168 ++++++++++++++++----------- transports/libhoth_usb.h | 16 ++- 19 files changed, 466 insertions(+), 324 deletions(-) diff --git a/examples/htool_console.c b/examples/htool_console.c index 2bcc0a0..645b98e 100644 --- a/examples/htool_console.c +++ b/examples/htool_console.c @@ -103,25 +103,29 @@ int htool_console_run(struct libhoth_device* dev, // buffer is much smaller than 2GB). if (opts->history) offset -= 0x80000000; bool quit = false; + libhoth_error transport_err = HOTH_SUCCESS; while (!quit) { // Any previous failure should reset all of the USB state before retrying - while (status != LIBHOTH_OK) { + while (status != LIBHOTH_OK || transport_err != HOTH_SUCCESS) { // TODO: Read STDIN during this time and buffer it so we can capture // quit events even when the console is disconnected. We will also want // to tune the reconnect time to match. - status = libhoth_device_reconnect(dev); + transport_err = libhoth_device_reconnect(dev); // If USB is down we might fail reconnect, just retry - if (status != LIBHOTH_OK) { + if (transport_err != HOTH_SUCCESS) { // Make sure we don't end up in a tight retry loop usleep(100 * 1000); + } else { + status = LIBHOTH_OK; } } // Give an opportunity for other clients to use the interface. libhoth_release_device(dev); usleep(1000 * opts->yield_ms); - status = libhoth_claim_device(dev, 1000 * 1000 * opts->claim_timeout_secs); - if (status != LIBHOTH_OK) { + transport_err = + libhoth_claim_device(dev, 1000 * 1000 * opts->claim_timeout_secs); + if (transport_err != HOTH_SUCCESS) { // If USB is down we might fail claim, just go back and retry continue; } diff --git a/examples/htool_usb.c b/examples/htool_usb.c index f32725b..6475f19 100644 --- a/examples/htool_usb.c +++ b/examples/htool_usb.c @@ -328,9 +328,10 @@ struct libhoth_device* htool_libhoth_usb_device(void) { .prng_seed = prng_seed, .timeout_us = timeout_us}; - int rv = libhoth_usb_open(&opts, &result); - if (rv != LIBHOTH_OK) { - fprintf(stderr, "libhoth_usb_open failed: %d\n", rv); + libhoth_error rv = libhoth_usb_open(&opts, &result); + if (rv != HOTH_SUCCESS) { + fprintf(stderr, "libhoth_usb_open failed: 0x%016llx\n", + (unsigned long long)rv); return NULL; } diff --git a/protocol/authz_record_test.cc b/protocol/authz_record_test.cc index c46b5e3..4c9f1e0 100644 --- a/protocol/authz_record_test.cc +++ b/protocol/authz_record_test.cc @@ -43,14 +43,14 @@ TEST_F(LibHothTest, authz_erase_test) { UsesCommand(HOTH_CMD_BOARD_SPECIFIC_BASE + HOTH_PRV_CMD_HOTH_SET_AUTHZ_RECORD), _)) - .WillOnce(Return(LIBHOTH_OK)); + .WillOnce(Return(HOTH_SUCCESS)); + libhoth_error mock_err = LIBHOTH_ERR_CONSTRUCT( + HOTH_CTX_USB, HOTH_HOST_SPACE_LIBHOTH, LIBHOTH_ERR_TIMEOUT); EXPECT_CALL(mock_, receive) - .WillOnce(DoAll(CopyResp(&dummy, 0), Return(LIBHOTH_ERR_TIMEOUT))); + .WillOnce(DoAll(CopyResp(&dummy, 0), Return(mock_err))); - EXPECT_EQ(libhoth_authz_record_erase(&hoth_dev_), - LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, - LIBHOTH_ERR_TIMEOUT)); + EXPECT_EQ(libhoth_authz_record_erase(&hoth_dev_), mock_err); } TEST_F(LibHothTest, authz_read_test) { diff --git a/protocol/dfu_hostcmd.c b/protocol/dfu_hostcmd.c index 55270ec..7e4921e 100644 --- a/protocol/dfu_hostcmd.c +++ b/protocol/dfu_hostcmd.c @@ -92,10 +92,5 @@ libhoth_error libhoth_dfu_update(struct libhoth_device* dev, // TODO: Wait for chip to come back and confirm version usleep(LIBHOTH_REBOOT_DELAY_MS * 1000); - int ret = libhoth_device_reconnect(dev); - if (ret != LIBHOTH_OK) { - return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, - ret); - } - return HOTH_SUCCESS; + return libhoth_device_reconnect(dev); } diff --git a/protocol/firmware_update.c b/protocol/firmware_update.c index 72bcdc2..697ac42 100644 --- a/protocol/firmware_update.c +++ b/protocol/firmware_update.c @@ -51,10 +51,5 @@ libhoth_error libhoth_firmware_update_from_flash_and_reset( "Lost connection after firmware update command (error code 0x%016lx). " "This is expected if the device reset. Attempting to reconnect...\n", err); - int ret = libhoth_device_reconnect(dev); - if (ret != LIBHOTH_OK) { - return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, - ret); - } - return HOTH_SUCCESS; + return libhoth_device_reconnect(dev); } diff --git a/protocol/host_cmd.c b/protocol/host_cmd.c index 7eda0c1..71c1d64 100644 --- a/protocol/host_cmd.c +++ b/protocol/host_cmd.c @@ -217,18 +217,18 @@ libhoth_error libhoth_hostcmd_exec_v2(struct libhoth_device* dev, if (req_payload) { memcpy(req.payload_buf, req_payload, req_payload_size); } - int status = populate_ec_request_header(command, version, req.payload_buf, - req_payload_size, &req.hdr); - if (status != 0) { - fprintf(stderr, "populate_ec_request_header() failed: %d\n", status); - return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_POSIX, - -status); + int rc = populate_ec_request_header(command, version, req.payload_buf, + req_payload_size, &req.hdr); + if (rc != 0) { + fprintf(stderr, "populate_ec_request_header() failed: %d\n", rc); + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_POSIX, -rc); } - 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 LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, - status); + libhoth_error status = + libhoth_send_request(dev, &req, sizeof(req.hdr) + req_payload_size); + if (status != HOTH_SUCCESS) { + fprintf(stderr, "libhoth_send_request() failed: 0x%016llx\n", + (unsigned long long)status); + return status; } struct { struct hoth_host_response hdr; @@ -238,16 +238,15 @@ libhoth_error libhoth_hostcmd_exec_v2(struct libhoth_device* dev, 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 LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH, - status); + if (status != HOTH_SUCCESS) { + fprintf(stderr, "libhoth_receive_response() failed: 0x%016llx\n", + (unsigned long long)status); + return status; } - 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 LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_POSIX, - -status); + rc = validate_ec_response_header(&resp.hdr, resp.payload_buf, resp_size); + if (rc != 0) { + fprintf(stderr, "EC response header invalid: %d\n", rc); + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_POSIX, -rc); } if (resp.hdr.result != HOTH_RES_SUCCESS) { fprintf(stderr, "EC response contained error: %d", resp.hdr.result); diff --git a/protocol/test/libhoth_device_mock.cc b/protocol/test/libhoth_device_mock.cc index ed17d63..0b745ca 100644 --- a/protocol/test/libhoth_device_mock.cc +++ b/protocol/test/libhoth_device_mock.cc @@ -1,20 +1,20 @@ #include "protocol/test/libhoth_device_mock.h" -static int send(struct libhoth_device* dev, const void* request, - size_t request_size) { +static libhoth_error send(struct libhoth_device* dev, const void* request, + size_t request_size) { LibHothDeviceMock* mock = (LibHothDeviceMock*)dev->user_ctx; return mock->send(dev, request, request_size); } -static int receive(struct libhoth_device* dev, void* response, - size_t max_response_size, size_t* actual_size, - int timeout_ms) { +static libhoth_error receive(struct libhoth_device* dev, void* response, + size_t max_response_size, size_t* actual_size, + int timeout_ms) { LibHothDeviceMock* mock = (LibHothDeviceMock*)dev->user_ctx; return mock->receive(dev, response, max_response_size, actual_size, timeout_ms); } -static int reconnect(struct libhoth_device* dev) { +static libhoth_error reconnect(struct libhoth_device* dev) { LibHothDeviceMock* mock = (LibHothDeviceMock*)dev->user_ctx; return mock->reconnect(dev); } diff --git a/protocol/test/libhoth_device_mock.h b/protocol/test/libhoth_device_mock.h index e03b13f..5e9b587 100644 --- a/protocol/test/libhoth_device_mock.h +++ b/protocol/test/libhoth_device_mock.h @@ -26,11 +26,11 @@ class LibHothDeviceMock { public: - MOCK_METHOD(int, send, + MOCK_METHOD(libhoth_error, send, (struct libhoth_device * dev, const void* request, size_t request_size), ()); - MOCK_METHOD(int, receive, + MOCK_METHOD(libhoth_error, receive, (struct libhoth_device * dev, void* response, size_t max_response_size, size_t* actual_size, int timeout_ms), ()); @@ -39,7 +39,7 @@ class LibHothDeviceMock { const void* request, size_t request_size, void* response, size_t max_response_size, size_t* bytes_read), ()); - MOCK_METHOD(int, reconnect, (struct libhoth_device * dev), ()); + MOCK_METHOD(libhoth_error, reconnect, (struct libhoth_device * dev), ()); }; class LibHothTest : public testing::Test { diff --git a/transports/BUILD b/transports/BUILD index 6915bc7..cad5f25 100644 --- a/transports/BUILD +++ b/transports/BUILD @@ -6,6 +6,9 @@ cc_library( name = "libhoth_device", srcs = ["libhoth_device.c"], hdrs = ["libhoth_device.h"], + deps = [ + "//protocol:libhoth_status", + ], ) cc_library( @@ -20,6 +23,7 @@ cc_library( deps = [ ":libhoth_device", ":libhoth_ec", + "//protocol:libhoth_status", ], ) @@ -30,6 +34,7 @@ cc_library( deps = [ ":libhoth_device", ":libhoth_ec", + "//protocol:libhoth_status", ], ) @@ -40,6 +45,7 @@ cc_library( deps = [ ":libhoth_device", ":libhoth_usb_device", + "//protocol:libhoth_status", "//protocol:util", "@libusb", ], @@ -51,7 +57,10 @@ cc_library( hdrs = ["libhoth_dbus.h"], defines = ["DBUS_BACKEND"], linkopts = ["-lsystemd"], - deps = [":libhoth_device"], + deps = [ + ":libhoth_device", + "//protocol:libhoth_status", + ], ) cc_library( diff --git a/transports/libhoth_dbus.c b/transports/libhoth_dbus.c index b17645d..df65c0a 100644 --- a/transports/libhoth_dbus.c +++ b/transports/libhoth_dbus.c @@ -22,6 +22,21 @@ #include "transports/libhoth_device.h" +static libhoth_error dbus_err_posix(int errnum) { + if (errnum == 0) { + return HOTH_SUCCESS; + } + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_POSIX, errnum); +} + +static libhoth_error dbus_err_libhoth(int libhoth_err) { + if (libhoth_err == LIBHOTH_OK) { + return HOTH_SUCCESS; + } + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + libhoth_err); +} + #define HOTHD_SERVICE "xyz.openbmc_project.Control.Hoth" #define HOTHD_OBJECT "/xyz/openbmc_project/Control/Hoth" #define HOTHD_INTERFACE "xyz.openbmc_project.Control.Hoth" @@ -39,8 +54,8 @@ struct libhoth_dbus_device { char* object; }; -static int send(struct libhoth_device* dev, const void* request, - size_t request_size) { +static libhoth_error send(struct libhoth_device* dev, const void* request, + size_t request_size) { struct libhoth_dbus_device* ctx = (struct libhoth_dbus_device*)dev->user_ctx; if (ctx->request) { @@ -70,33 +85,34 @@ static int send(struct libhoth_device* dev, const void* request, // Record the pending request. ctx->request = message; - return LIBHOTH_OK; + return HOTH_SUCCESS; cleanup: sd_bus_message_unref(message); - return rv; + return dbus_err_posix(-rv); } -static int receive(struct libhoth_device* dev, void* response, - size_t max_response_size, size_t* actual_size, - int timeout_ms) { +static libhoth_error receive(struct libhoth_device* dev, void* response, + size_t max_response_size, size_t* actual_size, + int timeout_ms) { struct libhoth_dbus_device* ctx = (struct libhoth_dbus_device*)dev->user_ctx; sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus_message* reply = NULL; - int rv = LIBHOTH_OK; + libhoth_error rc = HOTH_SUCCESS; if (!ctx->request) { fprintf(stderr, "Can't receive a response because there's no pending request.\n"); - rv = -1; + rc = dbus_err_libhoth(LIBHOTH_ERR_FAIL); goto cleanup; } // Send the pending host command request. uint64_t timeout_usec = timeout_ms * 1000; - rv = sd_bus_call(ctx->bus, ctx->request, timeout_usec, &error, &reply); + int rv = sd_bus_call(ctx->bus, ctx->request, timeout_usec, &error, &reply); if (rv < 0) { fprintf(stderr, "D-Bus call failed: %s\n", error.message); + rc = dbus_err_posix(-rv); goto cleanup; } @@ -106,13 +122,14 @@ static int receive(struct libhoth_device* dev, void* response, rv = sd_bus_message_read_array(reply, 'y', &buf, &size); if (rv < 0) { fprintf(stderr, "Failed to read response array: %s\n", strerror(-rv)); + rc = dbus_err_posix(-rv); goto cleanup; } if (size > max_response_size) { fprintf(stderr, "response size (%ld) greater than max allowed size (%ld)\n", size, max_response_size); - rv = -2; + rc = dbus_err_libhoth(LIBHOTH_ERR_RESPONSE_BUFFER_OVERFLOW); goto cleanup; } @@ -125,17 +142,15 @@ static int receive(struct libhoth_device* dev, void* response, // We need to copy the response bytes out. memcpy(response, buf, size); - rv = LIBHOTH_OK; - cleanup: sd_bus_message_unref(reply); sd_bus_error_free(&error); sd_bus_message_unref(ctx->request); ctx->request = NULL; - return rv; + return rc; } -static int close(struct libhoth_device* dev) { +static libhoth_error close(struct libhoth_device* dev) { struct libhoth_dbus_device* ctx = (struct libhoth_dbus_device*)dev->user_ctx; free(ctx->object); @@ -153,22 +168,22 @@ static int close(struct libhoth_device* dev) { free(ctx); dev->user_ctx = NULL; - return LIBHOTH_OK; + return HOTH_SUCCESS; } -static int claim(struct libhoth_device* dev) { +static libhoth_error claim(struct libhoth_device* dev) { // no-op - return LIBHOTH_OK; + return HOTH_SUCCESS; } -static int release(struct libhoth_device* dev) { +static libhoth_error release(struct libhoth_device* dev) { // no-op - return LIBHOTH_OK; + return HOTH_SUCCESS; } -static int reconnect(struct libhoth_device* dev) { +static libhoth_error reconnect(struct libhoth_device* dev) { // no-op - return LIBHOTH_OK; + return HOTH_SUCCESS; } char* with_hoth_id(const char* base, char delimiter, const char* hoth_id) { @@ -194,12 +209,13 @@ char* with_hoth_id(const char* base, char delimiter, const char* hoth_id) { return ret; } -int libhoth_dbus_open(const struct libhoth_dbus_device_init_options* options, - struct libhoth_device** out) { +libhoth_error libhoth_dbus_open( + const struct libhoth_dbus_device_init_options* options, + struct libhoth_device** out) { *out = NULL; if (!options || !options->hoth_id || !out) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return dbus_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } sd_bus* bus = NULL; @@ -207,34 +223,36 @@ int libhoth_dbus_open(const struct libhoth_dbus_device_init_options* options, struct libhoth_dbus_device* dbus_dev = NULL; char* service = NULL; char* object = NULL; + libhoth_error status = HOTH_SUCCESS; int rv = sd_bus_open_system(&bus); if (rv < 0) { fprintf(stderr, "Failed to connect to system bus: %s\n", strerror(-rv)); + status = dbus_err_posix(-rv); goto cleanup; } dev = calloc(1, sizeof(struct libhoth_device)); if (dev == NULL) { - rv = LIBHOTH_ERR_MALLOC_FAILED; + status = dbus_err_libhoth(LIBHOTH_ERR_MALLOC_FAILED); goto cleanup; } dbus_dev = calloc(1, sizeof(struct libhoth_dbus_device)); if (dbus_dev == NULL) { - rv = LIBHOTH_ERR_MALLOC_FAILED; + status = dbus_err_libhoth(LIBHOTH_ERR_MALLOC_FAILED); goto cleanup; } service = with_hoth_id(HOTHD_SERVICE, '.', options->hoth_id); if (service == NULL) { - rv = LIBHOTH_ERR_MALLOC_FAILED; + status = dbus_err_libhoth(LIBHOTH_ERR_MALLOC_FAILED); goto cleanup; } object = with_hoth_id(HOTHD_OBJECT, '/', options->hoth_id); if (object == NULL) { - rv = LIBHOTH_ERR_MALLOC_FAILED; + status = dbus_err_libhoth(LIBHOTH_ERR_MALLOC_FAILED); goto cleanup; } @@ -251,7 +269,7 @@ int libhoth_dbus_open(const struct libhoth_dbus_device_init_options* options, dev->user_ctx = dbus_dev; *out = dev; - return LIBHOTH_OK; + return HOTH_SUCCESS; cleanup: free(object); @@ -259,5 +277,5 @@ int libhoth_dbus_open(const struct libhoth_dbus_device_init_options* options, free(dbus_dev); free(dev); sd_bus_unref(bus); - return rv; + return status; } diff --git a/transports/libhoth_dbus.h b/transports/libhoth_dbus.h index 00a3aa6..d20c8ae 100644 --- a/transports/libhoth_dbus.h +++ b/transports/libhoth_dbus.h @@ -17,6 +17,8 @@ #include +#include "protocol/status.h" + #ifdef __cplusplus extern "C" { #endif @@ -27,8 +29,9 @@ struct libhoth_dbus_device_init_options { const char* hoth_id; }; -int libhoth_dbus_open(const struct libhoth_dbus_device_init_options* options, - struct libhoth_device** out); +libhoth_error libhoth_dbus_open( + const struct libhoth_dbus_device_init_options* options, + struct libhoth_device** out); #ifdef __cplusplus } diff --git a/transports/libhoth_device.c b/transports/libhoth_device.c index 7a56c3f..df59386 100644 --- a/transports/libhoth_device.c +++ b/transports/libhoth_device.c @@ -21,47 +21,58 @@ #include "libhoth_device.h" -int libhoth_send_request(struct libhoth_device* dev, const void* request, - size_t request_size) { +libhoth_error libhoth_send_request(struct libhoth_device* dev, + const void* request, size_t request_size) { if (dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_INVALID_PARAMETER); } return dev->send(dev, request, request_size); } -int libhoth_receive_response(struct libhoth_device* dev, void* response, - size_t max_response_size, size_t* actual_size, - int timeout_ms) { +libhoth_error libhoth_receive_response(struct libhoth_device* dev, + void* response, size_t max_response_size, + size_t* actual_size, int timeout_ms) { if (dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_INVALID_PARAMETER); } return dev->receive(dev, response, max_response_size, actual_size, timeout_ms); } -int libhoth_device_reconnect(struct libhoth_device* dev) { +libhoth_error libhoth_device_reconnect(struct libhoth_device* dev) { if (dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_INVALID_PARAMETER); } if (dev->reconnect == NULL) { - return LIBHOTH_ERR_UNSUPPORTED_VERSION; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_UNSUPPORTED_VERSION); } return dev->reconnect(dev); } -int libhoth_device_close(struct libhoth_device* dev) { +libhoth_error libhoth_device_close(struct libhoth_device* dev) { if (dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_INVALID_PARAMETER); } - int status = dev->close(dev); + libhoth_error status = dev->close(dev); free(dev); return status; } -int libhoth_claim_device(struct libhoth_device* dev, uint32_t timeout_us) { +libhoth_error libhoth_claim_device(struct libhoth_device* dev, + uint32_t timeout_us) { + if (dev == NULL) { + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_INVALID_PARAMETER); + } + enum { // The maximum time to sleep per attempt. // Limited by `usleep()` to <1 second. @@ -74,9 +85,14 @@ int libhoth_claim_device(struct libhoth_device* dev, uint32_t timeout_us) { uint32_t total_waiting_us = 0; while (true) { - int status = dev->claim(dev); + libhoth_error status = dev->claim(dev); - if (status != LIBHOTH_ERR_INTERFACE_BUSY) { + if (status == HOTH_SUCCESS) { + return HOTH_SUCCESS; + } + + uint32_t code = LIBHOTH_ERR_GET_CODE(status); + if (code != LIBHOTH_ERR_INTERFACE_BUSY) { // We either claimed the device or encountered an unexpected error. Let // the caller know. return status; @@ -87,7 +103,8 @@ int libhoth_claim_device(struct libhoth_device* dev, uint32_t timeout_us) { // within the configured timeout. fprintf(stderr, "libhoth: timed out claiming transport after %dus\n", timeout_us); - return LIBHOTH_ERR_INTERFACE_BUSY; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_INTERFACE_BUSY); } usleep(wait_us); @@ -108,9 +125,14 @@ int libhoth_claim_device(struct libhoth_device* dev, uint32_t timeout_us) { } // Unreachable - return LIBHOTH_ERR_FAIL; + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_FAIL); } -int libhoth_release_device(struct libhoth_device* dev) { +libhoth_error libhoth_release_device(struct libhoth_device* dev) { + if (dev == NULL) { + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + LIBHOTH_ERR_INVALID_PARAMETER); + } return dev->release(dev); } diff --git a/transports/libhoth_device.h b/transports/libhoth_device.h index d15585c..17fab34 100644 --- a/transports/libhoth_device.h +++ b/transports/libhoth_device.h @@ -18,6 +18,8 @@ #include #include +#include "protocol/status.h" + #ifdef __cplusplus extern "C" { #endif @@ -43,14 +45,15 @@ typedef enum { } libhoth_status; struct libhoth_device { - int (*send)(struct libhoth_device* dev, const void* request, - size_t request_size); - int (*receive)(struct libhoth_device* dev, void* response, - size_t max_response_size, size_t* actual_size, int timeout_ms); - int (*close)(struct libhoth_device* dev); - int (*claim)(struct libhoth_device* dev); - int (*release)(struct libhoth_device* dev); - int (*reconnect)(struct libhoth_device* dev); + libhoth_error (*send)(struct libhoth_device* dev, const void* request, + size_t request_size); + libhoth_error (*receive)(struct libhoth_device* dev, void* response, + size_t max_response_size, size_t* actual_size, + int timeout_ms); + libhoth_error (*close)(struct libhoth_device* dev); + libhoth_error (*claim)(struct libhoth_device* dev); + libhoth_error (*release)(struct libhoth_device* dev); + libhoth_error (*reconnect)(struct libhoth_device* dev); void* user_ctx; }; @@ -59,8 +62,8 @@ struct libhoth_device { // This function is not thread-safe. In multi-threaded contexts, callers must // ensure libhoth_send_request() and libhoth_receive_response() occur // atomically (with respect to other calls to those functions). -int libhoth_send_request(struct libhoth_device* dev, const void* request, - size_t request_size); +libhoth_error libhoth_send_request(struct libhoth_device* dev, + const void* request, size_t request_size); // Response is a buffer where the EC response header and trailing payload will // be written. Errors if libhoth_send_request() wasn't called previously. @@ -70,19 +73,20 @@ int libhoth_send_request(struct libhoth_device* dev, const void* request, // This function is not thread-safe. In multi-threaded contexts, callers must // ensure libhoth_send_request() and libhoth_receive_response() occur // atomically (with respect to other calls to those functions). -int libhoth_receive_response(struct libhoth_device* dev, void* response, - size_t max_response_size, size_t* actual_size, - int timeout_ms); +libhoth_error libhoth_receive_response(struct libhoth_device* dev, + void* response, size_t max_response_size, + size_t* actual_size, int timeout_ms); -int libhoth_device_reconnect(struct libhoth_device* dev); +libhoth_error libhoth_device_reconnect(struct libhoth_device* dev); -int libhoth_device_close(struct libhoth_device* dev); +libhoth_error libhoth_device_close(struct libhoth_device* dev); // Try to claim `dev`. If `dev` is already claimed, then try to claim later by // waiting an exponentially backed off amount of time. -int libhoth_claim_device(struct libhoth_device* dev, uint32_t timeout_us); +libhoth_error libhoth_claim_device(struct libhoth_device* dev, + uint32_t timeout_us); -int libhoth_release_device(struct libhoth_device* dev); +libhoth_error libhoth_release_device(struct libhoth_device* dev); #ifdef __cplusplus } diff --git a/transports/libhoth_mtd.c b/transports/libhoth_mtd.c index 5851533..9f06a8a 100644 --- a/transports/libhoth_mtd.c +++ b/transports/libhoth_mtd.c @@ -28,6 +28,14 @@ #include "transports/libhoth_device.h" #include "transports/libhoth_ec.h" +static libhoth_error mtd_err_libhoth(int libhoth_err) { + if (libhoth_err == LIBHOTH_OK) { + return HOTH_SUCCESS; + } + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_INIT, HOTH_HOST_SPACE_LIBHOTH, + libhoth_err); +} + static int mtd_read(int fd, unsigned int address, void* data, size_t data_len) { if (fd < 0 || !data) { return LIBHOTH_ERR_INVALID_PARAMETER; @@ -85,38 +93,38 @@ static int mtd_write(int fd, unsigned int address, const void* data, return LIBHOTH_OK; } -static int libhoth_mtd_claim(struct libhoth_device* dev) { +static libhoth_error libhoth_mtd_claim(struct libhoth_device* dev) { if (dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return mtd_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } const struct libhoth_mtd_device* mtd_dev = dev->user_ctx; if (mtd_dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return mtd_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } if (flock(mtd_dev->fd, LOCK_EX | LOCK_NB) != 0) { // Maybe some other process has the lock? - return LIBHOTH_ERR_INTERFACE_BUSY; + return mtd_err_libhoth(LIBHOTH_ERR_INTERFACE_BUSY); } - return LIBHOTH_OK; + return HOTH_SUCCESS; } -static int libhoth_mtd_release(struct libhoth_device* dev) { +static libhoth_error libhoth_mtd_release(struct libhoth_device* dev) { if (dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return mtd_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } const struct libhoth_mtd_device* mtd_dev = dev->user_ctx; if (mtd_dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return mtd_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } if (flock(mtd_dev->fd, LOCK_UN) != 0) { // Maybe `fd` is invalid? - return LIBHOTH_ERR_FAIL; + return mtd_err_libhoth(LIBHOTH_ERR_FAIL); } - return LIBHOTH_OK; + return HOTH_SUCCESS; } static int mtd_open(const char* path, const char* name) { @@ -163,21 +171,22 @@ static int mtd_open(const char* path, const char* name) { return -1; } -int libhoth_mtd_open(const struct libhoth_mtd_device_init_options* options, - struct libhoth_device** out) { +libhoth_error libhoth_mtd_open( + const struct libhoth_mtd_device_init_options* options, + struct libhoth_device** out) { if (out == NULL || options == NULL || options->path == NULL || options->name == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return mtd_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } - int status = LIBHOTH_ERR_FAIL; + libhoth_error status = mtd_err_libhoth(LIBHOTH_ERR_FAIL); int fd = -1; struct libhoth_device* dev = NULL; struct libhoth_mtd_device* mtd_dev = NULL; fd = mtd_open(options->path, options->name); if (fd < 0) { - status = LIBHOTH_ERR_INTERFACE_NOT_FOUND; + status = mtd_err_libhoth(LIBHOTH_ERR_INTERFACE_NOT_FOUND); goto err_out; } @@ -196,19 +205,19 @@ int libhoth_mtd_open(const struct libhoth_mtd_device_init_options* options, // lock using `libhoth_mtd_claim` and `libhoth_mtd_release` APIs if (flock(fd, LOCK_EX | LOCK_NB) != 0) { // Maybe some other process has the lock? - status = LIBHOTH_ERR_INTERFACE_BUSY; + status = mtd_err_libhoth(LIBHOTH_ERR_INTERFACE_BUSY); goto err_out; } dev = calloc(1, sizeof(struct libhoth_device)); if (dev == NULL) { - status = LIBHOTH_ERR_MALLOC_FAILED; + status = mtd_err_libhoth(LIBHOTH_ERR_MALLOC_FAILED); goto err_out; } mtd_dev = calloc(1, sizeof(struct libhoth_mtd_device)); if (mtd_dev == NULL) { - status = LIBHOTH_ERR_MALLOC_FAILED; + status = mtd_err_libhoth(LIBHOTH_ERR_MALLOC_FAILED); goto err_out; } @@ -224,7 +233,7 @@ int libhoth_mtd_open(const struct libhoth_mtd_device_init_options* options, dev->user_ctx = mtd_dev; *out = dev; - return LIBHOTH_OK; + return HOTH_SUCCESS; err_out: if (fd >= 0) { @@ -239,28 +248,31 @@ int libhoth_mtd_open(const struct libhoth_mtd_device_init_options* options, return status; } -int libhoth_mtd_send_request(struct libhoth_device* dev, const void* request, - size_t request_size) { +libhoth_error libhoth_mtd_send_request(struct libhoth_device* dev, + const void* request, + size_t request_size) { if (dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return mtd_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } struct libhoth_mtd_device* mtd_dev = (struct libhoth_mtd_device*)dev->user_ctx; - return mtd_write(mtd_dev->fd, mtd_dev->mailbox_address, request, - request_size); + return mtd_err_libhoth( + mtd_write(mtd_dev->fd, mtd_dev->mailbox_address, request, request_size)); } -int libhoth_mtd_receive_response(struct libhoth_device* dev, void* response, - size_t max_response_size, size_t* actual_size, - int timeout_ms) { +libhoth_error libhoth_mtd_receive_response(struct libhoth_device* dev, + void* response, + size_t max_response_size, + size_t* actual_size, + int timeout_ms) { if (dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return mtd_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } if (max_response_size < 8) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return mtd_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } size_t total_bytes = 0; @@ -272,7 +284,7 @@ int libhoth_mtd_receive_response(struct libhoth_device* dev, void* response, // Read Header From Mailbox status = mtd_read(mtd_dev->fd, mtd_dev->mailbox_address, response, 8); if (status != LIBHOTH_OK) { - return status; + return mtd_err_libhoth(status); } total_bytes = 8; @@ -282,7 +294,7 @@ int libhoth_mtd_receive_response(struct libhoth_device* dev, void* response, } if (max_response_size < (total_bytes + host_response.data_len)) { - return LIBHOTH_ERR_RESPONSE_BUFFER_OVERFLOW; + return mtd_err_libhoth(LIBHOTH_ERR_RESPONSE_BUFFER_OVERFLOW); } // Read remainder of data based on header length @@ -290,28 +302,28 @@ int libhoth_mtd_receive_response(struct libhoth_device* dev, void* response, status = mtd_read(mtd_dev->fd, mtd_dev->mailbox_address + total_bytes, data_start, host_response.data_len); if (status != LIBHOTH_OK) { - return status; + return mtd_err_libhoth(status); } if (actual_size) { *actual_size += host_response.data_len; } - return LIBHOTH_OK; + return HOTH_SUCCESS; } -int libhoth_mtd_close(struct libhoth_device* dev) { +libhoth_error libhoth_mtd_close(struct libhoth_device* dev) { if (dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return mtd_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } struct libhoth_mtd_device* mtd_dev = (struct libhoth_mtd_device*)dev->user_ctx; close(mtd_dev->fd); free(dev->user_ctx); - return LIBHOTH_OK; + return HOTH_SUCCESS; } -int libhoth_mtd_reconnect(struct libhoth_device* dev) { +libhoth_error libhoth_mtd_reconnect(struct libhoth_device* dev) { // no-op - return LIBHOTH_OK; + return HOTH_SUCCESS; } diff --git a/transports/libhoth_mtd.h b/transports/libhoth_mtd.h index 93159c9..219972f 100644 --- a/transports/libhoth_mtd.h +++ b/transports/libhoth_mtd.h @@ -17,6 +17,8 @@ #include +#include "protocol/status.h" + #ifdef __cplusplus extern "C" { #endif @@ -37,20 +39,23 @@ struct libhoth_mtd_device { unsigned int mailbox_address; }; -int libhoth_mtd_send_request(struct libhoth_device* dev, const void* request, - size_t request_size); +libhoth_error libhoth_mtd_send_request(struct libhoth_device* dev, + const void* request, + size_t request_size); -int libhoth_mtd_receive_response(struct libhoth_device* dev, void* response, - size_t max_response_size, size_t* actual_size, - int timeout_ms); +libhoth_error libhoth_mtd_receive_response(struct libhoth_device* dev, + void* response, + size_t max_response_size, + size_t* actual_size, int timeout_ms); -int libhoth_mtd_close(struct libhoth_device* dev); -int libhoth_mtd_reconnect(struct libhoth_device* dev); +libhoth_error libhoth_mtd_close(struct libhoth_device* dev); +libhoth_error libhoth_mtd_reconnect(struct libhoth_device* dev); // Note that the options struct only needs to to live for the duration of // this function call. It can be destroyed once libhoth_mtd_open returns. -int libhoth_mtd_open(const struct libhoth_mtd_device_init_options* options, - struct libhoth_device** out); +libhoth_error libhoth_mtd_open( + const struct libhoth_mtd_device_init_options* options, + struct libhoth_device** out); #ifdef __cplusplus } diff --git a/transports/libhoth_spi.c b/transports/libhoth_spi.c index 09070a8..7396e4b 100644 --- a/transports/libhoth_spi.c +++ b/transports/libhoth_spi.c @@ -15,6 +15,7 @@ #include "transports/libhoth_spi.h" #include +#include #include #include #include @@ -35,6 +36,21 @@ #define DID_VID_ADDR 0xD40F00 +static libhoth_error spi_err_posix(int errnum) { + if (errnum == 0) { + return HOTH_SUCCESS; + } + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_SPI, HOTH_HOST_SPACE_POSIX, errnum); +} + +static libhoth_error spi_err_libhoth(int libhoth_err) { + if (libhoth_err == LIBHOTH_OK) { + return HOTH_SUCCESS; + } + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_SPI, HOTH_HOST_SPACE_LIBHOTH, + libhoth_err); +} + static int spi_nor_address(uint8_t* buf, uint32_t address, bool address_mode_4b) { if (address_mode_4b) { @@ -209,72 +225,73 @@ static int spi_nor_read(int fd, bool address_mode_4b, unsigned int address, return LIBHOTH_OK; } -static int libhoth_spi_claim(struct libhoth_device* dev) { +static libhoth_error libhoth_spi_claim(struct libhoth_device* dev) { if (dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return spi_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } const struct libhoth_spi_device* spi_dev = dev->user_ctx; if (spi_dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return spi_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } if (flock(spi_dev->fd, LOCK_EX | LOCK_NB) != 0) { // Maybe some other process has the lock? - return LIBHOTH_ERR_INTERFACE_BUSY; + return spi_err_libhoth(LIBHOTH_ERR_INTERFACE_BUSY); } - return LIBHOTH_OK; + return HOTH_SUCCESS; } -static int libhoth_spi_release(struct libhoth_device* dev) { +static libhoth_error libhoth_spi_release(struct libhoth_device* dev) { if (dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return spi_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } const struct libhoth_spi_device* spi_dev = dev->user_ctx; if (spi_dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return spi_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } if (flock(spi_dev->fd, LOCK_UN) != 0) { // Maybe `fd` is invalid? - return LIBHOTH_ERR_FAIL; + return spi_err_libhoth(LIBHOTH_ERR_FAIL); } - return LIBHOTH_OK; + return HOTH_SUCCESS; } -static int libhoth_spi_reconnect(struct libhoth_device* dev) { +static libhoth_error libhoth_spi_reconnect(struct libhoth_device* dev) { // TODO: Maybe check for JEDEC ID? // no-op - return 0; + return HOTH_SUCCESS; } -int libhoth_spi_open(const struct libhoth_spi_device_init_options* options, - struct libhoth_device** out) { +libhoth_error libhoth_spi_open( + const struct libhoth_spi_device_init_options* options, + struct libhoth_device** out) { if (out == NULL || options == NULL || options->path == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return spi_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } - int status = LIBHOTH_OK; + libhoth_error status = HOTH_SUCCESS; int fd = -1; struct libhoth_device* dev = NULL; struct libhoth_spi_device* spi_dev = NULL; fd = open(options->path, O_RDWR | O_CLOEXEC); if (fd < 0) { - status = LIBHOTH_ERR_INTERFACE_NOT_FOUND; + status = spi_err_libhoth(LIBHOTH_ERR_INTERFACE_NOT_FOUND); goto err_out; } dev = calloc(1, sizeof(struct libhoth_device)); if (dev == NULL) { - status = LIBHOTH_ERR_MALLOC_FAILED; + status = spi_err_libhoth(LIBHOTH_ERR_MALLOC_FAILED); goto err_out; } spi_dev = calloc(1, sizeof(struct libhoth_spi_device)); if (spi_dev == NULL) { - status = LIBHOTH_ERR_MALLOC_FAILED; + status = spi_err_libhoth(LIBHOTH_ERR_MALLOC_FAILED); goto err_out; } @@ -299,14 +316,14 @@ int libhoth_spi_open(const struct libhoth_spi_device_init_options* options, dev->user_ctx = spi_dev; status = libhoth_claim_device(dev, options->timeout_us); - if (status != LIBHOTH_OK) { + if (status != HOTH_SUCCESS) { goto err_out; } if (options->bits) { const uint8_t bits = (uint8_t)options->bits; if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, bits) < 0) { - status = LIBHOTH_ERR_FAIL; + status = spi_err_libhoth(LIBHOTH_ERR_FAIL); goto err_out; } } @@ -314,7 +331,7 @@ int libhoth_spi_open(const struct libhoth_spi_device_init_options* options, if (options->mode) { const uint8_t mode = (uint8_t)options->mode; if (ioctl(fd, SPI_IOC_WR_MODE, &mode) < 0) { - status = LIBHOTH_ERR_FAIL; + status = spi_err_libhoth(LIBHOTH_ERR_FAIL); goto err_out; } } @@ -322,13 +339,13 @@ int libhoth_spi_open(const struct libhoth_spi_device_init_options* options, if (options->speed) { const uint32_t speed = (uint32_t)options->speed; if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) { - status = LIBHOTH_ERR_FAIL; + status = spi_err_libhoth(LIBHOTH_ERR_FAIL); goto err_out; } } *out = dev; - return LIBHOTH_OK; + return HOTH_SUCCESS; err_out: if (fd >= 0) { @@ -344,30 +361,33 @@ int libhoth_spi_open(const struct libhoth_spi_device_init_options* options, return status; } -int libhoth_spi_send_request(struct libhoth_device* dev, const void* request, - size_t request_size) { +libhoth_error libhoth_spi_send_request(struct libhoth_device* dev, + const void* request, + size_t request_size) { if (dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return spi_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } struct libhoth_spi_device* spi_dev = (struct libhoth_spi_device*)dev->user_ctx; - return spi_nor_write(spi_dev->fd, spi_dev->address_mode_4b, - spi_dev->mailbox_address, request, request_size, - spi_dev->device_busy_wait_timeout, - spi_dev->device_busy_wait_check_interval); + return spi_err_libhoth(spi_nor_write( + spi_dev->fd, spi_dev->address_mode_4b, spi_dev->mailbox_address, request, + request_size, spi_dev->device_busy_wait_timeout, + spi_dev->device_busy_wait_check_interval)); } -int libhoth_spi_receive_response(struct libhoth_device* dev, void* response, - size_t max_response_size, size_t* actual_size, - int timeout_ms) { +libhoth_error libhoth_spi_receive_response(struct libhoth_device* dev, + void* response, + size_t max_response_size, + size_t* actual_size, + int timeout_ms) { if (dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return spi_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } if (max_response_size < sizeof(struct hoth_host_response)) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return spi_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } size_t total_bytes = 0; @@ -381,7 +401,7 @@ int libhoth_spi_receive_response(struct libhoth_device* dev, void* response, spi_dev->mailbox_address, response, sizeof(struct hoth_host_response)); if (status != LIBHOTH_OK) { - return status; + return spi_err_libhoth(status); } total_bytes = sizeof(struct hoth_host_response); @@ -391,7 +411,7 @@ int libhoth_spi_receive_response(struct libhoth_device* dev, void* response, } if (max_response_size < (total_bytes + host_response.data_len)) { - return LIBHOTH_ERR_RESPONSE_BUFFER_OVERFLOW; + return spi_err_libhoth(LIBHOTH_ERR_RESPONSE_BUFFER_OVERFLOW); } if (host_response.data_len > 0) { @@ -401,7 +421,7 @@ int libhoth_spi_receive_response(struct libhoth_device* dev, void* response, spi_dev->mailbox_address + total_bytes, data_start, host_response.data_len); if (status != LIBHOTH_OK) { - return status; + return spi_err_libhoth(status); } } @@ -409,46 +429,51 @@ int libhoth_spi_receive_response(struct libhoth_device* dev, void* response, *actual_size += host_response.data_len; } - return LIBHOTH_OK; + return HOTH_SUCCESS; } -int libhoth_spi_buffer_request(struct libhoth_device* dev, const void* request, - size_t request_size) { +libhoth_error libhoth_spi_buffer_request(struct libhoth_device* dev, + const void* request, + size_t request_size) { if (dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return spi_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } struct libhoth_spi_device* spi_dev = (struct libhoth_spi_device*)dev->user_ctx; if (spi_dev->buffered_request != NULL) { - return LIBHOTH_ERR_INTERFACE_BUSY; + return spi_err_libhoth(LIBHOTH_ERR_INTERFACE_BUSY); } spi_dev->buffered_request = malloc(request_size); + if (spi_dev->buffered_request == NULL) { + return spi_err_libhoth(LIBHOTH_ERR_MALLOC_FAILED); + } spi_dev->buffered_request_size = request_size; memcpy(spi_dev->buffered_request, request, request_size); - return LIBHOTH_OK; + return HOTH_SUCCESS; } -int libhoth_spi_send_and_receive_response(struct libhoth_device* dev, - void* response, - size_t max_response_size, - size_t* actual_size, int timeout_ms) { +libhoth_error libhoth_spi_send_and_receive_response(struct libhoth_device* dev, + void* response, + size_t max_response_size, + size_t* actual_size, + int timeout_ms) { if (dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return spi_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } if (max_response_size < sizeof(struct hoth_host_response)) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return spi_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } struct libhoth_spi_device* spi_dev = (struct libhoth_spi_device*)dev->user_ctx; if (spi_dev->buffered_request == NULL) { - return LIBHOTH_ERR_INTERFACE_BUSY; + return spi_err_libhoth(LIBHOTH_ERR_INTERFACE_BUSY); } uint32_t address = spi_dev->mailbox_address; @@ -498,16 +523,16 @@ int libhoth_spi_send_and_receive_response(struct libhoth_device* dev, .len = max_response_size, }; - int rc = LIBHOTH_OK; + libhoth_error rc = HOTH_SUCCESS; int status = ioctl(spi_dev->fd, SPI_IOC_MESSAGE(5), xfer); if (status < 0) { - rc = LIBHOTH_ERR_FAIL; + rc = spi_err_posix(errno); } else { struct hoth_host_response* host_response = (struct hoth_host_response*)response; if (host_response->data_len > (max_response_size - sizeof(struct hoth_host_response))) { - rc = LIBHOTH_ERR_RESPONSE_BUFFER_OVERFLOW; + rc = spi_err_libhoth(LIBHOTH_ERR_RESPONSE_BUFFER_OVERFLOW); } else if (actual_size) { *actual_size = (size_t)host_response->data_len + sizeof(struct hoth_host_response); @@ -521,7 +546,10 @@ int libhoth_spi_send_and_receive_response(struct libhoth_device* dev, return rc; } -int libhoth_tpm_spi_probe(struct libhoth_device* dev) { +libhoth_error libhoth_tpm_spi_probe(struct libhoth_device* dev) { + if (dev == NULL) { + return spi_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); + } struct libhoth_spi_device* spi_dev = (struct libhoth_spi_device*)dev->user_ctx; @@ -545,7 +573,7 @@ int libhoth_tpm_spi_probe(struct libhoth_device* dev) { const int status = ioctl(spi_dev->fd, SPI_IOC_MESSAGE(2), xfer); if (status < 0) { printf("Failed to read DID_VID: %x\n", status); - return -1; + return spi_err_posix(errno); } uint16_t did = (uint16_t)rx_buf[4] << 8 | rx_buf[3]; @@ -554,17 +582,17 @@ int libhoth_tpm_spi_probe(struct libhoth_device* dev) { printf("DID: 0x%x\n", did); printf("VID: 0x%x\n", vid); - return LIBHOTH_OK; + return HOTH_SUCCESS; } -int libhoth_spi_close(struct libhoth_device* dev) { +libhoth_error libhoth_spi_close(struct libhoth_device* dev) { if (dev == NULL) { - return LIBHOTH_ERR_INVALID_PARAMETER; + return spi_err_libhoth(LIBHOTH_ERR_INVALID_PARAMETER); } struct libhoth_spi_device* spi_dev = (struct libhoth_spi_device*)dev->user_ctx; close(spi_dev->fd); free(dev->user_ctx); - return LIBHOTH_OK; + return HOTH_SUCCESS; } diff --git a/transports/libhoth_spi.h b/transports/libhoth_spi.h index f0dac8a..d2f3ac1 100644 --- a/transports/libhoth_spi.h +++ b/transports/libhoth_spi.h @@ -19,6 +19,8 @@ #include #include +#include "protocol/status.h" + #ifdef __cplusplus extern "C" { #endif @@ -61,26 +63,31 @@ enum { // Note that the options struct only needs to to live for the duration of // this function call. It can be destroyed once libhoth_spi_open returns. -int libhoth_spi_open(const struct libhoth_spi_device_init_options* options, - struct libhoth_device** out); -int libhoth_tpm_spi_probe(struct libhoth_device* dev); - -int libhoth_spi_send_request(struct libhoth_device* dev, const void* request, - size_t request_size); - -int libhoth_spi_receive_response(struct libhoth_device* dev, void* response, - size_t max_response_size, size_t* actual_size, - int timeout_ms); - -int libhoth_spi_buffer_request(struct libhoth_device* dev, const void* request, - size_t request_size); - -int libhoth_spi_send_and_receive_response(struct libhoth_device* dev, - void* response, - size_t max_response_size, - size_t* actual_size, int timeout_ms); - -int libhoth_spi_close(struct libhoth_device* dev); +libhoth_error libhoth_spi_open( + const struct libhoth_spi_device_init_options* options, + struct libhoth_device** out); +libhoth_error libhoth_tpm_spi_probe(struct libhoth_device* dev); + +libhoth_error libhoth_spi_send_request(struct libhoth_device* dev, + const void* request, + size_t request_size); + +libhoth_error libhoth_spi_receive_response(struct libhoth_device* dev, + void* response, + size_t max_response_size, + size_t* actual_size, int timeout_ms); + +libhoth_error libhoth_spi_buffer_request(struct libhoth_device* dev, + const void* request, + size_t request_size); + +libhoth_error libhoth_spi_send_and_receive_response(struct libhoth_device* dev, + void* response, + size_t max_response_size, + size_t* actual_size, + int timeout_ms); + +libhoth_error libhoth_spi_close(struct libhoth_device* dev); #ifdef __cplusplus } diff --git a/transports/libhoth_usb.c b/transports/libhoth_usb.c index 242b8a4..4f5c391 100644 --- a/transports/libhoth_usb.c +++ b/transports/libhoth_usb.c @@ -30,16 +30,44 @@ #define HOTH_D_PRODUCT_ID 0x022a #define HOTH_E_PRODUCT_ID 0x023b -static int libhoth_usb_device_open( +static libhoth_error usb_err_libusb(int libusb_err) { + if (libusb_err == LIBUSB_SUCCESS) { + return HOTH_SUCCESS; + } + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_USB, HOTH_HOST_SPACE_LIBUSB, + -libusb_err); +} + +static libhoth_error usb_err_libhoth(int libhoth_err) { + if (libhoth_err == LIBHOTH_OK) { + return HOTH_SUCCESS; + } + return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_USB, HOTH_HOST_SPACE_LIBHOTH, + libhoth_err); +} + +static libhoth_error wrap_usb_err(int ret) { + if (ret == 0) { + return HOTH_SUCCESS; + } + if (ret < 0) { + return usb_err_libusb(ret); + } + return usb_err_libhoth(ret); +} + +static libhoth_error libhoth_usb_device_open( const struct libhoth_usb_device_init_options* options, struct libhoth_device* dev); -int libhoth_usb_send_request(struct libhoth_device* dev, const void* request, - size_t request_size); +libhoth_error libhoth_usb_send_request(struct libhoth_device* dev, + const void* request, + size_t request_size); -int libhoth_usb_receive_response(struct libhoth_device* dev, void* response, - size_t max_response_size, size_t* actual_size, - int timeout_ms); +libhoth_error libhoth_usb_receive_response(struct libhoth_device* dev, + void* response, + size_t max_response_size, + size_t* actual_size, int timeout_ms); static struct libhoth_usb_interface_info libhoth_usb_find_interface( const struct libusb_config_descriptor* configuration) { @@ -74,22 +102,23 @@ static struct libhoth_usb_interface_info libhoth_usb_find_interface( return info; } -static int libhoth_usb_claim(struct libhoth_device* dev) { +static libhoth_error libhoth_usb_claim(struct libhoth_device* dev) { struct libhoth_usb_device* usb_dev = dev->user_ctx; int status = libusb_claim_interface(usb_dev->handle, usb_dev->info.interface_id); if (status == LIBUSB_ERROR_BUSY) { - return LIBHOTH_ERR_INTERFACE_BUSY; + return usb_err_libhoth(LIBHOTH_ERR_INTERFACE_BUSY); } - return status; + return usb_err_libusb(status); } -static int libhoth_usb_release(struct libhoth_device* dev) { +static libhoth_error libhoth_usb_release(struct libhoth_device* dev) { struct libhoth_usb_device* usb_dev = dev->user_ctx; - return libusb_release_interface(usb_dev->handle, usb_dev->info.interface_id); + return usb_err_libusb( + libusb_release_interface(usb_dev->handle, usb_dev->info.interface_id)); } static int libhoth_usb_close_internal(struct libhoth_usb_device* usb_dev) { @@ -113,10 +142,10 @@ static int libhoth_usb_close_internal(struct libhoth_usb_device* usb_dev) { return status; } -static int libhoth_usb_reconnect(struct libhoth_device* dev) { +static libhoth_error libhoth_usb_reconnect(struct libhoth_device* dev) { struct libhoth_usb_device* usb_dev = dev->user_ctx; if (usb_dev == NULL) { - return LIBUSB_ERROR_INVALID_PARAM; + return usb_err_libusb(LIBUSB_ERROR_INVALID_PARAM); } libusb_context* usb_ctx = usb_dev->ctx; uint64_t timeout_us = usb_dev->claim_timeout_us; @@ -135,9 +164,9 @@ static int libhoth_usb_reconnect(struct libhoth_device* dev) { // Close the old handle and driver data, but keep the usb_dev structure. libhoth_usb_close_internal(usb_dev); - ret = libhoth_usb_device_open(&opts, dev); + libhoth_error err = libhoth_usb_device_open(&opts, dev); libusb_unref_device(new_libusb_dev); - return ret; + return err; } uint64_t current_time_ms = libhoth_get_monotonic_ms(); @@ -147,7 +176,7 @@ static int libhoth_usb_reconnect(struct libhoth_device* dev) { stderr, "libhoth_usb_open timed out while reconnecting (error: %d (%s))\n", ret, libusb_strerror(ret)); - return ret; // Timeout + return usb_err_libusb(ret); } // 100ms delay @@ -155,27 +184,27 @@ static int libhoth_usb_reconnect(struct libhoth_device* dev) { } } -static int libhoth_usb_device_open( +static libhoth_error libhoth_usb_device_open( const struct libhoth_usb_device_init_options* options, struct libhoth_device* dev) { struct libhoth_usb_device* usb_dev = dev->user_ctx; struct libusb_device_descriptor device_descriptor; - int status = - libusb_get_device_descriptor(options->usb_device, &device_descriptor); - if (status != LIBUSB_SUCCESS) { + libhoth_error status = usb_err_libusb( + libusb_get_device_descriptor(options->usb_device, &device_descriptor)); + if (status != HOTH_SUCCESS) { return status; } // Ensure vendor ID matches if (device_descriptor.idVendor != LIBHOTH_USB_VENDOR_ID) { - return LIBHOTH_ERR_UNKNOWN_VENDOR; + return usb_err_libhoth(LIBHOTH_ERR_UNKNOWN_VENDOR); } // Pick the correct driver based on the interface type struct libusb_config_descriptor* config_descriptor = NULL; - status = libusb_get_active_config_descriptor(options->usb_device, - &config_descriptor); - if (status != LIBUSB_SUCCESS) { + status = usb_err_libusb(libusb_get_active_config_descriptor( + options->usb_device, &config_descriptor)); + if (status != HOTH_SUCCESS) { return status; } @@ -183,14 +212,14 @@ static int libhoth_usb_device_open( struct libhoth_usb_interface_info info = libhoth_usb_find_interface(config_descriptor); if (info.type == LIBHOTH_USB_INTERFACE_TYPE_UNKNOWN) { - status = LIBHOTH_ERR_INTERFACE_NOT_FOUND; + status = usb_err_libhoth(LIBHOTH_ERR_INTERFACE_NOT_FOUND); goto err_out; } if (usb_dev == NULL) { usb_dev = calloc(1, sizeof(struct libhoth_usb_device)); if (usb_dev == NULL) { - status = LIBHOTH_ERR_MALLOC_FAILED; + status = usb_err_libhoth(LIBHOTH_ERR_MALLOC_FAILED); goto err_out; } dev->user_ctx = usb_dev; @@ -200,19 +229,19 @@ static int libhoth_usb_device_open( usb_dev->claim_timeout_us = options->timeout_us; if (libhoth_get_usb_loc(options->usb_device, &usb_dev->loc) != 0) { - status = LIBUSB_ERROR_OTHER; + status = usb_err_libusb(LIBUSB_ERROR_OTHER); goto err_out; } uint32_t wait_time_us = 0; while (true) { - status = libusb_open(options->usb_device, &usb_dev->handle); + status = usb_err_libusb(libusb_open(options->usb_device, &usb_dev->handle)); - if (status == LIBUSB_SUCCESS) { + if (status == HOTH_SUCCESS) { break; } - if (status != LIBUSB_ERROR_ACCESS) { + if (LIBHOTH_ERR_GET_CODE(status) != -LIBUSB_ERROR_ACCESS) { goto err_out; } @@ -233,28 +262,29 @@ static int libhoth_usb_device_open( dev->reconnect = libhoth_usb_reconnect; status = libhoth_claim_device(dev, options->timeout_us); - if (status != LIBHOTH_OK) { + if (status != HOTH_SUCCESS) { goto err_out; } // Fill in driver-specific data switch (info.type) { case LIBHOTH_USB_INTERFACE_TYPE_MAILBOX: - status = libhoth_usb_mailbox_open(usb_dev, config_descriptor); + status = + wrap_usb_err(libhoth_usb_mailbox_open(usb_dev, config_descriptor)); break; case LIBHOTH_USB_INTERFACE_TYPE_FIFO: - status = - libhoth_usb_fifo_open(usb_dev, config_descriptor, options->prng_seed); + status = wrap_usb_err(libhoth_usb_fifo_open(usb_dev, config_descriptor, + options->prng_seed)); break; default: - status = LIBHOTH_ERR_INTERFACE_NOT_FOUND; + status = usb_err_libhoth(LIBHOTH_ERR_INTERFACE_NOT_FOUND); break; } - if (status != LIBHOTH_OK) goto err_out; + if (status != HOTH_SUCCESS) goto err_out; libusb_free_config_descriptor(config_descriptor); - return LIBHOTH_OK; + return HOTH_SUCCESS; err_out: if (usb_dev != NULL && usb_dev->handle != NULL) { @@ -266,19 +296,20 @@ static int libhoth_usb_device_open( return status; } -int libhoth_usb_open(const struct libhoth_usb_device_init_options* options, - struct libhoth_device** out) { +libhoth_error libhoth_usb_open( + const struct libhoth_usb_device_init_options* options, + struct libhoth_device** out) { if (out == NULL || options == NULL || options->usb_device == NULL) { - return LIBUSB_ERROR_INVALID_PARAM; + return usb_err_libusb(LIBUSB_ERROR_INVALID_PARAM); } struct libhoth_device* dev = calloc(1, sizeof(struct libhoth_device)); if (dev == NULL) { - return LIBHOTH_ERR_MALLOC_FAILED; + return usb_err_libhoth(LIBHOTH_ERR_MALLOC_FAILED); } - int ret = libhoth_usb_device_open(options, dev); - if (ret != LIBUSB_SUCCESS) { + libhoth_error ret = libhoth_usb_device_open(options, dev); + if (ret != HOTH_SUCCESS) { if (dev->user_ctx != NULL) { free(dev->user_ctx); } @@ -287,59 +318,64 @@ int libhoth_usb_open(const struct libhoth_usb_device_init_options* options, } *out = dev; - return LIBHOTH_OK; + return HOTH_SUCCESS; } -int libhoth_usb_send_request(struct libhoth_device* dev, const void* request, - size_t request_size) { +libhoth_error libhoth_usb_send_request(struct libhoth_device* dev, + const void* request, + size_t request_size) { if (dev->user_ctx == NULL) { - return LIBUSB_ERROR_INVALID_PARAM; + return usb_err_libusb(LIBUSB_ERROR_INVALID_PARAM); } struct libhoth_usb_device* usb_dev = (struct libhoth_usb_device*)dev->user_ctx; if (usb_dev->handle == NULL) { - return LIBUSB_ERROR_NO_DEVICE; + return usb_err_libusb(LIBUSB_ERROR_NO_DEVICE); } switch (usb_dev->info.type) { case LIBHOTH_USB_INTERFACE_TYPE_MAILBOX: - return libhoth_usb_mailbox_send_request(usb_dev, request, request_size); + return wrap_usb_err( + libhoth_usb_mailbox_send_request(usb_dev, request, request_size)); case LIBHOTH_USB_INTERFACE_TYPE_FIFO: - return libhoth_usb_fifo_send_request(usb_dev, request, request_size); + return wrap_usb_err( + libhoth_usb_fifo_send_request(usb_dev, request, request_size)); default: - return LIBHOTH_ERR_INTERFACE_NOT_FOUND; + return usb_err_libhoth(LIBHOTH_ERR_INTERFACE_NOT_FOUND); } - return LIBUSB_ERROR_NOT_SUPPORTED; + return usb_err_libusb(LIBUSB_ERROR_NOT_SUPPORTED); } -int libhoth_usb_receive_response(struct libhoth_device* dev, void* response, - size_t max_response_size, size_t* actual_size, - int timeout_ms) { +libhoth_error libhoth_usb_receive_response(struct libhoth_device* dev, + void* response, + size_t max_response_size, + size_t* actual_size, + int timeout_ms) { if (dev->user_ctx == NULL) { - return LIBUSB_ERROR_INVALID_PARAM; + return usb_err_libusb(LIBUSB_ERROR_INVALID_PARAM); } struct libhoth_usb_device* usb_dev = (struct libhoth_usb_device*)dev->user_ctx; if (usb_dev->handle == NULL) { - return LIBUSB_ERROR_NO_DEVICE; + return usb_err_libusb(LIBUSB_ERROR_NO_DEVICE); } switch (usb_dev->info.type) { case LIBHOTH_USB_INTERFACE_TYPE_MAILBOX: - return libhoth_usb_mailbox_receive_response( - usb_dev, response, max_response_size, actual_size, timeout_ms); + return wrap_usb_err(libhoth_usb_mailbox_receive_response( + usb_dev, response, max_response_size, actual_size, timeout_ms)); case LIBHOTH_USB_INTERFACE_TYPE_FIFO: - return libhoth_usb_fifo_receive_response( - usb_dev, response, max_response_size, actual_size, timeout_ms); + return wrap_usb_err(libhoth_usb_fifo_receive_response( + usb_dev, response, max_response_size, actual_size, timeout_ms)); default: - return LIBHOTH_ERR_INTERFACE_NOT_FOUND; + return usb_err_libhoth(LIBHOTH_ERR_INTERFACE_NOT_FOUND); } - return LIBUSB_ERROR_NOT_SUPPORTED; + return usb_err_libusb(LIBUSB_ERROR_NOT_SUPPORTED); } -int libhoth_usb_close(struct libhoth_device* dev) { +libhoth_error libhoth_usb_close(struct libhoth_device* dev) { if (dev->user_ctx == NULL) { - return LIBUSB_SUCCESS; + return HOTH_SUCCESS; } struct libhoth_usb_device* usb_dev = @@ -348,7 +384,7 @@ int libhoth_usb_close(struct libhoth_device* dev) { int status = libhoth_usb_close_internal(usb_dev); free(usb_dev); - return status; + return wrap_usb_err(status); } enum libusb_error transfer_status_to_error( diff --git a/transports/libhoth_usb.h b/transports/libhoth_usb.h index 0820156..dcb5497 100644 --- a/transports/libhoth_usb.h +++ b/transports/libhoth_usb.h @@ -21,6 +21,8 @@ #include #include +#include "protocol/status.h" + #ifdef __cplusplus extern "C" { #endif @@ -43,14 +45,16 @@ struct libhoth_usb_device_init_options { // Note that the options struct only needs to to live for the duration of // this function call. It can be destroyed once libhoth_usb_open returns. -int libhoth_usb_open(const struct libhoth_usb_device_init_options* options, - struct libhoth_device** out); +libhoth_error libhoth_usb_open( + const struct libhoth_usb_device_init_options* options, + struct libhoth_device** out); -int libhoth_usb_close(struct libhoth_device* dev); +libhoth_error libhoth_usb_close(struct libhoth_device* dev); -int libhoth_usb_receive_response(struct libhoth_device* dev, void* response, - size_t max_response_size, size_t* actual_size, - int timeout_ms); +libhoth_error libhoth_usb_receive_response(struct libhoth_device* dev, + void* response, + size_t max_response_size, + size_t* actual_size, int timeout_ms); bool libhoth_device_is_hoth(const struct libusb_device_descriptor* dev); int libhoth_usb_get_device(libusb_context* ctx,