commit
caa2a2e5ab
@ -1,142 +1,214 @@ |
||||
================ |
||||
Android Fastboot |
||||
~~~~~~~~~~~~~~~~ |
||||
================ |
||||
|
||||
Overview |
||||
======== |
||||
The protocol that is used over USB is described in |
||||
README.android-fastboot-protocol in same directory. |
||||
|
||||
The current implementation is a minimal support of the erase command,the |
||||
"oem format" command and flash command;it only supports eMMC devices. |
||||
The protocol that is used over USB and UDP is described in the |
||||
``README.android-fastboot-protocol`` file in the same directory. |
||||
|
||||
The current implementation supports the following standard commands: |
||||
|
||||
- ``boot`` |
||||
- ``continue`` |
||||
- ``download`` |
||||
- ``erase`` (if enabled) |
||||
- ``flash`` (if enabled) |
||||
- ``getvar`` |
||||
- ``reboot`` |
||||
- ``reboot-bootloader`` |
||||
- ``set_active`` (only a stub implementation which always succeeds) |
||||
|
||||
The following OEM commands are supported (if enabled): |
||||
|
||||
- oem format - this executes ``gpt write mmc %x $partitions`` |
||||
|
||||
Support for both eMMC and NAND devices is included. |
||||
|
||||
Client installation |
||||
=================== |
||||
The counterpart to this gadget is the fastboot client which can |
||||
be found in Android's platform/system/core repository in the fastboot |
||||
folder. It runs on Windows, Linux and even OSX. Linux user are lucky since |
||||
they only need libusb. |
||||
Windows users need to bring some time until they have Android SDK (currently |
||||
http://dl.google.com/android/installer_r12-windows.exe) installed. You |
||||
need to install ADB package which contains the required glue libraries for |
||||
accessing USB. Also you need "Google USB driver package" and "SDK platform |
||||
tools". Once installed the usb driver is placed in your SDK folder under |
||||
extras\google\usb_driver. The android_winusb.inf needs a line like |
||||
|
||||
%SingleBootLoaderInterface% = USB_Install, USB\VID_0451&PID_D022 |
||||
|
||||
either in the [Google.NTx86] section for 32bit Windows or [Google.NTamd64] |
||||
for 64bit Windows. VID and PID should match whatever the fastboot is |
||||
advertising. |
||||
|
||||
The counterpart to this is the fastboot client which can be found in |
||||
Android's ``platform/system/core`` repository in the fastboot |
||||
folder. It runs on Windows, Linux and OSX. The fastboot client is |
||||
part of the Android SDK Platform-Tools and can be downloaded from: |
||||
|
||||
https://developer.android.com/studio/releases/platform-tools |
||||
|
||||
Board specific |
||||
============== |
||||
|
||||
USB configuration |
||||
----------------- |
||||
|
||||
The fastboot gadget relies on the USB download gadget, so the following |
||||
options must be configured: |
||||
|
||||
CONFIG_USB_GADGET_DOWNLOAD |
||||
CONFIG_USB_GADGET_VENDOR_NUM |
||||
CONFIG_USB_GADGET_PRODUCT_NUM |
||||
CONFIG_USB_GADGET_MANUFACTURER |
||||
:: |
||||
|
||||
CONFIG_USB_GADGET_DOWNLOAD |
||||
CONFIG_USB_GADGET_VENDOR_NUM |
||||
CONFIG_USB_GADGET_PRODUCT_NUM |
||||
CONFIG_USB_GADGET_MANUFACTURER |
||||
|
||||
NOTE: The CONFIG_USB_GADGET_VENDOR_NUM must be one of the numbers supported by |
||||
the fastboot client. The list of vendor IDs supported can be found in the |
||||
fastboot client source code (fastboot.c) mentioned above. |
||||
NOTE: The ``CONFIG_USB_GADGET_VENDOR_NUM`` must be one of the numbers |
||||
supported by the fastboot client. The list of vendor IDs supported can |
||||
be found in the fastboot client source code. |
||||
|
||||
The fastboot function is enabled by defining CONFIG_USB_FUNCTION_FASTBOOT, |
||||
CONFIG_CMD_FASTBOOT and CONFIG_ANDROID_BOOT_IMAGE. |
||||
General configuration |
||||
--------------------- |
||||
|
||||
The fastboot protocol requires a large memory buffer for downloads. This |
||||
buffer should be as large as possible for a platform. The location of the |
||||
buffer and size are set with CONFIG_FASTBOOT_BUF_ADDR and |
||||
CONFIG_FASTBOOT_BUF_SIZE. |
||||
The fastboot protocol requires a large memory buffer for |
||||
downloads. This buffer should be as large as possible for a |
||||
platform. The location of the buffer and size are set with |
||||
``CONFIG_FASTBOOT_BUF_ADDR`` and ``CONFIG_FASTBOOT_BUF_SIZE``. These |
||||
may be overridden on the fastboot command line using ``-l`` and |
||||
``-s``. |
||||
|
||||
Fastboot environment variables |
||||
============================== |
||||
|
||||
Partition aliases |
||||
----------------- |
||||
|
||||
Fastboot partition aliases can also be defined for devices where GPT |
||||
limitations prevent user-friendly partition names such as "boot", "system" |
||||
and "cache". Or, where the actual partition name doesn't match a standard |
||||
partition name used commonly with fastboot. Current implentation checks |
||||
aliases when accessing partitions by name (flash_write and erase functions). |
||||
To define a partition alias add an environment variable similar to: |
||||
fastboot_partition_alias_<alias partition name>=<actual partition name> |
||||
Example: fastboot_partition_alias_boot=LNX |
||||
partition name used commonly with fastboot. |
||||
|
||||
The current implementation checks aliases when accessing partitions by |
||||
name (flash_write and erase functions). To define a partition alias |
||||
add an environment variable similar to: |
||||
|
||||
``fastboot_partition_alias_<alias partition name>=<actual partition name>`` |
||||
|
||||
for example: |
||||
|
||||
``fastboot_partition_alias_boot=LNX`` |
||||
|
||||
Variable overrides |
||||
------------------ |
||||
|
||||
Variables retrived through ``getvar`` can be overridden by defining |
||||
environment variables of the form ``fastboot.<variable>``. These are |
||||
looked up first so can be used to override values which would |
||||
otherwise be returned. Using this mechanism you can also return types |
||||
for NAND filesystems, as the fully parameterised variable is looked |
||||
up, e.g. |
||||
|
||||
``fastboot.partition-type:boot=jffs2`` |
||||
|
||||
Boot command |
||||
------------ |
||||
|
||||
When executing the fastboot ``boot`` command, if ``fastboot_bootcmd`` is set then |
||||
that will be executed in place of ``bootm <CONFIG_FASTBOOT_BUF_ADDR>``. |
||||
|
||||
Partition Names |
||||
=============== |
||||
The Fastboot implementation in U-boot allows to write images into disk |
||||
partitions (currently on eMMC). Target partitions are referred on the host |
||||
computer by their names. |
||||
|
||||
The Fastboot implementation in U-Boot allows to write images into disk |
||||
partitions. Target partitions are referred on the host computer by |
||||
their names. |
||||
|
||||
For GPT/EFI the respective partition name is used. |
||||
|
||||
For MBR the partitions are referred by generic names according to the |
||||
following schema: |
||||
|
||||
<device type> <device index letter> <partition index> |
||||
<device type><device index letter><partition index> |
||||
|
||||
Example: hda3, sdb1, usbda1 |
||||
Example: ``hda3``, ``sdb1``, ``usbda1`` |
||||
|
||||
The device type is as follows: |
||||
|
||||
* IDE, ATAPI and SATA disks: hd |
||||
* SCSI disks: sd |
||||
* USB media: usbd |
||||
* MMC and SD cards: mmcsd |
||||
* Disk on chip: docd |
||||
* other: xx |
||||
* IDE, ATAPI and SATA disks: ``hd`` |
||||
* SCSI disks: ``sd`` |
||||
* USB media: ``usbd`` |
||||
* MMC and SD cards: ``mmcsd`` |
||||
* Disk on chip: ``docd`` |
||||
* other: ``xx`` |
||||
|
||||
The device index starts from 'a' and refers to the interface (e.g. USB |
||||
The device index starts from ``a`` and refers to the interface (e.g. USB |
||||
controller, SD/MMC controller) or disk index. The partition index starts |
||||
from 1 and describes the partition number on the particular device. |
||||
from ``1`` and describes the partition number on the particular device. |
||||
|
||||
Writing Partition Table |
||||
======================= |
||||
|
||||
Fastboot also allows to write the partition table to the media. This can be |
||||
done by writing the respective partition table image to a special target |
||||
"gpt" or "mbr". These names can be customized by defining the following |
||||
configuration options: |
||||
|
||||
CONFIG_FASTBOOT_GPT_NAME |
||||
CONFIG_FASTBOOT_MBR_NAME |
||||
:: |
||||
|
||||
CONFIG_FASTBOOT_GPT_NAME |
||||
CONFIG_FASTBOOT_MBR_NAME |
||||
|
||||
In Action |
||||
========= |
||||
Enter into fastboot by executing the fastboot command in u-boot and you |
||||
should see: |
||||
|GADGET DRIVER: usb_dnl_fastboot |
||||
|
||||
Enter into fastboot by executing the fastboot command in U-Boot for either USB: |
||||
|
||||
:: |
||||
|
||||
=> fastboot usb 0 |
||||
|
||||
or UDP: |
||||
|
||||
:: |
||||
|
||||
=> fastboot udp |
||||
link up on port 0, speed 100, full duplex |
||||
Using ethernet@4a100000 device |
||||
Listening for fastboot command on 192.168.0.102 |
||||
|
||||
On the client side you can fetch the bootloader version for instance: |
||||
|>fastboot getvar bootloader-version |
||||
|bootloader-version: U-Boot 2014.04-00005-gd24cabc |
||||
|finished. total time: 0.000s |
||||
|
||||
:: |
||||
|
||||
$ fastboot getvar bootloader-version |
||||
bootloader-version: U-Boot 2014.04-00005-gd24cabc |
||||
finished. total time: 0.000s |
||||
|
||||
or initiate a reboot: |
||||
|>fastboot reboot |
||||
|
||||
:: |
||||
|
||||
$ fastboot reboot |
||||
|
||||
and once the client comes back, the board should reset. |
||||
|
||||
You can also specify a kernel image to boot. You have to either specify |
||||
the an image in Android format _or_ pass a binary kernel and let the |
||||
the an image in Android format *or* pass a binary kernel and let the |
||||
fastboot client wrap the Android suite around it. On OMAP for instance you |
||||
take zImage kernel and pass it to the fastboot client: |
||||
|
||||
|>fastboot -b 0x80000000 -c "console=ttyO2 earlyprintk root=/dev/ram0 |
||||
| mem=128M" boot zImage |
||||
|creating boot image... |
||||
|creating boot image - 1847296 bytes |
||||
|downloading 'boot.img'... |
||||
|OKAY [ 2.766s] |
||||
|booting... |
||||
|OKAY [ -0.000s] |
||||
|finished. total time: 2.766s |
||||
|
||||
and on the gadget side you should see: |
||||
|Starting download of 1847296 bytes |
||||
|........................................................ |
||||
|downloading of 1847296 bytes finished |
||||
|Booting kernel.. |
||||
|## Booting Android Image at 0x81000000 ... |
||||
|Kernel load addr 0x80008000 size 1801 KiB |
||||
|Kernel command line: console=ttyO2 earlyprintk root=/dev/ram0 mem=128M |
||||
| Loading Kernel Image ... OK |
||||
|OK |
||||
| |
||||
|Starting kernel ... |
||||
:: |
||||
|
||||
$ fastboot -b 0x80000000 -c "console=ttyO2 earlyprintk root=/dev/ram0 mem=128M" boot zImage |
||||
creating boot image... |
||||
creating boot image - 1847296 bytes |
||||
downloading 'boot.img'... |
||||
OKAY [ 2.766s] |
||||
booting... |
||||
OKAY [ -0.000s] |
||||
finished. total time: 2.766s |
||||
|
||||
and on the U-Boot side you should see: |
||||
|
||||
:: |
||||
|
||||
Starting download of 1847296 bytes |
||||
........................................................ |
||||
downloading of 1847296 bytes finished |
||||
Booting kernel.. |
||||
## Booting Android Image at 0x81000000 ... |
||||
Kernel load addr 0x80008000 size 1801 KiB |
||||
Kernel command line: console=ttyO2 earlyprintk root=/dev/ram0 mem=128M |
||||
Loading Kernel Image ... OK |
||||
OK |
||||
|
||||
Starting kernel ... |
||||
|
@ -0,0 +1,7 @@ |
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
obj-y += fb_common.o
|
||||
obj-y += fb_getvar.o
|
||||
obj-y += fb_command.o
|
||||
obj-$(CONFIG_FASTBOOT_FLASH_MMC) += fb_mmc.o
|
||||
obj-$(CONFIG_FASTBOOT_FLASH_NAND) += fb_nand.o
|
@ -0,0 +1,335 @@ |
||||
// 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 *); |
||||
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT) |
||||
static void oem_format(char *, char *); |
||||
#endif |
||||
|
||||
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 |
||||
}, |
||||
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT) |
||||
[FASTBOOT_COMMAND_OEM_FORMAT] = { |
||||
.command = "oem format", |
||||
.dispatch = oem_format, |
||||
}, |
||||
#endif |
||||
}; |
||||
|
||||
/**
|
||||
* 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); |
||||
} |
||||
|
||||
#if CONFIG_IS_ENABLED(FASTBOOT_CMD_OEM_FORMAT) |
||||
/**
|
||||
* oem_format() - Execute the OEM format command |
||||
* |
||||
* @cmd_parameter: Pointer to command parameter |
||||
* @response: Pointer to fastboot response buffer |
||||
*/ |
||||
static void oem_format(char *cmd_parameter, char *response) |
||||
{ |
||||
char cmdbuf[32]; |
||||
|
||||
if (!env_get("partitions")) { |
||||
fastboot_fail("partitions not set", response); |
||||
} else { |
||||
sprintf(cmdbuf, "gpt write mmc %x $partitions", |
||||
CONFIG_FASTBOOT_FLASH_MMC_DEV); |
||||
if (run_command(cmdbuf, 0)) |
||||
fastboot_fail("", response); |
||||
else |
||||
fastboot_okay(NULL, response); |
||||
} |
||||
} |
||||
#endif |
@ -0,0 +1,169 @@ |
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2008 - 2009 |
||||
* Windriver, <www.windriver.com> |
||||
* Tom Rix <Tom.Rix@windriver.com> |
||||
* |
||||
* Copyright 2011 Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
||||
* |
||||
* Copyright 2014 Linaro, Ltd. |
||||
* Rob Herring <robh@kernel.org> |
||||
*/ |
||||
|
||||
#include <common.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". |
||||
* |
||||
* @tag: The first part of the response |
||||
* @response: Pointer to fastboot response buffer |
||||
* @format: printf style format string |
||||
*/ |
||||
void fastboot_response(const char *tag, char *response, |
||||
const char *format, ...) |
||||
{ |
||||
va_list args; |
||||
|
||||
strlcpy(response, tag, FASTBOOT_RESPONSE_LEN); |
||||
if (format) { |
||||
va_start(args, format); |
||||
vsnprintf(response + strlen(response), |
||||
FASTBOOT_RESPONSE_LEN - strlen(response) - 1, |
||||
format, args); |
||||
va_end(args); |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* fastboot_fail() - Write a FAIL response of the form "FAIL$reason". |
||||
* |
||||
* @reason: Pointer to returned reason string |
||||
* @response: Pointer to fastboot response buffer |
||||
*/ |
||||
void fastboot_fail(const char *reason, char *response) |
||||
{ |
||||
fastboot_response("FAIL", response, "%s", reason); |
||||
} |
||||
|
||||
/**
|
||||
* fastboot_okay() - Write an OKAY response of the form "OKAY$reason". |
||||
* |
||||
* @reason: Pointer to returned reason string, or NULL to send a bare "OKAY" |
||||
* @response: Pointer to fastboot response buffer |
||||
*/ |
||||
void fastboot_okay(const char *reason, char *response) |
||||
{ |
||||
if (reason) |
||||
fastboot_response("OKAY", response, "%s", reason); |
||||
else |
||||
fastboot_response("OKAY", response, NULL); |
||||
} |
||||
|
||||
/**
|
||||
* fastboot_set_reboot_flag() - Set flag to indicate reboot-bootloader |
||||
* |
||||
* Set flag which indicates that we should reboot into the bootloader |
||||
* following the reboot that fastboot executes after this function. |
||||
* |
||||
* This function should be overridden in your board file with one |
||||
* which sets whatever flag your board specific Android bootloader flow |
||||
* requires in order to re-enter the bootloader. |
||||
*/ |
||||
int __weak fastboot_set_reboot_flag(void) |
||||
{ |
||||
return -ENOSYS; |
||||
} |
||||
|
||||
/**
|
||||
* 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); |
||||
} |
@ -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); |
||||
} |
||||
} |
@ -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 |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue