blob: f3482eaedc71fd8c17155390a4cd4e5c7da83061 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include "decompressor.h"
#include <assert.h>
#include <lib/zx/vmar.h>
#include <lib/zx/vmo.h>
#include <stddef.h>
#include <zstd/zstd.h>
#include "bump_allocator.h"
#include "mapper.h"
#include "util.h"
namespace {
constexpr size_t kHeapSize = 5u << 20;
void* zstd_alloc(void* opaque, size_t size) {
BumpAllocator* allocator = static_cast<BumpAllocator*>(opaque);
return allocator->malloc(size);
}
void zstd_free(void* opaque, void* address) {
BumpAllocator* allocator = static_cast<BumpAllocator*>(opaque);
allocator->free(address);
}
} // namespace
static zx_status_t decompress_with_zstd(const zx::vmar& vmar, std::byte* input_data,
size_t input_size, std::byte* output_data,
size_t output_size) {
BumpAllocator allocator(&vmar);
zx_status_t status = allocator.Init(kHeapSize);
if (status != ZX_OK) {
return status;
}
ZSTD_DCtx* dctx = ZSTD_createDCtx_advanced({&zstd_alloc, &zstd_free, &allocator});
auto rc = ZSTD_decompressDCtx(dctx, output_data, output_size, input_data, input_size);
ZSTD_freeDCtx(dctx);
if (ZSTD_isError(rc) || rc != output_size) {
return ZX_ERR_IO_DATA_INTEGRITY;
}
return ZX_OK;
}
zx_status_t zbi_decompress(const zx::debuglog& log, const zx::vmar& vmar, const zx::vmo& input_vmo,
uint64_t input_offset, size_t input_size, const zx::vmo& output_vmo,
uint64_t output_offset, size_t output_size) {
// Magic number at the start of a compressed image.
// Reading this much is enough to identify the format.
using Magic = uint32_t;
static constexpr Magic kZstdMagic = 0xFD2FB528;
Magic magic;
zx_status_t status = input_vmo.read(&magic, input_offset, sizeof(magic));
if (status != ZX_OK) {
check(log, status, "failed to read magic from ZBI");
return status;
}
Mapper input(&vmar);
status = input.Map(ZX_VM_PERM_READ | ZX_VM_MAP_RANGE, input_vmo, input_offset, input_size);
if (status != ZX_OK) {
check(log, status, "failed to map ZBI for decompresion");
return status;
}
Mapper output(&vmar);
status = output.Map(ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_MAP_RANGE, output_vmo,
output_offset, output_size);
if (status != ZX_OK) {
check(log, status, "failed to map output VMO for ZBI decompresion");
return status;
}
if (magic == kZstdMagic) {
return decompress_with_zstd(vmar, input.data(), input_size, output.data(), output_size);
} else {
return ZX_ERR_NOT_FOUND;
}
}