| // 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); |
| } |