From mboxrd@z Thu Jan 1 00:00:00 1970 From: Joe Hershberger Date: Thu, 3 May 2018 15:38:39 -0500 Subject: [U-Boot] [RFC PATCH v2 07/20] net: fastboot: Merge AOSP UDP fastboot In-Reply-To: <1525077174-6211-8-git-send-email-alex.kiernan@gmail.com> References: <1525077174-6211-1-git-send-email-alex.kiernan@gmail.com> <1525077174-6211-8-git-send-email-alex.kiernan@gmail.com> Message-ID: List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de On Mon, Apr 30, 2018 at 3:32 AM, Alex Kiernan wrote: > 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 > --- > > Changes in v2: > - ensure fastboot syntax is backward compatible - 'fastboot 0' means > 'fastboot usb 0' > > cmd/fastboot.c | 35 ++- > cmd/net.c | 6 + > drivers/fastboot/Kconfig | 16 +- > drivers/fastboot/fb_common.c | 18 ++ > drivers/fastboot/fb_mmc.c | 34 ++- > include/fastboot.h | 13 ++ > include/net.h | 6 +- > include/net/fastboot.h | 27 +++ > net/Makefile | 1 + > net/fastboot.c | 542 +++++++++++++++++++++++++++++++++++++++++++ > net/net.c | 9 + > 11 files changed, 695 insertions(+), 12 deletions(-) > create mode 100644 include/net/fastboot.h > create mode 100644 net/fastboot.c > > diff --git a/cmd/fastboot.c b/cmd/fastboot.c > index 8adcca5..68a41de 100644 > --- a/cmd/fastboot.c > +++ b/cmd/fastboot.c > @@ -11,17 +11,41 @@ > #include > #include > #include > +#include > #include > > static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) > { > +#ifdef CONFIG_USB_FUNCTION_FASTBOOT > int controller_index; > char *usb_controller; > int ret; > +#endif > > if (argc < 2) > return CMD_RET_USAGE; > > + if (!strcmp(argv[1], "udp")) { > +#ifndef CONFIG_UDP_FUNCTION_FASTBOOT > + pr_err("Fastboot UDP not enabled\n"); > + return -1; Commands should always return an enum command_ret_t. > +#else > + return do_fastboot_udp(cmdtp, flag, argc, argv); > +#endif > + } > + > + if (!strcmp(argv[1], "usb")) { > + argv++; > + argc--; > + } > + > + if (argc < 2) > + return CMD_RET_USAGE; > + > +#ifndef CONFIG_USB_FUNCTION_FASTBOOT > + pr_err("Fastboot USB not enabled\n"); > + return -1; Commands should always return an enum command_ret_t. > +#else > usb_controller = argv[1]; > controller_index = simple_strtoul(usb_controller, NULL, 0); > > @@ -59,11 +83,14 @@ exit: > board_usb_cleanup(controller_index, USB_INIT_DEVICE); > > return ret; > +#endif > } > > U_BOOT_CMD( > - fastboot, 2, 1, do_fastboot, > - "use USB Fastboot protocol", > - "\n" > - " - run as a fastboot usb device" > + fastboot, 3, 1, do_fastboot, > + "use USB or UDP Fastboot protocol", > + "[usb,udp] \n" > + " - run as a fastboot usb or udp device\n" > + " usb: specify \n" > + " udp: requires ip_addr set and ethernet initialized\n" > ); > diff --git a/cmd/net.c b/cmd/net.c > index 67888d4..668f344 100644 > --- a/cmd/net.c > +++ b/cmd/net.c > @@ -74,6 +74,12 @@ U_BOOT_CMD( > ); > #endif > > +#ifdef CONFIG_UDP_FUNCTION_FASTBOOT > +int do_fastboot_udp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) You should move this to cmd/fastboot.c and make it static. > +{ > + return netboot_common(FASTBOOT, cmdtp, argc, argv); Is this really what you want? You are passing these command parameters, but you don't really want them to be interpreted (as a load address or file name), right? I think you just want this: int err = net_loop(FASTBOOT); if (err < 0) { printf("fastboot udp error: %i\n", err); return CMD_RET_FAILURE; } return CMD_RET_SUCCESS; > +} > +#endif > > #ifdef CONFIG_CMD_RARP > int do_rarpb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) > diff --git a/drivers/fastboot/Kconfig b/drivers/fastboot/Kconfig > index 64b94f0..53c337f 100644 > --- a/drivers/fastboot/Kconfig > +++ b/drivers/fastboot/Kconfig > @@ -2,6 +2,8 @@ menu "Fastboot support" > > config FASTBOOT > bool > + imply ANDROID_BOOT_IMAGE > + imply CMD_FASTBOOT > > config USB_FUNCTION_FASTBOOT > bool "Enable USB fastboot gadget" > @@ -9,12 +11,17 @@ config USB_FUNCTION_FASTBOOT > default y if ARCH_SUNXI && USB_MUSB_GADGET > select FASTBOOT > select USB_GADGET_DOWNLOAD > - imply ANDROID_BOOT_IMAGE > - imply CMD_FASTBOOT > help > This enables the USB part of the fastboot gadget. > > -if USB_FUNCTION_FASTBOOT > +config UDP_FUNCTION_FASTBOOT > + depends on NET This is the correct level of dependency once you start using net_loop directly, but based on how you have it now, you would have to depend on CMD_NET. > + select FASTBOOT > + bool "Enable fastboot protocol over UDP" > + help > + This enables the fastboot protocol over UDP. > + > +if USB_FUNCTION_FASTBOOT || UDP_FUNCTION_FASTBOOT > > config FASTBOOT_BUF_ADDR > hex "Define FASTBOOT buffer address" > @@ -46,6 +53,7 @@ config FASTBOOT_BUF_SIZE > > 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 > @@ -117,6 +125,6 @@ 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". > > -endif # USB_FUNCTION_FASTBOOT > +endif # USB_FUNCTION_FASTBOOT || UDP_FUNCTION_FASTBOOT > > endmenu > diff --git a/drivers/fastboot/fb_common.c b/drivers/fastboot/fb_common.c > index fe58803..7367fbb 100644 > --- a/drivers/fastboot/fb_common.c > +++ b/drivers/fastboot/fb_common.c > @@ -12,6 +12,9 @@ > > #include > #include > +#ifdef CONFIG_UDP_FUNCTION_FASTBOOT > +#include > +#endif > > /** > * Writes a response to response buffer of the form "$tag$reason". > @@ -44,3 +47,18 @@ void fastboot_okay(const char *reason, char *response) > { > fastboot_response("OKAY", response, "%s", reason); > } > + > +void timed_send_info(ulong *start, const char *msg) This should be called fastboot_send_info()... it is in the global namespace! > +{ > +#ifdef CONFIG_UDP_FUNCTION_FASTBOOT > + /* Initialize timer */ > + if (*start == 0) You should probably be a little more defensive and check for NULL before dereferencing. > + *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_send_info(msg); This should call fastboot_(udp_)send_info() > + } > +#endif > +} > diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c > index 02864aa..304bda1 100644 > --- a/drivers/fastboot/fb_mmc.c > +++ b/drivers/fastboot/fb_mmc.c > @@ -29,6 +29,9 @@ > #define CONFIG_FASTBOOT_MBR_NAME "mbr" > #endif > > +#define FASTBOOT_MAX_BLK_WRITE 16384 > +static ulong timer; This timer seems like it should be a static variable inside of fastboot_send_info() (the function currently called timed_send_info). Then you don't have to pass it as a parameter and fb_mmc.c doesn't need to know what fb_common is doing with the info update. > + > #define BOOT_PARTITION_NAME "boot" > > struct fb_mmc_sparse { > @@ -57,13 +60,38 @@ static int part_get_info_by_name_or_alias(struct blk_desc *dev_desc, > return ret; > } > > +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) { > + timed_send_info(&timer, "writing"); > + blks_written = blk_dwrite(block_dev, blk, cur_blkcnt, > + buffer + (i * block_dev->blksz)); > + } else { > + timed_send_info(&timer, "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, > @@ -91,7 +119,7 @@ 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); > @@ -399,7 +427,7 @@ void fb_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", dev_desc->devnum); > fastboot_fail("failed erasing from device", response); > diff --git a/include/fastboot.h b/include/fastboot.h > index 2140c94..6f69423 100644 > --- a/include/fastboot.h > +++ b/include/fastboot.h > @@ -23,4 +23,17 @@ void fastboot_response(const char *tag, char *response, > void fastboot_fail(const char *reason, char *response); > void fastboot_okay(const char *reason, char *response); > > +/** > + * Send an INFO packet during long commands based on timer. If > + * CONFIG_UDP_FUNCTION_FASTBOOT is defined, an INFO packet is sent > + * if the time is 30 seconds after start. Else, noop. > + * > + * TODO: Handle the situation where both UDP and USB fastboot are > + * enabled. > + * > + * @param start: Time since last INFO packet was sent. > + * @param msg: String describing the reason for waiting > + */ > +void timed_send_info(ulong *start, const char *msg); > + > #endif /* _FASTBOOT_H_ */ > diff --git a/include/net.h b/include/net.h > index 3469811..890ae27 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 */ > @@ -549,6 +549,10 @@ extern char *net_dns_resolve; /* The host to resolve */ > extern char *net_dns_env_var; /* the env var to put the ip into */ > #endif > > +#if defined(CONFIG_UDP_FUNCTION_FASTBOOT) Probably not necessary to guard - the linker would complain if it's not there. > +int do_fastboot_udp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]); This would be better as a static function in cmd/fastboot.c > +#endif > + > #if defined(CONFIG_CMD_PING) > extern struct in_addr net_ping_ip; /* the ip address to ping */ > #endif > diff --git a/include/net/fastboot.h b/include/net/fastboot.h > new file mode 100644 > index 0000000..c0dd033 > --- /dev/null > +++ b/include/net/fastboot.h > @@ -0,0 +1,27 @@ > +/* 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); Since this is in the global namespace, it should probably be qualified... fastboot_udp_start_server() > +/** > + * Send an INFO packet during long commands > + * > + * @param msg: String describing the reason for waiting > + */ > +void fastboot_send_info(const char *msg); Same here... fastboot_udp_send_info() > + > +/**********************************************************************/ > + > +#endif /* __NET_FASTBOOT_H__ */ > diff --git a/net/Makefile b/net/Makefile > index ce6e5ad..3489ce5 100644 > --- a/net/Makefile > +++ b/net/Makefile > @@ -25,6 +25,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 0000000..32cb581 > --- /dev/null > +++ b/net/fastboot.c > @@ -0,0 +1,542 @@ > +// SPDX-License-Identifier: BSD-2-Clause > +/* > + * Copyright (C) 2016 The Android Open Source Project > + */ > + > +#include > +#include > +#include > +#include > +#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 FASTBOOT_HEADER_SIZE sizeof(struct fastboot_header) This define doesn't seem any better than just using the sizeof() directly. > +#define DATA_SIZE (PACKET_SIZE - FASTBOOT_HEADER_SIZE) > +#define FASTBOOT_VERSION "0.4" > + > +/* Sequence number sent for every packet */ > +static unsigned short fb_sequence_number = 1; > +static const unsigned short fb_packet_size = PACKET_SIZE; > +static const unsigned short fb_udp_version = 1; > + > +/* Keep track of last packet for resubmission */ > +static uchar last_packet[PACKET_SIZE]; > +static unsigned int last_packet_len; > + > +/* Parsed from first fastboot command packet */ > +static char *cmd_string; > +static char *cmd_parameter; > + > +/* Fastboot download parameters */ > +static unsigned int bytes_received; > +static unsigned int bytes_expected; These two are only ever used in fb_download(). They should be static variables in that function. > +static unsigned int image_size; > + > +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 fb_getvar(char *); > +static void fb_download(char *, unsigned int, char *); > +static void fb_flash(char *); > +static void fb_erase(char *); > +static void fb_continue(char *); > +static void fb_reboot(char *); > +static void boot_downloaded_image(void); > +static void cleanup_command_data(void); > +static void write_fb_response(const char *, const char *, char *); > + > +void fastboot_send_info(const char *msg) > +{ > + uchar *packet; > + uchar *packet_base; > + int len = 0; > + char response[FASTBOOT_RESPONSE_LEN] = {0}; > + > + struct fastboot_header fb_response_header = { > + .id = FASTBOOT_FASTBOOT, > + .flags = 0, > + .seq = htons(fb_sequence_number) > + }; > + ++fb_sequence_number; > + packet = net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE; > + packet_base = packet; > + > + /* Write headers */ > + memcpy(packet, &fb_response_header, sizeof(fb_response_header)); > + packet += sizeof(fb_response_header); > + /* Write response */ > + write_fb_response("INFO", msg, response); > + 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); > +} > + > +/** > + * Constructs and sends a packet in response to received fastboot packet > + * > + * @param fb_header Header for response packet > + * @param fastboot_data Pointer to received fastboot data > + * @param fastboot_data_len Length of received fastboot data > + * @param retransmit Nonzero if sending last sent packet > + */ > +static void fastboot_send(struct fastboot_header fb_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 fb_response_header = fb_header; > + 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; > + } > + > + fb_response_header.seq = htons(fb_response_header.seq); > + memcpy(packet, &fb_response_header, sizeof(fb_response_header)); > + packet += sizeof(fb_response_header); > + > + switch (fb_header.id) { > + case FASTBOOT_QUERY: > + tmp = htons(fb_sequence_number); > + memcpy(packet, &tmp, sizeof(tmp)); > + packet += sizeof(tmp); > + break; > + case FASTBOOT_INIT: > + tmp = htons(fb_udp_version); > + memcpy(packet, &tmp, sizeof(tmp)); > + packet += sizeof(tmp); > + tmp = htons(fb_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_string) { > + /* Parse command and send ack */ > + cmd_parameter = fastboot_data; This seems unnecessary. There are only 4 cases handled, and of them only download seems to be a command that happens more than once. And in download, the first past through this parameter is saved internally as bytes_expected. > + cmd_string = strsep(&cmd_parameter, ":"); > + cmd_string = strdup(cmd_string); > + if (cmd_parameter) > + cmd_parameter = strdup(cmd_parameter); > + } else if (!strcmp("getvar", cmd_string)) { > + fb_getvar(response); Seems like you should simply pass the "fastboot_data" as a parameter here rather than using a global. > + } else if (!strcmp("download", cmd_string)) { > + fb_download(fastboot_data, fastboot_data_len, response); > + } else if (!strcmp("flash", cmd_string)) { > + fb_flash(response); > + } else if (!strcmp("erase", cmd_string)) { > + fb_erase(response); > + } else if (!strcmp("boot", cmd_string)) { > + write_fb_response("OKAY", "", response); > + } else if (!strcmp("continue", cmd_string)) { > + fb_continue(response); > + } else if (!strncmp("reboot", cmd_string, 6)) { > + fb_reboot(response); > + } else if (!strcmp("set_active", cmd_string)) { > + /* A/B not implemented, for now do nothing */ > + write_fb_response("OKAY", "", response); > + } else { > + pr_err("command %s not implemented.\n", cmd_string); > + write_fb_response("FAIL", "unrecognized command", > + response); > + } > + /* Sent some INFO packets, need to update sequence number in > + * header > + */ > + if (fb_header.seq != fb_sequence_number) { > + fb_response_header.seq = htons(fb_sequence_number); > + memcpy(packet_base, &fb_response_header, > + sizeof(fb_response_header)); > + } > + /* Write response to packet */ > + memcpy(packet, response, strlen(response)); > + packet += strlen(response); > + break; > + default: > + pr_err("ID %d not implemented.\n", fb_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)) { > + if (!strcmp("boot", cmd_string)) { > + boot_downloaded_image(); > + } else if (!strcmp("continue", cmd_string)) { > + run_command(env_get("bootcmd"), CMD_FLAG_ENV); > + } else if (!strncmp("reboot", cmd_string, 6)) { > + /* Matches reboot or reboot-bootloader */ > + do_reset(NULL, 0, 0, NULL); > + } > + } > + > + /* OKAY and FAIL indicate command is complete */ > + if (!strncmp("OKAY", response, 4) || !strncmp("FAIL", response, 4)) > + cleanup_command_data(); > +} > + > +/** > + * Writes ascii string specified by cmd_parameter to response. > + * > + * @param repsonse Pointer to fastboot response buffer > + */ > +static void fb_getvar(char *response) > +{ > + if (!cmd_parameter) { > + write_fb_response("FAIL", "missing var", response); > + } else if (!strcmp("version", cmd_parameter)) { > + write_fb_response("OKAY", FASTBOOT_VERSION, response); > + } else if (!strcmp("bootloader-version", cmd_parameter) || > + !strcmp("version-bootloader", cmd_parameter)) { > + write_fb_response("OKAY", U_BOOT_VERSION, response); > + } else if (!strcmp("downloadsize", cmd_parameter) || > + !strcmp("max-download-size", cmd_parameter)) { > + char buf_size_str[12]; > + > + sprintf(buf_size_str, "0x%08x", CONFIG_FASTBOOT_BUF_SIZE); > + write_fb_response("OKAY", buf_size_str, response); > + } else if (!strcmp("serialno", cmd_parameter)) { > + const char *tmp = env_get("serial#"); > + > + if (tmp) > + write_fb_response("OKAY", tmp, response); > + else > + write_fb_response("FAIL", "Value not set", response); > + } else if (!strcmp("version-baseband", cmd_parameter)) { > + write_fb_response("OKAY", "N/A", response); > + } else if (!strcmp("product", cmd_parameter)) { > + const char *board = env_get("board"); > + > + if (board) > + write_fb_response("OKAY", board, response); > + else > + write_fb_response("FAIL", "Board not set", response); > + } else if (!strcmp("current-slot", cmd_parameter)) { > + /* A/B not implemented, for now always return _a */ > + write_fb_response("OKAY", "_a", response); > + } else if (!strcmp("slot-suffixes", cmd_parameter)) { > + write_fb_response("OKAY", "_a,_b", response); > + } else if (!strncmp("has-slot", cmd_parameter, 8)) { > + char *part_name = cmd_parameter; > + > + cmd_parameter = strsep(&part_name, ":"); > + if (!strcmp(part_name, "boot") || !strcmp(part_name, "system")) > + write_fb_response("OKAY", "yes", response); > + else > + write_fb_response("OKAY", "no", response); > + } else if (!strncmp("partition-type", cmd_parameter, 14) || > + !strncmp("partition-size", cmd_parameter, 14)) { > + disk_partition_t part_info; > + struct blk_desc *dev_desc; > + char *part_name = cmd_parameter; > + char part_size_str[20]; > + > + cmd_parameter = strsep(&part_name, ":"); > + dev_desc = blk_get_dev("mmc", 0); > + if (!dev_desc) { > + write_fb_response("FAIL", "block device not found", > + response); > + } else if (part_get_info_by_name(dev_desc, part_name, > + &part_info) < 0) { > + write_fb_response("FAIL", "partition not found", > + response); > + } else if (!strncmp("partition-type", cmd_parameter, 14)) { > + write_fb_response("OKAY", (char *)part_info.type, > + response); > + } else if (!strncmp("partition-size", cmd_parameter, 14)) { > + sprintf(part_size_str, "0x%016x", (int)part_info.size); > + write_fb_response("OKAY", part_size_str, response); > + } > + } else { > + printf("WARNING: unknown variable: %s\n", cmd_parameter); > + write_fb_response("FAIL", "Variable not implemented", > + response); > + } > +} > + > +/** > + * Copies image data from fastboot_data to CONFIG_FASTBOOT_BUF_ADDR. > + * Writes to response. > + * > + * @param fastboot_data Pointer to received fastboot data > + * @param fastboot_data_len Length of received fastboot data > + * @param repsonse Pointer to fastboot response buffer > + */ > +static void fb_download(char *fastboot_data, unsigned int fastboot_data_len, > + char *response) > +{ > + char *tmp; > + > + if (bytes_expected == 0) { > + if (!cmd_parameter) { > + write_fb_response("FAIL", "Expected command parameter", > + response); > + return; > + } > + bytes_expected = simple_strtoul(cmd_parameter, &tmp, 16); > + if (bytes_expected == 0) { > + write_fb_response("FAIL", "Expected nonzero image size", > + response); > + return; > + } > + } > + if (fastboot_data_len == 0 && bytes_received == 0) { > + /* Nothing to download yet. Response is of the form: > + * [DATA|FAIL]$cmd_parameter > + * > + * where cmd_parameter is an 8 digit hexadecimal number > + */ > + if (bytes_expected > CONFIG_FASTBOOT_BUF_SIZE) > + write_fb_response("FAIL", cmd_parameter, response); > + else > + write_fb_response("DATA", cmd_parameter, response); > + } else if (fastboot_data_len == 0 && > + (bytes_received >= bytes_expected)) { > + /* Download complete. Respond with "OKAY" */ > + write_fb_response("OKAY", "", response); > + image_size = bytes_received; > + bytes_expected = 0; > + bytes_received = 0; > + } else { > + if (fastboot_data_len == 0 || > + (bytes_received + fastboot_data_len) > bytes_expected) { > + write_fb_response("FAIL", > + "Received invalid data length", > + response); > + return; > + } > + /* Download data to CONFIG_FASTBOOT_BUF_ADDR */ > + memcpy((void *)CONFIG_FASTBOOT_BUF_ADDR + bytes_received, > + fastboot_data, fastboot_data_len); This is different than all the other approaches, which take the load address as a command parameter. Is there a good reason to have it baked in like this? > + bytes_received += fastboot_data_len; > + } > +} > + > +/** > + * Writes the previously downloaded image to the partition indicated by > + * cmd_parameter. Writes to response. > + * > + * @param repsonse Pointer to fastboot response buffer > + */ > +static void fb_flash(char *response) > +{ > + fb_mmc_flash_write(cmd_parameter, (void *)CONFIG_FASTBOOT_BUF_ADDR, > + image_size, response); It's peculiar that this hard-codes mmc. > +} > + > +/** > + * Erases the partition indicated by cmd_parameter (clear to 0x00s). Writes > + * to response. > + * > + * @param repsonse Pointer to fastboot response buffer > + */ > +static void fb_erase(char *response) > +{ > + fb_mmc_erase(cmd_parameter, response); > +} > + > +/** > + * Continues normal boot process by running "bootcmd". Writes > + * to response. > + * > + * @param repsonse Pointer to fastboot response buffer > + */ > +static void fb_continue(char *response) > +{ > + char *bootcmd; > + > + bootcmd = env_get("bootcmd"); > + if (bootcmd) > + write_fb_response("OKAY", "", response); > + else > + write_fb_response("FAIL", "bootcmd not set", response); > +} > + > +/** > + * Sets reboot bootloader flag if requested. Writes to response. > + * > + * @param repsonse Pointer to fastboot response buffer > + */ > +static void fb_reboot(char *response) > +{ > + write_fb_response("OKAY", "", response); > + if (!strcmp("reboot-bootloader", cmd_string)) > + strcpy((char *)CONFIG_FASTBOOT_BUF_ADDR, "reboot-bootloader"); > +} > + > +/** > + * Boots into downloaded image. > + */ > +static void boot_downloaded_image(void) > +{ > + char kernel_addr[12]; > + char *fdt_addr = env_get("fdt_addr_r"); > + char *const bootm_args[] = { > + "bootm", kernel_addr, "-", fdt_addr, NULL > + }; It seems like this should be able to affected from the host side... for instance choosing a config in an ITB. How is the fdt supposed to be populated in the scenario at all? > + > + sprintf(kernel_addr, "0x%lx", (long)CONFIG_FASTBOOT_BUF_ADDR); > + > + printf("\nBooting kernel at %s with fdt at %s...\n\n\n", > + kernel_addr, fdt_addr); > + do_bootm(NULL, 0, 4, bootm_args); > + > + /* This only happens if image is faulty so we start over. */ > + do_reset(NULL, 0, 0, NULL); > +} > + > +/** > + * Writes a response to response buffer of the form "$tag$reason". > + * > + * @param tag The first part of the response > + * @param reason The second part of the response > + * @param repsonse Pointer to fastboot response buffer > + */ > +static void write_fb_response(const char *tag, const char *reason, > + char *response) > +{ > + strncpy(response, tag, strlen(tag)); > + strncat(response, reason, FASTBOOT_RESPONSE_LEN - strlen(tag) - 1); > +} > + > +/** > + * Frees any resources allocated during current fastboot command. > + */ > +static void cleanup_command_data(void) > +{ > + /* cmd_parameter and cmd_string potentially point to memory allocated by Use correct multi-line comment format. "/*" on its own line. > + * strdup > + */ > + if (cmd_parameter) > + free(cmd_parameter); > + if (cmd_string) > + free(cmd_string); > + cmd_parameter = NULL; > + cmd_string = NULL; > +} > + > +/** > + * Incoming UDP packet handler. > + * > + * @param packet Pointer to incoming UDP packet > + * @param dport Destination UDP port > + * @param sip Source IP address > + * @param sport Source UDP port > + * @param 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 fb_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 < FASTBOOT_HEADER_SIZE || len > PACKET_SIZE) > + return; > + memcpy(&fb_header, packet, sizeof(fb_header)); > + fb_header.flags = 0; > + fb_header.seq = ntohs(fb_header.seq); > + packet += sizeof(fb_header); > + len -= sizeof(fb_header); > + > + switch (fb_header.id) { > + case FASTBOOT_QUERY: > + fastboot_send(fb_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 (fb_header.seq == fb_sequence_number) { > + fastboot_send(fb_header, fastboot_data, > + fastboot_data_len, 0); > + fb_sequence_number++; > + } else if (fb_header.seq == fb_sequence_number - 1) { > + /* Retransmit last sent packet */ > + fastboot_send(fb_header, fastboot_data, > + fastboot_data_len, 1); > + } > + break; > + default: > + pr_err("ID %d not implemented.\n", fb_header.id); > + fb_header.id = FASTBOOT_ERROR; > + fastboot_send(fb_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; > + > + 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 d222c1f..554df7a 100644 > --- a/net/net.c > +++ b/net/net.c > @@ -87,6 +87,9 @@ > #include > #include > #include > +#if defined(CONFIG_UDP_FUNCTION_FASTBOOT) I'd prefer we not proliferate the guards around includes. > +#include > +#endif > #include > #if defined(CONFIG_LED_STATUS) > #include > @@ -451,6 +454,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 +1330,7 @@ common: > /* Fall through */ > > case NETCONS: > + case FASTBOOT: > case TFTPSRV: > if (net_ip.s_addr == 0) { > puts("*** ERROR: `ipaddr' not set\n"); > -- > 2.7.4 > > _______________________________________________ > U-Boot mailing list > U-Boot at lists.denx.de > https://lists.denx.de/listinfo/u-boot