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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions protocol/payload_update.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,24 +115,24 @@ static libhoth_error payload_update_erase_chunk(
&request, sizeof(request), NULL, 0, NULL);
}

static const size_t kBlockErase = 64 * 1024;
static const size_t kSectorErase = 4 * 1024;

libhoth_error libhoth_payload_update_erase(struct libhoth_device* const dev,
const uint32_t offset,
const uint32_t len) {
struct libhoth_progress_stderr erase_progress;
libhoth_progress_stderr_init(&erase_progress, "Erase staging side");

const size_t block_erase = 64 * 1024;
const size_t sector_erase = 4 * 1024;

if (len == 0 || (len % sector_erase) != 0) {
if (len == 0 || (len % kSectorErase) != 0) {
fprintf(stderr,
"error: erase length (0x%" PRIx32
") is zero or not sector-aligned.\n",
len);
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH,
LIBHOTH_ERR_IMAGE_NOT_SECTOR_ALIGNED);
}
if ((offset % sector_erase) != 0) {
if ((offset % kSectorErase) != 0) {
fprintf(stderr, "error: offset (0x%" PRIx32 ") is not sector-aligned.\n",
offset);
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH,
Expand All @@ -154,8 +154,8 @@ libhoth_error libhoth_payload_update_erase(struct libhoth_device* const dev,
const uint32_t current_offset = offset + erased;
const uint32_t remaining = len - erased;
const bool send_block_erase =
(current_offset % block_erase == 0) && (remaining >= block_erase);
const uint32_t chunk_size = send_block_erase ? block_erase : sector_erase;
(current_offset % kBlockErase == 0) && (remaining >= kBlockErase);
const uint32_t chunk_size = send_block_erase ? kBlockErase : kSectorErase;
const libhoth_error ret =
payload_update_erase_chunk(dev, current_offset, chunk_size);
if (ret != HOTH_SUCCESS) {
Expand All @@ -178,7 +178,21 @@ libhoth_error libhoth_payload_update(struct libhoth_device* dev, uint8_t* image,
}

if (!skip_erase) {
libhoth_error err = libhoth_payload_update_erase(dev, 0, size);
size_t erase_size = size;
if (binary_file && (erase_size % kSectorErase) != 0) {
const size_t pad = kSectorErase - (erase_size % kSectorErase);
if (erase_size > UINT32_MAX - pad) {
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH,
LIBHOTH_ERR_INVALID_PARAMETER);
}
erase_size += pad;
}
if (erase_size > UINT32_MAX) {
return LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH,
LIBHOTH_ERR_INVALID_PARAMETER);
}
libhoth_error err =
libhoth_payload_update_erase(dev, 0, (uint32_t)erase_size);
if (err != HOTH_SUCCESS) {
return err;
}
Expand Down
62 changes: 62 additions & 0 deletions protocol/payload_update_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ constexpr int kCmd =
constexpr int64_t kMagic = 0x5F435344474D495F;
constexpr int64_t kAlign = 1 << 16;
constexpr int64_t kDummy = 0;
constexpr size_t kBlockErase = 64 * 1024;
constexpr size_t kSectorErase = 4 * 1024;

MATCHER_P2(IsEraseRequest, offset, len, "") {
const struct hoth_host_request* req =
Expand Down Expand Up @@ -461,6 +463,66 @@ TEST_F(LibHothTest, payload_update_test_with_binary_image) {
HOTH_SUCCESS);
}

TEST_F(LibHothTest, payload_update_unaligned_binary_rounds_up_erase) {
constexpr size_t kUnalignedSize = kBlockErase + 100;
uint8_t buffer[kUnalignedSize];
std::memset(buffer, 0xFF, kUnalignedSize);
buffer[0] = 0xAA;

{
InSequence s;

// 64KB Block Erase for [0, 64KB)
EXPECT_CALL(mock_, send(_, IsEraseRequest(0, kBlockErase), _))
.WillOnce(Return(LIBHOTH_OK));
EXPECT_CALL(mock_, receive)
.WillOnce(DoAll(CopyResp(&kDummy, 0), Return(LIBHOTH_OK)));

// 4KB Sector Erase for [64KB, 68KB) rounded up from 64KB + 100B
EXPECT_CALL(mock_, send(_, IsEraseRequest(kBlockErase, kSectorErase), _))
.WillOnce(Return(LIBHOTH_OK));
EXPECT_CALL(mock_, receive)
.WillOnce(DoAll(CopyResp(&kDummy, 0), Return(LIBHOTH_OK)));

// Flash payload data
EXPECT_CALL(mock_, send(_, UsesCommand(kCmd), _))
.WillOnce(Return(LIBHOTH_OK));
EXPECT_CALL(mock_, receive)
.WillOnce(DoAll(CopyResp(&kDummy, 0), Return(LIBHOTH_OK)));
}

EXPECT_EQ(libhoth_payload_update(&hoth_dev_, buffer, kUnalignedSize,
/*skip_erase=*/false,
/*binary_file=*/true),
HOTH_SUCCESS);
}

TEST_F(LibHothTest, payload_update_unaligned_non_binary_fails) {
constexpr size_t kUnalignedSize = kSectorErase + 100;
uint8_t buffer[kUnalignedSize] = {0};

struct image_descriptor desc = {};
desc.descriptor_magic = TITAN_IMAGE_DESCRIPTOR_MAGIC;
desc.descriptor_area_size = sizeof(desc);
std::memcpy(buffer, &desc, sizeof(desc));

EXPECT_EQ(libhoth_payload_update(&hoth_dev_, buffer, kUnalignedSize,
/*skip_erase=*/false,
/*binary_file=*/false),
LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH,
LIBHOTH_ERR_IMAGE_NOT_SECTOR_ALIGNED));
}

TEST_F(LibHothTest, payload_update_unaligned_binary_erase_overflow_fails) {
uint8_t dummy = 0;
// Rounding 0xFFFFF001 up to the next 4 KiB boundary would overflow uint32_t.
EXPECT_EQ(libhoth_payload_update(&hoth_dev_, &dummy, 0xFFFFF001u,
/*skip_erase=*/false,
/*binary_file=*/true),
LIBHOTH_ERR_CONSTRUCT(HOTH_CTX_CMD_EXEC, HOTH_HOST_SPACE_LIBHOTH,
LIBHOTH_ERR_INVALID_PARAMETER));
}

TEST_F(LibHothTest, payload_update_erase_cmd_test) {
constexpr size_t kBlockErase = 64 * 1024;
constexpr size_t kSectorErase = 4 * 1024;
Expand Down
Loading