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 --- include/fastboot.h | 4 ++-- include/fb_mmc.h | 4 ++-- include/fb_nand.h | 4 ++-- include/image-sparse.h | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/fastboot.h b/include/fastboot.h index 009f1a72e10..ed52daeb1b8 100644 --- a/include/fastboot.h +++ b/include/fastboot.h @@ -15,7 +15,7 @@ /* The 64 defined bytes plus \0 */ #define FASTBOOT_RESPONSE_LEN (64 + 1) -void fastboot_fail(const char *reason); -void fastboot_okay(const char *reason); +void fastboot_fail(const char *reason, char *response); +void fastboot_okay(const char *reason, char *response); #endif /* _FASTBOOT_H_ */ diff --git a/include/fb_mmc.h b/include/fb_mmc.h index a2d7c4895fa..39a960cc9d7 100644 --- a/include/fb_mmc.h +++ b/include/fb_mmc.h @@ -4,5 +4,5 @@ */ void fb_mmc_flash_write(const char *cmd, void *download_buffer, - unsigned int download_bytes); -void fb_mmc_erase(const char *cmd); + unsigned int download_bytes, char *response); +void fb_mmc_erase(const char *cmd, char *response); diff --git a/include/fb_nand.h b/include/fb_nand.h index 3daae8c4ca4..2c92a4eb50f 100644 --- a/include/fb_nand.h +++ b/include/fb_nand.h @@ -5,5 +5,5 @@ */ void fb_nand_flash_write(const char *cmd, void *download_buffer, - unsigned int download_bytes); -void fb_nand_erase(const char *cmd); + unsigned int download_bytes, char *response); +void fb_nand_erase(const char *cmd, char *response); diff --git a/include/image-sparse.h b/include/image-sparse.h index f39dc16617f..234c237b845 100644 --- a/include/image-sparse.h +++ b/include/image-sparse.h @@ -23,7 +23,7 @@ struct sparse_storage { lbaint_t blk, lbaint_t blkcnt); - void (*mssg)(const char *str); + void (*mssg)(const char *str, char *response); }; static inline int is_sparse_image(void *buf) @@ -38,4 +38,4 @@ static inline int is_sparse_image(void *buf) } int write_sparse_image(struct sparse_storage *info, const char *part_name, - void *data); + void *data, char *response); -- cgit v1.3.1 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 --------- include/fastboot.h | 24 ++++++++++++++++ 5 files changed, 88 insertions(+), 16 deletions(-) create mode 100644 drivers/fastboot/fb_common.c (limited to 'include') 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; diff --git a/include/fastboot.h b/include/fastboot.h index ed52daeb1b8..6cd44d2ab92 100644 --- a/include/fastboot.h +++ b/include/fastboot.h @@ -15,7 +15,31 @@ /* The 64 defined bytes plus \0 */ #define FASTBOOT_RESPONSE_LEN (64 + 1) +/** + * 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, ...) + __attribute__ ((format (__printf__, 3, 4))); + +/** + * 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_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); #endif /* _FASTBOOT_H_ */ -- cgit v1.3.1 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 --- arch/arm/mach-omap2/boot-common.c | 4 ++-- arch/arm/mach-rockchip/rk3128-board.c | 4 ++-- arch/arm/mach-rockchip/rk322x-board.c | 4 ++-- board/amazon/kc1/kc1.c | 2 +- board/lg/sniper/sniper.c | 2 +- drivers/fastboot/fb_common.c | 15 +++++++++++++++ drivers/usb/gadget/f_fastboot.c | 7 +------ include/fastboot.h | 2 +- 8 files changed, 25 insertions(+), 15 deletions(-) (limited to 'include') diff --git a/arch/arm/mach-omap2/boot-common.c b/arch/arm/mach-omap2/boot-common.c index 0e9fd03fefb..b22b6713e5f 100644 --- a/arch/arm/mach-omap2/boot-common.c +++ b/arch/arm/mach-omap2/boot-common.c @@ -237,8 +237,8 @@ void arch_preboot_os(void) } #endif -#if defined(CONFIG_USB_FUNCTION_FASTBOOT) && !defined(CONFIG_ENV_IS_NOWHERE) -int fb_set_reboot_flag(void) +#if CONFIG_IS_ENABLED(FASTBOOT) && !CONFIG_IS_ENABLED(ENV_IS_NOWHERE) +int fastboot_set_reboot_flag(void) { printf("Setting reboot to fastboot flag ...\n"); env_set("dofastboot", "1"); diff --git a/arch/arm/mach-rockchip/rk3128-board.c b/arch/arm/mach-rockchip/rk3128-board.c index 48cd8ba81e0..7fd667a0b8e 100644 --- a/arch/arm/mach-rockchip/rk3128-board.c +++ b/arch/arm/mach-rockchip/rk3128-board.c @@ -111,8 +111,8 @@ int board_usb_cleanup(int index, enum usb_init_type init) } #endif -#if defined(CONFIG_USB_FUNCTION_FASTBOOT) -int fb_set_reboot_flag(void) +#if CONFIG_IS_ENABLED(FASTBOOT) +int fastboot_set_reboot_flag(void) { struct rk3128_grf *grf; diff --git a/arch/arm/mach-rockchip/rk322x-board.c b/arch/arm/mach-rockchip/rk322x-board.c index 99a60c4e2ee..7366d45ab6c 100644 --- a/arch/arm/mach-rockchip/rk322x-board.c +++ b/arch/arm/mach-rockchip/rk322x-board.c @@ -139,8 +139,8 @@ int board_usb_cleanup(int index, enum usb_init_type init) } #endif -#if defined(CONFIG_USB_FUNCTION_FASTBOOT) -int fb_set_reboot_flag(void) +#if CONFIG_IS_ENABLED(FASTBOOT) +int fastboot_set_reboot_flag(void) { struct rk322x_grf *grf; diff --git a/board/amazon/kc1/kc1.c b/board/amazon/kc1/kc1.c index d9ca18363cd..031fd110923 100644 --- a/board/amazon/kc1/kc1.c +++ b/board/amazon/kc1/kc1.c @@ -161,7 +161,7 @@ void get_board_serial(struct tag_serialnr *serialnr) omap_die_id_get_board_serial(serialnr); } -int fb_set_reboot_flag(void) +int fastboot_set_reboot_flag(void) { return omap_reboot_mode_store("b"); } diff --git a/board/lg/sniper/sniper.c b/board/lg/sniper/sniper.c index 34a7a11f053..a7de4c21674 100644 --- a/board/lg/sniper/sniper.c +++ b/board/lg/sniper/sniper.c @@ -173,7 +173,7 @@ void reset_misc(void) omap_reboot_mode_store(reboot_mode); } -int fb_set_reboot_flag(void) +int fastboot_set_reboot_flag(void) { return omap_reboot_mode_store("b"); } 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; } diff --git a/include/fastboot.h b/include/fastboot.h index 6cd44d2ab92..816e71b4d0d 100644 --- a/include/fastboot.h +++ b/include/fastboot.h @@ -41,5 +41,5 @@ void fastboot_fail(const char *reason, char *response); * @response: Pointer to fastboot response buffer */ void fastboot_okay(const char *reason, char *response); - +int fastboot_set_reboot_flag(void); #endif /* _FASTBOOT_H_ */ -- cgit v1.3.1 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 -- include/fastboot.h | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') 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 diff --git a/include/fastboot.h b/include/fastboot.h index 816e71b4d0d..bf3d9e2f672 100644 --- a/include/fastboot.h +++ b/include/fastboot.h @@ -12,6 +12,8 @@ #ifndef _FASTBOOT_H_ #define _FASTBOOT_H_ +#define FASTBOOT_VERSION "0.4" + /* The 64 defined bytes plus \0 */ #define FASTBOOT_RESPONSE_LEN (64 + 1) -- cgit v1.3.1 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 ++++++------ include/fb_mmc.h | 21 ++++++++++++++++++--- include/fb_nand.h | 20 +++++++++++++++++--- 5 files changed, 75 insertions(+), 18 deletions(-) (limited to 'include') 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); } diff --git a/include/fb_mmc.h b/include/fb_mmc.h index 39a960cc9d7..daca81a2017 100644 --- a/include/fb_mmc.h +++ b/include/fb_mmc.h @@ -3,6 +3,21 @@ * Copyright 2014 Broadcom Corporation. */ -void fb_mmc_flash_write(const char *cmd, void *download_buffer, - unsigned int download_bytes, char *response); -void fb_mmc_erase(const char *cmd, 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); + +/** + * 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); diff --git a/include/fb_nand.h b/include/fb_nand.h index 2c92a4eb50f..b5d4c0cc5f2 100644 --- a/include/fb_nand.h +++ b/include/fb_nand.h @@ -4,6 +4,20 @@ * Copyright 2015 Free Electrons. */ -void fb_nand_flash_write(const char *cmd, void *download_buffer, - unsigned int download_bytes, char *response); -void fb_nand_erase(const char *cmd, 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); +/** + * 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); -- cgit v1.3.1 From 0d488e8f508e697e3b8fb4a3d8bd4f61ca8a225f Mon Sep 17 00:00:00 2001 From: Alex Kiernan Date: Tue, 29 May 2018 15:30:50 +0000 Subject: fs: Add fs_get_type_name to return current filesystem name Add fs_get_type_name so we can get the current filesystem type. Signed-off-by: Alex Kiernan Reviewed-by: Simon Glass Reviewed-by: Joe Hershberger --- fs/fs.c | 13 +++++++++++++ include/fs.h | 10 ++++++++++ 2 files changed, 23 insertions(+) (limited to 'include') diff --git a/fs/fs.c b/fs/fs.c index 94cdc37debf..33808d549e0 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -265,6 +265,19 @@ static struct fstype_info *fs_get_info(int fstype) return info; } +/** + * fs_get_type_name() - Get type of current filesystem + * + * Return: Pointer to filesystem name + * + * Returns a string describing the current filesystem, or the sentinel + * "unsupported" for any unrecognised filesystem. + */ +const char *fs_get_type_name(void) +{ + return fs_get_info(fs_type)->name; +} + int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype) { struct fstype_info *info; diff --git a/include/fs.h b/include/fs.h index d703ed5027e..163da103b47 100644 --- a/include/fs.h +++ b/include/fs.h @@ -37,6 +37,16 @@ int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype); */ int fs_set_blk_dev_with_part(struct blk_desc *desc, int part); +/** + * fs_get_type_name() - Get type of current filesystem + * + * Return: Pointer to filesystem name + * + * Returns a string describing the current filesystem, or the sentinel + * "unsupported" for any unrecognised filesystem. + */ +const char *fs_get_type_name(void); + /* * Print the list of files on the partition previously set by fs_set_blk_dev(), * in directory "dirname". -- cgit v1.3.1 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 --- cmd/Kconfig | 4 +- cmd/fastboot.c | 91 +++++++++++- 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 ++- include/fastboot-internal.h | 36 +++++ include/fastboot.h | 104 ++++++++++++++ include/fb_mmc.h | 18 ++- include/fb_nand.h | 19 ++- include/net.h | 2 +- include/net/fastboot.h | 21 +++ net/Makefile | 1 + net/fastboot.c | 317 ++++++++++++++++++++++++++++++++++++++++++ net/net.c | 7 + 18 files changed, 1338 insertions(+), 20 deletions(-) create mode 100644 drivers/fastboot/fb_command.c create mode 100644 drivers/fastboot/fb_getvar.c create mode 100644 include/fastboot-internal.h create mode 100644 include/net/fastboot.h create mode 100644 net/fastboot.c (limited to 'include') diff --git a/cmd/Kconfig b/cmd/Kconfig index 30cf63f172b..17ca0bb267d 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -655,8 +655,8 @@ config CMD_FASTBOOT This enables the command "fastboot" which enables the Android fastboot mode for the platform. Fastboot is a protocol for downloading images, flashing and device control used on - Android devices. Fastboot requires support for acting as a USB - device. + Android devices. Fastboot requires either the network stack + enabled or support for acting as a USB device. See doc/README.android-fastboot for more information. diff --git a/cmd/fastboot.c b/cmd/fastboot.c index a5ec5f46f63..557257aef84 100644 --- a/cmd/fastboot.c +++ b/cmd/fastboot.c @@ -10,10 +10,32 @@ #include #include #include +#include +#include #include -static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +static int do_fastboot_udp(int argc, char *const argv[], + uintptr_t buf_addr, size_t buf_size) { +#if CONFIG_IS_ENABLED(UDP_FUNCTION_FASTBOOT) + int err = net_loop(FASTBOOT); + + if (err < 0) { + printf("fastboot udp error: %d\n", err); + return CMD_RET_FAILURE; + } + + return CMD_RET_SUCCESS; +#else + pr_err("Fastboot UDP not enabled\n"); + return CMD_RET_FAILURE; +#endif +} + +static int do_fastboot_usb(int argc, char *const argv[], + uintptr_t buf_addr, size_t buf_size) +{ +#if CONFIG_IS_ENABLED(USB_FUNCTION_FASTBOOT) int controller_index; char *usb_controller; int ret; @@ -58,11 +80,70 @@ exit: board_usb_cleanup(controller_index, USB_INIT_DEVICE); return ret; +#else + pr_err("Fastboot USB not enabled\n"); + return CMD_RET_FAILURE; +#endif +} + +static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + uintptr_t buf_addr = (uintptr_t)NULL; + size_t buf_size = 0; + + if (argc < 2) + return CMD_RET_USAGE; + + while (argc > 1 && **(argv + 1) == '-') { + char *arg = *++argv; + + --argc; + while (*++arg) { + switch (*arg) { + case 'l': + if (--argc <= 0) + return CMD_RET_USAGE; + buf_addr = simple_strtoul(*++argv, NULL, 16); + goto NXTARG; + + case 's': + if (--argc <= 0) + return CMD_RET_USAGE; + buf_size = simple_strtoul(*++argv, NULL, 16); + goto NXTARG; + + default: + return CMD_RET_USAGE; + } + } +NXTARG: + ; + } + + fastboot_init((void *)buf_addr, buf_size); + + if (!strcmp(argv[1], "udp")) + return do_fastboot_udp(argc, argv, buf_addr, buf_size); + + if (!strcmp(argv[1], "usb")) { + argv++; + argc--; + } + + return do_fastboot_usb(argc, argv, buf_addr, buf_size); } +#ifdef CONFIG_SYS_LONGHELP +static char fastboot_help_text[] = + "[-l addr] [-s size] usb | udp\n" + "\taddr - address of buffer used during data transfers (" + __stringify(CONFIG_FASTBOOT_BUF_ADDR) ")\n" + "\tsize - size of buffer used during data transfers (" + __stringify(CONFIG_FASTBOOT_BUF_SIZE) ")" + ; +#endif + U_BOOT_CMD( - fastboot, 2, 1, do_fastboot, - "use USB Fastboot protocol", - "\n" - " - run as a fastboot usb device" + fastboot, CONFIG_SYS_MAXARGS, 1, do_fastboot, + "run as a fastboot usb or udp device", fastboot_help_text ); 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; diff --git a/include/fastboot-internal.h b/include/fastboot-internal.h new file mode 100644 index 00000000000..bf2f2b3c891 --- /dev/null +++ b/include/fastboot-internal.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#ifndef _FASTBOOT_INTERNAL_H_ +#define _FASTBOOT_INTERNAL_H_ + +/** + * fastboot_buf_addr - base address of the fastboot download buffer + */ +extern void *fastboot_buf_addr; + +/** + * fastboot_buf_size - size of the fastboot download buffer + */ +extern u32 fastboot_buf_size; + +/** + * fastboot_progress_callback - callback executed during long operations + */ +extern void (*fastboot_progress_callback)(const char *msg); + +/** + * 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); + +#endif diff --git a/include/fastboot.h b/include/fastboot.h index bf3d9e2f672..9a3d5ba693b 100644 --- a/include/fastboot.h +++ b/include/fastboot.h @@ -15,8 +15,28 @@ #define FASTBOOT_VERSION "0.4" /* The 64 defined bytes plus \0 */ +#define FASTBOOT_COMMAND_LEN (64 + 1) #define FASTBOOT_RESPONSE_LEN (64 + 1) +/** + * All known commands to fastboot + */ +enum { + FASTBOOT_COMMAND_GETVAR = 0, + FASTBOOT_COMMAND_DOWNLOAD, +#if CONFIG_IS_ENABLED(FASTBOOT_FLASH) + FASTBOOT_COMMAND_FLASH, + FASTBOOT_COMMAND_ERASE, +#endif + FASTBOOT_COMMAND_BOOT, + FASTBOOT_COMMAND_CONTINUE, + FASTBOOT_COMMAND_REBOOT, + FASTBOOT_COMMAND_REBOOT_BOOTLOADER, + FASTBOOT_COMMAND_SET_ACTIVE, + + FASTBOOT_COMMAND_COUNT +}; + /** * fastboot_response() - Writes a response of the form "$tag$reason". * @@ -43,5 +63,89 @@ void fastboot_fail(const char *reason, char *response); * @response: Pointer to fastboot response buffer */ void fastboot_okay(const char *reason, char *response); + +/** + * 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 fastboot_set_reboot_flag(void); + +/** + * 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_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_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); + +/** + * 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); + +/** + * fastboot_data_remaining() - return bytes remaining in current transfer + * + * Return: Number of bytes left in the current download + */ +u32 fastboot_data_remaining(void); + +/** + * 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. + */ +void fastboot_data_download(const void *fastboot_data, + unsigned int fastboot_data_len, char *response); + +/** + * 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); + #endif /* _FASTBOOT_H_ */ diff --git a/include/fb_mmc.h b/include/fb_mmc.h index daca81a2017..fd5db9eac87 100644 --- a/include/fb_mmc.h +++ b/include/fb_mmc.h @@ -3,6 +3,20 @@ * Copyright 2014 Broadcom Corporation. */ +#ifndef _FB_MMC_H_ +#define _FB_MMC_H_ + +/** + * 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); + /** * fastboot_mmc_flash_write() - Write image to eMMC for fastboot * @@ -12,8 +26,7 @@ * @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); /** * fastboot_mmc_flash_erase() - Erase eMMC for fastboot * @@ -21,3 +34,4 @@ void fastboot_mmc_flash_write(const char *cmd, void *download_buffer, * @response: Pointer to fastboot response buffer */ void fastboot_mmc_erase(const char *cmd, char *response); +#endif diff --git a/include/fb_nand.h b/include/fb_nand.h index b5d4c0cc5f2..08ab0e28a65 100644 --- a/include/fb_nand.h +++ b/include/fb_nand.h @@ -4,6 +4,21 @@ * Copyright 2015 Free Electrons. */ +#ifndef _FB_NAND_H_ +#define _FB_NAND_H_ + +#include + +/** + * 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); + /** * fastboot_nand_flash_write() - Write image to NAND for fastboot * @@ -13,7 +28,8 @@ * @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); + /** * fastboot_nand_flash_erase() - Erase NAND for fastboot * @@ -21,3 +37,4 @@ void fastboot_nand_flash_write(const char *cmd, void *download_buffer, * @response: Pointer to fastboot response buffer */ void fastboot_nand_erase(const char *cmd, char *response); +#endif diff --git a/include/net.h b/include/net.h index 65f51d77a55..57606855564 100644 --- a/include/net.h +++ b/include/net.h @@ -535,7 +535,7 @@ extern int net_restart_wrap; /* Tried all network devices */ enum proto_t { BOOTP, RARP, ARP, TFTPGET, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP, - TFTPSRV, TFTPPUT, LINKLOCAL + TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT }; extern char net_boot_file_name[1024];/* Boot File name */ diff --git a/include/net/fastboot.h b/include/net/fastboot.h new file mode 100644 index 00000000000..68602095d2b --- /dev/null +++ b/include/net/fastboot.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (C) 2016 The Android Open Source Project + */ + +#ifndef __NET_FASTBOOT_H__ +#define __NET_FASTBOOT_H__ + +/**********************************************************************/ +/* + * Global functions and variables. + */ + +/** + * Wait for incoming fastboot comands. + */ +void fastboot_start_server(void); + +/**********************************************************************/ + +#endif /* __NET_FASTBOOT_H__ */ diff --git a/net/Makefile b/net/Makefile index d1e8e01f62f..07466879f50 100644 --- a/net/Makefile +++ b/net/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_CMD_PING) += ping.o obj-$(CONFIG_CMD_RARP) += rarp.o obj-$(CONFIG_CMD_SNTP) += sntp.o obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o +obj-$(CONFIG_UDP_FUNCTION_FASTBOOT) += fastboot.o # Disable this warning as it is triggered by: # sprintf(buf, index ? "foo%d" : "foo", index) diff --git a/net/fastboot.c b/net/fastboot.c new file mode 100644 index 00000000000..a9f7c0743da --- /dev/null +++ b/net/fastboot.c @@ -0,0 +1,317 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Copyright (C) 2016 The Android Open Source Project + */ + +#include +#include +#include +#include + +/* Fastboot port # defined in spec */ +#define WELL_KNOWN_PORT 5554 + +enum { + FASTBOOT_ERROR = 0, + FASTBOOT_QUERY = 1, + FASTBOOT_INIT = 2, + FASTBOOT_FASTBOOT = 3, +}; + +struct __packed fastboot_header { + uchar id; + uchar flags; + unsigned short seq; +}; + +#define PACKET_SIZE 1024 +#define DATA_SIZE (PACKET_SIZE - sizeof(struct fastboot_header)) + +/* Sequence number sent for every packet */ +static unsigned short sequence_number = 1; +static const unsigned short packet_size = PACKET_SIZE; +static const unsigned short udp_version = 1; + +/* Keep track of last packet for resubmission */ +static uchar last_packet[PACKET_SIZE]; +static unsigned int last_packet_len; + +static struct in_addr fastboot_remote_ip; +/* The UDP port at their end */ +static int fastboot_remote_port; +/* The UDP port at our end */ +static int fastboot_our_port; + +static void boot_downloaded_image(void); + +#if CONFIG_IS_ENABLED(FASTBOOT_FLASH) +/** + * fastboot_udp_send_info() - Send an INFO packet during long commands. + * + * @msg: String describing the reason for waiting + */ +static void fastboot_udp_send_info(const char *msg) +{ + uchar *packet; + uchar *packet_base; + int len = 0; + char response[FASTBOOT_RESPONSE_LEN] = {0}; + + struct fastboot_header response_header = { + .id = FASTBOOT_FASTBOOT, + .flags = 0, + .seq = htons(sequence_number) + }; + ++sequence_number; + packet = net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE; + packet_base = packet; + + /* Write headers */ + memcpy(packet, &response_header, sizeof(response_header)); + packet += sizeof(response_header); + /* Write response */ + fastboot_response("INFO", response, "%s", msg); + memcpy(packet, response, strlen(response)); + packet += strlen(response); + + len = packet - packet_base; + + /* Save packet for retransmitting */ + last_packet_len = len; + memcpy(last_packet, packet_base, last_packet_len); + + net_send_udp_packet(net_server_ethaddr, fastboot_remote_ip, + fastboot_remote_port, fastboot_our_port, len); +} + +/** + * fastboot_timed_send_info() - Send INFO packet every 30 seconds + * + * @msg: String describing the reason for waiting + * + * Send an INFO packet during long commands based on timer. An INFO packet + * is sent if the time is 30 seconds after start. Else, noop. + */ +static void fastboot_timed_send_info(const char *msg) +{ + static ulong start; + + /* Initialize timer */ + if (start == 0) + start = get_timer(0); + ulong time = get_timer(start); + /* Send INFO packet to host every 30 seconds */ + if (time >= 30000) { + start = get_timer(0); + fastboot_udp_send_info(msg); + } +} +#endif + +/** + * fastboot_send() - Sends a packet in response to received fastboot packet + * + * @header: Header for response packet + * @fastboot_data: Pointer to received fastboot data + * @fastboot_data_len: Length of received fastboot data + * @retransmit: Nonzero if sending last sent packet + */ +static void fastboot_send(struct fastboot_header header, char *fastboot_data, + unsigned int fastboot_data_len, uchar retransmit) +{ + uchar *packet; + uchar *packet_base; + int len = 0; + const char *error_msg = "An error occurred."; + short tmp; + struct fastboot_header response_header = header; + static char command[FASTBOOT_COMMAND_LEN]; + static int cmd = -1; + static bool pending_command; + char response[FASTBOOT_RESPONSE_LEN] = {0}; + + /* + * We will always be sending some sort of packet, so + * cobble together the packet headers now. + */ + packet = net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE; + packet_base = packet; + + /* Resend last packet */ + if (retransmit) { + memcpy(packet, last_packet, last_packet_len); + net_send_udp_packet(net_server_ethaddr, fastboot_remote_ip, + fastboot_remote_port, fastboot_our_port, + last_packet_len); + return; + } + + response_header.seq = htons(response_header.seq); + memcpy(packet, &response_header, sizeof(response_header)); + packet += sizeof(response_header); + + switch (header.id) { + case FASTBOOT_QUERY: + tmp = htons(sequence_number); + memcpy(packet, &tmp, sizeof(tmp)); + packet += sizeof(tmp); + break; + case FASTBOOT_INIT: + tmp = htons(udp_version); + memcpy(packet, &tmp, sizeof(tmp)); + packet += sizeof(tmp); + tmp = htons(packet_size); + memcpy(packet, &tmp, sizeof(tmp)); + packet += sizeof(tmp); + break; + case FASTBOOT_ERROR: + memcpy(packet, error_msg, strlen(error_msg)); + packet += strlen(error_msg); + break; + case FASTBOOT_FASTBOOT: + if (cmd == FASTBOOT_COMMAND_DOWNLOAD) { + if (!fastboot_data_len && !fastboot_data_remaining()) { + fastboot_data_complete(response); + } else { + fastboot_data_download(fastboot_data, + fastboot_data_len, + response); + } + } else if (!pending_command) { + strlcpy(command, fastboot_data, + min((size_t)fastboot_data_len + 1, + sizeof(command))); + pending_command = true; + } else { + cmd = fastboot_handle_command(command, response); + pending_command = false; + } + /* + * Sent some INFO packets, need to update sequence number in + * header + */ + if (header.seq != sequence_number) { + response_header.seq = htons(sequence_number); + memcpy(packet_base, &response_header, + sizeof(response_header)); + } + /* Write response to packet */ + memcpy(packet, response, strlen(response)); + packet += strlen(response); + break; + default: + pr_err("ID %d not implemented.\n", header.id); + return; + } + + len = packet - packet_base; + + /* Save packet for retransmitting */ + last_packet_len = len; + memcpy(last_packet, packet_base, last_packet_len); + + net_send_udp_packet(net_server_ethaddr, fastboot_remote_ip, + fastboot_remote_port, fastboot_our_port, len); + + /* Continue boot process after sending response */ + if (!strncmp("OKAY", response, 4)) { + switch (cmd) { + case FASTBOOT_COMMAND_BOOT: + boot_downloaded_image(); + break; + + case FASTBOOT_COMMAND_CONTINUE: + net_set_state(NETLOOP_SUCCESS); + break; + + case FASTBOOT_COMMAND_REBOOT: + case FASTBOOT_COMMAND_REBOOT_BOOTLOADER: + do_reset(NULL, 0, 0, NULL); + break; + } + } + + if (!strncmp("OKAY", response, 4) || !strncmp("FAIL", response, 4)) + cmd = -1; +} + +/** + * boot_downloaded_image() - Boots into downloaded image. + */ +static void boot_downloaded_image(void) +{ + fastboot_boot(); + net_set_state(NETLOOP_SUCCESS); +} + +/** + * fastboot_handler() - Incoming UDP packet handler. + * + * @packet: Pointer to incoming UDP packet + * @dport: Destination UDP port + * @sip: Source IP address + * @sport: Source UDP port + * @len: Packet length + */ +static void fastboot_handler(uchar *packet, unsigned int dport, + struct in_addr sip, unsigned int sport, + unsigned int len) +{ + struct fastboot_header header; + char fastboot_data[DATA_SIZE] = {0}; + unsigned int fastboot_data_len = 0; + + if (dport != fastboot_our_port) + return; + + fastboot_remote_ip = sip; + fastboot_remote_port = sport; + + if (len < sizeof(struct fastboot_header) || len > PACKET_SIZE) + return; + memcpy(&header, packet, sizeof(header)); + header.flags = 0; + header.seq = ntohs(header.seq); + packet += sizeof(header); + len -= sizeof(header); + + switch (header.id) { + case FASTBOOT_QUERY: + fastboot_send(header, fastboot_data, 0, 0); + break; + case FASTBOOT_INIT: + case FASTBOOT_FASTBOOT: + fastboot_data_len = len; + if (len > 0) + memcpy(fastboot_data, packet, len); + if (header.seq == sequence_number) { + fastboot_send(header, fastboot_data, + fastboot_data_len, 0); + sequence_number++; + } else if (header.seq == sequence_number - 1) { + /* Retransmit last sent packet */ + fastboot_send(header, fastboot_data, + fastboot_data_len, 1); + } + break; + default: + pr_err("ID %d not implemented.\n", header.id); + header.id = FASTBOOT_ERROR; + fastboot_send(header, fastboot_data, 0, 0); + break; + } +} + +void fastboot_start_server(void) +{ + printf("Using %s device\n", eth_get_name()); + printf("Listening for fastboot command on %pI4\n", &net_ip); + + fastboot_our_port = WELL_KNOWN_PORT; + + fastboot_set_progress_callback(fastboot_timed_send_info); + net_set_udp_handler(fastboot_handler); + + /* zero out server ether in case the server ip has changed */ + memset(net_server_ethaddr, 0, 6); +} diff --git a/net/net.c b/net/net.c index 7f852114427..a4932f46d90 100644 --- a/net/net.c +++ b/net/net.c @@ -87,6 +87,7 @@ #include #include #include +#include #include #if defined(CONFIG_LED_STATUS) #include @@ -451,6 +452,11 @@ restart: tftp_start_server(); break; #endif +#ifdef CONFIG_UDP_FUNCTION_FASTBOOT + case FASTBOOT: + fastboot_start_server(); + break; +#endif #if defined(CONFIG_CMD_DHCP) case DHCP: bootp_reset(); @@ -1322,6 +1328,7 @@ common: /* Fall through */ case NETCONS: + case FASTBOOT: case TFTPSRV: if (net_ip.s_addr == 0) { puts("*** ERROR: `ipaddr' not set\n"); -- cgit v1.3.1 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 +++++++++++++++++++++++++++++++++ include/fastboot.h | 3 +++ 3 files changed, 44 insertions(+) (limited to 'include') 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 diff --git a/include/fastboot.h b/include/fastboot.h index 9a3d5ba693b..1933b1d98e3 100644 --- a/include/fastboot.h +++ b/include/fastboot.h @@ -33,6 +33,9 @@ enum { FASTBOOT_COMMAND_REBOOT, FASTBOOT_COMMAND_REBOOT_BOOTLOADER, FASTBOOT_COMMAND_SET_ACTIVE, +#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT) + FASTBOOT_COMMAND_OEM_FORMAT, +#endif FASTBOOT_COMMAND_COUNT }; -- cgit v1.3.1