blob: ed77f9b0127b5629b40132db22a523c89796ed0f [file] [log] [blame]
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/sparse/c/sparse.h>
#include <lib/storage/gpt_utils.h>
#include <lib/storage/sparse.h>
#include <sparse_format.h>
#include <string.h>
#include "lib/storage/storage.h"
#ifdef ENABLE_FIRMWARE_STORAGE_LOG
#define sparse_logger firmware_storage_log
#else
#define sparse_logger sparse_nop_logger
#endif
#define kScratchSize 4096
typedef struct IoBuffer {
uint8_t* data;
size_t size;
} IoBuffer;
static size_t IoBufferSize(SparseIoBufferHandle handle) {
IoBuffer* buffer = (IoBuffer*)(handle);
return buffer->size;
}
static bool IoBufferRead(SparseIoBufferHandle handle, uint64_t offset, uint8_t* dst, size_t size) {
IoBuffer* buffer = (IoBuffer*)(handle);
if (offset + size > buffer->size) {
return false;
}
memcpy(dst, buffer->data + offset, size);
return true;
}
static bool IoBufferWrite(SparseIoBufferHandle handle, uint64_t offset, const uint8_t* src,
size_t size) {
IoBuffer* buffer = (IoBuffer*)(handle);
if (offset + size > buffer->size) {
return false;
}
memcpy(buffer->data + offset, src, size);
return true;
}
static bool IoBufferFill(SparseIoBufferHandle handle, uint32_t payload) {
IoBuffer* buffer = (IoBuffer*)(handle);
// Make sure the buffer fits an exact multiple of payload items
// and is properly aligned to be assigned via cast.
if (!buffer || !buffer->data || buffer->size % sizeof(payload) != 0 ||
(uintptr_t)buffer->data % sizeof(payload) != 0) {
return false;
}
for (size_t i = 0; i < buffer->size / sizeof(payload); i++) {
((uint32_t*)buffer->data)[i] = payload;
}
return true;
}
typedef struct IoContext {
FuchsiaFirmwareStorage* ops;
const GptData* gpt_data;
const char* name;
} IoContext;
static bool IoWrite(void* ctx, uint64_t device_offset, SparseIoBufferHandle src,
uint64_t src_offset, size_t size) {
IoContext* io = (IoContext*)(ctx);
IoBuffer* src_buffer = (IoBuffer*)(src);
if (src_offset + size > src_buffer->size) {
return false;
}
return FuchsiaFirmwareStorageGptWrite(io->ops, io->gpt_data, io->name, device_offset, size,
src_buffer->data + src_offset);
}
bool FuchsiaIsSparseImage(const uint8_t* src, size_t size) {
static SparseIoBufferOps handle_interface = {
.size = IoBufferSize,
.read = IoBufferRead,
.write = IoBufferWrite,
.fill = IoBufferFill,
};
IoBuffer src_buffer = {
.size = size,
.data = (uint8_t*)src,
};
return sparse_is_sparse_image(&handle_interface, &src_buffer);
}
bool FuchsiaWriteSparseImage(FuchsiaFirmwareStorage* ops, const GptData* gpt_data, const char* name,
uint8_t* src, size_t size) {
IoContext context = {ops, gpt_data, name};
IoBuffer fill_buffer = {
.size = ops->fill_buffer_size_bytes,
.data = ops->fill_buffer,
};
SparseIoBufferOps handle_ops = {
.size = IoBufferSize,
.read = IoBufferRead,
.write = IoBufferWrite,
.fill = IoBufferFill,
};
SparseIoInterface io = {
.ctx = &context,
.fill_handle = &fill_buffer,
.handle_ops = handle_ops,
.write = IoWrite,
};
IoBuffer src_buffer = {
.size = size,
.data = src,
};
return sparse_unpack_image(&io, sparse_logger, &src_buffer);
}