- fastboot updates / fixes
This commit is contained in:
Tom Rini 2021-02-26 15:11:08 -05:00
commit 08cca188c1
21 changed files with 546 additions and 161 deletions

View file

@ -22,7 +22,8 @@ static int do_ab_select(struct cmd_tbl *cmdtp, int flag, int argc,
/* Lookup the "misc" partition from argv[2] and argv[3] */
if (part_get_info_by_dev_and_name_or_num(argv[2], argv[3],
&dev_desc, &part_info) < 0) {
&dev_desc, &part_info,
false) < 0) {
return CMD_RET_FAILURE;
}

View file

@ -443,6 +443,7 @@ static int usb_kbd_probe_dev(struct usb_device *dev, unsigned int ifnum)
struct usb_interface *iface;
struct usb_endpoint_descriptor *ep;
struct usb_kbd_pdata *data;
int epNum;
if (dev->descriptor.bNumConfigurations != 1)
return 0;
@ -458,19 +459,21 @@ static int usb_kbd_probe_dev(struct usb_device *dev, unsigned int ifnum)
if (iface->desc.bInterfaceProtocol != USB_PROT_HID_KEYBOARD)
return 0;
if (iface->desc.bNumEndpoints != 1)
for (epNum = 0; epNum < iface->desc.bNumEndpoints; epNum++) {
ep = &iface->ep_desc[epNum];
/* Check if endpoint is interrupt IN endpoint */
if ((ep->bmAttributes & 3) != 3)
continue;
if (ep->bEndpointAddress & 0x80)
break;
}
if (epNum == iface->desc.bNumEndpoints)
return 0;
ep = &iface->ep_desc[0];
/* Check if endpoint 1 is interrupt endpoint */
if (!(ep->bEndpointAddress & 0x80))
return 0;
if ((ep->bmAttributes & 3) != 3)
return 0;
debug("USB KBD: found set protocol...\n");
debug("USB KBD: found interrupt EP: 0x%x\n", ep->bEndpointAddress);
data = malloc(sizeof(struct usb_kbd_pdata));
if (!data) {
@ -498,13 +501,15 @@ static int usb_kbd_probe_dev(struct usb_device *dev, unsigned int ifnum)
data->last_report = -1;
/* We found a USB Keyboard, install it. */
debug("USB KBD: set boot protocol\n");
usb_set_protocol(dev, iface->desc.bInterfaceNumber, 0);
debug("USB KBD: found set idle...\n");
#if !defined(CONFIG_SYS_USB_EVENT_POLL_VIA_CONTROL_EP) && \
!defined(CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE)
debug("USB KBD: set idle interval...\n");
usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE / 4, 0);
#else
debug("USB KBD: set idle interval=0...\n");
usb_set_idle(dev, iface->desc.bInterfaceNumber, 0, 0);
#endif

View file

@ -111,6 +111,8 @@ CONFIG_DM_DEMO=y
CONFIG_DM_DEMO_SIMPLE=y
CONFIG_DM_DEMO_SHAPE=y
CONFIG_DFU_SF=y
CONFIG_FASTBOOT_FLASH=y
CONFIG_FASTBOOT_FLASH_MMC_DEV=0
CONFIG_GPIO_HOG=y
CONFIG_DM_GPIO_LOOKUP_LABEL=y
CONFIG_PM8916_GPIO=y

View file

@ -137,6 +137,8 @@ CONFIG_DFU_SF=y
CONFIG_DMA=y
CONFIG_DMA_CHANNELS=y
CONFIG_SANDBOX_DMA=y
CONFIG_FASTBOOT_FLASH=y
CONFIG_FASTBOOT_FLASH_MMC_DEV=0
CONFIG_GPIO_HOG=y
CONFIG_DM_GPIO_LOOKUP_LABEL=y
CONFIG_PM8916_GPIO=y

View file

@ -355,7 +355,7 @@ int part_get_info(struct blk_desc *dev_desc, int part,
}
#endif /* CONFIG_HAVE_BLOCK_DEVICE */
return -1;
return -ENOENT;
}
int part_get_info_whole_disk(struct blk_desc *dev_desc,
@ -417,7 +417,7 @@ int blk_get_device_by_str(const char *ifname, const char *dev_hwpart_str,
*dev_desc = get_dev_hwpart(ifname, dev, hwpart);
if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) {
debug("** Bad device %s %s **\n", ifname, dev_hwpart_str);
dev = -ENOENT;
dev = -ENODEV;
goto cleanup;
}
@ -441,7 +441,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
struct blk_desc **dev_desc,
struct disk_partition *info, int allow_whole_dev)
{
int ret = -1;
int ret;
const char *part_str;
char *dup_str = NULL;
const char *dev_str;
@ -483,7 +483,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
if (0 == strcmp(ifname, "ubi")) {
if (!ubifs_is_mounted()) {
printf("UBIFS not mounted, use ubifsmount to mount volume first!\n");
return -1;
return -EINVAL;
}
*dev_desc = NULL;
@ -505,6 +505,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
/* If still no dev_part_str, it's an error */
if (!dev_part_str) {
printf("** No device specified **\n");
ret = -ENODEV;
goto cleanup;
}
@ -521,8 +522,10 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
/* Look up the device */
dev = blk_get_device_by_str(ifname, dev_str, dev_desc);
if (dev < 0)
if (dev < 0) {
ret = dev;
goto cleanup;
}
/* Convert partition ID string to number */
if (!part_str || !*part_str) {
@ -539,6 +542,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
if (*ep || (part == 0 && !allow_whole_dev)) {
printf("** Bad partition specification %s %s **\n",
ifname, dev_part_str);
ret = -ENOENT;
goto cleanup;
}
}
@ -552,6 +556,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
if (!(*dev_desc)->lba) {
printf("** Bad device size - %s %s **\n", ifname,
dev_str);
ret = -EINVAL;
goto cleanup;
}
@ -563,6 +568,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
if ((part > 0) || (!allow_whole_dev)) {
printf("** No partition table - %s %s **\n", ifname,
dev_str);
ret = -EPROTONOSUPPORT;
goto cleanup;
}
@ -631,7 +637,6 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
*info = tmpinfo;
} else {
printf("** No valid partitions found **\n");
ret = -1;
goto cleanup;
}
}
@ -639,7 +644,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
printf("** Invalid partition type \"%.32s\""
" (expect \"" BOOT_PART_TYPE "\")\n",
info->type);
ret = -1;
ret = -EINVAL;
goto cleanup;
}
@ -675,7 +680,7 @@ int part_get_info_by_name_type(struct blk_desc *dev_desc, const char *name,
}
}
return -1;
return -ENOENT;
}
int part_get_info_by_name(struct blk_desc *dev_desc, const char *name,
@ -688,12 +693,13 @@ int part_get_info_by_name(struct blk_desc *dev_desc, const char *name,
* Get partition info from device number and partition name.
*
* Parse a device number and partition name string in the form of
* "device_num#partition_name", for example "0#misc". If the partition
* is found, sets dev_desc and part_info accordingly with the information
* of the partition with the given partition_name.
* "devicenum.hwpartnum#partition_name", for example "0.1#misc". devicenum and
* hwpartnum are both optional, defaulting to 0. If the partition is found,
* sets dev_desc and part_info accordingly with the information of the
* partition with the given partition_name.
*
* @param[in] dev_iface Device interface
* @param[in] dev_part_str Input string argument, like "0#misc"
* @param[in] dev_part_str Input string argument, like "0.1#misc"
* @param[out] dev_desc Place to store the device description pointer
* @param[out] part_info Place to store the partition information
* @return 0 on success, or a negative on error
@ -703,53 +709,57 @@ static int part_get_info_by_dev_and_name(const char *dev_iface,
struct blk_desc **dev_desc,
struct disk_partition *part_info)
{
char *ep;
const char *part_str;
int dev_num;
char *dup_str = NULL;
const char *dev_str, *part_str;
int ret;
/* Separate device and partition name specification */
part_str = strchr(dev_part_str, '#');
if (!part_str || part_str == dev_part_str)
return -EINVAL;
dev_num = simple_strtoul(dev_part_str, &ep, 16);
if (ep != part_str) {
/* Not all the first part before the # was parsed. */
if (part_str) {
dup_str = strdup(dev_part_str);
dup_str[part_str - dev_part_str] = 0;
dev_str = dup_str;
part_str++;
} else {
return -EINVAL;
}
part_str++;
*dev_desc = blk_get_dev(dev_iface, dev_num);
if (!*dev_desc) {
printf("Could not find %s %d\n", dev_iface, dev_num);
return -EINVAL;
}
if (part_get_info_by_name(*dev_desc, part_str, part_info) < 0) {
ret = blk_get_device_by_str(dev_iface, dev_str, dev_desc);
if (ret)
goto cleanup;
ret = part_get_info_by_name(*dev_desc, part_str, part_info);
if (ret < 0)
printf("Could not find \"%s\" partition\n", part_str);
return -EINVAL;
}
return 0;
cleanup:
free(dup_str);
return ret;
}
int part_get_info_by_dev_and_name_or_num(const char *dev_iface,
const char *dev_part_str,
struct blk_desc **dev_desc,
struct disk_partition *part_info)
struct disk_partition *part_info,
int allow_whole_dev)
{
int ret;
/* Split the part_name if passed as "$dev_num#part_name". */
if (!part_get_info_by_dev_and_name(dev_iface, dev_part_str,
dev_desc, part_info))
return 0;
ret = part_get_info_by_dev_and_name(dev_iface, dev_part_str,
dev_desc, part_info);
if (ret >= 0)
return ret;
/*
* Couldn't lookup by name, try looking up the partition description
* directly.
*/
if (blk_get_device_part_str(dev_iface, dev_part_str,
dev_desc, part_info, 1) < 0) {
ret = blk_get_device_part_str(dev_iface, dev_part_str,
dev_desc, part_info, allow_whole_dev);
if (ret < 0)
printf("Couldn't find partition %s %s\n",
dev_iface, dev_part_str);
return -EINVAL;
}
return 0;
return ret;
}
void part_set_generic_name(const struct blk_desc *dev_desc,

View file

@ -144,6 +144,11 @@ Command Reference
"powerdown" Power off the device.
"ucmd" execute any bootloader command and wait until it
finishs.
"acmd" execute any bootloader command, do not wait.
Client Variables
----------------

View file

@ -19,6 +19,8 @@ The current implementation supports the following standard commands:
- ``reboot``
- ``reboot-bootloader``
- ``set_active`` (only a stub implementation which always succeeds)
- ``ucmd`` (if enabled)
- ``acmd`` (if enabled)
The following OEM commands are supported (if enabled):
@ -154,6 +156,10 @@ The device index starts from ``a`` and refers to the interface (e.g. USB
controller, SD/MMC controller) or disk index. The partition index starts
from ``1`` and describes the partition number on the particular device.
Alternatively, partition types may be specified using :ref:`U-Boot's partition
syntax <partitions>`. This allows specifying partitions like ``0.1``,
``0#boot``, or ``:3``. The interface is always ``mmc``.
Writing Partition Table
-----------------------

View file

@ -258,7 +258,7 @@ SPI Flash
"""""""""
To load an image off of SPI flash, first set up a partition as described in
:ref:`partitions`. Then, use ``mtd`` to load that partition
:ref:`k210_partitions`. Then, use ``mtd`` to load that partition
.. code-block:: none
@ -401,7 +401,7 @@ Sipeed MAIX boards typically provide around 16 MiB of SPI NOR flash. U-Boot is
stored in the first 1 MiB or so of this flash. U-Boot's environment is stored at
the end of flash.
.. _partitions:
.. _k210_partitions:
Partitions
""""""""""

View file

@ -6,6 +6,7 @@ Use U-Boot
fdt_overlays
netconsole
partitions
Shell commands
--------------

80
doc/usage/partitions.rst Normal file
View file

@ -0,0 +1,80 @@
.. SPDX-License-Identifier: GPL-2.0+
.. _partitions:
Partitions
==========
Synopsis
--------
::
<command> <interface> [devnum][.hwpartnum][:partnum|#partname]
Description
-----------
Many U-Boot commands allow specifying partitions (or whole disks) using a
generic syntax.
interface
The interface used to access the partition's device, like ``mmc`` or
``scsi``. For a full list of supported interfaces, consult the
``if_typename_str`` array in ``drivers/block/blk-uclass.c``
devnum
The device number. This defaults to 0.
hwpartnum
The hardware partition number. All devices have at least one hardware
partition. On most devices, hardware partition 0 specifies the whole
device. On eMMC devices, hardware partition 0 is the user partition,
hardware partitions 1 and 2 are the boot partitions, hardware partition
3 is the RPMB partition, and further partitions are general-purpose
user-created partitions. The default hardware partition number is 0.
partnum
The partition number, starting from 1. The partition number 0 specifies
that the whole device is to be used as one "partition."
partname
The partition name. This is the partition label for GPT partitions. For
MBR partitions, the following syntax is used::
<devtype><devletter><partnum>
devtype
A device type like ``mmcsd`` or ``hd``. See the
``part_set_generic_name`` function in ``disk/part.c`` for a
complete list.
devletter
The device number as an offset from ``a``. For example, device
number 2 would have a device letter of ``c``.
partnum
The partition number. This is the same as above.
If neither ``partname`` nor ``partnum`` is specified and there is a partition
table, then partition 1 is used. If there is no partition table, then the whole
device is used as one "partition." If none of ``devnum``, ``hwpartnum``,
``partnum``, or ``partname`` is specified, or only ``-`` is specified, then
``devnum`` defaults to the value of the ``bootdevice`` environmental variable.
Examples
--------
List the root directory contents on MMC device 2, hardware partition 1,
and partition number 3::
ls mmc 2.1:3 /
Load ``/kernel.itb`` to address ``0x80000000`` from SCSI device 0, hardware partition
0, and the partition labeled ``boot``::
load scsi #boot 0x80000000 /kernel.itb
Print the partition UUID of the SATA device ``$bootdevice``, hardware partition
0, and partition number 0::
part uuid sata -

View file

@ -72,6 +72,15 @@ config FASTBOOT_FLASH
the downloaded image to a non-volatile storage device. Define
this to enable the "fastboot flash" command.
config FASTBOOT_UUU_SUPPORT
bool "Enable FASTBOOT i.MX UUU special command"
default n
help
The fastboot protocol includes "UCmd" and "ACmd" command.
Be aware that you provide full access to any U-Boot command,
including working with memory and may open a huge backdoor,
when enabling this option.
choice
prompt "Flash provider for FASTBOOT"
depends on FASTBOOT_FLASH

View file

@ -49,6 +49,11 @@ static void oem_partconf(char *, char *);
static void oem_bootbus(char *, char *);
#endif
#if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
static void run_ucmd(char *, char *);
static void run_acmd(char *, char *);
#endif
static const struct {
const char *command;
void (*dispatch)(char *cmd_parameter, char *response);
@ -117,6 +122,16 @@ static const struct {
.dispatch = oem_bootbus,
},
#endif
#if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
[FASTBOOT_COMMAND_UCMD] = {
.command = "UCmd",
.dispatch = run_ucmd,
},
[FASTBOOT_COMMAND_ACMD] = {
.command = "ACmd",
.dispatch = run_acmd,
},
#endif
};
/**
@ -327,6 +342,59 @@ static void erase(char *cmd_parameter, char *response)
}
#endif
#if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
/**
* run_ucmd() - Execute the UCmd command
*
* @cmd_parameter: Pointer to command parameter
* @response: Pointer to fastboot response buffer
*/
static void run_ucmd(char *cmd_parameter, char *response)
{
if (!cmd_parameter) {
pr_err("missing slot suffix\n");
fastboot_fail("missing command", response);
return;
}
if (run_command(cmd_parameter, 0))
fastboot_fail("", response);
else
fastboot_okay(NULL, response);
}
static char g_a_cmd_buff[64];
void fastboot_acmd_complete(void)
{
run_command(g_a_cmd_buff, 0);
}
/**
* run_acmd() - Execute the ACmd command
*
* @cmd_parameter: Pointer to command parameter
* @response: Pointer to fastboot response buffer
*/
static void run_acmd(char *cmd_parameter, char *response)
{
if (!cmd_parameter) {
pr_err("missing slot suffix\n");
fastboot_fail("missing command", response);
return;
}
if (strlen(cmd_parameter) > sizeof(g_a_cmd_buff)) {
pr_err("too long command\n");
fastboot_fail("too long command", response);
return;
}
strcpy(g_a_cmd_buff, cmd_parameter);
fastboot_okay(NULL, response);
}
#endif
/**
* reboot_bootloader() - Sets reboot bootloader flag.
*

View file

@ -28,30 +28,9 @@ struct fb_mmc_sparse {
struct blk_desc *dev_desc;
};
static int part_get_info_by_name_or_alias(struct blk_desc *dev_desc,
const char *name, struct disk_partition *info)
{
int ret;
ret = part_get_info_by_name(dev_desc, name, info);
if (ret < 0) {
/* strlen("fastboot_partition_alias_") + PART_NAME_LEN + 1 */
char env_alias_name[25 + PART_NAME_LEN + 1];
char *aliased_part_name;
/* check for alias */
strcpy(env_alias_name, "fastboot_partition_alias_");
strncat(env_alias_name, name, PART_NAME_LEN);
aliased_part_name = env_get(env_alias_name);
if (aliased_part_name != NULL)
ret = part_get_info_by_name(dev_desc,
aliased_part_name, info);
}
return ret;
}
static int raw_part_get_info_by_name(struct blk_desc *dev_desc,
const char *name, struct disk_partition *info, int *mmcpart)
const char *name,
struct disk_partition *info)
{
/* strlen("fastboot_raw_partition_") + PART_NAME_LEN + 1 */
char env_desc_name[23 + PART_NAME_LEN + 1];
@ -85,13 +64,65 @@ static int raw_part_get_info_by_name(struct blk_desc *dev_desc,
strncpy((char *)info->name, name, PART_NAME_LEN);
if (raw_part_desc) {
if (strcmp(strsep(&raw_part_desc, " "), "mmcpart") == 0)
*mmcpart = simple_strtoul(raw_part_desc, NULL, 0);
if (strcmp(strsep(&raw_part_desc, " "), "mmcpart") == 0) {
ulong mmcpart = simple_strtoul(raw_part_desc, NULL, 0);
int ret = blk_dselect_hwpart(dev_desc, mmcpart);
if (ret)
return ret;
}
}
return 0;
}
static int do_get_part_info(struct blk_desc **dev_desc, const char *name,
struct disk_partition *info)
{
int ret;
/* First try partition names on the default device */
*dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV);
if (*dev_desc) {
ret = part_get_info_by_name(*dev_desc, name, info);
if (ret >= 0)
return ret;
/* Then try raw partitions */
ret = raw_part_get_info_by_name(*dev_desc, name, info);
if (ret >= 0)
return ret;
}
/* Then try dev.hwpart:part */
ret = part_get_info_by_dev_and_name_or_num("mmc", name, dev_desc,
info, true);
return ret;
}
static int part_get_info_by_name_or_alias(struct blk_desc **dev_desc,
const char *name,
struct disk_partition *info)
{
int ret;
ret = do_get_part_info(dev_desc, name, info);
if (ret < 0) {
/* strlen("fastboot_partition_alias_") + PART_NAME_LEN + 1 */
char env_alias_name[25 + PART_NAME_LEN + 1];
char *aliased_part_name;
/* check for alias */
strcpy(env_alias_name, "fastboot_partition_alias_");
strncat(env_alias_name, name, PART_NAME_LEN);
aliased_part_name = env_get(env_alias_name);
if (aliased_part_name != NULL)
ret = do_get_part_info(dev_desc, aliased_part_name,
info);
}
return ret;
}
/**
* fb_mmc_blk_write() - Write/erase MMC in chunks of FASTBOOT_MAX_BLK_WRITE
*
@ -424,28 +455,49 @@ int fastboot_mmc_get_part_info(const char *part_name,
struct blk_desc **dev_desc,
struct disk_partition *part_info, char *response)
{
int r = 0;
int mmcpart;
int ret;
*dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV);
if (!*dev_desc) {
fastboot_fail("block device not found", response);
return -ENOENT;
}
if (!part_name || !strcmp(part_name, "")) {
fastboot_fail("partition not given", response);
return -ENOENT;
}
if (raw_part_get_info_by_name(*dev_desc, part_name, part_info, &mmcpart) < 0) {
r = part_get_info_by_name_or_alias(*dev_desc, part_name, part_info);
if (r < 0) {
fastboot_fail("partition not found", response);
return r;
ret = part_get_info_by_name_or_alias(dev_desc, part_name, part_info);
if (ret < 0) {
switch (ret) {
case -ENOSYS:
case -EINVAL:
fastboot_fail("invalid partition or device", response);
break;
case -ENODEV:
fastboot_fail("no such device", response);
break;
case -ENOENT:
fastboot_fail("no such partition", response);
break;
case -EPROTONOSUPPORT:
fastboot_fail("unknown partition table type", response);
break;
default:
fastboot_fail("unanticipated error", response);
break;
}
}
return r;
return ret;
}
static struct blk_desc *fastboot_mmc_get_dev(char *response)
{
struct blk_desc *ret = blk_get_dev("mmc",
CONFIG_FASTBOOT_FLASH_MMC_DEV);
if (!ret || ret->type == DEV_TYPE_UNKNOWN) {
pr_err("invalid mmc device\n");
fastboot_fail("invalid mmc device", response);
return NULL;
}
return ret;
}
/**
@ -461,24 +513,20 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
{
struct blk_desc *dev_desc;
struct disk_partition info;
int mmcpart = 0;
dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV);
if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
pr_err("invalid mmc device\n");
fastboot_fail("invalid mmc device", response);
return;
}
#ifdef CONFIG_FASTBOOT_MMC_BOOT_SUPPORT
if (strcmp(cmd, CONFIG_FASTBOOT_MMC_BOOT1_NAME) == 0) {
fb_mmc_boot_ops(dev_desc, download_buffer, 1,
download_bytes, response);
dev_desc = fastboot_mmc_get_dev(response);
if (dev_desc)
fb_mmc_boot_ops(dev_desc, download_buffer, 1,
download_bytes, response);
return;
}
if (strcmp(cmd, CONFIG_FASTBOOT_MMC_BOOT2_NAME) == 0) {
fb_mmc_boot_ops(dev_desc, download_buffer, 2,
download_bytes, response);
dev_desc = fastboot_mmc_get_dev(response);
if (dev_desc)
fb_mmc_boot_ops(dev_desc, download_buffer, 1,
download_bytes, response);
return;
}
#endif
@ -490,6 +538,10 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
if (strcmp(cmd, CONFIG_FASTBOOT_GPT_NAME) == 0 ||
strcmp(cmd, CONFIG_FASTBOOT_MMC_USER_NAME) == 0) {
#endif
dev_desc = fastboot_mmc_get_dev(response);
if (!dev_desc)
return;
printf("%s: updating MBR, Primary and Backup GPT(s)\n",
__func__);
if (is_valid_gpt_buf(dev_desc, download_buffer)) {
@ -513,6 +565,10 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
#if CONFIG_IS_ENABLED(DOS_PARTITION)
if (strcmp(cmd, CONFIG_FASTBOOT_MBR_NAME) == 0) {
dev_desc = fastboot_mmc_get_dev(response);
if (!dev_desc)
return;
printf("%s: updating MBR\n", __func__);
if (is_valid_dos_buf(download_buffer)) {
printf("%s: invalid MBR - refusing to write to flash\n",
@ -535,23 +591,16 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer,
#ifdef CONFIG_ANDROID_BOOT_IMAGE
if (strncasecmp(cmd, "zimage", 6) == 0) {
fb_mmc_update_zimage(dev_desc, download_buffer,
download_bytes, response);
dev_desc = fastboot_mmc_get_dev(response);
if (dev_desc)
fb_mmc_update_zimage(dev_desc, download_buffer,
download_bytes, response);
return;
}
#endif
if (raw_part_get_info_by_name(dev_desc, cmd, &info, &mmcpart) == 0) {
if (blk_dselect_hwpart(dev_desc, mmcpart)) {
pr_err("Failed to select hwpart\n");
fastboot_fail("Failed to select hwpart", response);
return;
}
} else if (part_get_info_by_name_or_alias(dev_desc, cmd, &info) < 0) {
pr_err("cannot find partition: '%s'\n", cmd);
fastboot_fail("cannot find partition", response);
if (fastboot_mmc_get_part_info(cmd, &dev_desc, &info, response) < 0)
return;
}
if (is_sparse_image(download_buffer)) {
struct fb_mmc_sparse sparse_priv;
@ -593,30 +642,20 @@ void fastboot_mmc_erase(const char *cmd, char *response)
struct disk_partition info;
lbaint_t blks, blks_start, blks_size, grp_size;
struct mmc *mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV);
int mmcpart = 0;
if (mmc == NULL) {
pr_err("invalid mmc device\n");
fastboot_fail("invalid mmc device", response);
return;
}
dev_desc = blk_get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV);
if (!dev_desc || dev_desc->type == DEV_TYPE_UNKNOWN) {
pr_err("invalid mmc device\n");
fastboot_fail("invalid mmc device", response);
return;
}
#ifdef CONFIG_FASTBOOT_MMC_BOOT_SUPPORT
if (strcmp(cmd, CONFIG_FASTBOOT_MMC_BOOT1_NAME) == 0) {
/* erase EMMC boot1 */
fb_mmc_boot_ops(dev_desc, NULL, 1, 0, response);
dev_desc = fastboot_mmc_get_dev(response);
if (dev_desc)
fb_mmc_boot_ops(dev_desc, NULL, 1, 0, response);
return;
}
if (strcmp(cmd, CONFIG_FASTBOOT_MMC_BOOT2_NAME) == 0) {
/* erase EMMC boot2 */
fb_mmc_boot_ops(dev_desc, NULL, 2, 0, response);
dev_desc = fastboot_mmc_get_dev(response);
if (dev_desc)
fb_mmc_boot_ops(dev_desc, NULL, 1, 0, response);
return;
}
#endif
@ -624,6 +663,10 @@ void fastboot_mmc_erase(const char *cmd, char *response)
#ifdef CONFIG_FASTBOOT_MMC_USER_SUPPORT
if (strcmp(cmd, CONFIG_FASTBOOT_MMC_USER_NAME) == 0) {
/* erase EMMC userdata */
dev_desc = fastboot_mmc_get_dev(response);
if (!dev_desc)
return;
if (fb_mmc_erase_mmc_hwpart(dev_desc))
fastboot_fail("Failed to erase EMMC_USER", response);
else
@ -632,17 +675,8 @@ void fastboot_mmc_erase(const char *cmd, char *response)
}
#endif
if (raw_part_get_info_by_name(dev_desc, cmd, &info, &mmcpart) == 0) {
if (blk_dselect_hwpart(dev_desc, mmcpart)) {
pr_err("Failed to select hwpart\n");
fastboot_fail("Failed to select hwpart", response);
return;
}
} else if (part_get_info_by_name_or_alias(dev_desc, cmd, &info) < 0) {
pr_err("cannot find partition: '%s'\n", cmd);
fastboot_fail("cannot find partition", response);
if (fastboot_mmc_get_part_info(cmd, &dev_desc, &info, response) < 0)
return;
}
/* Align blocks to erase group size to avoid erasing other partitions */
grp_size = mmc->erase_grp_size;

View file

@ -17,6 +17,17 @@ struct sandbox_mmc_plat {
struct mmc mmc;
};
#define MMC_CSIZE 0
#define MMC_CMULT 8 /* 8 because the card is high-capacity */
#define MMC_BL_LEN_SHIFT 10
#define MMC_BL_LEN BIT(MMC_BL_LEN_SHIFT)
#define MMC_CAPACITY (((MMC_CSIZE + 1) << (MMC_CMULT + 2)) \
* MMC_BL_LEN) /* 1 MiB */
struct sandbox_mmc_priv {
u8 buf[MMC_CAPACITY];
};
/**
* sandbox_mmc_send_cmd() - Emulate SD commands
*
@ -26,6 +37,10 @@ struct sandbox_mmc_plat {
static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
struct mmc_data *data)
{
struct sandbox_mmc_priv *priv = dev_get_priv(dev);
struct mmc *mmc = mmc_get_mmc_dev(dev);
static ulong erase_start, erase_end;
switch (cmd->cmdidx) {
case MMC_CMD_ALL_SEND_CID:
memset(cmd->response, '\0', sizeof(cmd->response));
@ -44,8 +59,9 @@ static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
break;
case MMC_CMD_SEND_CSD:
cmd->response[0] = 0;
cmd->response[1] = 10 << 16; /* 1 << block_len */
cmd->response[2] = 0;
cmd->response[1] = (MMC_BL_LEN_SHIFT << 16) |
((MMC_CSIZE >> 16) & 0x3f);
cmd->response[2] = (MMC_CSIZE & 0xffff) << 16;
cmd->response[3] = 0;
break;
case SD_CMD_SWITCH_FUNC: {
@ -59,13 +75,27 @@ static int sandbox_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
break;
}
case MMC_CMD_READ_SINGLE_BLOCK:
memset(data->dest, '\0', data->blocksize);
break;
case MMC_CMD_READ_MULTIPLE_BLOCK:
strcpy(data->dest, "this is a test");
memcpy(data->dest, &priv->buf[cmd->cmdarg * data->blocksize],
data->blocks * data->blocksize);
break;
case MMC_CMD_WRITE_SINGLE_BLOCK:
case MMC_CMD_WRITE_MULTIPLE_BLOCK:
memcpy(&priv->buf[cmd->cmdarg * data->blocksize], data->src,
data->blocks * data->blocksize);
break;
case MMC_CMD_STOP_TRANSMISSION:
break;
case SD_CMD_ERASE_WR_BLK_START:
erase_start = cmd->cmdarg;
break;
case SD_CMD_ERASE_WR_BLK_END:
erase_end = cmd->cmdarg;
break;
case MMC_CMD_ERASE:
memset(&priv->buf[erase_start * mmc->write_bl_len], '\0',
(erase_end - erase_start + 1) * mmc->write_bl_len);
break;
case SD_CMD_APP_SEND_OP_COND:
cmd->response[0] = OCR_BUSY | OCR_HCS;
cmd->response[1] = 0;
@ -148,5 +178,6 @@ U_BOOT_DRIVER(mmc_sandbox) = {
.bind = sandbox_mmc_bind,
.unbind = sandbox_mmc_unbind,
.probe = sandbox_mmc_probe,
.plat_auto = sizeof(struct sandbox_mmc_plat),
.priv_auto = sizeof(struct sandbox_mmc_priv),
.plat_auto = sizeof(struct sandbox_mmc_plat),
};

View file

@ -248,9 +248,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
debug_cond(DEBUG_SETUP != 0, "%s: %s\n", __func__, "no name");
if (!driver
|| (driver->speed != USB_SPEED_FULL
&& driver->speed != USB_SPEED_HIGH)
if (!driver || driver->speed < USB_SPEED_FULL
|| !driver->bind || !driver->disconnect || !driver->setup)
return -EINVAL;
if (!dev)
@ -320,9 +318,7 @@ static int dwc2_gadget_start(struct usb_gadget *g,
debug_cond(DEBUG_SETUP != 0, "%s: %s\n", __func__, "no name");
if (!driver ||
(driver->speed != USB_SPEED_FULL &&
driver->speed != USB_SPEED_HIGH) ||
if (!driver || driver->speed < USB_SPEED_FULL ||
!driver->bind || !driver->disconnect || !driver->setup)
return -EINVAL;

View file

@ -494,6 +494,18 @@ static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req)
do_exit_on_complete(ep, req);
}
#if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
static void do_acmd_complete(struct usb_ep *ep, struct usb_request *req)
{
/* When usb dequeue complete will be called
* Need status value before call run_command.
* otherwise, host can't get last message.
*/
if (req->status == 0)
fastboot_acmd_complete();
}
#endif
static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
{
char *cmdbuf = req->buf;
@ -532,6 +544,11 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req)
case FASTBOOT_COMMAND_REBOOT_RECOVERY:
fastboot_func->in_req->complete = compl_do_reset;
break;
#if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
case FASTBOOT_COMMAND_ACMD:
fastboot_func->in_req->complete = do_acmd_complete;
break;
#endif
}
}

View file

@ -44,6 +44,10 @@ enum {
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_BOOTBUS)
FASTBOOT_COMMAND_OEM_BOOTBUS,
#endif
#if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
FASTBOOT_COMMAND_ACMD,
FASTBOOT_COMMAND_UCMD,
#endif
FASTBOOT_COMMAND_COUNT
};
@ -169,4 +173,7 @@ void fastboot_data_download(const void *fastboot_data,
*/
void fastboot_data_complete(char *response);
#if CONFIG_IS_ENABLED(FASTBOOT_UUU_SUPPORT)
void fastboot_acmd_complete(void);
#endif
#endif /* _FASTBOOT_H_ */

View file

@ -227,12 +227,16 @@ int part_get_info_by_name(struct blk_desc *dev_desc,
* @param[in] dev_part_str Input partition description, like "0#misc" or "0:1"
* @param[out] dev_desc Place to store the device description pointer
* @param[out] part_info Place to store the partition information
* @param[in] allow_whole_dev true to allow the user to select partition 0
* (which means the whole device), false to require a valid
* partition number >= 1
* @return 0 on success, or a negative on error
*/
int part_get_info_by_dev_and_name_or_num(const char *dev_iface,
const char *dev_part_str,
struct blk_desc **dev_desc,
struct disk_partition *part_info);
struct disk_partition *part_info,
int allow_whole_dev);
/**
* part_set_generic_name() - create generic partition like hda1 or sdb2

View file

@ -95,5 +95,8 @@ obj-$(CONFIG_SCMI_FIRMWARE) += scmi.o
ifneq ($(CONFIG_PINMUX),)
obj-$(CONFIG_PINCONF) += pinmux.o
endif
ifneq ($(CONFIG_EFI_PARTITION),)
obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fastboot.o
endif
endif
endif # !SPL

95
test/dm/fastboot.c Normal file
View file

@ -0,0 +1,95 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2015 Google, Inc
*/
#include <common.h>
#include <dm.h>
#include <fastboot.h>
#include <fb_mmc.h>
#include <mmc.h>
#include <part.h>
#include <part_efi.h>
#include <dm/test.h>
#include <test/ut.h>
#include <linux/stringify.h>
#define FB_ALIAS_PREFIX "fastboot_partition_alias_"
static int dm_test_fastboot_mmc_part(struct unit_test_state *uts)
{
char response[FASTBOOT_RESPONSE_LEN] = {0};
char str_disk_guid[UUID_STR_LEN + 1];
struct blk_desc *mmc_dev_desc, *fb_dev_desc;
struct disk_partition part_info;
struct disk_partition parts[2] = {
{
.start = 48, /* GPT data takes up the first 34 blocks or so */
.size = 1,
.name = "test1",
},
{
.start = 49,
.size = 1,
.name = "test2",
},
};
/*
* There are a lot of literal 0s I don't want to have to construct from
* MMC_DEV.
*/
ut_asserteq(0, CONFIG_FASTBOOT_FLASH_MMC_DEV);
ut_assertok(blk_get_device_by_str("mmc", "0", &mmc_dev_desc));
if (CONFIG_IS_ENABLED(RANDOM_UUID)) {
gen_rand_uuid_str(parts[0].uuid, UUID_STR_FORMAT_STD);
gen_rand_uuid_str(parts[1].uuid, UUID_STR_FORMAT_STD);
gen_rand_uuid_str(str_disk_guid, UUID_STR_FORMAT_STD);
}
ut_assertok(gpt_restore(mmc_dev_desc, str_disk_guid, parts,
ARRAY_SIZE(parts)));
/* "Classic" partition labels */
ut_asserteq(1, fastboot_mmc_get_part_info("test1", &fb_dev_desc,
&part_info, response));
ut_asserteq(2, fastboot_mmc_get_part_info("test2", &fb_dev_desc,
&part_info, response));
/* Test aliases */
ut_assertnull(env_get(FB_ALIAS_PREFIX "test3"));
ut_assertok(env_set(FB_ALIAS_PREFIX "test3", "test1"));
ut_asserteq(1, fastboot_mmc_get_part_info("test3", &fb_dev_desc,
&part_info, response));
ut_assertok(env_set(FB_ALIAS_PREFIX "test3", NULL));
/* "New" partition labels */
ut_asserteq(1, fastboot_mmc_get_part_info("#test1", &fb_dev_desc,
&part_info, response));
ut_asserteq(1, fastboot_mmc_get_part_info("0#test1", &fb_dev_desc,
&part_info, response));
ut_asserteq(1, fastboot_mmc_get_part_info("0.0#test1", &fb_dev_desc,
&part_info, response));
ut_asserteq(1, fastboot_mmc_get_part_info("0:1", &fb_dev_desc,
&part_info, response));
ut_asserteq(1, fastboot_mmc_get_part_info("0.0:1", &fb_dev_desc,
&part_info, response));
ut_asserteq(1, fastboot_mmc_get_part_info("0", &fb_dev_desc,
&part_info, response));
ut_asserteq(1, fastboot_mmc_get_part_info("0.0", &fb_dev_desc,
&part_info, response));
ut_asserteq(0, fastboot_mmc_get_part_info("0:0", &fb_dev_desc,
&part_info, response));
ut_asserteq(0, fastboot_mmc_get_part_info("0.0:0", &fb_dev_desc,
&part_info, response));
ut_asserteq(0, fastboot_mmc_get_part_info("1", &fb_dev_desc,
&part_info, response));
ut_asserteq(0, fastboot_mmc_get_part_info("1.0", &fb_dev_desc,
&part_info, response));
ut_asserteq(1, fastboot_mmc_get_part_info(":1", &fb_dev_desc,
&part_info, response));
ut_asserteq(0, fastboot_mmc_get_part_info(":0", &fb_dev_desc,
&part_info, response));
return 0;
}
DM_TEST(dm_test_fastboot_mmc_part, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);

View file

@ -29,16 +29,25 @@ static int dm_test_mmc_blk(struct unit_test_state *uts)
{
struct udevice *dev;
struct blk_desc *dev_desc;
char cmp[1024];
int i;
char write[1024], read[1024];
ut_assertok(uclass_get_device(UCLASS_MMC, 0, &dev));
ut_assertok(blk_get_device_by_str("mmc", "0", &dev_desc));
/* Read a few blocks and look for the string we expect */
/* Write a few blocks and verify that we get the same data back */
ut_asserteq(512, dev_desc->blksz);
memset(cmp, '\0', sizeof(cmp));
ut_asserteq(2, blk_dread(dev_desc, 0, 2, cmp));
ut_assertok(strcmp(cmp, "this is a test"));
for (i = 0; i < sizeof(write); i++)
write[i] = i;
ut_asserteq(2, blk_dwrite(dev_desc, 0, 2, write));
ut_asserteq(2, blk_dread(dev_desc, 0, 2, read));
ut_asserteq_mem(write, read, sizeof(write));
/* Now erase them */
memset(write, '\0', sizeof(write));
ut_asserteq(2, blk_derase(dev_desc, 0, 2));
ut_asserteq(2, blk_dread(dev_desc, 0, 2, read));
ut_asserteq_mem(write, read, sizeof(write));
return 0;
}