mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-06-13 15:03:58 +03:00
Merge tag 'u-boot-dfu-next-20251203' of https://source.denx.de/u-boot/custodians/u-boot-dfu into next
u-boot-dfu-next-20251203: CI: https://source.denx.de/u-boot/custodians/u-boot-dfu/-/pipelines/28617 Fastboot: - Add generic flashing support using BLK
This commit is contained in:
@@ -90,8 +90,9 @@ config FASTBOOT_USB_DEV
|
||||
|
||||
config FASTBOOT_FLASH
|
||||
bool "Enable FASTBOOT FLASH command"
|
||||
default y if ARCH_SUNXI || ARCH_ROCKCHIP
|
||||
depends on MMC || (MTD_RAW_NAND && CMD_MTDPARTS) || DM_SPI_FLASH
|
||||
default y if ARCH_SUNXI && ( MMC || MTD_RAW_NAND )
|
||||
default y if ARCH_ROCKCHIP && MMC
|
||||
depends on MMC || (MTD_RAW_NAND && CMD_MTDPARTS) || DM_SPI_FLASH || BLK
|
||||
select IMAGE_SPARSE
|
||||
help
|
||||
The fastboot protocol includes a "flash" command for writing
|
||||
@@ -123,6 +124,10 @@ config FASTBOOT_FLASH_SPI
|
||||
bool "FASTBOOT on SPI flash"
|
||||
depends on DM_SPI_FLASH
|
||||
|
||||
config FASTBOOT_FLASH_BLOCK
|
||||
bool "FASTBOOT on block device"
|
||||
depends on BLK
|
||||
|
||||
endchoice
|
||||
|
||||
config FASTBOOT_FLASH_MMC_DEV
|
||||
@@ -197,6 +202,29 @@ config FASTBOOT_MMC_USER_NAME
|
||||
defined here.
|
||||
The default target name for erasing EMMC_USER is "mmc0".
|
||||
|
||||
config FASTBOOT_FLASH_BLOCK_INTERFACE_NAME
|
||||
string "Define FASTBOOT block interface name"
|
||||
depends on FASTBOOT_FLASH_BLOCK
|
||||
help
|
||||
The fastboot "flash" and "erase" commands support operations
|
||||
on any Block device, this should specify the block device name
|
||||
like ide, scsi, usb, sata, nvme, virtio, blkmap, mtd...
|
||||
The mmc block device type can be used but most of the features
|
||||
available in the FASTBOOT_MMC will be missing.
|
||||
Consider using FASTBOOT_MMC on a MMC block device until all
|
||||
features are migrated.
|
||||
|
||||
config FASTBOOT_FLASH_BLOCK_DEVICE_ID
|
||||
int "Define FASTBOOT block device identifier"
|
||||
depends on FASTBOOT_FLASH_BLOCK
|
||||
default 0
|
||||
help
|
||||
The fastboot "flash" and "erase" commands support operations
|
||||
on any Block device, this should specify the block device
|
||||
identifier on the system, as a number.
|
||||
Device identifiers are numbered starting from 0 and the most
|
||||
common case is to use the first controller on the system.
|
||||
|
||||
config FASTBOOT_GPT_NAME
|
||||
string "Target name for updating GPT"
|
||||
depends on FASTBOOT_FLASH_MMC && EFI_PARTITION
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
obj-y += fb_common.o
|
||||
obj-y += fb_getvar.o
|
||||
obj-y += fb_command.o
|
||||
obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fb_mmc.o
|
||||
obj-$(CONFIG_FASTBOOT_FLASH_BLOCK) += fb_block.o
|
||||
# MMC reuses block implementation
|
||||
obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fb_block.o fb_mmc.o
|
||||
obj-$(CONFIG_FASTBOOT_FLASH_NAND) += fb_nand.o
|
||||
obj-$(CONFIG_FASTBOOT_FLASH_SPI) += fb_spi_flash.o
|
||||
|
||||
322
drivers/fastboot/fb_block.c
Normal file
322
drivers/fastboot/fb_block.c
Normal file
@@ -0,0 +1,322 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*/
|
||||
|
||||
#include <blk.h>
|
||||
#include <div64.h>
|
||||
#include <fastboot.h>
|
||||
#include <fastboot-internal.h>
|
||||
#include <fb_block.h>
|
||||
#include <image-sparse.h>
|
||||
#include <malloc.h>
|
||||
#include <part.h>
|
||||
|
||||
/**
|
||||
* FASTBOOT_MAX_BLOCKS_ERASE - maximum blocks to erase per derase call
|
||||
*
|
||||
* in the ERASE case we can have much larger buffer size since
|
||||
* we're not transferring an actual buffer
|
||||
*/
|
||||
#define FASTBOOT_MAX_BLOCKS_ERASE 1048576
|
||||
/**
|
||||
* FASTBOOT_MAX_BLOCKS_SOFT_ERASE - maximum blocks to software erase at once
|
||||
*/
|
||||
#define FASTBOOT_MAX_BLOCKS_SOFT_ERASE 4096
|
||||
/**
|
||||
* FASTBOOT_MAX_BLOCKS_WRITE - maximum blocks to write per dwrite call
|
||||
*/
|
||||
#define FASTBOOT_MAX_BLOCKS_WRITE 65536
|
||||
|
||||
struct fb_block_sparse {
|
||||
struct blk_desc *dev_desc;
|
||||
};
|
||||
|
||||
/* Write 0s instead of using erase operation, inefficient but functional */
|
||||
static lbaint_t fb_block_soft_erase(struct blk_desc *block_dev, lbaint_t blk,
|
||||
lbaint_t cur_blkcnt, lbaint_t erase_buf_blks,
|
||||
void *erase_buffer)
|
||||
{
|
||||
lbaint_t blks_written = 0;
|
||||
lbaint_t j;
|
||||
|
||||
memset(erase_buffer, 0, erase_buf_blks * block_dev->blksz);
|
||||
|
||||
for (j = 0; j < cur_blkcnt; j += erase_buf_blks) {
|
||||
lbaint_t remain = min(cur_blkcnt - j, erase_buf_blks);
|
||||
|
||||
blks_written += blk_dwrite(block_dev, blk + j,
|
||||
remain, erase_buffer);
|
||||
printf(".");
|
||||
}
|
||||
|
||||
return blks_written;
|
||||
}
|
||||
|
||||
static lbaint_t fb_block_write(struct blk_desc *block_dev, lbaint_t start,
|
||||
lbaint_t blkcnt, const void *buffer)
|
||||
{
|
||||
lbaint_t blk = start;
|
||||
lbaint_t blks_written = 0;
|
||||
lbaint_t blks = 0;
|
||||
void *erase_buf = NULL;
|
||||
int erase_buf_blks = 0;
|
||||
lbaint_t step = buffer ? FASTBOOT_MAX_BLOCKS_WRITE : FASTBOOT_MAX_BLOCKS_ERASE;
|
||||
lbaint_t i;
|
||||
|
||||
for (i = 0; i < blkcnt; i += step) {
|
||||
lbaint_t cur_blkcnt = min(blkcnt - i, step);
|
||||
|
||||
if (buffer) {
|
||||
if (fastboot_progress_callback)
|
||||
fastboot_progress_callback("writing");
|
||||
blks_written = blk_dwrite(block_dev, blk, cur_blkcnt,
|
||||
buffer + (i * block_dev->blksz));
|
||||
} else {
|
||||
if (fastboot_progress_callback)
|
||||
fastboot_progress_callback("erasing");
|
||||
|
||||
if (!erase_buf) {
|
||||
blks_written = blk_derase(block_dev, blk, cur_blkcnt);
|
||||
|
||||
/* Allocate erase buffer if erase is not implemented */
|
||||
if ((long)blks_written == -ENOSYS) {
|
||||
erase_buf_blks = min_t(long, blkcnt,
|
||||
FASTBOOT_MAX_BLOCKS_SOFT_ERASE);
|
||||
erase_buf = malloc(erase_buf_blks * block_dev->blksz);
|
||||
|
||||
printf("Slowly writing empty buffers due to missing erase operation\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (erase_buf)
|
||||
blks_written = fb_block_soft_erase(block_dev, blk, cur_blkcnt,
|
||||
erase_buf_blks, erase_buf);
|
||||
}
|
||||
blk += blks_written;
|
||||
blks += blks_written;
|
||||
}
|
||||
|
||||
if (erase_buf)
|
||||
free(erase_buf);
|
||||
|
||||
return blks;
|
||||
}
|
||||
|
||||
static lbaint_t fb_block_sparse_write(struct sparse_storage *info,
|
||||
lbaint_t blk, lbaint_t blkcnt,
|
||||
const void *buffer)
|
||||
{
|
||||
struct fb_block_sparse *sparse = info->priv;
|
||||
struct blk_desc *dev_desc = sparse->dev_desc;
|
||||
|
||||
return fb_block_write(dev_desc, blk, blkcnt, buffer);
|
||||
}
|
||||
|
||||
static lbaint_t fb_block_sparse_reserve(struct sparse_storage *info,
|
||||
lbaint_t blk, lbaint_t blkcnt)
|
||||
{
|
||||
return blkcnt;
|
||||
}
|
||||
|
||||
int fastboot_block_get_part_info(const char *part_name,
|
||||
struct blk_desc **dev_desc,
|
||||
struct disk_partition *part_info,
|
||||
char *response)
|
||||
{
|
||||
int ret;
|
||||
const char *interface = config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK,
|
||||
CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME,
|
||||
NULL);
|
||||
const int device = config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK,
|
||||
CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID, -1);
|
||||
|
||||
if (!part_name || !strcmp(part_name, "")) {
|
||||
fastboot_fail("partition not given", response);
|
||||
return -ENOENT;
|
||||
}
|
||||
if (!interface || !strcmp(interface, "")) {
|
||||
fastboot_fail("block interface isn't provided", response);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*dev_desc = blk_get_dev(interface, device);
|
||||
if (!dev_desc) {
|
||||
fastboot_fail("no such device", response);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = part_get_info_by_name(*dev_desc, part_name, part_info);
|
||||
if (ret < 0)
|
||||
fastboot_fail("failed to get partition info", response);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void fastboot_block_raw_erase_disk(struct blk_desc *dev_desc, const char *disk_name,
|
||||
char *response)
|
||||
{
|
||||
lbaint_t written;
|
||||
|
||||
debug("Start Erasing %s...\n", disk_name);
|
||||
|
||||
written = fb_block_write(dev_desc, 0, dev_desc->lba, NULL);
|
||||
if (written != dev_desc->lba) {
|
||||
pr_err("Failed to erase %s\n", disk_name);
|
||||
fastboot_response("FAIL", response, "Failed to erase %s", disk_name);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("........ erased " LBAFU " bytes from '%s'\n",
|
||||
dev_desc->lba * dev_desc->blksz, disk_name);
|
||||
fastboot_okay(NULL, response);
|
||||
}
|
||||
|
||||
void fastboot_block_raw_erase(struct blk_desc *dev_desc, struct disk_partition *info,
|
||||
const char *part_name, uint alignment, char *response)
|
||||
{
|
||||
lbaint_t written, blks_start, blks_size;
|
||||
|
||||
if (alignment) {
|
||||
blks_start = (info->start + alignment - 1) & ~(alignment - 1);
|
||||
if (info->size >= alignment)
|
||||
blks_size = (info->size - (blks_start - info->start)) &
|
||||
(~(alignment - 1));
|
||||
else
|
||||
blks_size = 0;
|
||||
|
||||
printf("Erasing blocks " LBAFU " to " LBAFU " due to alignment\n",
|
||||
blks_start, blks_start + blks_size);
|
||||
} else {
|
||||
blks_start = info->start;
|
||||
blks_size = info->size;
|
||||
}
|
||||
|
||||
written = fb_block_write(dev_desc, blks_start, blks_size, NULL);
|
||||
if (written != blks_size) {
|
||||
fastboot_fail("failed to erase partition", response);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("........ erased " LBAFU " bytes from '%s'\n",
|
||||
blks_size * info->blksz, part_name);
|
||||
fastboot_okay(NULL, response);
|
||||
}
|
||||
|
||||
void fastboot_block_erase(const char *part_name, char *response)
|
||||
{
|
||||
struct blk_desc *dev_desc;
|
||||
struct disk_partition part_info;
|
||||
|
||||
if (fastboot_block_get_part_info(part_name, &dev_desc, &part_info, response) < 0)
|
||||
return;
|
||||
|
||||
fastboot_block_raw_erase(dev_desc, &part_info, part_name, 0, response);
|
||||
}
|
||||
|
||||
void fastboot_block_write_raw_disk(struct blk_desc *dev_desc, const char *disk_name,
|
||||
void *buffer, u32 download_bytes, char *response)
|
||||
{
|
||||
lbaint_t blkcnt;
|
||||
lbaint_t blks;
|
||||
|
||||
/* determine number of blocks to write */
|
||||
blkcnt = ((download_bytes + (dev_desc->blksz - 1)) & ~(dev_desc->blksz - 1));
|
||||
blkcnt = lldiv(blkcnt, dev_desc->blksz);
|
||||
|
||||
if (blkcnt > dev_desc->lba) {
|
||||
pr_err("too large for disk: '%s'\n", disk_name);
|
||||
fastboot_fail("too large for disk", response);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Flashing Raw Image\n");
|
||||
|
||||
blks = fb_block_write(dev_desc, 0, blkcnt, buffer);
|
||||
|
||||
if (blks != blkcnt) {
|
||||
pr_err("failed writing to %s\n", disk_name);
|
||||
fastboot_fail("failed writing to device", response);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("........ wrote " LBAFU " bytes to '%s'\n", blkcnt * dev_desc->blksz,
|
||||
disk_name);
|
||||
fastboot_okay(NULL, response);
|
||||
}
|
||||
|
||||
void fastboot_block_write_raw_image(struct blk_desc *dev_desc,
|
||||
struct disk_partition *info, const char *part_name,
|
||||
void *buffer, u32 download_bytes, char *response)
|
||||
{
|
||||
lbaint_t blkcnt;
|
||||
lbaint_t blks;
|
||||
|
||||
/* determine number of blocks to write */
|
||||
blkcnt = ((download_bytes + (info->blksz - 1)) & ~(info->blksz - 1));
|
||||
blkcnt = lldiv(blkcnt, info->blksz);
|
||||
|
||||
if (blkcnt > info->size) {
|
||||
pr_err("too large for partition: '%s'\n", part_name);
|
||||
fastboot_fail("too large for partition", response);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Flashing Raw Image\n");
|
||||
|
||||
blks = fb_block_write(dev_desc, info->start, blkcnt, buffer);
|
||||
|
||||
if (blks != blkcnt) {
|
||||
pr_err("failed writing to device %d\n", dev_desc->devnum);
|
||||
fastboot_fail("failed writing to device", response);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("........ wrote " LBAFU " bytes to '%s'\n", blkcnt * info->blksz,
|
||||
part_name);
|
||||
fastboot_okay(NULL, response);
|
||||
}
|
||||
|
||||
void fastboot_block_write_sparse_image(struct blk_desc *dev_desc, struct disk_partition *info,
|
||||
const char *part_name, void *buffer, char *response)
|
||||
{
|
||||
struct fb_block_sparse sparse_priv;
|
||||
struct sparse_storage sparse;
|
||||
int err;
|
||||
|
||||
sparse_priv.dev_desc = dev_desc;
|
||||
|
||||
sparse.blksz = info->blksz;
|
||||
sparse.start = info->start;
|
||||
sparse.size = info->size;
|
||||
sparse.write = fb_block_sparse_write;
|
||||
sparse.reserve = fb_block_sparse_reserve;
|
||||
sparse.mssg = fastboot_fail;
|
||||
|
||||
printf("Flashing sparse image at offset " LBAFU "\n",
|
||||
sparse.start);
|
||||
|
||||
sparse.priv = &sparse_priv;
|
||||
err = write_sparse_image(&sparse, part_name, buffer,
|
||||
response);
|
||||
if (!err)
|
||||
fastboot_okay(NULL, response);
|
||||
}
|
||||
|
||||
void fastboot_block_flash_write(const char *part_name, void *download_buffer,
|
||||
u32 download_bytes, char *response)
|
||||
{
|
||||
struct blk_desc *dev_desc;
|
||||
struct disk_partition part_info;
|
||||
|
||||
if (fastboot_block_get_part_info(part_name, &dev_desc, &part_info, response) < 0)
|
||||
return;
|
||||
|
||||
if (is_sparse_image(download_buffer)) {
|
||||
fastboot_block_write_sparse_image(dev_desc, &part_info, part_name,
|
||||
download_buffer, response);
|
||||
} else {
|
||||
fastboot_block_write_raw_image(dev_desc, &part_info, part_name,
|
||||
download_buffer, download_bytes, response);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <env.h>
|
||||
#include <fastboot.h>
|
||||
#include <fastboot-internal.h>
|
||||
#include <fb_block.h>
|
||||
#include <fb_mmc.h>
|
||||
#include <fb_nand.h>
|
||||
#include <fb_spi_flash.h>
|
||||
@@ -338,6 +339,10 @@ void fastboot_data_complete(char *response)
|
||||
*/
|
||||
static void __maybe_unused flash(char *cmd_parameter, char *response)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_BLOCK))
|
||||
fastboot_block_flash_write(cmd_parameter, fastboot_buf_addr,
|
||||
image_size, response);
|
||||
|
||||
if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_MMC))
|
||||
fastboot_mmc_flash_write(cmd_parameter, fastboot_buf_addr,
|
||||
image_size, response);
|
||||
@@ -362,6 +367,9 @@ static void __maybe_unused flash(char *cmd_parameter, char *response)
|
||||
*/
|
||||
static void __maybe_unused erase(char *cmd_parameter, char *response)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_BLOCK))
|
||||
fastboot_block_erase(cmd_parameter, response);
|
||||
|
||||
if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_MMC))
|
||||
fastboot_mmc_erase(cmd_parameter, response);
|
||||
|
||||
|
||||
@@ -97,16 +97,24 @@ int __weak fastboot_set_reboot_flag(enum fastboot_reboot_reason reason)
|
||||
[FASTBOOT_REBOOT_REASON_FASTBOOTD] = "boot-fastboot",
|
||||
[FASTBOOT_REBOOT_REASON_RECOVERY] = "boot-recovery"
|
||||
};
|
||||
const int mmc_dev = config_opt_enabled(CONFIG_FASTBOOT_FLASH_MMC,
|
||||
CONFIG_FASTBOOT_FLASH_MMC_DEV, -1);
|
||||
|
||||
if (!IS_ENABLED(CONFIG_FASTBOOT_FLASH_MMC))
|
||||
int device = config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK,
|
||||
CONFIG_FASTBOOT_FLASH_BLOCK_DEVICE_ID, -1);
|
||||
if (device == -1) {
|
||||
device = config_opt_enabled(CONFIG_FASTBOOT_FLASH_MMC,
|
||||
CONFIG_FASTBOOT_FLASH_MMC_DEV, -1);
|
||||
}
|
||||
const char *bcb_iface = config_opt_enabled(CONFIG_FASTBOOT_FLASH_BLOCK,
|
||||
CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME,
|
||||
"mmc");
|
||||
|
||||
if (device == -1)
|
||||
return -EINVAL;
|
||||
|
||||
if (reason >= FASTBOOT_REBOOT_REASONS_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
ret = bcb_find_partition_and_load("mmc", mmc_dev, "misc");
|
||||
ret = bcb_find_partition_and_load(bcb_iface, device, "misc");
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@@ -226,8 +234,14 @@ void fastboot_set_progress_callback(void (*progress)(const char *msg))
|
||||
*/
|
||||
void fastboot_init(void *buf_addr, u32 buf_size)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_FASTBOOT_FLASH_BLOCK)
|
||||
if (!strcmp(CONFIG_FASTBOOT_FLASH_BLOCK_INTERFACE_NAME, "mmc"))
|
||||
printf("Warning: the fastboot block backend features are limited, consider using the MMC backend\n");
|
||||
#endif
|
||||
|
||||
fastboot_buf_addr = buf_addr ? buf_addr :
|
||||
(void *)CONFIG_FASTBOOT_BUF_ADDR;
|
||||
fastboot_buf_size = buf_size ? buf_size : CONFIG_FASTBOOT_BUF_SIZE;
|
||||
fastboot_set_progress_callback(NULL);
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <fastboot.h>
|
||||
#include <fastboot-internal.h>
|
||||
#include <fb_mmc.h>
|
||||
#include <fb_block.h>
|
||||
#include <fb_nand.h>
|
||||
#include <fb_spi_flash.h>
|
||||
#include <fs.h>
|
||||
@@ -115,7 +116,12 @@ static int getvar_get_part_info(const char *part_name, char *response,
|
||||
struct disk_partition disk_part;
|
||||
struct part_info *part_info;
|
||||
|
||||
if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_MMC)) {
|
||||
if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_BLOCK)) {
|
||||
r = fastboot_block_get_part_info(part_name, &dev_desc, &disk_part,
|
||||
response);
|
||||
if (r >= 0 && size)
|
||||
*size = disk_part.size * disk_part.blksz;
|
||||
} else if (IS_ENABLED(CONFIG_FASTBOOT_FLASH_MMC)) {
|
||||
r = fastboot_mmc_get_part_info(part_name, &dev_desc, &disk_part,
|
||||
response);
|
||||
if (r >= 0 && size)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <env.h>
|
||||
#include <fastboot.h>
|
||||
#include <fastboot-internal.h>
|
||||
#include <fb_block.h>
|
||||
#include <fb_mmc.h>
|
||||
#include <image-sparse.h>
|
||||
#include <image.h>
|
||||
@@ -20,10 +21,6 @@
|
||||
|
||||
#define BOOT_PARTITION_NAME "boot"
|
||||
|
||||
struct fb_mmc_sparse {
|
||||
struct blk_desc *dev_desc;
|
||||
};
|
||||
|
||||
static int raw_part_get_info_by_name(struct blk_desc *dev_desc,
|
||||
const char *name,
|
||||
struct disk_partition *info)
|
||||
@@ -114,118 +111,10 @@ static int part_get_info_by_name_or_alias(struct blk_desc **dev_desc,
|
||||
return do_get_part_info(dev_desc, name, info);
|
||||
}
|
||||
|
||||
/**
|
||||
* fb_mmc_blk_write() - Write/erase MMC in chunks of FASTBOOT_MAX_BLK_WRITE
|
||||
*
|
||||
* @block_dev: Pointer to block device
|
||||
* @start: First block to write/erase
|
||||
* @blkcnt: Count of blocks
|
||||
* @buffer: Pointer to data buffer for write or NULL for erase
|
||||
*/
|
||||
static lbaint_t fb_mmc_blk_write(struct blk_desc *block_dev, lbaint_t start,
|
||||
lbaint_t blkcnt, const void *buffer)
|
||||
{
|
||||
lbaint_t blk = start;
|
||||
lbaint_t blks_written;
|
||||
lbaint_t cur_blkcnt;
|
||||
lbaint_t blks = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < blkcnt; i += FASTBOOT_MAX_BLK_WRITE) {
|
||||
cur_blkcnt = min((int)blkcnt - i, FASTBOOT_MAX_BLK_WRITE);
|
||||
if (buffer) {
|
||||
if (fastboot_progress_callback)
|
||||
fastboot_progress_callback("writing");
|
||||
blks_written = blk_dwrite(block_dev, blk, cur_blkcnt,
|
||||
buffer + (i * block_dev->blksz));
|
||||
} else {
|
||||
if (fastboot_progress_callback)
|
||||
fastboot_progress_callback("erasing");
|
||||
blks_written = blk_derase(block_dev, blk, cur_blkcnt);
|
||||
}
|
||||
blk += blks_written;
|
||||
blks += blks_written;
|
||||
}
|
||||
return blks;
|
||||
}
|
||||
|
||||
static lbaint_t fb_mmc_sparse_write(struct sparse_storage *info,
|
||||
lbaint_t blk, lbaint_t blkcnt, const void *buffer)
|
||||
{
|
||||
struct fb_mmc_sparse *sparse = info->priv;
|
||||
struct blk_desc *dev_desc = sparse->dev_desc;
|
||||
|
||||
return fb_mmc_blk_write(dev_desc, blk, blkcnt, buffer);
|
||||
}
|
||||
|
||||
static lbaint_t fb_mmc_sparse_reserve(struct sparse_storage *info,
|
||||
lbaint_t blk, lbaint_t blkcnt)
|
||||
{
|
||||
return blkcnt;
|
||||
}
|
||||
|
||||
static void write_raw_image(struct blk_desc *dev_desc,
|
||||
struct disk_partition *info, const char *part_name,
|
||||
void *buffer, u32 download_bytes, char *response)
|
||||
{
|
||||
lbaint_t blkcnt;
|
||||
lbaint_t blks;
|
||||
|
||||
/* determine number of blocks to write */
|
||||
blkcnt = ((download_bytes + (info->blksz - 1)) & ~(info->blksz - 1));
|
||||
blkcnt = lldiv(blkcnt, info->blksz);
|
||||
|
||||
if (blkcnt > info->size) {
|
||||
pr_err("too large for partition: '%s'\n", part_name);
|
||||
fastboot_fail("too large for partition", response);
|
||||
return;
|
||||
}
|
||||
|
||||
puts("Flashing Raw Image\n");
|
||||
|
||||
blks = fb_mmc_blk_write(dev_desc, info->start, blkcnt, buffer);
|
||||
|
||||
if (blks != blkcnt) {
|
||||
pr_err("failed writing to device %d\n", dev_desc->devnum);
|
||||
fastboot_fail("failed writing to device", response);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("........ wrote " LBAFU " bytes to '%s'\n", blkcnt * info->blksz,
|
||||
part_name);
|
||||
fastboot_okay(NULL, response);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_FASTBOOT_MMC_BOOT_SUPPORT) || \
|
||||
defined(CONFIG_FASTBOOT_MMC_USER_SUPPORT)
|
||||
static int fb_mmc_erase_mmc_hwpart(struct blk_desc *dev_desc)
|
||||
{
|
||||
lbaint_t blks;
|
||||
|
||||
debug("Start Erasing mmc hwpart[%u]...\n", dev_desc->hwpart);
|
||||
|
||||
blks = fb_mmc_blk_write(dev_desc, 0, dev_desc->lba, NULL);
|
||||
|
||||
if (blks != dev_desc->lba) {
|
||||
pr_err("Failed to erase mmc hwpart[%u]\n", dev_desc->hwpart);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("........ erased %llu bytes from mmc hwpart[%u]\n",
|
||||
(u64)(dev_desc->lba * dev_desc->blksz), dev_desc->hwpart);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_FASTBOOT_MMC_BOOT_SUPPORT
|
||||
static void fb_mmc_boot_ops(struct blk_desc *dev_desc, void *buffer,
|
||||
int hwpart, u32 buff_sz, char *response)
|
||||
{
|
||||
lbaint_t blkcnt;
|
||||
lbaint_t blks;
|
||||
unsigned long blksz;
|
||||
|
||||
// To operate on EMMC_BOOT1/2 (mmc0boot0/1) we first change the hwpart
|
||||
if (blk_dselect_hwpart(dev_desc, hwpart)) {
|
||||
pr_err("Failed to select hwpart\n");
|
||||
@@ -233,42 +122,11 @@ static void fb_mmc_boot_ops(struct blk_desc *dev_desc, void *buffer,
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer) { /* flash */
|
||||
|
||||
/* determine number of blocks to write */
|
||||
blksz = dev_desc->blksz;
|
||||
blkcnt = ((buff_sz + (blksz - 1)) & ~(blksz - 1));
|
||||
blkcnt = lldiv(blkcnt, blksz);
|
||||
|
||||
if (blkcnt > dev_desc->lba) {
|
||||
pr_err("Image size too large\n");
|
||||
fastboot_fail("Image size too large", response);
|
||||
return;
|
||||
}
|
||||
|
||||
debug("Start Flashing Image to EMMC_BOOT%d...\n", hwpart);
|
||||
|
||||
blks = fb_mmc_blk_write(dev_desc, 0, blkcnt, buffer);
|
||||
|
||||
if (blks != blkcnt) {
|
||||
pr_err("Failed to write EMMC_BOOT%d\n", hwpart);
|
||||
fastboot_fail("Failed to write EMMC_BOOT part",
|
||||
response);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("........ wrote %llu bytes to EMMC_BOOT%d\n",
|
||||
(u64)(blkcnt * blksz), hwpart);
|
||||
} else { /* erase */
|
||||
if (fb_mmc_erase_mmc_hwpart(dev_desc)) {
|
||||
pr_err("Failed to erase EMMC_BOOT%d\n", hwpart);
|
||||
fastboot_fail("Failed to erase EMMC_BOOT part",
|
||||
response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fastboot_okay(NULL, response);
|
||||
if (buffer) /* flash */
|
||||
fastboot_block_write_raw_disk(dev_desc, "EMMC_BOOT",
|
||||
buffer, buff_sz, response);
|
||||
else /* erase */
|
||||
fastboot_block_raw_erase_disk(dev_desc, "EMMC_BOOT", response);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -609,30 +467,11 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
|
||||
return;
|
||||
|
||||
if (is_sparse_image(download_buffer)) {
|
||||
struct fb_mmc_sparse sparse_priv;
|
||||
struct sparse_storage sparse;
|
||||
int err;
|
||||
|
||||
sparse_priv.dev_desc = dev_desc;
|
||||
|
||||
sparse.blksz = info.blksz;
|
||||
sparse.start = info.start;
|
||||
sparse.size = info.size;
|
||||
sparse.write = fb_mmc_sparse_write;
|
||||
sparse.reserve = fb_mmc_sparse_reserve;
|
||||
sparse.mssg = fastboot_fail;
|
||||
|
||||
printf("Flashing sparse image at offset " LBAFU "\n",
|
||||
sparse.start);
|
||||
|
||||
sparse.priv = &sparse_priv;
|
||||
err = write_sparse_image(&sparse, cmd, download_buffer,
|
||||
response);
|
||||
if (!err)
|
||||
fastboot_okay(NULL, response);
|
||||
fastboot_block_write_sparse_image(dev_desc, &info, cmd,
|
||||
download_buffer, response);
|
||||
} else {
|
||||
write_raw_image(dev_desc, &info, cmd, download_buffer,
|
||||
download_bytes, response);
|
||||
fastboot_block_write_raw_image(dev_desc, &info, cmd, download_buffer,
|
||||
download_bytes, response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -646,7 +485,6 @@ void fastboot_mmc_erase(const char *cmd, char *response)
|
||||
{
|
||||
struct blk_desc *dev_desc;
|
||||
struct disk_partition info;
|
||||
lbaint_t blks, blks_start, blks_size, grp_size;
|
||||
struct mmc *mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV);
|
||||
|
||||
#ifdef CONFIG_FASTBOOT_MMC_BOOT_SUPPORT
|
||||
@@ -673,10 +511,7 @@ void fastboot_mmc_erase(const char *cmd, char *response)
|
||||
if (!dev_desc)
|
||||
return;
|
||||
|
||||
if (fb_mmc_erase_mmc_hwpart(dev_desc))
|
||||
fastboot_fail("Failed to erase EMMC_USER", response);
|
||||
else
|
||||
fastboot_okay(NULL, response);
|
||||
fastboot_block_raw_erase_disk(dev_desc, "EMMC_USER", response);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -685,26 +520,5 @@ void fastboot_mmc_erase(const char *cmd, char *response)
|
||||
return;
|
||||
|
||||
/* Align blocks to erase group size to avoid erasing other partitions */
|
||||
grp_size = mmc->erase_grp_size;
|
||||
blks_start = (info.start + grp_size - 1) & ~(grp_size - 1);
|
||||
if (info.size >= grp_size)
|
||||
blks_size = (info.size - (blks_start - info.start)) &
|
||||
(~(grp_size - 1));
|
||||
else
|
||||
blks_size = 0;
|
||||
|
||||
printf("Erasing blocks " LBAFU " to " LBAFU " due to alignment\n",
|
||||
blks_start, blks_start + blks_size);
|
||||
|
||||
blks = fb_mmc_blk_write(dev_desc, blks_start, blks_size, NULL);
|
||||
|
||||
if (blks != blks_size) {
|
||||
pr_err("failed erasing from device %d\n", dev_desc->devnum);
|
||||
fastboot_fail("failed erasing from device", response);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("........ erased " LBAFU " bytes from '%s'\n",
|
||||
blks_size * info.blksz, cmd);
|
||||
fastboot_okay(NULL, response);
|
||||
fastboot_block_raw_erase(dev_desc, &info, cmd, mmc->erase_grp_size, response);
|
||||
}
|
||||
|
||||
105
include/fb_block.h
Normal file
105
include/fb_block.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*/
|
||||
|
||||
#ifndef _FB_BLOCK_H_
|
||||
#define _FB_BLOCK_H_
|
||||
|
||||
struct blk_desc;
|
||||
struct disk_partition;
|
||||
|
||||
/**
|
||||
* fastboot_block_get_part_info() - Lookup block partition by name
|
||||
*
|
||||
* @part_name: Named partition to lookup
|
||||
* @dev_desc: Pointer to returned blk_desc pointer
|
||||
* @part_info: Pointer to returned struct disk_partition
|
||||
* @response: Pointer to fastboot response buffer
|
||||
* Return: 0 on success, -ve on error
|
||||
*/
|
||||
int fastboot_block_get_part_info(const char *part_name,
|
||||
struct blk_desc **dev_desc,
|
||||
struct disk_partition *part_info,
|
||||
char *response);
|
||||
|
||||
/**
|
||||
* fastboot_block_raw_erase() - Erase raw block device partition
|
||||
*
|
||||
* @dev_desc: Block device we're going write to
|
||||
* @info: Partition we're going write to
|
||||
* @part_name: Name of partition we're going write to
|
||||
* @alignment: erase start and size alignment, specify 0 to ignore
|
||||
* @response: Pointer to fastboot response buffer
|
||||
*/
|
||||
void fastboot_block_raw_erase(struct blk_desc *dev_desc, struct disk_partition *info,
|
||||
const char *part_name, uint alignment, char *response);
|
||||
|
||||
/**
|
||||
* fastboot_block_raw_erase_disk() - Erase raw block device
|
||||
*
|
||||
* @dev_desc: Block device we're going write to
|
||||
* @disk_name: Name of disk we're going write to
|
||||
* @response: Pointer to fastboot response buffer
|
||||
*/
|
||||
void fastboot_block_raw_erase_disk(struct blk_desc *dev_desc, const char *disk_name,
|
||||
char *response);
|
||||
|
||||
/**
|
||||
* fastboot_block_erase() - Erase partition on block device for fastboot
|
||||
*
|
||||
* @part_name: Named partition to erase
|
||||
* @response: Pointer to fastboot response buffer
|
||||
*/
|
||||
void fastboot_block_erase(const char *part_name, char *response);
|
||||
|
||||
/**
|
||||
* fastboot_block_write_raw_disk() - Write raw image to block device
|
||||
*
|
||||
* @dev_desc: Block device we're going write to
|
||||
* @disk_name: Name of disk we're going write to
|
||||
* @buffer: Downloaded buffer pointer
|
||||
* @download_bytes: Size of content on downloaded buffer pointer
|
||||
* @response: Pointer to fastboot response buffer
|
||||
*/
|
||||
void fastboot_block_write_raw_disk(struct blk_desc *dev_desc, const char *disk_name,
|
||||
void *buffer, u32 download_bytes, char *response);
|
||||
|
||||
/**
|
||||
* fastboot_block_write_raw_image() - Write raw image to block device partition
|
||||
*
|
||||
* @dev_desc: Block device we're going write to
|
||||
* @info: Partition we're going write to
|
||||
* @part_name: Name of partition we're going write to
|
||||
* @buffer: Downloaded buffer pointer
|
||||
* @download_bytes: Size of content on downloaded buffer pointer
|
||||
* @response: Pointer to fastboot response buffer
|
||||
*/
|
||||
void fastboot_block_write_raw_image(struct blk_desc *dev_desc,
|
||||
struct disk_partition *info, const char *part_name,
|
||||
void *buffer, u32 download_bytes, char *response);
|
||||
|
||||
/**
|
||||
* fastboot_block_write_sparse_image() - Write sparse image to block device partition
|
||||
*
|
||||
* @dev_desc: Block device we're going write to
|
||||
* @info: Partition we're going write to
|
||||
* @part_name: Name of partition we're going write to
|
||||
* @buffer: Downloaded buffer pointer
|
||||
* @response: Pointer to fastboot response buffer
|
||||
*/
|
||||
void fastboot_block_write_sparse_image(struct blk_desc *dev_desc, struct disk_partition *info,
|
||||
const char *part_name, void *buffer, char *response);
|
||||
|
||||
/**
|
||||
* fastboot_block_flash_write() - Write image to block device for fastboot
|
||||
*
|
||||
* @part_name: Named partition to write image to
|
||||
* @download_buffer: Pointer to image data
|
||||
* @download_bytes: Size of image data
|
||||
* @response: Pointer to fastboot response buffer
|
||||
*/
|
||||
void fastboot_block_flash_write(const char *part_name, void *download_buffer,
|
||||
u32 download_bytes, char *response);
|
||||
|
||||
#endif // _FB_BLOCK_H_
|
||||
Reference in New Issue
Block a user