blob: e640d0bd9b7960a713da7989b0a2ffe3e5155219 [file] [log] [blame]
/*
* Copyright (c) 2019 The Fuchsia Authors
*/
#include <common.h>
#include <amlogic/storage.h>
#include <config.h>
#include <fastboot.h>
#include <image-sparse.h>
#include <zircon_uboot/partition.h>
#include "lz4_wrapper.h"
static lbaint_t fb_zircon_sparse_write(struct sparse_storage *info,
lbaint_t blk, lbaint_t blkcnt,
const void *buffer)
{
zircon_partition *part = (zircon_partition *)info->priv;
uint64_t offset = blk * info->blksz;
size_t size = blkcnt * info->blksz;
return part->write(part, offset, buffer, size) ? 0 : blkcnt;
}
static lbaint_t fb_zircon_sparse_reserve(struct sparse_storage *info,
lbaint_t blk, lbaint_t blkcnt)
{
return blkcnt;
}
static uint8_t lz4_image_decompress_buffer[4 * 1024 * 1024];
static int write_lz4_compressed_image(zircon_partition *part,
void *download_buffer,
unsigned int download_bytes)
{
int ret = 0;
struct lz4_frame_header lz4_header;
size_t lz4_data_offset;
if ((ret = check_and_extract_lz4_frame_header(
download_buffer, download_bytes, &lz4_header,
&lz4_data_offset))) {
printf("Failed to extract lz4 frame header\n");
return -1;
}
const uint8_t *compressed_end = download_buffer + download_bytes;
const uint8_t *compressed_curr =
(uint8_t *)download_buffer + lz4_data_offset;
printf("Flashing lz4 compressed image to partition\n");
size_t write_offset = 0;
bool has_more_data = true;
while (has_more_data) {
size_t decompressed_size = sizeof(lz4_image_decompress_buffer);
size_t compressed_size = compressed_end - compressed_curr;
if ((ret = lz4_decompress(
&lz4_header, compressed_curr, &compressed_size,
lz4_image_decompress_buffer, &decompressed_size,
&has_more_data))) {
printf("Failed to decompress, %d\n", ret);
return -1;
}
compressed_curr += compressed_size;
if ((ret = part->write(part, write_offset,
lz4_image_decompress_buffer,
decompressed_size))) {
printf("Failed to write to storage\n");
return -1;
}
write_offset += decompressed_size;
}
return 0;
}
void fb_zircon_flash_write(const char *part_name, void *download_buffer,
unsigned int download_bytes)
{
// `write_sparse_image` sets fastboot_fail() on error, so start with
// fastboot_okay() to avoid clobbering the return value.
fastboot_okay(NULL);
zircon_partition *part = zircon_get_fastboot_partition(part_name);
if (!part) {
fastboot_fail("partition not found");
return;
}
if (!part->write) {
zircon_free_partition(part);
fastboot_fail("Device must be unlocked to run this command");
return;
}
printf("Flashing '%s'\n", part_name);
if (is_sparse_image(download_buffer)) {
struct sparse_storage sparse = {
.blksz = 1,
.start = 0,
.size = part->size,
.priv = (void *)part,
.write = fb_zircon_sparse_write,
.reserve = fb_zircon_sparse_reserve,
};
printf("Flashing sparse image to partition %s\n", part_name);
// sets `fastboot_fail()` on error.
write_sparse_image(&sparse, part_name, download_buffer,
download_bytes);
} else if (is_data_lz4_compressed(download_buffer, download_bytes)) {
if ((write_lz4_compressed_image(part, download_buffer,
download_bytes))) {
fastboot_fail("failed to write lz4 compressed image");
}
} else {
if (part->write(part, 0, download_buffer, download_bytes)) {
printf("partition flash failed: %s\n", part_name);
fastboot_fail("error writing the image");
}
}
printf("Flashing '%s' done\n", part_name);
zircon_free_partition(part);
}
void fb_zircon_erase(const char *part_name)
{
zircon_partition *part = zircon_get_fastboot_partition(part_name);
if (!part) {
fastboot_fail("partition not found");
return;
}
if (!part->erase) {
zircon_free_partition(part);
fastboot_fail("Device must be unlocked to run this command");
return;
}
printf("Erasing '%s'\n", part_name);
if (part->erase(part)) {
printf("partition erase failed: %s\n", part_name);
fastboot_fail("failed erasing from device");
} else {
fastboot_okay(NULL);
}
zircon_free_partition(part);
}