blob: a167fca32d7e253dd9fdd97cb9000bb1be12b3f5 [file] [log] [blame]
/*
* Copyright (c) 2015 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of the Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* EXPORT LAWS: THIS LICENSE ADDS NO RESTRICTIONS TO THE EXPORT LAWS
* OF YOUR JURISDICTION. It is licensee's responsibility to comply
* with any export regulations applicable in licensee's
* jurisdiction. Under CURRENT (May 2000) U.S. export regulations this
* software is eligible for export from the U.S. and can be downloaded
* by or otherwise exported or reexported worldwide EXCEPT to
* U.S. embargoed destinations which include Cuba, Iraq, Libya, North
* Korea, Iran, Syria, Sudan, Afghanistan and any other country to
* which the U.S. has embargoed goods and services.
*/
/*
* SPDX-License-Identifier: Intel
*/
#include <common.h>
#include <asm/bootm.h>
#include <asm/zimage.h>
#include <android_image.h>
#include <command.h>
#include <errno.h>
#include <memalign.h>
#include <cmd_boot_brillo.h>
#include <mmc.h>
#include <intel_scu_ipc.h>
#include <bootloader.h>
#define BOOT_SIGNATURE_MAX_SIZE 4096
#define BOOT_MAX_IMAGE_SIZE (32 * 1024 * 1024) /* 32 MiB */
#ifndef CONFIG_BRILLO_MMC_BOOT_DEVICE
#define CONFIG_BRILLO_MMC_BOOT_DEVICE CONFIG_FASTBOOT_FLASH_MMC_DEV
#endif
#define BOOT_ARG_SLOT_SUFFIX_STR "androidboot.slot_suffix="
#define BOOT_ARG_DEVICE_STATE_STR "androidboot.bvb.device_state="
#define BOOT_ARG_SLOT_CHOSEN_STR "androidboot.bvb.slot_chosen="
#define BOOT_ARG_FALLBACK_REASON_STR "androidboot.bvb.fallback_reason="
#define BOOT_ARG_ROOT_STR "root="
#define BOOTCTRL_SUFFIX_A "_a"
#define BOOTCTRL_SUFFIX_B "_b"
#define BOOTCTRL_SUFFIX_NA "no suffix available"
#define BOOTCTRL_SUFFIX_A_PART "/dev/mmcblk0p5"
#define BOOTCTRL_SUFFIX_B_PART "/dev/mmcblk0p6"
#define BOOT_CONTROL_VERSION 1
#define BOOT_STATE_VAR L"BootState"
#define BOOT_STATE_GREEN 0
#define BOOT_STATE_YELLOW 1
#define BOOT_STATE_ORANGE 2
#define BOOT_STATE_RED 3
/*Status LED modes*/
#define MODE_NORMAL 0x0
#define MODE_FASTBOOT 0x1
#define MODE_RECOVERY 0x2
typedef struct bootloader_control boot_ctrl_t;
int fb_read_lock_state(uint8_t* lock_state);
/*status LED functions*/
static void set_boot_status_led(int mode)
{
red_led_off();
blue_led_off();
green_led_off();
if (MODE_NORMAL == mode)
green_led_on();
else if (MODE_FASTBOOT == mode)
blue_led_on();
else if (MODE_RECOVERY == mode)
red_led_on();
}
/* Properly initialise the metadata partition */
static void ab_init_default_metadata(boot_ctrl_t *ctrl)
{
ctrl->magic = BOOT_CTRL_MAGIC;
ctrl->version = 1;
ctrl->slot_info[0].priority = 0;
ctrl->slot_info[0].tries_remaining = 0;
ctrl->slot_info[0].successful_boot = 0;
ctrl->slot_info[1].priority = 0;
ctrl->slot_info[1].tries_remaining = 0;
ctrl->slot_info[1].successful_boot = 0;
ctrl->recovery_tries_remaining = 0;
}
static int ab_read_bootloader_message(block_dev_desc_t *dev,
disk_partition_t *misc_part, struct bootloader_message_ab *msg)
{
void *tmp;
lbaint_t blkcnt;
boot_ctrl_t *ctrl = (boot_ctrl_t*)&msg->slot_suffix;
blkcnt = BLOCK_CNT(sizeof(*msg), dev);
tmp = calloc(blkcnt, dev->blksz);
if (!tmp)
return -ENOMEM;
if (dev->block_read(dev->dev, misc_part->start, blkcnt, tmp)
!= blkcnt) {
free(tmp);
return -EIO;
}
memcpy(msg, tmp, sizeof(*msg));
free(tmp);
/* Check if the metadata is correct. */
if (ctrl->magic != BOOT_CTRL_MAGIC) {
printf("WARNING: A/B Selector Metadata is not initialised"
" or corrupted, using defaults\n");
ab_init_default_metadata(ctrl);
}
return 0;
}
static int ab_write_bootloader_message(block_dev_desc_t *dev,
disk_partition_t *misc_part, struct bootloader_message_ab *msg)
{
void *tmp;
lbaint_t blkcnt, i;
blkcnt = BLOCK_CNT(sizeof(*msg), dev);
tmp = calloc(blkcnt, dev->blksz);
if (!tmp)
return -ENOMEM;
memcpy(tmp, msg, sizeof(*msg));
for (i = 0; i < blkcnt; i++) {
if (dev->block_write(dev->dev, misc_part->start + i, 1,
tmp + i * dev->blksz) != 1) {
free(tmp);
return -EIO;
}
}
free(tmp);
return 0;
}
int ab_set_active(int slot_num)
{
struct bootloader_message_ab message;
boot_ctrl_t *metadata = (boot_ctrl_t*)&message.slot_suffix;
struct slot_metadata *slot = &metadata->slot_info[slot_num];
struct slot_metadata *other_slot = &metadata->slot_info[slot_num ^ 1];
block_dev_desc_t *dev;
disk_partition_t misc_part;
int ret;
if (slot_num < 0 || slot_num > 1)
return -EINVAL;
if (!(dev = get_dev("mmc", CONFIG_BRILLO_MMC_BOOT_DEVICE)))
return -ENODEV;
if (get_partition_info_efi_by_name(dev, "misc", &misc_part))
return -ENOENT;
if ((ret = ab_read_bootloader_message(dev, &misc_part, &message)))
return ret;
slot->priority = 15;
slot->tries_remaining = 7;
slot->successful_boot = 0;
if (other_slot->priority == 15)
other_slot->priority = 14;
if ((ret = ab_write_bootloader_message(dev, &misc_part, &message)))
return ret;
return 0;
}
/* Loads an android boot image from the given device and named
* partition into CONFIG_SYS_LOAD_ADDR.
*/
static int load_boot_image(block_dev_desc_t *dev, const char *part_name)
{
struct andr_img_hdr *hdr = (struct andr_img_hdr*)CONFIG_SYS_LOAD_ADDR;
void *rest;
disk_partition_t boot_part;
lbaint_t hdr_blkcnt, rest_blkcnt;
if (get_partition_info_efi_by_name(dev, part_name, &boot_part))
return -ENOENT;
hdr_blkcnt = BLOCK_CNT(sizeof(*hdr), dev);
if (dev->block_read(dev->dev, boot_part.start, hdr_blkcnt,
(void*)CONFIG_SYS_LOAD_ADDR) != hdr_blkcnt)
return -EIO;
if (android_image_check_header(hdr))
return -EINVAL;
if (hdr->page_size < 2048 || hdr->page_size > 16384
|| hdr->page_size & (hdr->page_size - 1))
return -EINVAL;
rest = ((void*)hdr) + (hdr_blkcnt * dev->blksz);
rest_blkcnt = BLOCK_CNT((uint64_t)hdr->page_size
+ (uint64_t)ROUND(hdr->kernel_size, hdr->page_size)
+ (uint64_t)ROUND(hdr->ramdisk_size, hdr->page_size)
+ (uint64_t)ROUND(hdr->second_size, hdr->page_size)
+ (uint64_t)BOOT_SIGNATURE_MAX_SIZE,
dev) - hdr_blkcnt;
if (hdr_blkcnt + rest_blkcnt > BLOCK_CNT(BOOT_MAX_IMAGE_SIZE, dev))
return -EINVAL;
if (dev->block_read(dev->dev, boot_part.start + hdr_blkcnt,
rest_blkcnt, rest) != rest_blkcnt)
return -EIO;
return 0;
}
static void append_to_bootargs(const char *str) {
char *bootargs = getenv("bootargs");
if (!bootargs) {
if (*str == ' ') str++;
setenv("bootargs", str);
return;
}
int newlen = strlen(str) + strlen(bootargs) + 1;
char *newbootargs = malloc(newlen);
snprintf(newbootargs, newlen, "%s%s", bootargs, str);
setenv("bootargs", newbootargs);
free(newbootargs);
}
/* Boots to the image already successfully loaded at
* CONFIG_SYS_LOAD_ADDR. If the function returns then booting has
* failed.
*/
static void boot_image(void)
{
struct andr_img_hdr *hdr = (struct andr_img_hdr*)CONFIG_SYS_LOAD_ADDR;
ulong load_address;
char *bootargs = getenv("bootargs");
if (bootargs) {
bootargs = strdup(bootargs);
setenv("bootargs", hdr->cmdline);
append_to_bootargs(" ");
append_to_bootargs(bootargs);
free(bootargs);
} else
setenv("bootargs", hdr->cmdline);
struct boot_params *params =
load_zimage((void*)CONFIG_SYS_LOAD_ADDR + hdr->page_size,
hdr->kernel_size, &load_address);
setup_zimage(params, ((void*)params) + 0x9000, 0,
(ulong)(((void*)hdr) + ROUND(hdr->kernel_size, hdr->page_size)
+ hdr->page_size),
hdr->ramdisk_size);
boot_linux_kernel((ulong)params, load_address, false);
}
static void boot_recovery_image(block_dev_desc_t *dev, boot_ctrl_t *metadata,
disk_partition_t *misc_part, struct bootloader_message_ab *message)
{
int slot_num = 0;
char boot_part[8];
char *suffixes[] = { BOOTCTRL_SUFFIX_A, BOOTCTRL_SUFFIX_B };
char *root_partitions[] = {BOOTCTRL_SUFFIX_A_PART, BOOTCTRL_SUFFIX_B_PART};
if (metadata->slot_info[1].priority > metadata->slot_info[0].priority)
slot_num = 1;
append_to_bootargs(" " BOOT_ARG_SLOT_SUFFIX_STR);
append_to_bootargs(suffixes[slot_num]);
append_to_bootargs(" " BOOT_ARG_ROOT_STR);
append_to_bootargs(root_partitions[slot_num]);
if (metadata->recovery_tries_remaining > 0) {
metadata->recovery_tries_remaining--;
snprintf(boot_part, sizeof(boot_part), "boot%s",
suffixes[slot_num]);
if (load_boot_image(dev, boot_part)) {
/* Failed to load, set remaining tries to zero */
metadata->recovery_tries_remaining = 0;
ab_write_bootloader_message(dev, misc_part, message);
return;
}
ab_write_bootloader_message(dev, misc_part, message);
boot_image();
/* Failed to boot, set remaining tries to zero */
metadata->recovery_tries_remaining = 0;
ab_write_bootloader_message(dev, misc_part, message);
}
}
static void brillo_do_recovery(void)
{
struct bootloader_message_ab message;
boot_ctrl_t *metadata = (boot_ctrl_t*)&message.slot_suffix;
block_dev_desc_t *dev;
disk_partition_t misc_part;
set_boot_status_led(MODE_RECOVERY);
if (!(dev = get_dev("mmc", CONFIG_BRILLO_MMC_BOOT_DEVICE)))
return;
if (get_partition_info_efi_by_name(dev, "misc", &misc_part))
return;
if (ab_read_bootloader_message(dev, &misc_part, &message))
return;
boot_recovery_image(dev, metadata, &misc_part, &message);
}
static void brillo_do_fastboot(void)
{
char *fastboot_args[] = {NULL, "0"};
cmd_tbl_t *fastboot_cmd = find_cmd("fastboot");
if (fastboot_cmd) {
printf("FASTBOOT MODE...\n");
set_boot_status_led(MODE_FASTBOOT);
fastboot_cmd->cmd(fastboot_cmd, 0, 2, fastboot_args);
}
}
static void brillo_do_reset(void)
{
char *reset_args[] = {NULL};
cmd_tbl_t *reset_cmd = find_cmd("reset");
if (reset_cmd)
reset_cmd->cmd(reset_cmd, 0, 1, reset_args);
hang();
}
static void brillo_setup_bootargs(void)
{
char serial_arg[56] = "androidboot.serialno=";
char *serial;
serial = getenv("serial#");
if (serial) {
strncat(serial_arg, serial, sizeof(serial_arg) - strlen(serial_arg) - 1);
setenv("bootargs", serial_arg);
}
}
char* get_active_slot(void) {
struct bootloader_message_ab message;
boot_ctrl_t *metadata = (boot_ctrl_t*)&message.slot_suffix;
block_dev_desc_t *dev;
disk_partition_t misc_part;
char *suffixes[] = { BOOTCTRL_SUFFIX_A, BOOTCTRL_SUFFIX_B };
if (!(dev = get_dev("mmc", CONFIG_BRILLO_MMC_BOOT_DEVICE)))
return BOOTCTRL_SUFFIX_NA;
if (get_partition_info_efi_by_name(dev, "misc", &misc_part))
return BOOTCTRL_SUFFIX_NA;
if (ab_read_bootloader_message(dev, &misc_part, &message))
return BOOTCTRL_SUFFIX_NA;
if(metadata->slot_info[1].priority > metadata->slot_info[0].priority)
return suffixes[1];
return suffixes[0];
}
int get_slot_retry_count(char *suffix) {
struct bootloader_message_ab message;
boot_ctrl_t *metadata = (boot_ctrl_t*)&message.slot_suffix;
block_dev_desc_t *dev;
disk_partition_t misc_part;
int i = 0;
int ret;
char *suffixes[] = { BOOTCTRL_SUFFIX_A, BOOTCTRL_SUFFIX_B };
if (!(dev = get_dev("mmc", CONFIG_BRILLO_MMC_BOOT_DEVICE)))
return -ENODEV;
if (get_partition_info_efi_by_name(dev, "misc", &misc_part))
return -ENOENT;
if ((ret = ab_read_bootloader_message(dev, &misc_part, &message)))
return ret;
for(i = 0; i < 2; i++){
if(!strcmp(suffixes[i], suffix)) {
return metadata->slot_info[i].tries_remaining;
}
}
return -EINVAL;
}
bool is_successful_slot (char *suffix) {
struct bootloader_message_ab message;
boot_ctrl_t *metadata = (boot_ctrl_t*)&message.slot_suffix;
block_dev_desc_t *dev;
disk_partition_t misc_part;
int i = 0;
char *suffixes[] = { BOOTCTRL_SUFFIX_A, BOOTCTRL_SUFFIX_B };
if (!(dev = get_dev("mmc", CONFIG_BRILLO_MMC_BOOT_DEVICE)))
return false;
if (get_partition_info_efi_by_name(dev, "misc", &misc_part))
return false;
if (ab_read_bootloader_message(dev, &misc_part, &message))
return false;
for(i = 0; i < 2; i++){
if(!strcmp(suffixes[i], suffix)) {
if(metadata->slot_info[i].successful_boot == 1) {
return true;
}
}
}
return false;
}
bool is_unbootable_slot (char *suffix) {
struct bootloader_message_ab message;
boot_ctrl_t *metadata = (boot_ctrl_t*)&message.slot_suffix;
block_dev_desc_t *dev;
disk_partition_t misc_part;
int i = 0;
char *suffixes[] = { BOOTCTRL_SUFFIX_A, BOOTCTRL_SUFFIX_B };
if (!(dev = get_dev("mmc", CONFIG_BRILLO_MMC_BOOT_DEVICE)))
return false;
if (get_partition_info_efi_by_name(dev, "misc", &misc_part))
return false;
if (ab_read_bootloader_message(dev, &misc_part, &message))
return false;
for(i = 0; i < 2; i++){
if(!strcmp(suffixes[i], suffix)) {
return (metadata->slot_info[i].priority == 0);
}
}
return false;
}
static void __mark_slot_as_failed(struct slot_metadata *slot, char *slot_name)
{
slot->successful_boot = 0;
slot->tries_remaining = 0;
slot->priority = 0;
printf("WARNING: failed to boot %s slot!\n", slot_name);
}
/* Fallback reasons
*
* This must be set only if slot_chosen is set to "fallback" or "recovery"
* and explains why the slot with the highest priority didn’t work. Possible values include:
*/
#define FBR_UNKOWN 0
#define FBR_TRY_COUNT_EXHAUSTED 1
#define FBR_READ_FAILED FBR_TRY_COUNT_EXHAUSTED << 1
#define FBR_HASH_MISMATCH FBR_READ_FAILED << 1
#define FBR_SIGNATURE_INVALID FBR_HASH_MISMATCH << 1
#define FBR_UNKOWN_PUBLIC_KEY FBR_SIGNATURE_INVALID << 1
#define FBR_INVALID_ROLLBACK_INDEX FBR_UNKOWN_PUBLIC_KEY << 1
static int brillo_boot_ab(void)
{
struct bootloader_message_ab message;
boot_ctrl_t *metadata = (boot_ctrl_t*)&message.slot_suffix;
block_dev_desc_t *dev;
disk_partition_t misc_part;
int ret, index, slots_by_priority[2] = {0, 1};
char *suffixes[] = { BOOTCTRL_SUFFIX_A, BOOTCTRL_SUFFIX_B };
char *root_partitions[] = {BOOTCTRL_SUFFIX_A_PART, BOOTCTRL_SUFFIX_B_PART};
char boot_part[8];
char *old_bootargs;
#ifdef CONFIG_EDISON_ENABLE_EMMC_PWR_ON_WP
struct mmc *mmc;
#endif
uint8_t lock_state = 0; /* Lock state is default unlocked */
uint8_t fallback_reason = FBR_UNKOWN;
if (!(dev = get_dev("mmc", CONFIG_BRILLO_MMC_BOOT_DEVICE)))
return -ENODEV;
if (get_partition_info_efi_by_name(dev, "misc", &misc_part))
return -ENOENT;
if ((ret = ab_read_bootloader_message(dev, &misc_part, &message)))
return ret;
if (metadata->slot_info[1].priority > metadata->slot_info[0].priority) {
slots_by_priority[0] = 1;
slots_by_priority[1] = 0;
}
#ifdef CONFIG_EDISON_ENABLE_EMMC_PWR_ON_WP
/* Enable power on write protection on the first 8MB of the booting MMC
* Use this space for protecting MBR, GPT header, u-boot and security
* partitions. Additional partitions can be placed under the write
* protected area by using more than one 8MB WP block in the function
* below or by changing the GPT layout of the first 8MB.
* Once Power On Write Protect is enabled for a specific WP block that
* block remains read-only until the next device's power cycle. If this
* option is enabled and you want to write data in the WP block then the
* only way to do it is to enter in FASTBOOT from device's Power Off state.
* You can achieve that by pressing and holding RM button while executing
* a power cycle on the device. Release the RM button once fastboot logs
* appeared in the serial console or more than 5 seconds passed since
* power on.
*/
mmc = find_mmc_device(dev->dev);
if (!mmc)
printf("WARNING: Cannot access EMMC device, power on write protection is disabled\n");
else
if (mmc_usr_power_on_wp(mmc, 0ULL, 8 * 1024 * 1024))
printf("WARNING: Cannot enable power on write protection\n");
#endif
old_bootargs = strdup(getenv("bootargs"));
append_to_bootargs(" skip_initramfs");
for (index = 0; index < ARRAY_SIZE(slots_by_priority); index++) {
int slot_num = slots_by_priority[index];
struct slot_metadata *slot = &metadata->slot_info[slot_num];
if (slot->successful_boot == 0 && slot->tries_remaining == 0) {
fallback_reason = FBR_TRY_COUNT_EXHAUSTED;
/* This is a failed slot, lower priority to zero */
slot->priority = 0;
} else {
if (!slot->priority)
continue;
/* either previously successful or tries
remaining. attempt to boot. */
snprintf(boot_part, sizeof(boot_part), "boot%s",
suffixes[slot_num]);
if (load_boot_image(dev, boot_part)) {
/* Failed to load, mark as failed */
__mark_slot_as_failed(slot, suffixes[slot_num]);
fallback_reason = FBR_READ_FAILED;
continue;
}
if (slot->tries_remaining > 0)
slot->tries_remaining--;
metadata->recovery_tries_remaining = 7;
ab_write_bootloader_message(dev, &misc_part, &message);
append_to_bootargs(" " BOOT_ARG_SLOT_SUFFIX_STR);
append_to_bootargs(suffixes[slot_num]);
/* add "root" mount partition to cmdline \
as per slot suffix */
append_to_bootargs(" " BOOT_ARG_ROOT_STR);
append_to_bootargs(root_partitions[slot_num]);
fb_read_lock_state(&lock_state);
append_to_bootargs(" " BOOT_ARG_DEVICE_STATE_STR);
if (lock_state == 1)
append_to_bootargs("locked");
else
append_to_bootargs("unlocked");
append_to_bootargs(" " BOOT_ARG_SLOT_CHOSEN_STR);
if (slots_by_priority[index] == 0) {
append_to_bootargs("highest");
} else {
append_to_bootargs("fallback");
switch (fallback_reason) {
case FBR_READ_FAILED:
append_to_bootargs(" " BOOT_ARG_FALLBACK_REASON_STR);
append_to_bootargs("read_failed");
break;
case FBR_TRY_COUNT_EXHAUSTED:
append_to_bootargs(" " BOOT_ARG_FALLBACK_REASON_STR);
append_to_bootargs("try_count_exhausted");
break;
default:
break;
}
}
boot_image();
/* Failed to boot, mark as failed */
setenv("bootargs", old_bootargs);
__mark_slot_as_failed(slot, suffixes[slot_num]);
ab_write_bootloader_message(dev, &misc_part, &message);
}
}
/* Failed to boot any partition. Try recovery. */
boot_recovery_image(dev, metadata, &misc_part, &message);
return -ENOENT;
}
static int read_boot_reason(void)
{
struct bootloader_message_ab message;
block_dev_desc_t *dev;
disk_partition_t misc_part;
char command[33] = {'\0'};
int ret;
uint8_t target;
/* RM Key is pressed on Edison Arduino Board */
if (!(*(uint8_t*)0xff00800b & 0x20))
return DEVICE_FASTBOOT;
if (!(dev = get_dev("mmc", CONFIG_BRILLO_MMC_BOOT_DEVICE))) {
printf("WARNING: couldn't get mmc device\n");
goto skip_bootctl;
}
if (get_partition_info_efi_by_name(dev, "misc", &misc_part)) {
printf("WARNING: misc partition is missing\n");
goto skip_bootctl;
}
if ((ret = ab_read_bootloader_message(dev, &misc_part, &message))) {
printf("WARNING: couldn't read bootloader message\n");
goto skip_bootctl;
}
strncpy(command, message.message.command, sizeof(message.message.command));
memcpy(message.message.command, 0, sizeof(message.message.command));
if (ab_write_bootloader_message(dev, &misc_part, &message)) {
printf("WARNING: couldn't write bootloader message\n");
}
skip_bootctl:
/* Read reboot reason written in OSNIB */
target = *(uint8_t*)0xfffff807;
*(uint8_t*)0xfffff807 = 0;
*(uint8_t*)0xfffff81f += target;
/* Clear OSNIB */
intel_scu_ipc_raw_cmd(0xe4, 0, NULL, 0, NULL, 0, 0, 0xffffffff);
if (!strncmp(command, "boot-recovery", sizeof("boot-recovery")))
return BOOTCTL_RECOVERY;
else if (target == 0x0c)
return ADB_RECOVERY;
else if (!strncmp(command, "fastboot", sizeof("fastboot")))
return BOOTCTL_FASTBOOT;
else if (target == 0x0e)
return ADB_FASTBOOT;
return DEVICE_REBOOT;
}
static int do_boot_brillo(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
#ifdef CONFIG_BRILLO_FASTBOOT_ONLY
brillo_do_fastboot();
brillo_do_reset();
hang();
#endif
brillo_setup_bootargs();
int reboot_target = read_boot_reason();
switch (reboot_target) {
case BOOTCTL_RECOVERY:
case ADB_RECOVERY:
brillo_do_recovery();
goto boot_failed;
case DEVICE_FASTBOOT:
case BOOTCTL_FASTBOOT:
case ADB_FASTBOOT:
brillo_do_fastboot();
brillo_do_reset();
case DEVICE_REBOOT:
break;
}
/*turn on BOOT(green) LED*/
set_boot_status_led(MODE_NORMAL);
brillo_boot_ab();
boot_failed:
/* Return from boot_ab means normal and recovery via disk
* failed. Here we do fastboot as 'Diskless Recovery' */
brillo_do_fastboot();
brillo_do_reset();
hang();
return -ENOENT;
}
U_BOOT_CMD(
boot_brillo, 1, 0, do_boot_brillo,
"Boot to Brillo",
""
);
static int brillo_fb_write_security_partition(struct security_flags sec_flag)
{
void *tmp;
lbaint_t blkcnt, i;
block_dev_desc_t *dev;
disk_partition_t security_part;
if (!(dev = get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV))) {
printf("ERROR: cannot access the eMMC\n");
return -ENODEV;
}
if (get_partition_info_efi_by_name(dev, "security", &security_part)) {
printf("ERROR: cannot find security partition\n");
return -ENOENT;
}
blkcnt = BLOCK_CNT(sizeof(sec_flag), dev);
tmp = calloc(blkcnt, dev->blksz);
if (!tmp)
return -ENOMEM;
memcpy(tmp, &sec_flag, sizeof(sec_flag));
for (i = 0; i < blkcnt; i++) {
if (dev->block_write(dev->dev, security_part.start + i, 1,
tmp + i * dev->blksz) != 1) {
free(tmp);
return -EIO;
}
}
free(tmp);
return 0;
}
static int brillo_fb_read_security_partition(struct security_flags *security_data)
{
void *tmp;
lbaint_t blkcnt;
block_dev_desc_t *dev;
disk_partition_t security_partition;
if (!(dev = get_dev("mmc", CONFIG_FASTBOOT_FLASH_MMC_DEV))) {
printf("ERROR: cannot access the eMMC\n");
return -ENODEV;
}
if (get_partition_info_efi_by_name(dev, "security", &security_partition)) {
printf("ERROR: cannot find security partition\n");
return -ENOENT;
}
blkcnt = BLOCK_CNT(sizeof(struct security_flags), dev);
tmp = calloc(blkcnt, dev->blksz);
if (!tmp)
return -ENOMEM;
if (dev->block_read(dev->dev, security_partition.start, blkcnt, tmp) != blkcnt) {
free(tmp);
return -EIO;
}
memcpy(security_data, tmp, sizeof(struct security_flags));
free(tmp);
return 0;
}
int fb_write_lock_state(uint8_t lock)
{
struct security_flags sec;
int ret;
ret = brillo_fb_read_security_partition(&sec);
if (ret)
return ret;
sec.lock = lock;
return brillo_fb_write_security_partition(sec);
}
int fb_write_dev_key(uint8_t* devkey, unsigned int number_of_bytes)
{
struct security_flags sec;
int ret;
if (number_of_bytes > BVB_DEVKEY_MAX) {
printf("ERROR: key size is bigger than %d\n", BVB_DEVKEY_MAX);
return -ENOMEM;
}
ret = brillo_fb_read_security_partition(&sec);
if (ret)
return ret;
memcpy(sec.devkey, devkey, number_of_bytes);
sec.devkey_length = number_of_bytes;
return brillo_fb_write_security_partition(sec);
}
int fb_read_dev_key(uint8_t* dev_key, uint16_t *dev_key_length)
{
struct security_flags sec_flag;
int ret;
ret = brillo_fb_read_security_partition(&sec_flag);
if (ret)
return ret;
if (sec_flag.devkey_length > BVB_DEVKEY_MAX) {
printf("ERROR: key size is bigger than %d\n", BVB_DEVKEY_MAX);
return -ENOMEM;
}
memcpy(dev_key, sec_flag.devkey, sec_flag.devkey_length);
*dev_key_length = sec_flag.devkey_length;
return 0;
}
int fb_read_lock_state(uint8_t* lock_state)
{
struct security_flags sec_flag;
int ret;
ret = brillo_fb_read_security_partition(&sec_flag);
if (ret)
return ret;
*lock_state = sec_flag.lock;
return 0;
}