From 3f484226793166c75bd56784832d4c1a84061ad5 Mon Sep 17 00:00:00 2001 From: Matthias Blankertz Date: Tue, 22 May 2018 15:24:48 +0200 Subject: usb: xhci-rcar: deregister before deactivating clock During the execution of xhci_deregister xHCI registers are accessed. If the clock is already deactivated when xhci_deregister is called this can lead to undefined behavior. Change the order to deregister the device before deactivating the clock. Signed-off-by: Matthias Blankertz --- drivers/usb/host/xhci-rcar.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index a837afc483b..f2e91ef0feb 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -117,12 +117,15 @@ err_clk: static int xhci_rcar_deregister(struct udevice *dev) { + int ret; struct rcar_xhci_platdata *plat = dev_get_platdata(dev); + ret = xhci_deregister(dev); + clk_disable(&plat->clk); clk_free(&plat->clk); - return xhci_deregister(dev); + return ret; } static int xhci_rcar_ofdata_to_platdata(struct udevice *dev) -- cgit v1.2.3 From 793c819c6e2168110ad7cfca0349738c79d79a1f Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 23 May 2018 23:40:47 -0700 Subject: usb: xhci: Set accurate add context flags when updating hub attributes If a USB 3.0 hub is plugged into the root port of the xHC, the xHCI driver will issue a 'Configure Endpoint' command to the xHC for it to update its internal data structure for this hub device. The hub attributes are in the slot context so we need tell xHC to update the slot context by setting the add context flags of the input control context to only cover the slot context. At present the add context flags is or'ed with the slot context bit, but it should really be accurately set to the slot context, as the variable that holds the value of the add context flags comes from whatever was set in the last command execution, which may contain additional contexts that 'Configure Endpoint' command should not touch. Some xHC implementations like x86 don't complain such, but it was observed on Renesas RCar Gen3 platform that the RCar xHC complains with a 'TRB error' completion codes as the response. Reported-by: Marek Vasut Signed-off-by: Bin Meng Tested-by: Marek Vasut Tested-by: Matthias Blankertz --- drivers/usb/host/xhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 3adb0028f2a..565948c1199 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1424,7 +1424,7 @@ static int xhci_update_hub_device(struct udevice *dev, struct usb_device *udev) ctrl_ctx = xhci_get_input_control_ctx(in_ctx); /* Initialize the input context control */ - ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG); + ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG); ctrl_ctx->drop_flags = 0; xhci_inval_cache((uintptr_t)out_ctx->bytes, out_ctx->size); -- cgit v1.2.3 From ae751b060e8cee3f9c48112898cd3e31ee6c0734 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 23 May 2018 23:40:48 -0700 Subject: usb: xhci: Initialize dev_state to 0 in the input slot context Per xHCI spec chapter 6.2.2 table 6-7, as input, software shall initialize the dev_state field to '0'. Though this does not seem to cause any issue with most xHC implementations, let's do this to conform with the spec. Signed-off-by: Bin Meng Tested-by: Marek Vasut Tested-by: Matthias Blankertz --- drivers/usb/host/xhci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 565948c1199..8c1126e79dd 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1452,6 +1452,7 @@ static int xhci_update_hub_device(struct udevice *dev, struct usb_device *udev) think_time = (think_time / 666) - 1; if (udev->speed == USB_SPEED_HIGH) slot_ctx->tt_info |= cpu_to_le32(TT_THINK_TIME(think_time)); + slot_ctx->dev_state = 0; return xhci_configure_endpoints(udev, false); } -- cgit v1.2.3 From eaaefb066c86f08fb285e73fb8c5fbf497be6b57 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 23 May 2018 23:40:49 -0700 Subject: usb: xhci: Fix config fail of FS hub behind a HS hub with MTT If a full speed hub connects to a high speed hub which supports MTT, the MTT field of its slot context will be set to 1 when xHCI driver setups an xHCI virtual device in xhci_setup_addressable_virt_dev(). Once usb core fetch its hub descriptor, and need to update the xHC's internal data structures for the device, the HUB field of its slot context will be set to 1 too, meanwhile MTT is also set before, this will cause configure endpoint command fail. In the case, we should clear MTT to 0 for full speed hub according to section 6.2.2. This keeps in sync with Linux kernel commit: 096b110: usb: xhci: fix config fail of FS hub behind a HS hub with MTT Signed-off-by: Bin Meng --- drivers/usb/host/xhci.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 8c1126e79dd..f9c6bbb9e98 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1435,8 +1435,15 @@ static int xhci_update_hub_device(struct udevice *dev, struct usb_device *udev) /* Update hub related fields */ slot_ctx->dev_info |= cpu_to_le32(DEV_HUB); - if (hub->tt.multi && udev->speed == USB_SPEED_HIGH) + /* + * refer to section 6.2.2: MTT should be 0 for full speed hub, + * but it may be already set to 1 when setup an xHCI virtual + * device, so clear it anyway. + */ + if (hub->tt.multi) slot_ctx->dev_info |= cpu_to_le32(DEV_MTT); + else if (udev->speed == USB_SPEED_FULL) + slot_ctx->dev_info &= cpu_to_le32(~DEV_MTT); slot_ctx->dev_info2 |= cpu_to_le32(XHCI_MAX_PORTS(udev->maxchild)); /* * Set TT think time - convert from ns to FS bit times. -- cgit v1.2.3 From e40406603fe22a5b18d7e8ac7a2eb0f2d2b13cf1 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 23 May 2018 23:40:50 -0700 Subject: usb: xhci: Handle endianness in xhci_set_configuration() In xhci_set_configuration(), 'Context Entries' field in the slot context was cleared with mask LAST_CTX_MASK, but it should have taken the endianness into consideration. Signed-off-by: Bin Meng --- drivers/usb/host/xhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index f9c6bbb9e98..9ded14cc3cb 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -536,7 +536,7 @@ static int xhci_set_configuration(struct usb_device *udev) /* slot context */ xhci_slot_copy(ctrl, in_ctx, out_ctx); slot_ctx = xhci_get_slot_ctx(ctrl, in_ctx); - slot_ctx->dev_info &= ~(LAST_CTX_MASK); + slot_ctx->dev_info &= ~(cpu_to_le32(LAST_CTX_MASK)); slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(max_ep_flag + 1) | 0); xhci_endpoint_copy(ctrl, in_ctx, out_ctx, 0); -- cgit v1.2.3 From afa314d3a37797bd88c9a379a6fa150e6829fdf9 Mon Sep 17 00:00:00 2001 From: Philipp Tomsich Date: Thu, 24 May 2018 17:11:57 +0200 Subject: rockchip: xhci: remove DTS parsing for PHY (which is unused) The xhci wrapper-driver for Rockchip searches the DTS to find its child node compatbile with 'rockchip,rk3399-usb3-phy' to retrieve the base-address of the PHY. However, this is currently broken (and always has been), returning NULL. However, the (wrongly) retrieved base-address is never used. We thus remove this code for now. Signed-off-by: Philipp Tomsich --- drivers/usb/host/xhci-rockchip.c | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/xhci-rockchip.c b/drivers/usb/host/xhci-rockchip.c index 060a6c43092..f19bea3a91b 100644 --- a/drivers/usb/host/xhci-rockchip.c +++ b/drivers/usb/host/xhci-rockchip.c @@ -17,7 +17,6 @@ struct rockchip_xhci_platdata { fdt_addr_t hcd_base; - fdt_addr_t phy_base; struct udevice *vbus_supply; }; @@ -35,7 +34,6 @@ struct rockchip_xhci { static int xhci_usb_ofdata_to_platdata(struct udevice *dev) { struct rockchip_xhci_platdata *plat = dev_get_platdata(dev); - struct udevice *child; int ret = 0; /* @@ -47,20 +45,6 @@ static int xhci_usb_ofdata_to_platdata(struct udevice *dev) return -ENXIO; } - /* Get the base address for usbphy from the device node */ - for (device_find_first_child(dev, &child); child; - device_find_next_child(&child)) { - if (!device_is_compatible(child, "rockchip,rk3399-usb3-phy")) - continue; - plat->phy_base = devfdt_get_addr(child); - break; - } - - if (plat->phy_base == FDT_ADDR_T_NONE) { - pr_err("Can't get the usbphy register address\n"); - return -ENXIO; - } - /* Vbus regulator */ ret = device_get_supply_regulator(dev, "vbus-supply", &plat->vbus_supply); -- cgit v1.2.3 From 6aae84769a0be095daf94d34fdd61b12d59a7022 Mon Sep 17 00:00:00 2001 From: Seung-Woo Kim Date: Fri, 25 May 2018 14:21:01 +0900 Subject: gadget: f_thor: Fix memory leaks of usb request and its buffer There are memory leaks of usb request and its buffer for ep0, in_ep, and out ep. Fix memory leaks of usb request and its buffer. Signed-off-by: Seung-Woo Kim --- drivers/usb/gadget/f_thor.c | 65 ++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_thor.c b/drivers/usb/gadget/f_thor.c index c8eda058329..1aa6be44bb4 100644 --- a/drivers/usb/gadget/f_thor.c +++ b/drivers/usb/gadget/f_thor.c @@ -620,22 +620,6 @@ static void thor_rx_tx_complete(struct usb_ep *ep, struct usb_request *req) status, req->actual, req->length); } -static struct usb_request *thor_start_ep(struct usb_ep *ep) -{ - struct usb_request *req; - - req = alloc_ep_req(ep, THOR_PACKET_SIZE); - debug("%s: ep:%p req:%p\n", __func__, ep, req); - - if (!req) - return NULL; - - memset(req->buf, 0, req->length); - req->complete = thor_rx_tx_complete; - - return req; -} - static void thor_setup_complete(struct usb_ep *ep, struct usb_request *req) { if (req->status || req->actual != req->length) @@ -752,6 +736,13 @@ int thor_handle(void) return 0; } +static void free_ep_req(struct usb_ep *ep, struct usb_request *req) +{ + if (req->buf) + free(req->buf); + usb_ep_free_request(ep, req); +} + static int thor_func_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_gadget *gadget = c->cdev->gadget; @@ -860,21 +851,18 @@ static int thor_func_bind(struct usb_configuration *c, struct usb_function *f) return 0; fail: + if (dev->req) + free_ep_req(gadget->ep0, dev->req); free(dev); return status; } -static void free_ep_req(struct usb_ep *ep, struct usb_request *req) -{ - free(req->buf); - usb_ep_free_request(ep, req); -} - static void thor_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_thor *f_thor = func_to_thor(f); struct thor_dev *dev = f_thor->dev; + free_ep_req(dev->gadget->ep0, dev->req); free(dev); memset(thor_func, 0, sizeof(*thor_func)); thor_func = NULL; @@ -895,8 +883,6 @@ static void thor_func_disable(struct usb_function *f) } if (dev->out_ep->driver_data) { - free(dev->out_req->buf); - dev->out_req->buf = NULL; usb_ep_free_request(dev->out_ep, dev->out_req); usb_ep_disable(dev->out_ep); dev->out_ep->driver_data = NULL; @@ -924,16 +910,17 @@ static int thor_eps_setup(struct usb_function *f) result = usb_ep_enable(ep, d); if (result) - goto exit; + goto err; ep->driver_data = cdev; /* claim */ - req = thor_start_ep(ep); + req = alloc_ep_req(ep, THOR_PACKET_SIZE); if (!req) { - usb_ep_disable(ep); result = -EIO; - goto exit; + goto err_disable_in_ep; } + memset(req->buf, 0, req->length); + req->complete = thor_rx_tx_complete; dev->in_req = req; ep = dev->out_ep; d = ep_desc(gadget, &hs_out_desc, &fs_out_desc); @@ -941,22 +928,34 @@ static int thor_eps_setup(struct usb_function *f) result = usb_ep_enable(ep, d); if (result) - goto exit; + goto err_free_in_req; ep->driver_data = cdev; /* claim */ - req = thor_start_ep(ep); + req = usb_ep_alloc_request(ep, 0); if (!req) { - usb_ep_disable(ep); result = -EIO; - goto exit; + goto err_disable_out_ep; } + req->complete = thor_rx_tx_complete; dev->out_req = req; /* ACM control EP */ ep = dev->int_ep; ep->driver_data = cdev; /* claim */ - exit: + return 0; + + err_disable_out_ep: + usb_ep_disable(dev->out_ep); + + err_free_in_req: + free_ep_req(dev->in_ep, dev->in_req); + dev->in_req = NULL; + + err_disable_in_ep: + usb_ep_disable(dev->in_ep); + + err: return result; } -- cgit v1.2.3 From 312a10f16bf3e8b68066fa359d4dd6a887b5fd55 Mon Sep 17 00:00:00 2001 From: Alex Kiernan Date: Tue, 29 May 2018 15:30:39 +0000 Subject: fastboot: Move fastboot to drivers/fastboot Separate CMD_FASTBOOT from FASTBOOT and move code and configuration to drivers/fastboot. Switch dependencies on FASTBOOT to USB_FUNCTION_FASTBOOT as anyone who wants FASTBOOT before this series wants USB_FUNCTION_FASTBOOT. Split USB_FUNCTION_FASTBOOT from FASTBOOT so they retain their existing behaviour. Signed-off-by: Alex Kiernan Reviewed-by: Simon Glass Acked-by: Joe Hershberger --- drivers/Kconfig | 2 + drivers/Makefile | 3 + drivers/fastboot/Kconfig | 123 ++++++++++++++ drivers/fastboot/Makefile | 8 + drivers/fastboot/fb_mmc.c | 406 +++++++++++++++++++++++++++++++++++++++++++++ drivers/fastboot/fb_nand.c | 230 +++++++++++++++++++++++++ 6 files changed, 772 insertions(+) create mode 100644 drivers/fastboot/Kconfig create mode 100644 drivers/fastboot/Makefile create mode 100644 drivers/fastboot/fb_mmc.c create mode 100644 drivers/fastboot/fb_nand.c (limited to 'drivers') diff --git a/drivers/Kconfig b/drivers/Kconfig index c2e813f5adf..8424898dbdc 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -28,6 +28,8 @@ source "drivers/dfu/Kconfig" source "drivers/dma/Kconfig" +source "drivers/fastboot/Kconfig" + source "drivers/firmware/Kconfig" source "drivers/fpga/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index b3f1b600a55..a79ff2e6b00 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -71,6 +71,9 @@ obj-y += block/ obj-$(CONFIG_BOOTCOUNT_LIMIT) += bootcount/ obj-$(CONFIG_CPU) += cpu/ obj-y += crypto/ +ifneq ($(CONFIG_FASTBOOT_FLASH_MMC_DEV)$(CONFIG_FASTBOOT_FLASH_NAND_DEV),) +obj-y += fastboot/ +endif obj-y += firmware/ obj-$(CONFIG_FPGA) += fpga/ obj-y += misc/ diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig new file mode 100644 index 00000000000..93a8ac64e76 --- /dev/null +++ b/drivers/fastboot/Kconfig @@ -0,0 +1,123 @@ +menu "Fastboot support" + +config FASTBOOT + bool + imply ANDROID_BOOT_IMAGE + imply CMD_FASTBOOT + +config USB_FUNCTION_FASTBOOT + bool "Enable USB fastboot gadget" + depends on USB_GADGET + default y if ARCH_SUNXI && USB_MUSB_GADGET + select FASTBOOT + select USB_GADGET_DOWNLOAD + help + This enables the USB part of the fastboot gadget. + +if FASTBOOT + +config FASTBOOT_BUF_ADDR + hex "Define FASTBOOT buffer address" + default 0x82000000 if MX6SX || MX6SL || MX6UL || MX6SLL + default 0x81000000 if ARCH_OMAP2PLUS + default 0x42000000 if ARCH_SUNXI && !MACH_SUN9I + default 0x22000000 if ARCH_SUNXI && MACH_SUN9I + default 0x60800800 if ROCKCHIP_RK3036 || ROCKCHIP_RK3188 || \ + ROCKCHIP_RK322X + default 0x800800 if ROCKCHIP_RK3288 || ROCKCHIP_RK3329 || \ + ROCKCHIP_RK3399 + default 0x280000 if ROCKCHIP_RK3368 + default 0x100000 if ARCH_ZYNQMP + help + The fastboot protocol requires a large memory buffer for + downloads. Define this to the starting RAM address to use for + downloaded images. + +config FASTBOOT_BUF_SIZE + hex "Define FASTBOOT buffer size" + default 0x8000000 if ARCH_ROCKCHIP + default 0x6000000 if ARCH_ZYNQMP + default 0x2000000 if ARCH_SUNXI + default 0x7000000 + help + The fastboot protocol requires a large memory buffer for + downloads. This buffer should be as large as possible for a + platform. Define this to the size available RAM for fastboot. + +config FASTBOOT_USB_DEV + int "USB controller number" + depends on USB_FUNCTION_FASTBOOT + default 0 + help + Some boards have USB OTG controller other than 0. Define this + option so it can be used in compiled environment (e.g. in + CONFIG_BOOTCOMMAND). + +config FASTBOOT_FLASH + bool "Enable FASTBOOT FLASH command" + default y if ARCH_SUNXI + help + The fastboot protocol includes a "flash" command for writing + the downloaded image to a non-volatile storage device. Define + this to enable the "fastboot flash" command. + +choice + prompt "Flash provider for FASTBOOT" + depends on FASTBOOT_FLASH + +config FASTBOOT_FLASH_MMC + bool "FASTBOOT on MMC" + depends on MMC + +config FASTBOOT_FLASH_NAND + bool "FASTBOOT on NAND" + depends on NAND + +endchoice + +config FASTBOOT_FLASH_MMC_DEV + int "Define FASTBOOT MMC FLASH default device" + depends on FASTBOOT_FLASH_MMC + default 0 if ARCH_SUNXI && MMC_SUNXI_SLOT_EXTRA = -1 + default 1 if ARCH_SUNXI && MMC_SUNXI_SLOT_EXTRA != -1 + help + The fastboot "flash" command requires additional information + regarding the non-volatile storage device. Define this to + the eMMC device that fastboot should use to store the image. + +config FASTBOOT_FLASH_NAND_DEV + int "Define FASTBOOT NAND FLASH default device" + depends on FASTBOOT_FLASH_NAND + depends on CMD_MTDPARTS + default 0 if ARCH_SUNXI && NAND_SUNXI + help + The fastboot "flash" command requires additional information + regarding the non-volatile storage device. Define this to + the NAND device that fastboot should use to store the image. + +config FASTBOOT_GPT_NAME + string "Target name for updating GPT" + depends on FASTBOOT_FLASH + default "gpt" + help + The fastboot "flash" command supports writing the downloaded + image to the Protective MBR and the Primary GUID Partition + Table. (Additionally, this downloaded image is post-processed + to generate and write the Backup GUID Partition Table.) + This occurs when the specified "partition name" on the + "fastboot flash" command line matches the value defined here. + The default target name for updating GPT is "gpt". + +config FASTBOOT_MBR_NAME + string "Target name for updating MBR" + depends on FASTBOOT_FLASH + default "mbr" + help + The fastboot "flash" command allows to write the downloaded image + to the Master Boot Record. This occurs when the "partition name" + specified on the "fastboot flash" command line matches the value + defined here. The default target name for updating MBR is "mbr". + +endif # FASTBOOT + +endmenu diff --git a/drivers/fastboot/Makefile b/drivers/fastboot/Makefile new file mode 100644 index 00000000000..651fbf0935a --- /dev/null +++ b/drivers/fastboot/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0+ + +ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV +obj-y += fb_mmc.o +endif +ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV +obj-y += fb_nand.o +endif diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c new file mode 100644 index 00000000000..46f0073dbc2 --- /dev/null +++ b/drivers/fastboot/fb_mmc.c @@ -0,0 +1,406 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2014 Broadcom Corporation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * FIXME: Ensure we always set these names via Kconfig once xxx_PARTITION is + * migrated + */ +#ifndef CONFIG_FASTBOOT_GPT_NAME +#define CONFIG_FASTBOOT_GPT_NAME "gpt" +#endif + + +#ifndef CONFIG_FASTBOOT_MBR_NAME +#define CONFIG_FASTBOOT_MBR_NAME "mbr" +#endif + +#define BOOT_PARTITION_NAME "boot" + +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, disk_partition_t *info) +{ + int ret; + + ret = part_get_info_by_name(dev_desc, name, info); + if (ret < 0) { + /* strlen("fastboot_partition_alias_") + 32(part_name) + 1 */ + char env_alias_name[25 + 32 + 1]; + char *aliased_part_name; + + /* check for alias */ + strcpy(env_alias_name, "fastboot_partition_alias_"); + strncat(env_alias_name, name, 32); + 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 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 blk_dwrite(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, disk_partition_t *info, + const char *part_name, void *buffer, + unsigned int download_bytes) +{ + 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"); + return; + } + + puts("Flashing Raw Image\n"); + + blks = blk_dwrite(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"); + return; + } + + printf("........ wrote " LBAFU " bytes to '%s'\n", blkcnt * info->blksz, + part_name); + fastboot_okay(""); +} + +#ifdef CONFIG_ANDROID_BOOT_IMAGE +/** + * Read Android boot image header from boot partition. + * + * @param[in] dev_desc MMC device descriptor + * @param[in] info Boot partition info + * @param[out] hdr Where to store read boot image header + * + * @return Boot image header sectors count or 0 on error + */ +static lbaint_t fb_mmc_get_boot_header(struct blk_desc *dev_desc, + disk_partition_t *info, + struct andr_img_hdr *hdr) +{ + ulong sector_size; /* boot partition sector size */ + lbaint_t hdr_sectors; /* boot image header sectors count */ + int res; + + /* Calculate boot image sectors count */ + sector_size = info->blksz; + hdr_sectors = DIV_ROUND_UP(sizeof(struct andr_img_hdr), sector_size); + if (hdr_sectors == 0) { + pr_err("invalid number of boot sectors: 0"); + fastboot_fail("invalid number of boot sectors: 0"); + return 0; + } + + /* Read the boot image header */ + res = blk_dread(dev_desc, info->start, hdr_sectors, (void *)hdr); + if (res != hdr_sectors) { + pr_err("cannot read header from boot partition"); + fastboot_fail("cannot read header from boot partition"); + return 0; + } + + /* Check boot header magic string */ + res = android_image_check_header(hdr); + if (res != 0) { + pr_err("bad boot image magic"); + fastboot_fail("boot partition not initialized"); + return 0; + } + + return hdr_sectors; +} + +/** + * Write downloaded zImage to boot partition and repack it properly. + * + * @param dev_desc MMC device descriptor + * @param download_buffer Address to fastboot buffer with zImage in it + * @param download_bytes Size of fastboot buffer, in bytes + * + * @return 0 on success or -1 on error + */ +static int fb_mmc_update_zimage(struct blk_desc *dev_desc, + void *download_buffer, + unsigned int download_bytes) +{ + uintptr_t hdr_addr; /* boot image header address */ + struct andr_img_hdr *hdr; /* boot image header */ + lbaint_t hdr_sectors; /* boot image header sectors */ + u8 *ramdisk_buffer; + u32 ramdisk_sector_start; + u32 ramdisk_sectors; + u32 kernel_sector_start; + u32 kernel_sectors; + u32 sectors_per_page; + disk_partition_t info; + int res; + + puts("Flashing zImage\n"); + + /* Get boot partition info */ + res = part_get_info_by_name(dev_desc, BOOT_PARTITION_NAME, &info); + if (res < 0) { + pr_err("cannot find boot partition"); + fastboot_fail("cannot find boot partition"); + return -1; + } + + /* Put boot image header in fastboot buffer after downloaded zImage */ + hdr_addr = (uintptr_t)download_buffer + ALIGN(download_bytes, PAGE_SIZE); + hdr = (struct andr_img_hdr *)hdr_addr; + + /* Read boot image header */ + hdr_sectors = fb_mmc_get_boot_header(dev_desc, &info, hdr); + if (hdr_sectors == 0) { + pr_err("unable to read boot image header"); + fastboot_fail("unable to read boot image header"); + return -1; + } + + /* Check if boot image has second stage in it (we don't support it) */ + if (hdr->second_size > 0) { + pr_err("moving second stage is not supported yet"); + fastboot_fail("moving second stage is not supported yet"); + return -1; + } + + /* Extract ramdisk location */ + sectors_per_page = hdr->page_size / info.blksz; + ramdisk_sector_start = info.start + sectors_per_page; + ramdisk_sector_start += DIV_ROUND_UP(hdr->kernel_size, hdr->page_size) * + sectors_per_page; + ramdisk_sectors = DIV_ROUND_UP(hdr->ramdisk_size, hdr->page_size) * + sectors_per_page; + + /* Read ramdisk and put it in fastboot buffer after boot image header */ + ramdisk_buffer = (u8 *)hdr + (hdr_sectors * info.blksz); + res = blk_dread(dev_desc, ramdisk_sector_start, ramdisk_sectors, + ramdisk_buffer); + if (res != ramdisk_sectors) { + pr_err("cannot read ramdisk from boot partition"); + fastboot_fail("cannot read ramdisk from boot partition"); + return -1; + } + + /* Write new kernel size to boot image header */ + hdr->kernel_size = download_bytes; + res = blk_dwrite(dev_desc, info.start, hdr_sectors, (void *)hdr); + if (res == 0) { + pr_err("cannot writeback boot image header"); + fastboot_fail("cannot write back boot image header"); + return -1; + } + + /* Write the new downloaded kernel */ + kernel_sector_start = info.start + sectors_per_page; + kernel_sectors = DIV_ROUND_UP(hdr->kernel_size, hdr->page_size) * + sectors_per_page; + res = blk_dwrite(dev_desc, kernel_sector_start, kernel_sectors, + download_buffer); + if (res == 0) { + pr_err("cannot write new kernel"); + fastboot_fail("cannot write new kernel"); + return -1; + } + + /* Write the saved ramdisk back */ + ramdisk_sector_start = info.start + sectors_per_page; + ramdisk_sector_start += DIV_ROUND_UP(hdr->kernel_size, hdr->page_size) * + sectors_per_page; + res = blk_dwrite(dev_desc, ramdisk_sector_start, ramdisk_sectors, + ramdisk_buffer); + if (res == 0) { + pr_err("cannot write back original ramdisk"); + fastboot_fail("cannot write back original ramdisk"); + return -1; + } + + puts("........ zImage was updated in boot partition\n"); + fastboot_okay(""); + return 0; +} +#endif + +void fb_mmc_flash_write(const char *cmd, void *download_buffer, + unsigned int download_bytes) +{ + struct blk_desc *dev_desc; + disk_partition_t info; + + 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"); + return; + } + +#if CONFIG_IS_ENABLED(EFI_PARTITION) + if (strcmp(cmd, CONFIG_FASTBOOT_GPT_NAME) == 0) { + printf("%s: updating MBR, Primary and Backup GPT(s)\n", + __func__); + if (is_valid_gpt_buf(dev_desc, download_buffer)) { + printf("%s: invalid GPT - refusing to write to flash\n", + __func__); + fastboot_fail("invalid GPT partition"); + return; + } + if (write_mbr_and_gpt_partitions(dev_desc, download_buffer)) { + printf("%s: writing GPT partitions failed\n", __func__); + fastboot_fail("writing GPT partitions failed"); + return; + } + printf("........ success\n"); + fastboot_okay(""); + return; + } +#endif + +#if CONFIG_IS_ENABLED(DOS_PARTITION) + if (strcmp(cmd, CONFIG_FASTBOOT_MBR_NAME) == 0) { + printf("%s: updating MBR\n", __func__); + if (is_valid_dos_buf(download_buffer)) { + printf("%s: invalid MBR - refusing to write to flash\n", + __func__); + fastboot_fail("invalid MBR partition"); + return; + } + if (write_mbr_partition(dev_desc, download_buffer)) { + printf("%s: writing MBR partition failed\n", __func__); + fastboot_fail("writing MBR partition failed"); + return; + } + printf("........ success\n"); + fastboot_okay(""); + return; + } +#endif + +#ifdef CONFIG_ANDROID_BOOT_IMAGE + if (strncasecmp(cmd, "zimage", 6) == 0) { + fb_mmc_update_zimage(dev_desc, download_buffer, download_bytes); + return; + } +#endif + + 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"); + 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); + if (!err) + fastboot_okay(""); + } else { + write_raw_image(dev_desc, &info, cmd, download_buffer, + download_bytes); + } +} + +void fb_mmc_erase(const char *cmd) +{ + int ret; + struct blk_desc *dev_desc; + disk_partition_t info; + lbaint_t blks, blks_start, blks_size, grp_size; + struct mmc *mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV); + + if (mmc == NULL) { + pr_err("invalid mmc device"); + fastboot_fail("invalid mmc device"); + 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"); + fastboot_fail("invalid mmc device"); + return; + } + + ret = part_get_info_by_name_or_alias(dev_desc, cmd, &info); + if (ret < 0) { + pr_err("cannot find partition: '%s'", cmd); + fastboot_fail("cannot find partition"); + 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 = blk_derase(dev_desc, blks_start, blks_size); + if (blks != blks_size) { + pr_err("failed erasing from device %d", dev_desc->devnum); + fastboot_fail("failed erasing from device"); + return; + } + + printf("........ erased " LBAFU " bytes from '%s'\n", + blks_size * info.blksz, cmd); + fastboot_okay(""); +} diff --git a/drivers/fastboot/fb_nand.c b/drivers/fastboot/fb_nand.c new file mode 100644 index 00000000000..c07655e49ed --- /dev/null +++ b/drivers/fastboot/fb_nand.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2014 Broadcom Corporation. + * Copyright 2015 Free Electrons. + */ + +#include +#include + +#include +#include + +#include +#include +#include + +struct fb_nand_sparse { + struct mtd_info *mtd; + struct part_info *part; +}; + +__weak int board_fastboot_erase_partition_setup(char *name) +{ + return 0; +} + +__weak int board_fastboot_write_partition_setup(char *name) +{ + return 0; +} + +static int fb_nand_lookup(const char *partname, + struct mtd_info **mtd, + struct part_info **part) +{ + struct mtd_device *dev; + int ret; + u8 pnum; + + ret = mtdparts_init(); + if (ret) { + pr_err("Cannot initialize MTD partitions\n"); + fastboot_fail("cannot init mtdparts"); + return ret; + } + + ret = find_dev_and_part(partname, &dev, &pnum, part); + if (ret) { + pr_err("cannot find partition: '%s'", partname); + fastboot_fail("cannot find partition"); + return ret; + } + + if (dev->id->type != MTD_DEV_TYPE_NAND) { + pr_err("partition '%s' is not stored on a NAND device", + partname); + fastboot_fail("not a NAND device"); + return -EINVAL; + } + + *mtd = get_nand_dev_by_index(dev->id->num); + + return 0; +} + +static int _fb_nand_erase(struct mtd_info *mtd, struct part_info *part) +{ + nand_erase_options_t opts; + int ret; + + memset(&opts, 0, sizeof(opts)); + opts.offset = part->offset; + opts.length = part->size; + opts.quiet = 1; + + printf("Erasing blocks 0x%llx to 0x%llx\n", + part->offset, part->offset + part->size); + + ret = nand_erase_opts(mtd, &opts); + if (ret) + return ret; + + printf("........ erased 0x%llx bytes from '%s'\n", + part->size, part->name); + + return 0; +} + +static int _fb_nand_write(struct mtd_info *mtd, struct part_info *part, + void *buffer, unsigned int offset, + unsigned int length, size_t *written) +{ + int flags = WITH_WR_VERIFY; + +#ifdef CONFIG_FASTBOOT_FLASH_NAND_TRIMFFS + flags |= WITH_DROP_FFS; +#endif + + return nand_write_skip_bad(mtd, offset, &length, written, + part->size - (offset - part->offset), + buffer, flags); +} + +static lbaint_t fb_nand_sparse_write(struct sparse_storage *info, + lbaint_t blk, lbaint_t blkcnt, const void *buffer) +{ + struct fb_nand_sparse *sparse = info->priv; + size_t written; + int ret; + + ret = _fb_nand_write(sparse->mtd, sparse->part, (void *)buffer, + blk * info->blksz, + blkcnt * info->blksz, &written); + if (ret < 0) { + printf("Failed to write sparse chunk\n"); + return ret; + } + +/* TODO - verify that the value "written" includes the "bad-blocks" ... */ + + /* + * the return value must be 'blkcnt' ("good-blocks") plus the + * number of "bad-blocks" encountered within this space... + */ + return written / info->blksz; +} + +static lbaint_t fb_nand_sparse_reserve(struct sparse_storage *info, + lbaint_t blk, lbaint_t blkcnt) +{ + int bad_blocks = 0; + +/* + * TODO - implement a function to determine the total number + * of blocks which must be used in order to reserve the specified + * number ("blkcnt") of "good-blocks", starting at "blk"... + * ( possibly something like the "check_skip_len()" function ) + */ + + /* + * the return value must be 'blkcnt' ("good-blocks") plus the + * number of "bad-blocks" encountered within this space... + */ + return blkcnt + bad_blocks; +} + +void fb_nand_flash_write(const char *cmd, void *download_buffer, + unsigned int download_bytes) +{ + struct part_info *part; + struct mtd_info *mtd = NULL; + int ret; + + ret = fb_nand_lookup(cmd, &mtd, &part); + if (ret) { + pr_err("invalid NAND device"); + fastboot_fail("invalid NAND device"); + return; + } + + ret = board_fastboot_write_partition_setup(part->name); + if (ret) + return; + + if (is_sparse_image(download_buffer)) { + struct fb_nand_sparse sparse_priv; + struct sparse_storage sparse; + + sparse_priv.mtd = mtd; + sparse_priv.part = part; + + sparse.blksz = mtd->writesize; + sparse.start = part->offset / sparse.blksz; + sparse.size = part->size / sparse.blksz; + sparse.write = fb_nand_sparse_write; + sparse.reserve = fb_nand_sparse_reserve; + sparse.mssg = fastboot_fail; + + printf("Flashing sparse image at offset " LBAFU "\n", + sparse.start); + + sparse.priv = &sparse_priv; + ret = write_sparse_image(&sparse, cmd, download_buffer); + if (!ret) + fastboot_okay(""); + } else { + printf("Flashing raw image at offset 0x%llx\n", + part->offset); + + ret = _fb_nand_write(mtd, part, download_buffer, part->offset, + download_bytes, NULL); + + printf("........ wrote %u bytes to '%s'\n", + download_bytes, part->name); + } + + if (ret) { + fastboot_fail("error writing the image"); + return; + } + + fastboot_okay(""); +} + +void fb_nand_erase(const char *cmd) +{ + struct part_info *part; + struct mtd_info *mtd = NULL; + int ret; + + ret = fb_nand_lookup(cmd, &mtd, &part); + if (ret) { + pr_err("invalid NAND device"); + fastboot_fail("invalid NAND device"); + return; + } + + ret = board_fastboot_erase_partition_setup(part->name); + if (ret) + return; + + ret = _fb_nand_erase(mtd, part); + if (ret) { + pr_err("failed erasing from device %s", mtd->name); + fastboot_fail("failed erasing from device"); + return; + } + + fastboot_okay(""); +} -- cgit v1.2.3 From c4ded03ef608be37db105200010d2f3f88195bd6 Mon Sep 17 00:00:00 2001 From: Alex Kiernan Date: Tue, 29 May 2018 15:30:40 +0000 Subject: fastboot: Refactor fastboot_okay/fail to take response Add the response string as a parameter to fastboot_okay/fail, instead of modifying a global, to match the contract expected by the AOSP U-Boot code. Signed-off-by: Alex Kiernan Reviewed-by: Joe Hershberger --- drivers/fastboot/fb_mmc.c | 83 +++++++++++++++++++++++------------------ drivers/fastboot/fb_nand.c | 34 +++++++++-------- drivers/usb/gadget/f_fastboot.c | 35 +++++++---------- 3 files changed, 77 insertions(+), 75 deletions(-) (limited to 'drivers') diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c index 46f0073dbc2..1bcb2e52d49 100644 --- a/drivers/fastboot/fb_mmc.c +++ b/drivers/fastboot/fb_mmc.c @@ -73,7 +73,7 @@ static lbaint_t fb_mmc_sparse_reserve(struct sparse_storage *info, static void write_raw_image(struct blk_desc *dev_desc, disk_partition_t *info, const char *part_name, void *buffer, - unsigned int download_bytes) + unsigned int download_bytes, char *response) { lbaint_t blkcnt; lbaint_t blks; @@ -84,7 +84,7 @@ static void write_raw_image(struct blk_desc *dev_desc, disk_partition_t *info, if (blkcnt > info->size) { pr_err("too large for partition: '%s'\n", part_name); - fastboot_fail("too large for partition"); + fastboot_fail("too large for partition", response); return; } @@ -93,13 +93,13 @@ static void write_raw_image(struct blk_desc *dev_desc, disk_partition_t *info, blks = blk_dwrite(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"); + fastboot_fail("failed writing to device", response); return; } printf("........ wrote " LBAFU " bytes to '%s'\n", blkcnt * info->blksz, part_name); - fastboot_okay(""); + fastboot_okay(NULL, response); } #ifdef CONFIG_ANDROID_BOOT_IMAGE @@ -114,7 +114,8 @@ static void write_raw_image(struct blk_desc *dev_desc, disk_partition_t *info, */ static lbaint_t fb_mmc_get_boot_header(struct blk_desc *dev_desc, disk_partition_t *info, - struct andr_img_hdr *hdr) + struct andr_img_hdr *hdr, + char *response) { ulong sector_size; /* boot partition sector size */ lbaint_t hdr_sectors; /* boot image header sectors count */ @@ -125,7 +126,7 @@ static lbaint_t fb_mmc_get_boot_header(struct blk_desc *dev_desc, hdr_sectors = DIV_ROUND_UP(sizeof(struct andr_img_hdr), sector_size); if (hdr_sectors == 0) { pr_err("invalid number of boot sectors: 0"); - fastboot_fail("invalid number of boot sectors: 0"); + fastboot_fail("invalid number of boot sectors: 0", response); return 0; } @@ -133,7 +134,8 @@ static lbaint_t fb_mmc_get_boot_header(struct blk_desc *dev_desc, res = blk_dread(dev_desc, info->start, hdr_sectors, (void *)hdr); if (res != hdr_sectors) { pr_err("cannot read header from boot partition"); - fastboot_fail("cannot read header from boot partition"); + fastboot_fail("cannot read header from boot partition", + response); return 0; } @@ -141,7 +143,7 @@ static lbaint_t fb_mmc_get_boot_header(struct blk_desc *dev_desc, res = android_image_check_header(hdr); if (res != 0) { pr_err("bad boot image magic"); - fastboot_fail("boot partition not initialized"); + fastboot_fail("boot partition not initialized", response); return 0; } @@ -159,7 +161,8 @@ static lbaint_t fb_mmc_get_boot_header(struct blk_desc *dev_desc, */ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, void *download_buffer, - unsigned int download_bytes) + unsigned int download_bytes, + char *response) { uintptr_t hdr_addr; /* boot image header address */ struct andr_img_hdr *hdr; /* boot image header */ @@ -179,7 +182,7 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, res = part_get_info_by_name(dev_desc, BOOT_PARTITION_NAME, &info); if (res < 0) { pr_err("cannot find boot partition"); - fastboot_fail("cannot find boot partition"); + fastboot_fail("cannot find boot partition", response); return -1; } @@ -188,17 +191,18 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, hdr = (struct andr_img_hdr *)hdr_addr; /* Read boot image header */ - hdr_sectors = fb_mmc_get_boot_header(dev_desc, &info, hdr); + hdr_sectors = fb_mmc_get_boot_header(dev_desc, &info, hdr, response); if (hdr_sectors == 0) { pr_err("unable to read boot image header"); - fastboot_fail("unable to read boot image header"); + fastboot_fail("unable to read boot image header", response); return -1; } /* Check if boot image has second stage in it (we don't support it) */ if (hdr->second_size > 0) { pr_err("moving second stage is not supported yet"); - fastboot_fail("moving second stage is not supported yet"); + fastboot_fail("moving second stage is not supported yet", + response); return -1; } @@ -216,7 +220,8 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, ramdisk_buffer); if (res != ramdisk_sectors) { pr_err("cannot read ramdisk from boot partition"); - fastboot_fail("cannot read ramdisk from boot partition"); + fastboot_fail("cannot read ramdisk from boot partition", + response); return -1; } @@ -225,7 +230,7 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, res = blk_dwrite(dev_desc, info.start, hdr_sectors, (void *)hdr); if (res == 0) { pr_err("cannot writeback boot image header"); - fastboot_fail("cannot write back boot image header"); + fastboot_fail("cannot write back boot image header", response); return -1; } @@ -237,7 +242,7 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, download_buffer); if (res == 0) { pr_err("cannot write new kernel"); - fastboot_fail("cannot write new kernel"); + fastboot_fail("cannot write new kernel", response); return -1; } @@ -249,18 +254,18 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, ramdisk_buffer); if (res == 0) { pr_err("cannot write back original ramdisk"); - fastboot_fail("cannot write back original ramdisk"); + fastboot_fail("cannot write back original ramdisk", response); return -1; } puts("........ zImage was updated in boot partition\n"); - fastboot_okay(""); + fastboot_okay(NULL, response); return 0; } #endif void fb_mmc_flash_write(const char *cmd, void *download_buffer, - unsigned int download_bytes) + unsigned int download_bytes, char *response) { struct blk_desc *dev_desc; disk_partition_t info; @@ -268,7 +273,7 @@ void fb_mmc_flash_write(const char *cmd, void *download_buffer, 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"); + fastboot_fail("invalid mmc device", response); return; } @@ -279,16 +284,17 @@ void fb_mmc_flash_write(const char *cmd, void *download_buffer, if (is_valid_gpt_buf(dev_desc, download_buffer)) { printf("%s: invalid GPT - refusing to write to flash\n", __func__); - fastboot_fail("invalid GPT partition"); + fastboot_fail("invalid GPT partition", response); return; } if (write_mbr_and_gpt_partitions(dev_desc, download_buffer)) { printf("%s: writing GPT partitions failed\n", __func__); - fastboot_fail("writing GPT partitions failed"); + fastboot_fail("writing GPT partitions failed", + response); return; } printf("........ success\n"); - fastboot_okay(""); + fastboot_okay(NULL, response); return; } #endif @@ -299,30 +305,32 @@ void fb_mmc_flash_write(const char *cmd, void *download_buffer, if (is_valid_dos_buf(download_buffer)) { printf("%s: invalid MBR - refusing to write to flash\n", __func__); - fastboot_fail("invalid MBR partition"); + fastboot_fail("invalid MBR partition", response); return; } if (write_mbr_partition(dev_desc, download_buffer)) { printf("%s: writing MBR partition failed\n", __func__); - fastboot_fail("writing MBR partition failed"); + fastboot_fail("writing MBR partition failed", + response); return; } printf("........ success\n"); - fastboot_okay(""); + fastboot_okay(NULL, response); return; } #endif #ifdef CONFIG_ANDROID_BOOT_IMAGE if (strncasecmp(cmd, "zimage", 6) == 0) { - fb_mmc_update_zimage(dev_desc, download_buffer, download_bytes); + fb_mmc_update_zimage(dev_desc, download_buffer, + download_bytes, response); return; } #endif 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"); + fastboot_fail("cannot find partition", response); return; } @@ -344,16 +352,17 @@ void fb_mmc_flash_write(const char *cmd, void *download_buffer, sparse.start); sparse.priv = &sparse_priv; - err = write_sparse_image(&sparse, cmd, download_buffer); + err = write_sparse_image(&sparse, cmd, download_buffer, + response); if (!err) - fastboot_okay(""); + fastboot_okay(NULL, response); } else { write_raw_image(dev_desc, &info, cmd, download_buffer, - download_bytes); + download_bytes, response); } } -void fb_mmc_erase(const char *cmd) +void fb_mmc_erase(const char *cmd, char *response) { int ret; struct blk_desc *dev_desc; @@ -363,21 +372,21 @@ void fb_mmc_erase(const char *cmd) if (mmc == NULL) { pr_err("invalid mmc device"); - fastboot_fail("invalid mmc device"); + 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"); - fastboot_fail("invalid mmc device"); + fastboot_fail("invalid mmc device", response); return; } ret = part_get_info_by_name_or_alias(dev_desc, cmd, &info); if (ret < 0) { pr_err("cannot find partition: '%s'", cmd); - fastboot_fail("cannot find partition"); + fastboot_fail("cannot find partition", response); return; } @@ -396,11 +405,11 @@ void fb_mmc_erase(const char *cmd) blks = blk_derase(dev_desc, blks_start, blks_size); if (blks != blks_size) { pr_err("failed erasing from device %d", dev_desc->devnum); - fastboot_fail("failed erasing from device"); + fastboot_fail("failed erasing from device", response); return; } printf("........ erased " LBAFU " bytes from '%s'\n", blks_size * info.blksz, cmd); - fastboot_okay(""); + fastboot_okay(NULL, response); } diff --git a/drivers/fastboot/fb_nand.c b/drivers/fastboot/fb_nand.c index c07655e49ed..2ee0d644e0c 100644 --- a/drivers/fastboot/fb_nand.c +++ b/drivers/fastboot/fb_nand.c @@ -31,7 +31,8 @@ __weak int board_fastboot_write_partition_setup(char *name) static int fb_nand_lookup(const char *partname, struct mtd_info **mtd, - struct part_info **part) + struct part_info **part, + char *response) { struct mtd_device *dev; int ret; @@ -40,21 +41,21 @@ static int fb_nand_lookup(const char *partname, ret = mtdparts_init(); if (ret) { pr_err("Cannot initialize MTD partitions\n"); - fastboot_fail("cannot init mtdparts"); + fastboot_fail("cannot init mtdparts", response); return ret; } ret = find_dev_and_part(partname, &dev, &pnum, part); if (ret) { pr_err("cannot find partition: '%s'", partname); - fastboot_fail("cannot find partition"); + fastboot_fail("cannot find partition", response); return ret; } if (dev->id->type != MTD_DEV_TYPE_NAND) { pr_err("partition '%s' is not stored on a NAND device", partname); - fastboot_fail("not a NAND device"); + fastboot_fail("not a NAND device", response); return -EINVAL; } @@ -145,16 +146,16 @@ static lbaint_t fb_nand_sparse_reserve(struct sparse_storage *info, } void fb_nand_flash_write(const char *cmd, void *download_buffer, - unsigned int download_bytes) + unsigned int download_bytes, char *response) { struct part_info *part; struct mtd_info *mtd = NULL; int ret; - ret = fb_nand_lookup(cmd, &mtd, &part); + ret = fb_nand_lookup(cmd, &mtd, &part, response); if (ret) { pr_err("invalid NAND device"); - fastboot_fail("invalid NAND device"); + fastboot_fail("invalid NAND device", response); return; } @@ -180,9 +181,10 @@ void fb_nand_flash_write(const char *cmd, void *download_buffer, sparse.start); sparse.priv = &sparse_priv; - ret = write_sparse_image(&sparse, cmd, download_buffer); + ret = write_sparse_image(&sparse, cmd, download_buffer, + response); if (!ret) - fastboot_okay(""); + fastboot_okay(NULL, response); } else { printf("Flashing raw image at offset 0x%llx\n", part->offset); @@ -195,23 +197,23 @@ void fb_nand_flash_write(const char *cmd, void *download_buffer, } if (ret) { - fastboot_fail("error writing the image"); + fastboot_fail("error writing the image", response); return; } - fastboot_okay(""); + fastboot_okay(NULL, response); } -void fb_nand_erase(const char *cmd) +void fb_nand_erase(const char *cmd, char *response) { struct part_info *part; struct mtd_info *mtd = NULL; int ret; - ret = fb_nand_lookup(cmd, &mtd, &part); + ret = fb_nand_lookup(cmd, &mtd, &part, response); if (ret) { pr_err("invalid NAND device"); - fastboot_fail("invalid NAND device"); + fastboot_fail("invalid NAND device", response); return; } @@ -222,9 +224,9 @@ void fb_nand_erase(const char *cmd) ret = _fb_nand_erase(mtd, part); if (ret) { pr_err("failed erasing from device %s", mtd->name); - fastboot_fail("failed erasing from device"); + fastboot_fail("failed erasing from device", response); return; } - fastboot_okay(""); + fastboot_okay(NULL, response); } diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 3acadae8b17..bb60612647d 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -150,18 +150,16 @@ static void rx_handler_command(struct usb_ep *ep, struct usb_request *req); static int strcmp_l1(const char *s1, const char *s2); -static char *fb_response_str; - -void fastboot_fail(const char *reason) +void fastboot_fail(const char *reason, char *response) { - strncpy(fb_response_str, "FAIL\0", 5); - strncat(fb_response_str, reason, FASTBOOT_RESPONSE_LEN - 4 - 1); + strncpy(response, "FAIL\0", 5); + strncat(response, reason, FASTBOOT_RESPONSE_LEN - 4 - 1); } -void fastboot_okay(const char *reason) +void fastboot_okay(const char *reason, char *response) { - strncpy(fb_response_str, "OKAY\0", 5); - strncat(fb_response_str, reason, FASTBOOT_RESPONSE_LEN - 4 - 1); + strncpy(response, "OKAY\0", 5); + strncat(response, reason, FASTBOOT_RESPONSE_LEN - 4 - 1); } static void fastboot_complete(struct usb_ep *ep, struct usb_request *req) @@ -597,18 +595,14 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req) return; } - /* initialize the response buffer */ - fb_response_str = response; - - fastboot_fail("no flash device defined"); + fastboot_fail("no flash device defined", response); #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV fb_mmc_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR, - download_bytes); + download_bytes, response); #endif #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV - fb_nand_flash_write(cmd, - (void *)CONFIG_FASTBOOT_BUF_ADDR, - download_bytes); + fb_nand_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR, + download_bytes, response); #endif fastboot_tx_write_str(response); } @@ -649,15 +643,12 @@ static void cb_erase(struct usb_ep *ep, struct usb_request *req) return; } - /* initialize the response buffer */ - fb_response_str = response; - - fastboot_fail("no flash device defined"); + fastboot_fail("no flash device defined", response); #ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV - fb_mmc_erase(cmd); + fb_mmc_erase(cmd, response); #endif #ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV - fb_nand_erase(cmd); + fb_nand_erase(cmd, response); #endif fastboot_tx_write_str(response); } -- cgit v1.2.3 From d2df2abbcd4b88539605f8329edd244e6474d7a0 Mon Sep 17 00:00:00 2001 From: Alex Kiernan Date: Tue, 29 May 2018 15:30:41 +0000 Subject: fastboot: Extract fastboot_okay/fail to fb_common.c Add drivers/fastboot/fb_common.c, where fastboot_okay/fail are implemented so we can call them from a non-USB implementation. Introduce fastboot_response which takes varargs parameters so we can use it to generate formatted response strings. Refactor fastboot_okay/fail to use it. Signed-off-by: Alex Kiernan Reviewed-by: Joe Hershberger --- drivers/Makefile | 4 +-- drivers/fastboot/Makefile | 2 ++ drivers/fastboot/fb_common.c | 61 +++++++++++++++++++++++++++++++++++++++++ drivers/usb/gadget/f_fastboot.c | 13 --------- 4 files changed, 64 insertions(+), 16 deletions(-) create mode 100644 drivers/fastboot/fb_common.c (limited to 'drivers') diff --git a/drivers/Makefile b/drivers/Makefile index a79ff2e6b00..d29a6e467b6 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -71,9 +71,7 @@ obj-y += block/ obj-$(CONFIG_BOOTCOUNT_LIMIT) += bootcount/ obj-$(CONFIG_CPU) += cpu/ obj-y += crypto/ -ifneq ($(CONFIG_FASTBOOT_FLASH_MMC_DEV)$(CONFIG_FASTBOOT_FLASH_NAND_DEV),) -obj-y += fastboot/ -endif +obj-$(CONFIG_FASTBOOT) += fastboot/ obj-y += firmware/ obj-$(CONFIG_FPGA) += fpga/ obj-y += misc/ diff --git a/drivers/fastboot/Makefile b/drivers/fastboot/Makefile index 651fbf0935a..b38dcff2026 100644 --- a/drivers/fastboot/Makefile +++ b/drivers/fastboot/Makefile @@ -1,5 +1,7 @@ # SPDX-License-Identifier: GPL-2.0+ +obj-y += fb_common.o + ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV obj-y += fb_mmc.o endif diff --git a/drivers/fastboot/fb_common.c b/drivers/fastboot/fb_common.c new file mode 100644 index 00000000000..c4a7702bb3d --- /dev/null +++ b/drivers/fastboot/fb_common.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2008 - 2009 + * Windriver, + * Tom Rix + * + * Copyright 2011 Sebastian Andrzej Siewior + * + * Copyright 2014 Linaro, Ltd. + * Rob Herring + */ + +#include +#include + +/** + * fastboot_response() - Writes a response of the form "$tag$reason". + * + * @tag: The first part of the response + * @response: Pointer to fastboot response buffer + * @format: printf style format string + */ +void fastboot_response(const char *tag, char *response, + const char *format, ...) +{ + va_list args; + + strlcpy(response, tag, FASTBOOT_RESPONSE_LEN); + if (format) { + va_start(args, format); + vsnprintf(response + strlen(response), + FASTBOOT_RESPONSE_LEN - strlen(response) - 1, + format, args); + va_end(args); + } +} + +/** + * fastboot_fail() - Write a FAIL response of the form "FAIL$reason". + * + * @reason: Pointer to returned reason string + * @response: Pointer to fastboot response buffer + */ +void fastboot_fail(const char *reason, char *response) +{ + fastboot_response("FAIL", response, "%s", reason); +} + +/** + * fastboot_okay() - Write an OKAY response of the form "OKAY$reason". + * + * @reason: Pointer to returned reason string, or NULL to send a bare "OKAY" + * @response: Pointer to fastboot response buffer + */ +void fastboot_okay(const char *reason, char *response) +{ + if (reason) + fastboot_response("OKAY", response, "%s", reason); + else + fastboot_response("OKAY", response, NULL); +} diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index bb60612647d..2e6e1615bfc 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -149,19 +149,6 @@ static struct usb_gadget_strings *fastboot_strings[] = { static void rx_handler_command(struct usb_ep *ep, struct usb_request *req); static int strcmp_l1(const char *s1, const char *s2); - -void fastboot_fail(const char *reason, char *response) -{ - strncpy(response, "FAIL\0", 5); - strncat(response, reason, FASTBOOT_RESPONSE_LEN - 4 - 1); -} - -void fastboot_okay(const char *reason, char *response) -{ - strncpy(response, "OKAY\0", 5); - strncat(response, reason, FASTBOOT_RESPONSE_LEN - 4 - 1); -} - static void fastboot_complete(struct usb_ep *ep, struct usb_request *req) { int status = req->status; -- cgit v1.2.3 From 42d8dd4424099ad65400b34af1eb51258130e0b6 Mon Sep 17 00:00:00 2001 From: Alex Kiernan Date: Tue, 29 May 2018 15:30:42 +0000 Subject: fastboot: Correct dependencies in FASTBOOT_FLASH Ensure that when selecting FASTBOOT_FLASH you end up with a buildable configuration. Prior to this you could select NAND without MTDPARTS and end up with an image which (surprisingly) excluded NAND. Also fix dependencies on FASTBOOT_GPT_NAME/FASTBOOT_MBR_NAME which require you have EFI_PARTITION/DOS_PARTITION enabled. Delete redundant FASTBOOT_FLASH_NAND_DEV from Kconfig - it was only ever used as a guard and the value was ignored in all cases, we're using FASTBOOT_FLASH_NAND as the guard now. Signed-off-by: Alex Kiernan Reviewed-by: Joe Hershberger --- drivers/fastboot/Kconfig | 17 ++++------------- drivers/fastboot/Makefile | 8 ++------ drivers/usb/gadget/f_fastboot.c | 14 +++++++------- 3 files changed, 13 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig index 93a8ac64e76..9bbc5c661d4 100644 --- a/drivers/fastboot/Kconfig +++ b/drivers/fastboot/Kconfig @@ -56,6 +56,7 @@ config FASTBOOT_USB_DEV config FASTBOOT_FLASH bool "Enable FASTBOOT FLASH command" default y if ARCH_SUNXI + depends on MMC || (NAND && CMD_MTDPARTS) help The fastboot protocol includes a "flash" command for writing the downloaded image to a non-volatile storage device. Define @@ -71,7 +72,7 @@ config FASTBOOT_FLASH_MMC config FASTBOOT_FLASH_NAND bool "FASTBOOT on NAND" - depends on NAND + depends on NAND && CMD_MTDPARTS endchoice @@ -85,19 +86,9 @@ config FASTBOOT_FLASH_MMC_DEV regarding the non-volatile storage device. Define this to the eMMC device that fastboot should use to store the image. -config FASTBOOT_FLASH_NAND_DEV - int "Define FASTBOOT NAND FLASH default device" - depends on FASTBOOT_FLASH_NAND - depends on CMD_MTDPARTS - default 0 if ARCH_SUNXI && NAND_SUNXI - help - The fastboot "flash" command requires additional information - regarding the non-volatile storage device. Define this to - the NAND device that fastboot should use to store the image. - config FASTBOOT_GPT_NAME string "Target name for updating GPT" - depends on FASTBOOT_FLASH + depends on FASTBOOT_FLASH_MMC && EFI_PARTITION default "gpt" help The fastboot "flash" command supports writing the downloaded @@ -110,7 +101,7 @@ config FASTBOOT_GPT_NAME config FASTBOOT_MBR_NAME string "Target name for updating MBR" - depends on FASTBOOT_FLASH + depends on FASTBOOT_FLASH_MMC && DOS_PARTITION default "mbr" help The fastboot "flash" command allows to write the downloaded image diff --git a/drivers/fastboot/Makefile b/drivers/fastboot/Makefile index b38dcff2026..e4bd389adf0 100644 --- a/drivers/fastboot/Makefile +++ b/drivers/fastboot/Makefile @@ -2,9 +2,5 @@ obj-y += fb_common.o -ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV -obj-y += fb_mmc.o -endif -ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV -obj-y += fb_nand.o -endif +obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fb_mmc.o +obj-$(CONFIG_FASTBOOT_FLASH_NAND) += fb_nand.o diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 2e6e1615bfc..323ac89417a 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -20,10 +20,10 @@ #include #include #include -#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV +#ifdef CONFIG_FASTBOOT_FLASH_MMC #include #endif -#ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV +#ifdef CONFIG_FASTBOOT_FLASH_NAND #include #endif @@ -583,11 +583,11 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req) } fastboot_fail("no flash device defined", response); -#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV +#ifdef CONFIG_FASTBOOT_FLASH_MMC fb_mmc_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR, download_bytes, response); #endif -#ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV +#ifdef CONFIG_FASTBOOT_FLASH_NAND fb_nand_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR, download_bytes, response); #endif @@ -598,7 +598,7 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req) static void cb_oem(struct usb_ep *ep, struct usb_request *req) { char *cmd = req->buf; -#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV +#ifdef CONFIG_FASTBOOT_FLASH_MMC if (strncmp("format", cmd + 4, 6) == 0) { char cmdbuf[32]; sprintf(cmdbuf, "gpt write mmc %x $partitions", @@ -631,10 +631,10 @@ static void cb_erase(struct usb_ep *ep, struct usb_request *req) } fastboot_fail("no flash device defined", response); -#ifdef CONFIG_FASTBOOT_FLASH_MMC_DEV +#ifdef CONFIG_FASTBOOT_FLASH_MMC fb_mmc_erase(cmd, response); #endif -#ifdef CONFIG_FASTBOOT_FLASH_NAND_DEV +#ifdef CONFIG_FASTBOOT_FLASH_NAND fb_nand_erase(cmd, response); #endif fastboot_tx_write_str(response); -- cgit v1.2.3 From 1ad5facbdd5233a2c1288b7bcd79464435c32d37 Mon Sep 17 00:00:00 2001 From: Alex Kiernan Date: Tue, 29 May 2018 15:30:43 +0000 Subject: fastboot: Add missing newlines Add newlines so we format our output correctly. Signed-off-by: Alex Kiernan Acked-by: Joe Hershberger Reviewed-by: Jocelyn Bohr --- drivers/fastboot/fb_mmc.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c index 1bcb2e52d49..b1db29684d0 100644 --- a/drivers/fastboot/fb_mmc.c +++ b/drivers/fastboot/fb_mmc.c @@ -125,7 +125,7 @@ static lbaint_t fb_mmc_get_boot_header(struct blk_desc *dev_desc, sector_size = info->blksz; hdr_sectors = DIV_ROUND_UP(sizeof(struct andr_img_hdr), sector_size); if (hdr_sectors == 0) { - pr_err("invalid number of boot sectors: 0"); + pr_err("invalid number of boot sectors: 0\n"); fastboot_fail("invalid number of boot sectors: 0", response); return 0; } @@ -133,7 +133,7 @@ static lbaint_t fb_mmc_get_boot_header(struct blk_desc *dev_desc, /* Read the boot image header */ res = blk_dread(dev_desc, info->start, hdr_sectors, (void *)hdr); if (res != hdr_sectors) { - pr_err("cannot read header from boot partition"); + pr_err("cannot read header from boot partition\n"); fastboot_fail("cannot read header from boot partition", response); return 0; @@ -142,7 +142,7 @@ static lbaint_t fb_mmc_get_boot_header(struct blk_desc *dev_desc, /* Check boot header magic string */ res = android_image_check_header(hdr); if (res != 0) { - pr_err("bad boot image magic"); + pr_err("bad boot image magic\n"); fastboot_fail("boot partition not initialized", response); return 0; } @@ -181,7 +181,7 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, /* Get boot partition info */ res = part_get_info_by_name(dev_desc, BOOT_PARTITION_NAME, &info); if (res < 0) { - pr_err("cannot find boot partition"); + pr_err("cannot find boot partition\n"); fastboot_fail("cannot find boot partition", response); return -1; } @@ -193,14 +193,14 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, /* Read boot image header */ hdr_sectors = fb_mmc_get_boot_header(dev_desc, &info, hdr, response); if (hdr_sectors == 0) { - pr_err("unable to read boot image header"); + pr_err("unable to read boot image header\n"); fastboot_fail("unable to read boot image header", response); return -1; } /* Check if boot image has second stage in it (we don't support it) */ if (hdr->second_size > 0) { - pr_err("moving second stage is not supported yet"); + pr_err("moving second stage is not supported yet\n"); fastboot_fail("moving second stage is not supported yet", response); return -1; @@ -219,7 +219,7 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, res = blk_dread(dev_desc, ramdisk_sector_start, ramdisk_sectors, ramdisk_buffer); if (res != ramdisk_sectors) { - pr_err("cannot read ramdisk from boot partition"); + pr_err("cannot read ramdisk from boot partition\n"); fastboot_fail("cannot read ramdisk from boot partition", response); return -1; @@ -229,7 +229,7 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, hdr->kernel_size = download_bytes; res = blk_dwrite(dev_desc, info.start, hdr_sectors, (void *)hdr); if (res == 0) { - pr_err("cannot writeback boot image header"); + pr_err("cannot writeback boot image header\n"); fastboot_fail("cannot write back boot image header", response); return -1; } @@ -241,7 +241,7 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, res = blk_dwrite(dev_desc, kernel_sector_start, kernel_sectors, download_buffer); if (res == 0) { - pr_err("cannot write new kernel"); + pr_err("cannot write new kernel\n"); fastboot_fail("cannot write new kernel", response); return -1; } @@ -253,7 +253,7 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, res = blk_dwrite(dev_desc, ramdisk_sector_start, ramdisk_sectors, ramdisk_buffer); if (res == 0) { - pr_err("cannot write back original ramdisk"); + pr_err("cannot write back original ramdisk\n"); fastboot_fail("cannot write back original ramdisk", response); return -1; } @@ -371,21 +371,21 @@ void fb_mmc_erase(const char *cmd, char *response) struct mmc *mmc = find_mmc_device(CONFIG_FASTBOOT_FLASH_MMC_DEV); if (mmc == NULL) { - pr_err("invalid mmc device"); + 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"); + pr_err("invalid mmc device\n"); fastboot_fail("invalid mmc device", response); return; } ret = part_get_info_by_name_or_alias(dev_desc, cmd, &info); if (ret < 0) { - pr_err("cannot find partition: '%s'", cmd); + pr_err("cannot find partition: '%s'\n", cmd); fastboot_fail("cannot find partition", response); return; } @@ -404,7 +404,7 @@ void fb_mmc_erase(const char *cmd, char *response) blks = blk_derase(dev_desc, blks_start, blks_size); if (blks != blks_size) { - pr_err("failed erasing from device %d", dev_desc->devnum); + pr_err("failed erasing from device %d\n", dev_desc->devnum); fastboot_fail("failed erasing from device", response); return; } -- cgit v1.2.3 From 08f6bec456f06a6f5090ab6f23d0e18536008451 Mon Sep 17 00:00:00 2001 From: Alex Kiernan Date: Tue, 29 May 2018 15:30:44 +0000 Subject: fastboot: Remove FIXME for CONFIG_FASTBOOT_...NAME CONFIG_FASTBOOT_GPT_NAME and CONFIG_FASTBOOT_MBR_NAME are always defined by Kconfig if you're compiling this code, so remove these redundant defaults. Signed-off-by: Alex Kiernan Reviewed-by: Simon Glass Acked-by: Joe Hershberger --- drivers/fastboot/fb_mmc.c | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'drivers') diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c index b1db29684d0..038905face3 100644 --- a/drivers/fastboot/fb_mmc.c +++ b/drivers/fastboot/fb_mmc.c @@ -15,19 +15,6 @@ #include #include -/* - * FIXME: Ensure we always set these names via Kconfig once xxx_PARTITION is - * migrated - */ -#ifndef CONFIG_FASTBOOT_GPT_NAME -#define CONFIG_FASTBOOT_GPT_NAME "gpt" -#endif - - -#ifndef CONFIG_FASTBOOT_MBR_NAME -#define CONFIG_FASTBOOT_MBR_NAME "mbr" -#endif - #define BOOT_PARTITION_NAME "boot" struct fb_mmc_sparse { -- cgit v1.2.3 From 52fdf10708ef8022117c803609e85f295ad753c6 Mon Sep 17 00:00:00 2001 From: Alex Kiernan Date: Tue, 29 May 2018 15:30:45 +0000 Subject: fastboot: Fix parameter types in _fb_nand_write MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compiling on a 64 bit target the arguments to _fb_nand_write are incompatible: drivers/fastboot/fb_nand.c: In function ‘_fb_nand_write’: drivers/fastboot/fb_nand.c:101:42: warning: passing argument 3 of ‘nand_write_skip_bad’ from incompatible pointer type [-Wincompatible-pointer-types] return nand_write_skip_bad(mtd, offset, &length, written, ^ In file included from drivers/fastboot/fb_nand.c:16:0: include/nand.h:107:5: note: expected ‘size_t * {aka long unsigned int *}’ but argument is of type ‘unsigned int *’ int nand_write_skip_bad(struct mtd_info *mtd, loff_t offset, size_t *length, ^~~~~~~~~~~~~~~~~~~ Signed-off-by: Alex Kiernan Reviewed-by: Simon Glass Acked-by: Joe Hershberger --- drivers/fastboot/fb_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/fastboot/fb_nand.c b/drivers/fastboot/fb_nand.c index 2ee0d644e0c..849a6f16a51 100644 --- a/drivers/fastboot/fb_nand.c +++ b/drivers/fastboot/fb_nand.c @@ -89,7 +89,7 @@ static int _fb_nand_erase(struct mtd_info *mtd, struct part_info *part) static int _fb_nand_write(struct mtd_info *mtd, struct part_info *part, void *buffer, unsigned int offset, - unsigned int length, size_t *written) + size_t length, size_t *written) { int flags = WITH_WR_VERIFY; -- cgit v1.2.3 From 8a65bd63720b813d8082a2c14bdde5ade4673d87 Mon Sep 17 00:00:00 2001 From: Alex Kiernan Date: Tue, 29 May 2018 15:30:46 +0000 Subject: fastboot: Rename fb_set_reboot_flag to fastboot_set_reboot_flag Rename fb_set_reboot_flag to fastboot_set_reboot_flag so it matches all other fastboot code in the global name space. Fix the guards around them so that they're dependent on FASTBOOT, not just USB_FUNCTION_FASTBOOT. Move the weak implementation of fastboot_set_reboot_flag to fb_common.c so we can call it from non-USB fastboot code. Signed-off-by: Alex Kiernan Reviewed-by: Simon Glass Acked-by: Joe Hershberger --- drivers/fastboot/fb_common.c | 15 +++++++++++++++ drivers/usb/gadget/f_fastboot.c | 7 +------ 2 files changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/fastboot/fb_common.c b/drivers/fastboot/fb_common.c index c4a7702bb3d..79e080ac876 100644 --- a/drivers/fastboot/fb_common.c +++ b/drivers/fastboot/fb_common.c @@ -59,3 +59,18 @@ void fastboot_okay(const char *reason, char *response) else fastboot_response("OKAY", response, NULL); } + +/** + * fastboot_set_reboot_flag() - Set flag to indicate reboot-bootloader + * + * Set flag which indicates that we should reboot into the bootloader + * following the reboot that fastboot executes after this function. + * + * This function should be overridden in your board file with one + * which sets whatever flag your board specific Android bootloader flow + * requires in order to re-enter the bootloader. + */ +int __weak fastboot_set_reboot_flag(void) +{ + return -ENOSYS; +} diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 323ac89417a..697eee57d00 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -357,16 +357,11 @@ static void compl_do_reset(struct usb_ep *ep, struct usb_request *req) do_reset(NULL, 0, 0, NULL); } -int __weak fb_set_reboot_flag(void) -{ - return -ENOSYS; -} - static void cb_reboot(struct usb_ep *ep, struct usb_request *req) { char *cmd = req->buf; if (!strcmp_l1("reboot-bootloader", cmd)) { - if (fb_set_reboot_flag()) { + if (fastboot_set_reboot_flag()) { fastboot_tx_write_str("FAILCannot set reboot flag"); return; } -- cgit v1.2.3 From 1a28d38c398ede6e077af01bdab49cffa1bdf194 Mon Sep 17 00:00:00 2001 From: Alex Kiernan Date: Tue, 29 May 2018 15:30:47 +0000 Subject: fastboot: Extract common definitions from USB fastboot Move FASTBOOT_VERSION to include/fastboot.h so when we merge the UDP code we only have one definition. Signed-off-by: Alex Kiernan Reviewed-by: Simon Glass Acked-by: Joe Hershberger --- drivers/usb/gadget/f_fastboot.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 697eee57d00..25784a193eb 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -27,8 +27,6 @@ #include #endif -#define FASTBOOT_VERSION "0.4" - #define FASTBOOT_INTERFACE_CLASS 0xff #define FASTBOOT_INTERFACE_SUB_CLASS 0x42 #define FASTBOOT_INTERFACE_PROTOCOL 0x03 -- cgit v1.2.3 From d1a119d4f058628a65dd3b95703bd779cd1a44c9 Mon Sep 17 00:00:00 2001 From: Alex Kiernan Date: Tue, 29 May 2018 15:30:48 +0000 Subject: fastboot: Rename public fb_ functions to fastboot_ Rename fb_mmc_flash_write/fb_mmc_erase/fb_nand_flash_write/fb_nand_erase to fastboot_... as they form a public interface Signed-off-by: Alex Kiernan Reviewed-by: Simon Glass --- drivers/fastboot/fb_mmc.c | 20 +++++++++++++++++--- drivers/fastboot/fb_nand.c | 20 +++++++++++++++++--- drivers/usb/gadget/f_fastboot.c | 12 ++++++------ 3 files changed, 40 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c index 038905face3..47fcf74b697 100644 --- a/drivers/fastboot/fb_mmc.c +++ b/drivers/fastboot/fb_mmc.c @@ -251,8 +251,16 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, } #endif -void fb_mmc_flash_write(const char *cmd, void *download_buffer, - unsigned int download_bytes, char *response) +/** + * fastboot_mmc_flash_write() - Write image to eMMC for fastboot + * + * @cmd: 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_mmc_flash_write(const char *cmd, void *download_buffer, + unsigned int download_bytes, char *response) { struct blk_desc *dev_desc; disk_partition_t info; @@ -349,7 +357,13 @@ void fb_mmc_flash_write(const char *cmd, void *download_buffer, } } -void fb_mmc_erase(const char *cmd, char *response) +/** + * fastboot_mmc_flash_erase() - Erase eMMC for fastboot + * + * @cmd: Named partition to erase + * @response: Pointer to fastboot response buffer + */ +void fastboot_mmc_erase(const char *cmd, char *response) { int ret; struct blk_desc *dev_desc; diff --git a/drivers/fastboot/fb_nand.c b/drivers/fastboot/fb_nand.c index 849a6f16a51..535f541eb86 100644 --- a/drivers/fastboot/fb_nand.c +++ b/drivers/fastboot/fb_nand.c @@ -145,8 +145,16 @@ static lbaint_t fb_nand_sparse_reserve(struct sparse_storage *info, return blkcnt + bad_blocks; } -void fb_nand_flash_write(const char *cmd, void *download_buffer, - unsigned int download_bytes, char *response) +/** + * fastboot_nand_flash_write() - Write image to NAND for fastboot + * + * @cmd: Named device to write image to + * @download_buffer: Pointer to image data + * @download_bytes: Size of image data + * @response: Pointer to fastboot response buffer + */ +void fastboot_nand_flash_write(const char *cmd, void *download_buffer, + unsigned int download_bytes, char *response) { struct part_info *part; struct mtd_info *mtd = NULL; @@ -204,7 +212,13 @@ void fb_nand_flash_write(const char *cmd, void *download_buffer, fastboot_okay(NULL, response); } -void fb_nand_erase(const char *cmd, char *response) +/** + * fastboot_nand_flash_erase() - Erase NAND for fastboot + * + * @cmd: Named device to erase + * @response: Pointer to fastboot response buffer + */ +void fastboot_nand_erase(const char *cmd, char *response) { struct part_info *part; struct mtd_info *mtd = NULL; diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 25784a193eb..07d6a621554 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -577,12 +577,12 @@ static void cb_flash(struct usb_ep *ep, struct usb_request *req) fastboot_fail("no flash device defined", response); #ifdef CONFIG_FASTBOOT_FLASH_MMC - fb_mmc_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR, - download_bytes, response); + fastboot_mmc_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR, + download_bytes, response); #endif #ifdef CONFIG_FASTBOOT_FLASH_NAND - fb_nand_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR, - download_bytes, response); + fastboot_nand_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR, + download_bytes, response); #endif fastboot_tx_write_str(response); } @@ -625,10 +625,10 @@ static void cb_erase(struct usb_ep *ep, struct usb_request *req) fastboot_fail("no flash device defined", response); #ifdef CONFIG_FASTBOOT_FLASH_MMC - fb_mmc_erase(cmd, response); + fastboot_mmc_erase(cmd, response); #endif #ifdef CONFIG_FASTBOOT_FLASH_NAND - fb_nand_erase(cmd, response); + fastboot_nand_erase(cmd, response); #endif fastboot_tx_write_str(response); } -- cgit v1.2.3 From 4085b90303790ca2f7b2633de78245e8fe98a87a Mon Sep 17 00:00:00 2001 From: Alex Kiernan Date: Tue, 29 May 2018 15:30:51 +0000 Subject: fastboot: Migrate FASTBOOT_FLASH_NAND_TRIMFFS to Kconfig Add FASTBOOT_FLASH_NAND_TRIMFFS to Kconfig; note there are no in-tree users of it. Signed-off-by: Alex Kiernan Reviewed-by: Simon Glass --- drivers/fastboot/Kconfig | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig index 9bbc5c661d4..1d7caaff996 100644 --- a/drivers/fastboot/Kconfig +++ b/drivers/fastboot/Kconfig @@ -86,6 +86,13 @@ config FASTBOOT_FLASH_MMC_DEV regarding the non-volatile storage device. Define this to the eMMC device that fastboot should use to store the image. +config FASTBOOT_FLASH_NAND_TRIMFFS + bool "Skip empty pages when flashing NAND" + depends on FASTBOOT_FLASH_NAND + help + When flashing NAND enable the DROP_FFS flag to drop trailing all-0xff + pages. + config FASTBOOT_GPT_NAME string "Target name for updating GPT" depends on FASTBOOT_FLASH_MMC && EFI_PARTITION -- cgit v1.2.3 From c232d14d11e29c88f2c6149d2c152f496caa5889 Mon Sep 17 00:00:00 2001 From: Alex Kiernan Date: Tue, 29 May 2018 15:30:52 +0000 Subject: mmc: Separate "mmc swrite" from fastboot Introduce CONFIG_IMAGE_SPARSE and CONFIG_CMD_MMC_SWRITE so the "mmc swrite" command is separated from the fastboot code. Move image-sparse from common to lib so it's clear it's library code. Rename CONFIG_FASTBOOT_FLASH_FILLBUF_SIZE to CONFIG_IMAGE_SPARSE_FILLBUF_SIZE and migrate it to Kconfig. Signed-off-by: Alex Kiernan Acked-by: Jassi Brar Reviewed-by: Simon Glass --- drivers/fastboot/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig index 1d7caaff996..0c9ced53dea 100644 --- a/drivers/fastboot/Kconfig +++ b/drivers/fastboot/Kconfig @@ -57,6 +57,7 @@ config FASTBOOT_FLASH bool "Enable FASTBOOT FLASH command" default y if ARCH_SUNXI depends on MMC || (NAND && CMD_MTDPARTS) + select IMAGE_SPARSE help The fastboot protocol includes a "flash" command for writing the downloaded image to a non-volatile storage device. Define -- cgit v1.2.3 From f73a7df984a9820d9beb829b32ccb5c3d55dc152 Mon Sep 17 00:00:00 2001 From: Alex Kiernan Date: Tue, 29 May 2018 15:30:53 +0000 Subject: net: fastboot: Merge AOSP UDP fastboot Merge UDP fastboot support from AOSP: https://android.googlesource.com/platform/external/u-boot/+/android-o-mr1-iot-preview-8 Signed-off-by: Alex Kiernan Signed-off-by: Alex Deymo Signed-off-by: Jocelyn Bohr Reviewed-by: Simon Glass --- drivers/fastboot/Kconfig | 7 + drivers/fastboot/Makefile | 3 +- drivers/fastboot/fb_command.c | 302 ++++++++++++++++++++++++++++++++++++++++++ drivers/fastboot/fb_common.c | 93 +++++++++++++ drivers/fastboot/fb_getvar.c | 230 ++++++++++++++++++++++++++++++++ drivers/fastboot/fb_mmc.c | 84 +++++++++++- drivers/fastboot/fb_nand.c | 19 ++- 7 files changed, 729 insertions(+), 9 deletions(-) create mode 100644 drivers/fastboot/fb_command.c create mode 100644 drivers/fastboot/fb_getvar.c (limited to 'drivers') diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig index 0c9ced53dea..625f0166003 100644 --- a/drivers/fastboot/Kconfig +++ b/drivers/fastboot/Kconfig @@ -14,6 +14,13 @@ config USB_FUNCTION_FASTBOOT help This enables the USB part of the fastboot gadget. +config UDP_FUNCTION_FASTBOOT + depends on NET + select FASTBOOT + bool "Enable fastboot protocol over UDP" + help + This enables the fastboot protocol over UDP. + if FASTBOOT config FASTBOOT_BUF_ADDR diff --git a/drivers/fastboot/Makefile b/drivers/fastboot/Makefile index e4bd389adf0..88310961814 100644 --- a/drivers/fastboot/Makefile +++ b/drivers/fastboot/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0+ obj-y += fb_common.o - +obj-$(CONFIG_UDP_FUNCTION_FASTBOOT) += fb_getvar.o +obj-$(CONFIG_UDP_FUNCTION_FASTBOOT) += fb_command.o obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fb_mmc.o obj-$(CONFIG_FASTBOOT_FLASH_NAND) += fb_nand.o diff --git a/drivers/fastboot/fb_command.c b/drivers/fastboot/fb_command.c new file mode 100644 index 00000000000..af4f5006943 --- /dev/null +++ b/drivers/fastboot/fb_command.c @@ -0,0 +1,302 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#include +#include +#include +#include +#include +#include +#include + +/** + * image_size - final fastboot image size + */ +static u32 image_size; + +/** + * fastboot_bytes_received - number of bytes received in the current download + */ +static u32 fastboot_bytes_received; + +/** + * fastboot_bytes_expected - number of bytes expected in the current download + */ +static u32 fastboot_bytes_expected; + +static void okay(char *, char *); +static void getvar(char *, char *); +static void download(char *, char *); +#if CONFIG_IS_ENABLED(FASTBOOT_FLASH) +static void flash(char *, char *); +static void erase(char *, char *); +#endif +static void reboot_bootloader(char *, char *); + +static const struct { + const char *command; + void (*dispatch)(char *cmd_parameter, char *response); +} commands[FASTBOOT_COMMAND_COUNT] = { + [FASTBOOT_COMMAND_GETVAR] = { + .command = "getvar", + .dispatch = getvar + }, + [FASTBOOT_COMMAND_DOWNLOAD] = { + .command = "download", + .dispatch = download + }, +#if CONFIG_IS_ENABLED(FASTBOOT_FLASH) + [FASTBOOT_COMMAND_FLASH] = { + .command = "flash", + .dispatch = flash + }, + [FASTBOOT_COMMAND_ERASE] = { + .command = "erase", + .dispatch = erase + }, +#endif + [FASTBOOT_COMMAND_BOOT] = { + .command = "boot", + .dispatch = okay + }, + [FASTBOOT_COMMAND_CONTINUE] = { + .command = "continue", + .dispatch = okay + }, + [FASTBOOT_COMMAND_REBOOT] = { + .command = "reboot", + .dispatch = okay + }, + [FASTBOOT_COMMAND_REBOOT_BOOTLOADER] = { + .command = "reboot-bootloader", + .dispatch = reboot_bootloader + }, + [FASTBOOT_COMMAND_SET_ACTIVE] = { + .command = "set_active", + .dispatch = okay + }, +}; + +/** + * fastboot_handle_command - Handle fastboot command + * + * @cmd_string: Pointer to command string + * @response: Pointer to fastboot response buffer + * + * Return: Executed command, or -1 if not recognized + */ +int fastboot_handle_command(char *cmd_string, char *response) +{ + int i; + char *cmd_parameter; + + cmd_parameter = cmd_string; + strsep(&cmd_parameter, ":"); + + for (i = 0; i < FASTBOOT_COMMAND_COUNT; i++) { + if (!strcmp(commands[i].command, cmd_string)) { + if (commands[i].dispatch) { + commands[i].dispatch(cmd_parameter, + response); + return i; + } else { + break; + } + } + } + + pr_err("command %s not recognized.\n", cmd_string); + fastboot_fail("unrecognized command", response); + return -1; +} + +/** + * okay() - Send bare OKAY response + * + * @cmd_parameter: Pointer to command parameter + * @response: Pointer to fastboot response buffer + * + * Send a bare OKAY fastboot response. This is used where the command is + * valid, but all the work is done after the response has been sent (e.g. + * boot, reboot etc.) + */ +static void okay(char *cmd_parameter, char *response) +{ + fastboot_okay(NULL, response); +} + +/** + * getvar() - Read a config/version variable + * + * @cmd_parameter: Pointer to command parameter + * @response: Pointer to fastboot response buffer + */ +static void getvar(char *cmd_parameter, char *response) +{ + fastboot_getvar(cmd_parameter, response); +} + +/** + * fastboot_download() - Start a download transfer from the client + * + * @cmd_parameter: Pointer to command parameter + * @response: Pointer to fastboot response buffer + */ +static void download(char *cmd_parameter, char *response) +{ + char *tmp; + + if (!cmd_parameter) { + fastboot_fail("Expected command parameter", response); + return; + } + fastboot_bytes_received = 0; + fastboot_bytes_expected = simple_strtoul(cmd_parameter, &tmp, 16); + if (fastboot_bytes_expected == 0) { + fastboot_fail("Expected nonzero image size", response); + return; + } + /* + * Nothing to download yet. Response is of the form: + * [DATA|FAIL]$cmd_parameter + * + * where cmd_parameter is an 8 digit hexadecimal number + */ + if (fastboot_bytes_expected > fastboot_buf_size) { + fastboot_fail(cmd_parameter, response); + } else { + printf("Starting download of %d bytes\n", + fastboot_bytes_expected); + fastboot_response("DATA", response, "%s", cmd_parameter); + } +} + +/** + * fastboot_data_remaining() - return bytes remaining in current transfer + * + * Return: Number of bytes left in the current download + */ +u32 fastboot_data_remaining(void) +{ + return fastboot_bytes_expected - fastboot_bytes_received; +} + +/** + * fastboot_data_download() - Copy image data to fastboot_buf_addr. + * + * @fastboot_data: Pointer to received fastboot data + * @fastboot_data_len: Length of received fastboot data + * @response: Pointer to fastboot response buffer + * + * Copies image data from fastboot_data to fastboot_buf_addr. Writes to + * response. fastboot_bytes_received is updated to indicate the number + * of bytes that have been transferred. + * + * On completion sets image_size and ${filesize} to the total size of the + * downloaded image. + */ +void fastboot_data_download(const void *fastboot_data, + unsigned int fastboot_data_len, + char *response) +{ +#define BYTES_PER_DOT 0x20000 + u32 pre_dot_num, now_dot_num; + + if (fastboot_data_len == 0 || + (fastboot_bytes_received + fastboot_data_len) > + fastboot_bytes_expected) { + fastboot_fail("Received invalid data length", + response); + return; + } + /* Download data to fastboot_buf_addr */ + memcpy(fastboot_buf_addr + fastboot_bytes_received, + fastboot_data, fastboot_data_len); + + pre_dot_num = fastboot_bytes_received / BYTES_PER_DOT; + fastboot_bytes_received += fastboot_data_len; + now_dot_num = fastboot_bytes_received / BYTES_PER_DOT; + + if (pre_dot_num != now_dot_num) { + putc('.'); + if (!(now_dot_num % 74)) + putc('\n'); + } + *response = '\0'; +} + +/** + * fastboot_data_complete() - Mark current transfer complete + * + * @response: Pointer to fastboot response buffer + * + * Set image_size and ${filesize} to the total size of the downloaded image. + */ +void fastboot_data_complete(char *response) +{ + /* Download complete. Respond with "OKAY" */ + fastboot_okay(NULL, response); + printf("\ndownloading of %d bytes finished\n", fastboot_bytes_received); + image_size = fastboot_bytes_received; + env_set_hex("filesize", image_size); + fastboot_bytes_expected = 0; + fastboot_bytes_received = 0; +} + +#if CONFIG_IS_ENABLED(FASTBOOT_FLASH) +/** + * flash() - write the downloaded image to the indicated partition. + * + * @cmd_parameter: Pointer to partition name + * @response: Pointer to fastboot response buffer + * + * Writes the previously downloaded image to the partition indicated by + * cmd_parameter. Writes to response. + */ +static void flash(char *cmd_parameter, char *response) +{ +#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) + fastboot_mmc_flash_write(cmd_parameter, fastboot_buf_addr, image_size, + response); +#endif +#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND) + fastboot_nand_flash_write(cmd_parameter, fastboot_buf_addr, image_size, + response); +#endif +} + +/** + * erase() - erase the indicated partition. + * + * @cmd_parameter: Pointer to partition name + * @response: Pointer to fastboot response buffer + * + * Erases the partition indicated by cmd_parameter (clear to 0x00s). Writes + * to response. + */ +static void erase(char *cmd_parameter, char *response) +{ +#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) + fastboot_mmc_erase(cmd_parameter, response); +#endif +#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND) + fastboot_nand_erase(cmd_parameter, response); +#endif +} +#endif + +/** + * reboot_bootloader() - Sets reboot bootloader flag. + * + * @cmd_parameter: Pointer to command parameter + * @response: Pointer to fastboot response buffer + */ +static void reboot_bootloader(char *cmd_parameter, char *response) +{ + if (fastboot_set_reboot_flag()) + fastboot_fail("Cannot set reboot flag", response); + else + fastboot_okay(NULL, response); +} diff --git a/drivers/fastboot/fb_common.c b/drivers/fastboot/fb_common.c index 79e080ac876..c6e06aab7aa 100644 --- a/drivers/fastboot/fb_common.c +++ b/drivers/fastboot/fb_common.c @@ -12,6 +12,22 @@ #include #include +#include + +/** + * fastboot_buf_addr - base address of the fastboot download buffer + */ +void *fastboot_buf_addr; + +/** + * fastboot_buf_size - size of the fastboot download buffer + */ +u32 fastboot_buf_size; + +/** + * fastboot_progress_callback - callback executed during long operations + */ +void (*fastboot_progress_callback)(const char *msg); /** * fastboot_response() - Writes a response of the form "$tag$reason". @@ -74,3 +90,80 @@ int __weak fastboot_set_reboot_flag(void) { return -ENOSYS; } + +/** + * fastboot_get_progress_callback() - Return progress callback + * + * Return: Pointer to function called during long operations + */ +void (*fastboot_get_progress_callback(void))(const char *) +{ + return fastboot_progress_callback; +} + +/** + * fastboot_boot() - Execute fastboot boot command + * + * If ${fastboot_bootcmd} is set, run that command to execute the boot + * process, if that returns, then exit the fastboot server and return + * control to the caller. + * + * Otherwise execute "bootm ", if that fails, reset + * the board. + */ +void fastboot_boot(void) +{ + char *s; + + s = env_get("fastboot_bootcmd"); + if (s) { + run_command(s, CMD_FLAG_ENV); + } else { + static char boot_addr_start[12]; + static char *const bootm_args[] = { + "bootm", boot_addr_start, NULL + }; + + snprintf(boot_addr_start, sizeof(boot_addr_start) - 1, + "0x%p", fastboot_buf_addr); + printf("Booting kernel at %s...\n\n\n", boot_addr_start); + + do_bootm(NULL, 0, 2, bootm_args); + + /* + * This only happens if image is somehow faulty so we start + * over. We deliberately leave this policy to the invocation + * of fastbootcmd if that's what's being run + */ + do_reset(NULL, 0, 0, NULL); + } +} + +/** + * fastboot_set_progress_callback() - set progress callback + * + * @progress: Pointer to progress callback + * + * Set a callback which is invoked periodically during long running operations + * (flash and erase). This can be used (for example) by the UDP transport to + * send INFO responses to keep the client alive whilst those commands are + * executing. + */ +void fastboot_set_progress_callback(void (*progress)(const char *msg)) +{ + fastboot_progress_callback = progress; +} + +/* + * fastboot_init() - initialise new fastboot protocol session + * + * @buf_addr: Pointer to download buffer, or NULL for default + * @buf_size: Size of download buffer, or zero for default + */ +void fastboot_init(void *buf_addr, u32 buf_size) +{ + 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); +} diff --git a/drivers/fastboot/fb_getvar.c b/drivers/fastboot/fb_getvar.c new file mode 100644 index 00000000000..4d264c985d7 --- /dev/null +++ b/drivers/fastboot/fb_getvar.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#include +#include +#include +#include +#include +#include +#include + +static void getvar_version(char *var_parameter, char *response); +static void getvar_bootloader_version(char *var_parameter, char *response); +static void getvar_downloadsize(char *var_parameter, char *response); +static void getvar_serialno(char *var_parameter, char *response); +static void getvar_version_baseband(char *var_parameter, char *response); +static void getvar_product(char *var_parameter, char *response); +static void getvar_current_slot(char *var_parameter, char *response); +static void getvar_slot_suffixes(char *var_parameter, char *response); +static void getvar_has_slot(char *var_parameter, char *response); +#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) +static void getvar_partition_type(char *part_name, char *response); +#endif +#if CONFIG_IS_ENABLED(FASTBOOT_FLASH) +static void getvar_partition_size(char *part_name, char *response); +#endif + +static const struct { + const char *variable; + void (*dispatch)(char *var_parameter, char *response); +} getvar_dispatch[] = { + { + .variable = "version", + .dispatch = getvar_version + }, { + .variable = "bootloader-version", + .dispatch = getvar_bootloader_version + }, { + .variable = "version-bootloader", + .dispatch = getvar_bootloader_version + }, { + .variable = "downloadsize", + .dispatch = getvar_downloadsize + }, { + .variable = "max-download-size", + .dispatch = getvar_downloadsize + }, { + .variable = "serialno", + .dispatch = getvar_serialno + }, { + .variable = "version-baseband", + .dispatch = getvar_version_baseband + }, { + .variable = "product", + .dispatch = getvar_product + }, { + .variable = "current-slot", + .dispatch = getvar_current_slot + }, { + .variable = "slot-suffixes", + .dispatch = getvar_slot_suffixes + }, { + .variable = "has_slot", + .dispatch = getvar_has_slot +#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) + }, { + .variable = "partition-type", + .dispatch = getvar_partition_type +#endif +#if CONFIG_IS_ENABLED(FASTBOOT_FLASH) + }, { + .variable = "partition-size", + .dispatch = getvar_partition_size +#endif + } +}; + +static void getvar_version(char *var_parameter, char *response) +{ + fastboot_okay(FASTBOOT_VERSION, response); +} + +static void getvar_bootloader_version(char *var_parameter, char *response) +{ + fastboot_okay(U_BOOT_VERSION, response); +} + +static void getvar_downloadsize(char *var_parameter, char *response) +{ + fastboot_response("OKAY", response, "0x%08x", fastboot_buf_size); +} + +static void getvar_serialno(char *var_parameter, char *response) +{ + const char *tmp = env_get("serial#"); + + if (tmp) + fastboot_okay(tmp, response); + else + fastboot_fail("Value not set", response); +} + +static void getvar_version_baseband(char *var_parameter, char *response) +{ + fastboot_okay("N/A", response); +} + +static void getvar_product(char *var_parameter, char *response) +{ + const char *board = env_get("board"); + + if (board) + fastboot_okay(board, response); + else + fastboot_fail("Board not set", response); +} + +static void getvar_current_slot(char *var_parameter, char *response) +{ + /* A/B not implemented, for now always return _a */ + fastboot_okay("_a", response); +} + +static void getvar_slot_suffixes(char *var_parameter, char *response) +{ + fastboot_okay("_a,_b", response); +} + +static void getvar_has_slot(char *part_name, char *response) +{ + if (part_name && (!strcmp(part_name, "boot") || + !strcmp(part_name, "system"))) + fastboot_okay("yes", response); + else + fastboot_okay("no", response); +} + +#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) +static void getvar_partition_type(char *part_name, char *response) +{ + int r; + struct blk_desc *dev_desc; + disk_partition_t part_info; + + r = fastboot_mmc_get_part_info(part_name, &dev_desc, &part_info, + response); + if (r >= 0) { + r = fs_set_blk_dev_with_part(dev_desc, r); + if (r < 0) + fastboot_fail("failed to set partition", response); + else + fastboot_okay(fs_get_type_name(), response); + } +} +#endif + +#if CONFIG_IS_ENABLED(FASTBOOT_FLASH) +static void getvar_partition_size(char *part_name, char *response) +{ + int r; + size_t size; + +#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC) + struct blk_desc *dev_desc; + disk_partition_t part_info; + + r = fastboot_mmc_get_part_info(part_name, &dev_desc, &part_info, + response); + if (r >= 0) + size = part_info.size; +#endif +#if CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND) + struct part_info *part_info; + + r = fastboot_nand_get_part_info(part_name, &part_info, response); + if (r >= 0) + size = part_info->size; +#endif + if (r >= 0) + fastboot_response("OKAY", response, "0x%016zx", size); +} +#endif + +/** + * fastboot_getvar() - Writes variable indicated by cmd_parameter to response. + * + * @cmd_parameter: Pointer to command parameter + * @response: Pointer to fastboot response buffer + * + * Look up cmd_parameter first as an environment variable of the form + * fastboot., if that exists return use its value to set + * response. + * + * Otherwise lookup the name of variable and execute the appropriate + * function to return the requested value. + */ +void fastboot_getvar(char *cmd_parameter, char *response) +{ + if (!cmd_parameter) { + fastboot_fail("missing var", response); + } else { +#define FASTBOOT_ENV_PREFIX "fastboot." + int i; + char *var_parameter = cmd_parameter; + char envstr[FASTBOOT_RESPONSE_LEN]; + const char *s; + + snprintf(envstr, sizeof(envstr) - 1, + FASTBOOT_ENV_PREFIX "%s", cmd_parameter); + s = env_get(envstr); + if (s) { + fastboot_response("OKAY", response, "%s", s); + return; + } + + strsep(&var_parameter, ":"); + for (i = 0; i < ARRAY_SIZE(getvar_dispatch); ++i) { + if (!strcmp(getvar_dispatch[i].variable, + cmd_parameter)) { + getvar_dispatch[i].dispatch(var_parameter, + response); + return; + } + } + pr_warn("WARNING: unknown variable: %s\n", cmd_parameter); + fastboot_fail("Variable not implemented", response); + } +} diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c index 47fcf74b697..4c1c7fd2cd8 100644 --- a/drivers/fastboot/fb_mmc.c +++ b/drivers/fastboot/fb_mmc.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,8 @@ #include #include +#define FASTBOOT_MAX_BLK_WRITE 16384 + #define BOOT_PARTITION_NAME "boot" struct fb_mmc_sparse { @@ -43,13 +46,48 @@ static int part_get_info_by_name_or_alias(struct blk_desc *dev_desc, return ret; } +/** + * 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 blk_dwrite(dev_desc, blk, blkcnt, buffer); + return fb_mmc_blk_write(dev_desc, blk, blkcnt, buffer); } static lbaint_t fb_mmc_sparse_reserve(struct sparse_storage *info, @@ -60,7 +98,7 @@ static lbaint_t fb_mmc_sparse_reserve(struct sparse_storage *info, static void write_raw_image(struct blk_desc *dev_desc, disk_partition_t *info, const char *part_name, void *buffer, - unsigned int download_bytes, char *response) + u32 download_bytes, char *response) { lbaint_t blkcnt; lbaint_t blks; @@ -77,7 +115,8 @@ static void write_raw_image(struct blk_desc *dev_desc, disk_partition_t *info, puts("Flashing Raw Image\n"); - blks = blk_dwrite(dev_desc, info->start, blkcnt, buffer); + 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); @@ -148,7 +187,7 @@ static lbaint_t fb_mmc_get_boot_header(struct blk_desc *dev_desc, */ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, void *download_buffer, - unsigned int download_bytes, + u32 download_bytes, char *response) { uintptr_t hdr_addr; /* boot image header address */ @@ -251,6 +290,38 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, } #endif +/** + * fastboot_mmc_get_part_info() - Lookup eMMC partion by name + * + * @part_name: Named partition to lookup + * @dev_desc: Pointer to returned blk_desc pointer + * @part_info: Pointer to returned disk_partition_t + * @response: Pointer to fastboot response buffer + */ +int fastboot_mmc_get_part_info(char *part_name, struct blk_desc **dev_desc, + disk_partition_t *part_info, char *response) +{ + int r; + + *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) { + fastboot_fail("partition not found", response); + return -ENOENT; + } + + 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; + } + + return r; +} + /** * fastboot_mmc_flash_write() - Write image to eMMC for fastboot * @@ -260,7 +331,7 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc, * @response: Pointer to fastboot response buffer */ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer, - unsigned int download_bytes, char *response) + u32 download_bytes, char *response) { struct blk_desc *dev_desc; disk_partition_t info; @@ -403,7 +474,8 @@ void fastboot_mmc_erase(const char *cmd, char *response) printf("Erasing blocks " LBAFU " to " LBAFU " due to alignment\n", blks_start, blks_start + blks_size); - blks = blk_derase(dev_desc, 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); diff --git a/drivers/fastboot/fb_nand.c b/drivers/fastboot/fb_nand.c index 535f541eb86..526bc12307f 100644 --- a/drivers/fastboot/fb_nand.c +++ b/drivers/fastboot/fb_nand.c @@ -88,7 +88,7 @@ static int _fb_nand_erase(struct mtd_info *mtd, struct part_info *part) } static int _fb_nand_write(struct mtd_info *mtd, struct part_info *part, - void *buffer, unsigned int offset, + void *buffer, u32 offset, size_t length, size_t *written) { int flags = WITH_WR_VERIFY; @@ -145,6 +145,21 @@ static lbaint_t fb_nand_sparse_reserve(struct sparse_storage *info, return blkcnt + bad_blocks; } +/** + * fastboot_nand_get_part_info() - Lookup NAND partion by name + * + * @part_name: Named device to lookup + * @part_info: Pointer to returned part_info pointer + * @response: Pointer to fastboot response buffer + */ +int fastboot_nand_get_part_info(char *part_name, struct part_info **part_info, + char *response) +{ + struct mtd_info *mtd = NULL; + + return fb_nand_lookup(part_name, &mtd, part_info, response); +} + /** * fastboot_nand_flash_write() - Write image to NAND for fastboot * @@ -154,7 +169,7 @@ static lbaint_t fb_nand_sparse_reserve(struct sparse_storage *info, * @response: Pointer to fastboot response buffer */ void fastboot_nand_flash_write(const char *cmd, void *download_buffer, - unsigned int download_bytes, char *response) + u32 download_bytes, char *response) { struct part_info *part; struct mtd_info *mtd = NULL; -- cgit v1.2.3 From 3845b9065fea9859bf2cd6413168e3cb4ba38f06 Mon Sep 17 00:00:00 2001 From: Alex Kiernan Date: Tue, 29 May 2018 15:30:54 +0000 Subject: fastboot: Add support for 'oem format' command Introduce 'oem format' which matches the USB implementation, guard this with CONFIG_FASTBOOT_CMD_OEM_FORMAT so that you can configure it out. Signed-off-by: Alex Kiernan Reviewed-by: Simon Glass --- drivers/fastboot/Kconfig | 8 ++++++++ drivers/fastboot/fb_command.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) (limited to 'drivers') diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig index 625f0166003..bc25ea1d9c7 100644 --- a/drivers/fastboot/Kconfig +++ b/drivers/fastboot/Kconfig @@ -124,6 +124,14 @@ config FASTBOOT_MBR_NAME specified on the "fastboot flash" command line matches the value defined here. The default target name for updating MBR is "mbr". +config FASTBOOT_CMD_OEM_FORMAT + bool "Enable the 'oem format' command" + depends on FASTBOOT_FLASH_MMC && CMD_GPT + help + Add support for the "oem format" command from a client. This + relies on the env variable partitions to contain the list of + partitions as required by the gpt command. + endif # FASTBOOT endmenu diff --git a/drivers/fastboot/fb_command.c b/drivers/fastboot/fb_command.c index af4f5006943..200f9910c56 100644 --- a/drivers/fastboot/fb_command.c +++ b/drivers/fastboot/fb_command.c @@ -34,6 +34,9 @@ static void flash(char *, char *); static void erase(char *, char *); #endif static void reboot_bootloader(char *, char *); +#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT) +static void oem_format(char *, char *); +#endif static const struct { const char *command; @@ -77,6 +80,12 @@ static const struct { .command = "set_active", .dispatch = okay }, +#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT) + [FASTBOOT_COMMAND_OEM_FORMAT] = { + .command = "oem format", + .dispatch = oem_format, + }, +#endif }; /** @@ -300,3 +309,27 @@ static void reboot_bootloader(char *cmd_parameter, char *response) else fastboot_okay(NULL, response); } + +#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT) +/** + * oem_format() - Execute the OEM format command + * + * @cmd_parameter: Pointer to command parameter + * @response: Pointer to fastboot response buffer + */ +static void oem_format(char *cmd_parameter, char *response) +{ + char cmdbuf[32]; + + if (!env_get("partitions")) { + fastboot_fail("partitions not set", response); + } else { + sprintf(cmdbuf, "gpt write mmc %x $partitions", + CONFIG_FASTBOOT_FLASH_MMC_DEV); + if (run_command(cmdbuf, 0)) + fastboot_fail("", response); + else + fastboot_okay(NULL, response); + } +} +#endif -- cgit v1.2.3 From 65c96757fe9ab3bd451674ac12271a5e3703153a Mon Sep 17 00:00:00 2001 From: Alex Kiernan Date: Tue, 29 May 2018 15:30:55 +0000 Subject: usb: fastboot: Convert USB f_fastboot to shared fastboot Convert USB fastboot code to use shared fastboot protocol. Signed-off-by: Alex Kiernan Reviewed-by: Simon Glass --- drivers/fastboot/Makefile | 4 +- drivers/usb/gadget/f_fastboot.c | 318 +++++----------------------------------- 2 files changed, 39 insertions(+), 283 deletions(-) (limited to 'drivers') diff --git a/drivers/fastboot/Makefile b/drivers/fastboot/Makefile index 88310961814..a2421565e23 100644 --- a/drivers/fastboot/Makefile +++ b/drivers/fastboot/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0+ obj-y += fb_common.o -obj-$(CONFIG_UDP_FUNCTION_FASTBOOT) += fb_getvar.o -obj-$(CONFIG_UDP_FUNCTION_FASTBOOT) += fb_command.o +obj-y += fb_getvar.o +obj-y += fb_command.o obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fb_mmc.o obj-$(CONFIG_FASTBOOT_FLASH_NAND) += fb_nand.o diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 07d6a621554..3ad4346f2d0 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -18,14 +18,7 @@ #include #include #include -#include #include -#ifdef CONFIG_FASTBOOT_FLASH_MMC -#include -#endif -#ifdef CONFIG_FASTBOOT_FLASH_NAND -#include -#endif #define FASTBOOT_INTERFACE_CLASS 0xff #define FASTBOOT_INTERFACE_SUB_CLASS 0x42 @@ -56,8 +49,6 @@ static inline struct f_fastboot *func_to_fastboot(struct usb_function *f) } static struct f_fastboot *fastboot_func; -static unsigned int download_size; -static unsigned int download_bytes; static struct usb_endpoint_descriptor fs_ep_in = { .bLength = USB_DT_ENDPOINT_SIZE, @@ -145,7 +136,6 @@ static struct usb_gadget_strings *fastboot_strings[] = { }; static void rx_handler_command(struct usb_ep *ep, struct usb_request *req); -static int strcmp_l1(const char *s1, const char *s2); static void fastboot_complete(struct usb_ep *ep, struct usb_request *req) { @@ -355,85 +345,9 @@ static void compl_do_reset(struct usb_ep *ep, struct usb_request *req) do_reset(NULL, 0, 0, NULL); } -static void cb_reboot(struct usb_ep *ep, struct usb_request *req) -{ - char *cmd = req->buf; - if (!strcmp_l1("reboot-bootloader", cmd)) { - if (fastboot_set_reboot_flag()) { - fastboot_tx_write_str("FAILCannot set reboot flag"); - return; - } - } - fastboot_func->in_req->complete = compl_do_reset; - fastboot_tx_write_str("OKAY"); -} - -static int strcmp_l1(const char *s1, const char *s2) -{ - if (!s1 || !s2) - return -1; - return strncmp(s1, s2, strlen(s1)); -} - -static void cb_getvar(struct usb_ep *ep, struct usb_request *req) -{ - char *cmd = req->buf; - char response[FASTBOOT_RESPONSE_LEN]; - const char *s; - size_t chars_left; - - strcpy(response, "OKAY"); - chars_left = sizeof(response) - strlen(response) - 1; - - strsep(&cmd, ":"); - if (!cmd) { - pr_err("missing variable"); - fastboot_tx_write_str("FAILmissing var"); - return; - } - - if (!strcmp_l1("version", cmd)) { - strncat(response, FASTBOOT_VERSION, chars_left); - } else if (!strcmp_l1("bootloader-version", cmd)) { - strncat(response, U_BOOT_VERSION, chars_left); - } else if (!strcmp_l1("downloadsize", cmd) || - !strcmp_l1("max-download-size", cmd)) { - char str_num[12]; - - sprintf(str_num, "0x%08x", CONFIG_FASTBOOT_BUF_SIZE); - strncat(response, str_num, chars_left); - } else if (!strcmp_l1("serialno", cmd)) { - s = env_get("serial#"); - if (s) - strncat(response, s, chars_left); - else - strcpy(response, "FAILValue not set"); - } else { - char *envstr; - - envstr = malloc(strlen("fastboot.") + strlen(cmd) + 1); - if (!envstr) { - fastboot_tx_write_str("FAILmalloc error"); - return; - } - - sprintf(envstr, "fastboot.%s", cmd); - s = env_get(envstr); - if (s) { - strncat(response, s, chars_left); - } else { - printf("WARNING: unknown variable: %s\n", cmd); - strcpy(response, "FAILVariable not implemented"); - } - - free(envstr); - } - fastboot_tx_write_str(response); -} - static unsigned int rx_bytes_expected(struct usb_ep *ep) { - int rx_remain = download_size - download_bytes; + int rx_remain = fastboot_data_remaining(); unsigned int rem; unsigned int maxpacket = ep->maxpacket; @@ -455,14 +369,12 @@ static unsigned int rx_bytes_expected(struct usb_ep *ep) return rx_remain; } -#define BYTES_PER_DOT 0x20000 static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) { - char response[FASTBOOT_RESPONSE_LEN]; - unsigned int transfer_size = download_size - download_bytes; + char response[FASTBOOT_RESPONSE_LEN] = {0}; + unsigned int transfer_size = fastboot_data_remaining(); const unsigned char *buffer = req->buf; unsigned int buffer_size = req->actual; - unsigned int pre_dot_num, now_dot_num; if (req->status != 0) { printf("Bad status: %d\n", req->status); @@ -472,33 +384,19 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) if (buffer_size < transfer_size) transfer_size = buffer_size; - memcpy((void *)CONFIG_FASTBOOT_BUF_ADDR + download_bytes, - buffer, transfer_size); - - pre_dot_num = download_bytes / BYTES_PER_DOT; - download_bytes += transfer_size; - now_dot_num = download_bytes / BYTES_PER_DOT; - - if (pre_dot_num != now_dot_num) { - putc('.'); - if (!(now_dot_num % 74)) - putc('\n'); - } + fastboot_data_download(buffer, transfer_size, response); + if (response[0]) { + fastboot_tx_write_str(response); + } else if (!fastboot_data_remaining()) { + fastboot_data_complete(response); - /* Check if transfer is done */ - if (download_bytes >= download_size) { /* - * Reset global transfer variable, keep download_bytes because - * it will be used in the next possible flashing command + * Reset global transfer variable */ - download_size = 0; req->complete = rx_handler_command; req->length = EP_BUFFER_SIZE; - strcpy(response, "OKAY"); fastboot_tx_write_str(response); - - printf("\ndownloading of %d bytes finished\n", download_bytes); } else { req->length = rx_bytes_expected(ep); } @@ -507,197 +405,55 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req) usb_ep_queue(ep, req, 0); } -static void cb_download(struct usb_ep *ep, struct usb_request *req) -{ - char *cmd = req->buf; - char response[FASTBOOT_RESPONSE_LEN]; - - strsep(&cmd, ":"); - download_size = simple_strtoul(cmd, NULL, 16); - download_bytes = 0; - - printf("Starting download of %d bytes\n", download_size); - - if (0 == download_size) { - strcpy(response, "FAILdata invalid size"); - } else if (download_size > CONFIG_FASTBOOT_BUF_SIZE) { - download_size = 0; - strcpy(response, "FAILdata too large"); - } else { - sprintf(response, "DATA%08x", download_size); - req->complete = rx_handler_dl_image; - req->length = rx_bytes_expected(ep); - } - fastboot_tx_write_str(response); -} - -static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req) -{ - char boot_addr_start[12]; - char *bootm_args[] = { "bootm", boot_addr_start, NULL }; - - puts("Booting kernel..\n"); - - sprintf(boot_addr_start, "0x%lx", (long)CONFIG_FASTBOOT_BUF_ADDR); - do_bootm(NULL, 0, 2, bootm_args); - - /* This only happens if image is somehow faulty so we start over */ - do_reset(NULL, 0, 0, NULL); -} - -static void cb_boot(struct usb_ep *ep, struct usb_request *req) -{ - fastboot_func->in_req->complete = do_bootm_on_complete; - fastboot_tx_write_str("OKAY"); -} - static void do_exit_on_complete(struct usb_ep *ep, struct usb_request *req) { g_dnl_trigger_detach(); } -static void cb_continue(struct usb_ep *ep, struct usb_request *req) +static void do_bootm_on_complete(struct usb_ep *ep, struct usb_request *req) { - fastboot_func->in_req->complete = do_exit_on_complete; - fastboot_tx_write_str("OKAY"); + fastboot_boot(); + do_exit_on_complete(ep, req); } -#ifdef CONFIG_FASTBOOT_FLASH -static void cb_flash(struct usb_ep *ep, struct usb_request *req) +static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) { - char *cmd = req->buf; - char response[FASTBOOT_RESPONSE_LEN]; + char *cmdbuf = req->buf; + char response[FASTBOOT_RESPONSE_LEN] = {0}; + int cmd = -1; - strsep(&cmd, ":"); - if (!cmd) { - pr_err("missing partition name"); - fastboot_tx_write_str("FAILmissing partition name"); + if (req->status != 0 || req->length == 0) return; - } - - fastboot_fail("no flash device defined", response); -#ifdef CONFIG_FASTBOOT_FLASH_MMC - fastboot_mmc_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR, - download_bytes, response); -#endif -#ifdef CONFIG_FASTBOOT_FLASH_NAND - fastboot_nand_flash_write(cmd, (void *)CONFIG_FASTBOOT_BUF_ADDR, - download_bytes, response); -#endif - fastboot_tx_write_str(response); -} -#endif -static void cb_oem(struct usb_ep *ep, struct usb_request *req) -{ - char *cmd = req->buf; -#ifdef CONFIG_FASTBOOT_FLASH_MMC - if (strncmp("format", cmd + 4, 6) == 0) { - char cmdbuf[32]; - sprintf(cmdbuf, "gpt write mmc %x $partitions", - CONFIG_FASTBOOT_FLASH_MMC_DEV); - if (run_command(cmdbuf, 0)) - fastboot_tx_write_str("FAIL"); - else - fastboot_tx_write_str("OKAY"); - } else -#endif - if (strncmp("unlock", cmd + 4, 8) == 0) { - fastboot_tx_write_str("FAILnot implemented"); - } - else { - fastboot_tx_write_str("FAILunknown oem command"); + if (req->actual < req->length) { + cmdbuf[req->actual] = '\0'; + cmd = fastboot_handle_command(cmdbuf, response); + } else { + pr_err("buffer overflow"); + fastboot_fail("buffer overflow", response); } -} -#ifdef CONFIG_FASTBOOT_FLASH -static void cb_erase(struct usb_ep *ep, struct usb_request *req) -{ - char *cmd = req->buf; - char response[FASTBOOT_RESPONSE_LEN]; - - strsep(&cmd, ":"); - if (!cmd) { - pr_err("missing partition name"); - fastboot_tx_write_str("FAILmissing partition name"); - return; + if (!strncmp("DATA", response, 4)) { + req->complete = rx_handler_dl_image; + req->length = rx_bytes_expected(ep); } - fastboot_fail("no flash device defined", response); -#ifdef CONFIG_FASTBOOT_FLASH_MMC - fastboot_mmc_erase(cmd, response); -#endif -#ifdef CONFIG_FASTBOOT_FLASH_NAND - fastboot_nand_erase(cmd, response); -#endif fastboot_tx_write_str(response); -} -#endif -struct cmd_dispatch_info { - char *cmd; - void (*cb)(struct usb_ep *ep, struct usb_request *req); -}; - -static const struct cmd_dispatch_info cmd_dispatch_info[] = { - { - .cmd = "reboot", - .cb = cb_reboot, - }, { - .cmd = "getvar:", - .cb = cb_getvar, - }, { - .cmd = "download:", - .cb = cb_download, - }, { - .cmd = "boot", - .cb = cb_boot, - }, { - .cmd = "continue", - .cb = cb_continue, - }, -#ifdef CONFIG_FASTBOOT_FLASH - { - .cmd = "flash", - .cb = cb_flash, - }, { - .cmd = "erase", - .cb = cb_erase, - }, -#endif - { - .cmd = "oem", - .cb = cb_oem, - }, -}; - -static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) -{ - char *cmdbuf = req->buf; - void (*func_cb)(struct usb_ep *ep, struct usb_request *req) = NULL; - int i; - - if (req->status != 0 || req->length == 0) - return; + if (!strncmp("OKAY", response, 4)) { + switch (cmd) { + case FASTBOOT_COMMAND_BOOT: + fastboot_func->in_req->complete = do_bootm_on_complete; + break; - for (i = 0; i < ARRAY_SIZE(cmd_dispatch_info); i++) { - if (!strcmp_l1(cmd_dispatch_info[i].cmd, cmdbuf)) { - func_cb = cmd_dispatch_info[i].cb; + case FASTBOOT_COMMAND_CONTINUE: + fastboot_func->in_req->complete = do_exit_on_complete; break; - } - } - if (!func_cb) { - pr_err("unknown command: %.*s", req->actual, cmdbuf); - fastboot_tx_write_str("FAILunknown command"); - } else { - if (req->actual < req->length) { - u8 *buf = (u8 *)req->buf; - buf[req->actual] = 0; - func_cb(ep, req); - } else { - pr_err("buffer overflow"); - fastboot_tx_write_str("FAILbuffer overflow"); + case FASTBOOT_COMMAND_REBOOT: + case FASTBOOT_COMMAND_REBOOT_BOOTLOADER: + fastboot_func->in_req->complete = compl_do_reset; + break; } } -- cgit v1.2.3