mirror of
https://github.com/AsahiLinux/u-boot
synced 2025-02-17 22:49:02 +00:00
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 <alex.kiernan@gmail.com> Signed-off-by: Alex Deymo <deymo@google.com> Signed-off-by: Jocelyn Bohr <bohr@google.com> Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
c232d14d11
commit
f73a7df984
18 changed files with 1338 additions and 20 deletions
|
@ -655,8 +655,8 @@ config CMD_FASTBOOT
|
||||||
This enables the command "fastboot" which enables the Android
|
This enables the command "fastboot" which enables the Android
|
||||||
fastboot mode for the platform. Fastboot is a protocol for
|
fastboot mode for the platform. Fastboot is a protocol for
|
||||||
downloading images, flashing and device control used on
|
downloading images, flashing and device control used on
|
||||||
Android devices. Fastboot requires support for acting as a USB
|
Android devices. Fastboot requires either the network stack
|
||||||
device.
|
enabled or support for acting as a USB device.
|
||||||
|
|
||||||
See doc/README.android-fastboot for more information.
|
See doc/README.android-fastboot for more information.
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,32 @@
|
||||||
#include <command.h>
|
#include <command.h>
|
||||||
#include <console.h>
|
#include <console.h>
|
||||||
#include <g_dnl.h>
|
#include <g_dnl.h>
|
||||||
|
#include <fastboot.h>
|
||||||
|
#include <net.h>
|
||||||
#include <usb.h>
|
#include <usb.h>
|
||||||
|
|
||||||
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;
|
int controller_index;
|
||||||
char *usb_controller;
|
char *usb_controller;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -58,11 +80,70 @@ exit:
|
||||||
board_usb_cleanup(controller_index, USB_INIT_DEVICE);
|
board_usb_cleanup(controller_index, USB_INIT_DEVICE);
|
||||||
|
|
||||||
return ret;
|
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 <controller> | 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(
|
U_BOOT_CMD(
|
||||||
fastboot, 2, 1, do_fastboot,
|
fastboot, CONFIG_SYS_MAXARGS, 1, do_fastboot,
|
||||||
"use USB Fastboot protocol",
|
"run as a fastboot usb or udp device", fastboot_help_text
|
||||||
"<USB_controller>\n"
|
|
||||||
" - run as a fastboot usb device"
|
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,6 +14,13 @@ config USB_FUNCTION_FASTBOOT
|
||||||
help
|
help
|
||||||
This enables the USB part of the fastboot gadget.
|
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
|
if FASTBOOT
|
||||||
|
|
||||||
config FASTBOOT_BUF_ADDR
|
config FASTBOOT_BUF_ADDR
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0+
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
obj-y += fb_common.o
|
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_MMC) += fb_mmc.o
|
||||||
obj-$(CONFIG_FASTBOOT_FLASH_NAND) += fb_nand.o
|
obj-$(CONFIG_FASTBOOT_FLASH_NAND) += fb_nand.o
|
||||||
|
|
302
drivers/fastboot/fb_command.c
Normal file
302
drivers/fastboot/fb_command.c
Normal file
|
@ -0,0 +1,302 @@
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <fastboot.h>
|
||||||
|
#include <fastboot-internal.h>
|
||||||
|
#include <fb_mmc.h>
|
||||||
|
#include <fb_nand.h>
|
||||||
|
#include <part.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
|
@ -12,6 +12,22 @@
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <fastboot.h>
|
#include <fastboot.h>
|
||||||
|
#include <net/fastboot.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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".
|
* fastboot_response() - Writes a response of the form "$tag$reason".
|
||||||
|
@ -74,3 +90,80 @@ int __weak fastboot_set_reboot_flag(void)
|
||||||
{
|
{
|
||||||
return -ENOSYS;
|
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 <fastboot_buf_addr>", 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);
|
||||||
|
}
|
||||||
|
|
230
drivers/fastboot/fb_getvar.c
Normal file
230
drivers/fastboot/fb_getvar.c
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <fastboot.h>
|
||||||
|
#include <fastboot-internal.h>
|
||||||
|
#include <fb_mmc.h>
|
||||||
|
#include <fb_nand.h>
|
||||||
|
#include <fs.h>
|
||||||
|
#include <version.h>
|
||||||
|
|
||||||
|
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.<cmd_parameter>, 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
#include <blk.h>
|
#include <blk.h>
|
||||||
#include <fastboot.h>
|
#include <fastboot.h>
|
||||||
|
#include <fastboot-internal.h>
|
||||||
#include <fb_mmc.h>
|
#include <fb_mmc.h>
|
||||||
#include <image-sparse.h>
|
#include <image-sparse.h>
|
||||||
#include <part.h>
|
#include <part.h>
|
||||||
|
@ -15,6 +16,8 @@
|
||||||
#include <linux/compat.h>
|
#include <linux/compat.h>
|
||||||
#include <android_image.h>
|
#include <android_image.h>
|
||||||
|
|
||||||
|
#define FASTBOOT_MAX_BLK_WRITE 16384
|
||||||
|
|
||||||
#define BOOT_PARTITION_NAME "boot"
|
#define BOOT_PARTITION_NAME "boot"
|
||||||
|
|
||||||
struct fb_mmc_sparse {
|
struct fb_mmc_sparse {
|
||||||
|
@ -43,13 +46,48 @@ static int part_get_info_by_name_or_alias(struct blk_desc *dev_desc,
|
||||||
return ret;
|
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,
|
static lbaint_t fb_mmc_sparse_write(struct sparse_storage *info,
|
||||||
lbaint_t blk, lbaint_t blkcnt, const void *buffer)
|
lbaint_t blk, lbaint_t blkcnt, const void *buffer)
|
||||||
{
|
{
|
||||||
struct fb_mmc_sparse *sparse = info->priv;
|
struct fb_mmc_sparse *sparse = info->priv;
|
||||||
struct blk_desc *dev_desc = sparse->dev_desc;
|
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,
|
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,
|
static void write_raw_image(struct blk_desc *dev_desc, disk_partition_t *info,
|
||||||
const char *part_name, void *buffer,
|
const char *part_name, void *buffer,
|
||||||
unsigned int download_bytes, char *response)
|
u32 download_bytes, char *response)
|
||||||
{
|
{
|
||||||
lbaint_t blkcnt;
|
lbaint_t blkcnt;
|
||||||
lbaint_t blks;
|
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");
|
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) {
|
if (blks != blkcnt) {
|
||||||
pr_err("failed writing to device %d\n", dev_desc->devnum);
|
pr_err("failed writing to device %d\n", dev_desc->devnum);
|
||||||
fastboot_fail("failed writing to device", response);
|
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,
|
static int fb_mmc_update_zimage(struct blk_desc *dev_desc,
|
||||||
void *download_buffer,
|
void *download_buffer,
|
||||||
unsigned int download_bytes,
|
u32 download_bytes,
|
||||||
char *response)
|
char *response)
|
||||||
{
|
{
|
||||||
uintptr_t hdr_addr; /* boot image header address */
|
uintptr_t hdr_addr; /* boot image header address */
|
||||||
|
@ -251,6 +290,38 @@ static int fb_mmc_update_zimage(struct blk_desc *dev_desc,
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
* 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
|
* @response: Pointer to fastboot response buffer
|
||||||
*/
|
*/
|
||||||
void fastboot_mmc_flash_write(const char *cmd, void *download_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;
|
struct blk_desc *dev_desc;
|
||||||
disk_partition_t info;
|
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",
|
printf("Erasing blocks " LBAFU " to " LBAFU " due to alignment\n",
|
||||||
blks_start, blks_start + blks_size);
|
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) {
|
if (blks != blks_size) {
|
||||||
pr_err("failed erasing from device %d\n", dev_desc->devnum);
|
pr_err("failed erasing from device %d\n", dev_desc->devnum);
|
||||||
fastboot_fail("failed erasing from device", response);
|
fastboot_fail("failed erasing from device", response);
|
||||||
|
|
|
@ -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,
|
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)
|
size_t length, size_t *written)
|
||||||
{
|
{
|
||||||
int flags = WITH_WR_VERIFY;
|
int flags = WITH_WR_VERIFY;
|
||||||
|
@ -145,6 +145,21 @@ static lbaint_t fb_nand_sparse_reserve(struct sparse_storage *info,
|
||||||
return blkcnt + bad_blocks;
|
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
|
* 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
|
* @response: Pointer to fastboot response buffer
|
||||||
*/
|
*/
|
||||||
void fastboot_nand_flash_write(const char *cmd, void *download_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 part_info *part;
|
||||||
struct mtd_info *mtd = NULL;
|
struct mtd_info *mtd = NULL;
|
||||||
|
|
36
include/fastboot-internal.h
Normal file
36
include/fastboot-internal.h
Normal file
|
@ -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.<cmd_parameter>, 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
|
|
@ -15,8 +15,28 @@
|
||||||
#define FASTBOOT_VERSION "0.4"
|
#define FASTBOOT_VERSION "0.4"
|
||||||
|
|
||||||
/* The 64 defined bytes plus \0 */
|
/* The 64 defined bytes plus \0 */
|
||||||
|
#define FASTBOOT_COMMAND_LEN (64 + 1)
|
||||||
#define FASTBOOT_RESPONSE_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".
|
* 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
|
* @response: Pointer to fastboot response buffer
|
||||||
*/
|
*/
|
||||||
void fastboot_okay(const char *reason, char *response);
|
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);
|
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 <fastboot_buf_addr>", 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_ */
|
#endif /* _FASTBOOT_H_ */
|
||||||
|
|
|
@ -3,6 +3,20 @@
|
||||||
* Copyright 2014 Broadcom Corporation.
|
* 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
|
* fastboot_mmc_flash_write() - Write image to eMMC for fastboot
|
||||||
*
|
*
|
||||||
|
@ -12,8 +26,7 @@
|
||||||
* @response: Pointer to fastboot response buffer
|
* @response: Pointer to fastboot response buffer
|
||||||
*/
|
*/
|
||||||
void fastboot_mmc_flash_write(const char *cmd, void *download_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
|
* 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
|
* @response: Pointer to fastboot response buffer
|
||||||
*/
|
*/
|
||||||
void fastboot_mmc_erase(const char *cmd, char *response);
|
void fastboot_mmc_erase(const char *cmd, char *response);
|
||||||
|
#endif
|
||||||
|
|
|
@ -4,6 +4,21 @@
|
||||||
* Copyright 2015 Free Electrons.
|
* Copyright 2015 Free Electrons.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef _FB_NAND_H_
|
||||||
|
#define _FB_NAND_H_
|
||||||
|
|
||||||
|
#include <jffs2/load_kernel.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* fastboot_nand_flash_write() - Write image to NAND for fastboot
|
||||||
*
|
*
|
||||||
|
@ -13,7 +28,8 @@
|
||||||
* @response: Pointer to fastboot response buffer
|
* @response: Pointer to fastboot response buffer
|
||||||
*/
|
*/
|
||||||
void fastboot_nand_flash_write(const char *cmd, void *download_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
|
* 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
|
* @response: Pointer to fastboot response buffer
|
||||||
*/
|
*/
|
||||||
void fastboot_nand_erase(const char *cmd, char *response);
|
void fastboot_nand_erase(const char *cmd, char *response);
|
||||||
|
#endif
|
||||||
|
|
|
@ -535,7 +535,7 @@ extern int net_restart_wrap; /* Tried all network devices */
|
||||||
|
|
||||||
enum proto_t {
|
enum proto_t {
|
||||||
BOOTP, RARP, ARP, TFTPGET, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP,
|
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 */
|
extern char net_boot_file_name[1024];/* Boot File name */
|
||||||
|
|
21
include/net/fastboot.h
Normal file
21
include/net/fastboot.h
Normal file
|
@ -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__ */
|
|
@ -23,6 +23,7 @@ obj-$(CONFIG_CMD_PING) += ping.o
|
||||||
obj-$(CONFIG_CMD_RARP) += rarp.o
|
obj-$(CONFIG_CMD_RARP) += rarp.o
|
||||||
obj-$(CONFIG_CMD_SNTP) += sntp.o
|
obj-$(CONFIG_CMD_SNTP) += sntp.o
|
||||||
obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o
|
obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o
|
||||||
|
obj-$(CONFIG_UDP_FUNCTION_FASTBOOT) += fastboot.o
|
||||||
|
|
||||||
# Disable this warning as it is triggered by:
|
# Disable this warning as it is triggered by:
|
||||||
# sprintf(buf, index ? "foo%d" : "foo", index)
|
# sprintf(buf, index ? "foo%d" : "foo", index)
|
||||||
|
|
317
net/fastboot.c
Normal file
317
net/fastboot.c
Normal file
|
@ -0,0 +1,317 @@
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The Android Open Source Project
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <fastboot.h>
|
||||||
|
#include <net.h>
|
||||||
|
#include <net/fastboot.h>
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
|
@ -87,6 +87,7 @@
|
||||||
#include <environment.h>
|
#include <environment.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <net.h>
|
#include <net.h>
|
||||||
|
#include <net/fastboot.h>
|
||||||
#include <net/tftp.h>
|
#include <net/tftp.h>
|
||||||
#if defined(CONFIG_LED_STATUS)
|
#if defined(CONFIG_LED_STATUS)
|
||||||
#include <miiphy.h>
|
#include <miiphy.h>
|
||||||
|
@ -451,6 +452,11 @@ restart:
|
||||||
tftp_start_server();
|
tftp_start_server();
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_UDP_FUNCTION_FASTBOOT
|
||||||
|
case FASTBOOT:
|
||||||
|
fastboot_start_server();
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
#if defined(CONFIG_CMD_DHCP)
|
#if defined(CONFIG_CMD_DHCP)
|
||||||
case DHCP:
|
case DHCP:
|
||||||
bootp_reset();
|
bootp_reset();
|
||||||
|
@ -1322,6 +1328,7 @@ common:
|
||||||
/* Fall through */
|
/* Fall through */
|
||||||
|
|
||||||
case NETCONS:
|
case NETCONS:
|
||||||
|
case FASTBOOT:
|
||||||
case TFTPSRV:
|
case TFTPSRV:
|
||||||
if (net_ip.s_addr == 0) {
|
if (net_ip.s_addr == 0) {
|
||||||
puts("*** ERROR: `ipaddr' not set\n");
|
puts("*** ERROR: `ipaddr' not set\n");
|
||||||
|
|
Loading…
Add table
Reference in a new issue