diff --git a/components/esp_blockdev_util/generic_partition.c b/components/esp_blockdev_util/generic_partition.c index 92560f063ff..71a382939df 100644 --- a/components/esp_blockdev_util/generic_partition.c +++ b/components/esp_blockdev_util/generic_partition.c @@ -8,7 +8,6 @@ #include #include #include -#include #include "esp_blockdev.h" #include "esp_err.h" @@ -21,38 +20,44 @@ static const char *TAG = "esp_blockdev/generic_partition"; typedef struct { esp_blockdev_t dev; esp_blockdev_handle_t parent; - size_t start_offset; + uint64_t start_offset; } esp_blockdev_generic_partition_t; -ssize_t esp_blockdev_generic_partition_translate_address_to_parent(esp_blockdev_handle_t dev_handle, size_t address) +esp_err_t esp_blockdev_generic_partition_translate_address_to_parent(esp_blockdev_handle_t dev_handle, uint64_t address, uint64_t *output) { - ESP_RETURN_ON_FALSE(dev_handle != NULL, -1, TAG, "The dev_handle cannot be NULL"); + ESP_RETURN_ON_FALSE(dev_handle != NULL, ESP_ERR_INVALID_ARG, TAG, "The dev_handle cannot be NULL"); + ESP_RETURN_ON_FALSE(output != NULL, ESP_ERR_INVALID_ARG, TAG, "The output pointer cannot be NULL"); esp_blockdev_generic_partition_t *dev = (esp_blockdev_generic_partition_t *)dev_handle; esp_blockdev_handle_t parent = dev->parent; - ESP_RETURN_ON_FALSE(address <= dev->dev.geometry.disk_size, -1, TAG, "The address falls outside of the partition"); + ESP_RETURN_ON_FALSE(address <= dev->dev.geometry.disk_size, ESP_ERR_INVALID_ARG, TAG, "The address falls outside of the partition"); - uint64_t translated = (uint64_t)dev->start_offset + (uint64_t)address; - ESP_RETURN_ON_FALSE(translated >= (uint64_t)address, -1, TAG, "Address translation overflowed"); - ESP_RETURN_ON_FALSE(translated <= parent->geometry.disk_size, -1, TAG, "The address range falls outside of the parent device"); + uint64_t translated = dev->start_offset + address; + ESP_RETURN_ON_FALSE(translated >= address, ESP_ERR_INVALID_ARG, TAG, "Address translation overflowed"); + ESP_RETURN_ON_FALSE(translated <= parent->geometry.disk_size, ESP_ERR_INVALID_ARG, TAG, "The address range falls outside of the parent device"); - return (ssize_t)translated; + *output = translated; + + return ESP_OK; } -ssize_t esp_blockdev_generic_partition_translate_address_to_child(esp_blockdev_handle_t dev_handle, size_t address) +esp_err_t esp_blockdev_generic_partition_translate_address_to_child(esp_blockdev_handle_t dev_handle, uint64_t address, uint64_t *output) { - ESP_RETURN_ON_FALSE(dev_handle != NULL, -1, TAG, "The dev_handle cannot be NULL"); + ESP_RETURN_ON_FALSE(dev_handle != NULL, ESP_ERR_INVALID_ARG, TAG, "The dev_handle cannot be NULL"); + ESP_RETURN_ON_FALSE(output != NULL, ESP_ERR_INVALID_ARG, TAG, "The output pointer cannot be NULL"); esp_blockdev_generic_partition_t *dev = (esp_blockdev_generic_partition_t *)dev_handle; uint64_t start_offset = dev->start_offset; - ESP_RETURN_ON_FALSE((uint64_t)address >= start_offset, -1, TAG, "The parent address is below the partition base"); + ESP_RETURN_ON_FALSE(address >= start_offset, ESP_ERR_INVALID_ARG, TAG, "The parent address is below the partition base"); - uint64_t translated = (uint64_t)address - start_offset; - ESP_RETURN_ON_FALSE(translated <= dev->dev.geometry.disk_size, -1, TAG, "The address falls outside of the partition"); + uint64_t translated = address - start_offset; + ESP_RETURN_ON_FALSE(translated <= dev->dev.geometry.disk_size, ESP_ERR_INVALID_ARG, TAG, "The address falls outside of the partition"); - return (ssize_t)translated; + *output = translated; + + return ESP_OK; } static esp_err_t bd_gp_read(esp_blockdev_handle_t dev_handle, uint8_t *dst_buf, size_t dst_buf_size, uint64_t src_addr, size_t data_read_len) @@ -68,10 +73,11 @@ static esp_err_t bd_gp_read(esp_blockdev_handle_t dev_handle, uint8_t *dst_buf, assert(src_addr % dev_handle->geometry.read_size == 0); assert(data_read_len % dev_handle->geometry.read_size == 0); - ssize_t addr_parent = esp_blockdev_generic_partition_translate_address_to_parent(dev_handle, src_addr); - ESP_RETURN_ON_FALSE(addr_parent >= 0, ESP_ERR_INVALID_ARG, TAG, "Failed to translate address"); + uint64_t addr_parent; + ESP_RETURN_ON_ERROR(esp_blockdev_generic_partition_translate_address_to_parent(dev_handle, src_addr, &addr_parent), + TAG, "Failed to translate address"); - return parent->ops->read(parent, dst_buf, dst_buf_size, (uint64_t)addr_parent, data_read_len); + return parent->ops->read(parent, dst_buf, dst_buf_size, addr_parent, data_read_len); } static esp_err_t bd_gp_write(esp_blockdev_handle_t dev_handle, const uint8_t* src_buf, uint64_t dst_addr, size_t data_write_len) @@ -92,10 +98,11 @@ static esp_err_t bd_gp_write(esp_blockdev_handle_t dev_handle, const uint8_t* sr assert(dst_addr % dev_handle->geometry.write_size == 0); assert(data_write_len % dev_handle->geometry.write_size == 0); - ssize_t addr_parent = esp_blockdev_generic_partition_translate_address_to_parent(dev_handle, dst_addr); - ESP_RETURN_ON_FALSE(addr_parent >= 0, ESP_ERR_INVALID_ARG, TAG, "Failed to translate address"); + uint64_t addr_parent; + ESP_RETURN_ON_ERROR(esp_blockdev_generic_partition_translate_address_to_parent(dev_handle, dst_addr, &addr_parent), + TAG, "Failed to translate address"); - return parent->ops->write(parent, src_buf, (uint64_t)addr_parent, data_write_len); + return parent->ops->write(parent, src_buf, addr_parent, data_write_len); } static esp_err_t bd_gp_erase(esp_blockdev_handle_t dev_handle, uint64_t start_addr, size_t erase_len) @@ -113,10 +120,11 @@ static esp_err_t bd_gp_erase(esp_blockdev_handle_t dev_handle, uint64_t start_ad return ESP_ERR_INVALID_ARG; } - ssize_t addr_parent = esp_blockdev_generic_partition_translate_address_to_parent(dev_handle, start_addr); - ESP_RETURN_ON_FALSE(addr_parent >= 0, ESP_ERR_INVALID_ARG, TAG, "Failed to translate address"); + uint64_t addr_parent; + ESP_RETURN_ON_ERROR(esp_blockdev_generic_partition_translate_address_to_parent(dev_handle, start_addr, &addr_parent), + TAG, "Failed to translate address"); - return parent->ops->erase(parent, (uint64_t)addr_parent, erase_len); + return parent->ops->erase(parent, addr_parent, erase_len); } static esp_err_t bd_gp_sync(esp_blockdev_handle_t dev_handle) @@ -152,11 +160,13 @@ static esp_err_t bd_gp_ioctl(esp_blockdev_handle_t dev_handle, const uint8_t cmd assert(erase_args->start_addr % dev->dev.geometry.erase_size == 0); assert(erase_args->erase_len % dev->dev.geometry.erase_size == 0); - ssize_t addr_parent = esp_blockdev_generic_partition_translate_address_to_parent(dev_handle, erase_args->start_addr); - ESP_RETURN_ON_FALSE(addr_parent >= 0, ESP_ERR_INVALID_ARG, TAG, "Failed to translate address"); + uint64_t addr_parent; + ESP_RETURN_ON_ERROR(esp_blockdev_generic_partition_translate_address_to_parent(dev_handle, erase_args->start_addr, + &addr_parent), + TAG, "Failed to translate address"); esp_blockdev_cmd_arg_erase_t translated_args = *erase_args; - translated_args.start_addr = (uint64_t)addr_parent; + translated_args.start_addr = addr_parent; ESP_RETURN_ON_FALSE(parent->ops->ioctl != NULL, ESP_ERR_NOT_SUPPORTED, TAG, "Parent device does not implement ioctl"); return parent->ops->ioctl(parent, cmd, &translated_args); @@ -184,7 +194,7 @@ static const esp_blockdev_ops_t g_generic_partition_ops = { .release = bd_gp_release, }; -esp_err_t esp_blockdev_generic_partition_get(esp_blockdev_handle_t parent, size_t start_offset, size_t size, esp_blockdev_handle_t *out) +esp_err_t esp_blockdev_generic_partition_get(esp_blockdev_handle_t parent, uint64_t start_offset, uint64_t size, esp_blockdev_handle_t *out) { ESP_RETURN_ON_FALSE(parent != NULL, ESP_ERR_INVALID_ARG, TAG, "The parent device handle cannot be NULL"); ESP_RETURN_ON_FALSE(out != NULL, ESP_ERR_INVALID_ARG, TAG, "The out pointer cannot be NULL"); diff --git a/components/esp_blockdev_util/include/esp_blockdev/generic_partition.h b/components/esp_blockdev_util/include/esp_blockdev/generic_partition.h index f09899e2653..0b3519ebff6 100644 --- a/components/esp_blockdev_util/include/esp_blockdev/generic_partition.h +++ b/components/esp_blockdev_util/include/esp_blockdev/generic_partition.h @@ -5,8 +5,8 @@ */ #pragma once -#include #include +#include #include "esp_blockdev.h" @@ -26,29 +26,31 @@ extern "C" { * ESP_ERR_NO_MEM - Failed to allocate the struct * ESP_OK */ -esp_err_t esp_blockdev_generic_partition_get(esp_blockdev_handle_t parent, size_t start, size_t size, esp_blockdev_handle_t *out); +esp_err_t esp_blockdev_generic_partition_get(esp_blockdev_handle_t parent, uint64_t start, uint64_t size, esp_blockdev_handle_t *out); /** * @brief Translate virtual partition address to parents address space * * @param device The device for which to do the translation * @param address Address to be translated, relative to the partition start + * @param output Where to store the translated parent-space address. Will be unchanged upon failure. * - * @return Parent-space address on success - * -1 on error (invalid argument or overflow) + * @return ESP_OK on success + * ESP_ERR_INVALID_ARG if an argument is invalid or the address cannot be translated */ -ssize_t esp_blockdev_generic_partition_translate_address_to_parent(esp_blockdev_handle_t device, size_t address); +esp_err_t esp_blockdev_generic_partition_translate_address_to_parent(esp_blockdev_handle_t device, uint64_t address, uint64_t *output); /** * @brief Translate virtual partition address from parents address space * * @param device The device for which to do the translation * @param address Address to be translated, in the parent address space + * @param output Where to store the translated partition-relative address. Will be unchanged upon failure. * - * @return Partition-relative address on success - * -1 on error (invalid argument or underflow) + * @return ESP_OK on success + * ESP_ERR_INVALID_ARG if an argument is invalid or the address cannot be translated */ -ssize_t esp_blockdev_generic_partition_translate_address_to_child(esp_blockdev_handle_t device, size_t address); +esp_err_t esp_blockdev_generic_partition_translate_address_to_child(esp_blockdev_handle_t device, uint64_t address, uint64_t *output); #ifdef __cplusplus } diff --git a/components/esp_blockdev_util/test_apps/generic_partition/main/test_generic_partition.c b/components/esp_blockdev_util/test_apps/generic_partition/main/test_generic_partition.c index 04124e11bc4..827a7894233 100644 --- a/components/esp_blockdev_util/test_apps/generic_partition/main/test_generic_partition.c +++ b/components/esp_blockdev_util/test_apps/generic_partition/main/test_generic_partition.c @@ -85,21 +85,60 @@ TEST_CASE("generic partition translate helpers", "[generic_partition]") esp_blockdev_handle_t part = NULL; TEST_ESP_OK(esp_blockdev_generic_partition_get(parent, 4, 16, &part)); - ssize_t parent_addr = esp_blockdev_generic_partition_translate_address_to_parent(part, 3); - TEST_ASSERT_GREATER_OR_EQUAL(0, parent_addr); - TEST_ASSERT_EQUAL_INT(7, parent_addr); + uint64_t parent_addr = 0; + TEST_ESP_OK(esp_blockdev_generic_partition_translate_address_to_parent(part, 3, &parent_addr)); + TEST_ASSERT_EQUAL_UINT64(7, parent_addr); - ssize_t child_addr = esp_blockdev_generic_partition_translate_address_to_child(part, 10); - TEST_ASSERT_GREATER_OR_EQUAL(0, child_addr); - TEST_ASSERT_EQUAL_INT(6, child_addr); + uint64_t child_addr = 0; + TEST_ESP_OK(esp_blockdev_generic_partition_translate_address_to_child(part, 10, &child_addr)); + TEST_ASSERT_EQUAL_UINT64(6, child_addr); - TEST_ASSERT_EQUAL_INT(-1, esp_blockdev_generic_partition_translate_address_to_parent(part, 20)); - TEST_ASSERT_EQUAL_INT(-1, esp_blockdev_generic_partition_translate_address_to_child(part, 2)); + parent_addr = UINT64_MAX; + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, + esp_blockdev_generic_partition_translate_address_to_parent(part, 20, &parent_addr)); + TEST_ASSERT_EQUAL_UINT64(UINT64_MAX, parent_addr); + + child_addr = UINT64_MAX; + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, + esp_blockdev_generic_partition_translate_address_to_child(part, 2, &child_addr)); + TEST_ASSERT_EQUAL_UINT64(UINT64_MAX, child_addr); + + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, + esp_blockdev_generic_partition_translate_address_to_parent(part, 3, NULL)); + TEST_ASSERT_EQUAL(ESP_ERR_INVALID_ARG, + esp_blockdev_generic_partition_translate_address_to_child(part, 10, NULL)); TEST_ESP_OK(part->ops->release(part)); TEST_ESP_OK(parent->ops->release(parent)); } +TEST_CASE("generic partition supports byte ranges above 4 GiB", "[generic_partition]") +{ + const uint64_t partition_offset = UINT64_C(5) * 1024 * 1024 * 1024; + const uint64_t partition_size = UINT64_C(2) * 1024 * 1024 * 1024; + const uint64_t parent_size = partition_offset + partition_size; + esp_blockdev_t parent = { + .geometry = { + .disk_size = parent_size, + .read_size = 512, + .write_size = 512, + .erase_size = 512, + }, + }; + + esp_blockdev_handle_t part = NULL; + TEST_ESP_OK(esp_blockdev_generic_partition_get(&parent, partition_offset, partition_size, &part)); + TEST_ASSERT_EQUAL_UINT64(partition_size, part->geometry.disk_size); + uint64_t translated_address = 0; + TEST_ESP_OK(esp_blockdev_generic_partition_translate_address_to_parent(part, 512, &translated_address)); + TEST_ASSERT_EQUAL_UINT64(partition_offset + 512, translated_address); + TEST_ESP_OK(esp_blockdev_generic_partition_translate_address_to_child(part, partition_offset + 512, + &translated_address)); + TEST_ASSERT_EQUAL_UINT64(512, translated_address); + + TEST_ESP_OK(part->ops->release(part)); +} + typedef struct { esp_blockdev_t dev; struct {