diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/gadget/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/bootctrl.c | 393 | ||||
-rw-r--r-- | drivers/usb/gadget/bootctrl.h | 17 | ||||
-rw-r--r-- | drivers/usb/gadget/f_fastboot.c | 143 |
4 files changed, 530 insertions, 24 deletions
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 4869867..8e9732a 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o obj-$(CONFIG_DFU_FUNCTION) += f_dfu.o obj-$(CONFIG_USB_GADGET_MASS_STORAGE) += f_mass_storage.o obj-$(CONFIG_CMD_FASTBOOT) += f_fastboot.o +obj-$(CONFIG_BRILLO_SUPPORT) += bootctrl.o endif ifdef CONFIG_USB_ETHER obj-y += ether.o diff --git a/drivers/usb/gadget/bootctrl.c b/drivers/usb/gadget/bootctrl.c new file mode 100644 index 0000000..bb54ebc --- /dev/null +++ b/drivers/usb/gadget/bootctrl.c @@ -0,0 +1,393 @@ +/* + * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <g_dnl.h> +#include <fsl_fastboot.h> +#include <ext_common.h> +#include "bootctrl.h" + +#define SLOT_NUM (unsigned int)2 +#define META_FILE "slotmeta.data" +#define META_BAK_FILE ".slotmeta.data.bak" +#define META_FILE_ABS_PATH "/slotmeta.data" +#define META_BAK_FILE_ABS_PATH "/.slotmeta.data.bak" + +struct slot_meta { + unsigned int priority; + unsigned int tryremain; + unsigned int bootsuc; + unsigned int reserved[4]; +}; + +struct boot_ctl { + unsigned int crc; + unsigned int recovery_tryremain; + struct slot_meta a_slot_meta[SLOT_NUM]; + unsigned int reserved[4]; +}; + + +static unsigned int g_mmc_id; +static unsigned int g_slot_selected; +static const char *g_slot_suffix[SLOT_NUM] = {"_a", "_b"}; + +static int strcmp_l1(const char *s1, const char *s2) +{ + if (!s1 || !s2) + return -1; + return strncmp(s1, s2, strlen(s1)); +} + +void set_mmc_id(unsigned int id) +{ + g_mmc_id = id; +} + +static void dump_slotmeta(struct boot_ctl *ptbootctl) +{ + int i; + + if (ptbootctl == NULL) + return; + + printf("RecoveryTryRemain %d, crc %u\n", + ptbootctl->recovery_tryremain, ptbootctl->crc); + + for (i = 0; i < SLOT_NUM; i++) { + printf("slot %d: pri %d, try %d, suc %d\n", i, + ptbootctl->a_slot_meta[i].priority, + ptbootctl->a_slot_meta[i].tryremain, + ptbootctl->a_slot_meta[i].bootsuc); + } + + return; +} + +const char *get_slot_suffix(void) +{ + return g_slot_suffix[g_slot_selected]; +} + +static unsigned int slot_find(struct boot_ctl *ptbootctl) +{ + unsigned int max_pri = 0; + unsigned int slot = -1; + int i; + + for (i = 0; i < SLOT_NUM; i++) { + struct slot_meta *pslot_meta = &(ptbootctl->a_slot_meta[i]); + if ((pslot_meta->priority > max_pri) && + ((pslot_meta->bootsuc > 0) || + (pslot_meta->tryremain > 0))) { + max_pri = pslot_meta->priority; + slot = i; + printf("select_slot slot %d\n", slot); + } + } + + return slot; +} +static int read_bootctl(struct boot_ctl *ptbootctl) +{ + int ret; + char *argv[6]; + char addr_str[20]; + char len_str[8]; + char devpart_str[8]; + unsigned int crc; + int load_count = 0; + char *pmeta_file = META_FILE; + + if (ptbootctl == NULL) + return -1; + + sprintf(len_str, "0x%x", sizeof(struct boot_ctl)); + sprintf(addr_str, "0x%x", (unsigned int)ptbootctl); + sprintf(devpart_str, "%d:%d", g_mmc_id, + CONFIG_ANDROID_SLOTMETA_PARTITION_MMC); + +load_meta: + argv[0] = "ext4load"; + argv[1] = "mmc"; + argv[2] = devpart_str; + argv[3] = addr_str; + argv[4] = pmeta_file; + argv[5] = len_str; + + ret = do_ext4_load(NULL, 0, 5, argv); + if (ret) { + printf("do_ext4_load %s failed, ret %d\n", pmeta_file, ret); + return -1; + } + + /* check crc, if faled, load backup meta data */ + crc = crc32(0, (unsigned char *)ptbootctl + 4, + sizeof(struct boot_ctl) - 4); + if (crc != ptbootctl->crc) { + printf("%s, crc check failed, caculated %d, read %d\n", + pmeta_file, crc, ptbootctl->crc); + + if (load_count == 0) { + load_count++; + pmeta_file = META_BAK_FILE; + printf("load backup meta %s\n", pmeta_file); + goto load_meta; + } + return -1; + } + + /* use backup meta to recover */ + if (load_count > 0) { + printf("use backup meta to recover\n"); + argv[0] = "ext4write"; + argv[4] = META_FILE_ABS_PATH; + do_ext4_write(NULL, 0, 6, argv); + } + + return 0; +} + +static int write_bootctl(struct boot_ctl *ptbootctl) +{ + int ret = 0; + char *argv[6]; + char addr_str[20]; + char len_str[8]; + char devpart_str[8]; + + if (ptbootctl == NULL) + return -1; + + ptbootctl->crc = crc32(0, (unsigned char *)ptbootctl + 4, + sizeof(struct boot_ctl) - 4); + + sprintf(len_str, "0x%x", sizeof(struct boot_ctl)); + sprintf(addr_str, "0x%x", (unsigned int)ptbootctl); + sprintf(devpart_str, "%d:%d", g_mmc_id, + CONFIG_ANDROID_SLOTMETA_PARTITION_MMC); + + argv[0] = "ext4write"; + argv[1] = "mmc"; + argv[2] = devpart_str; + argv[3] = addr_str; + argv[4] = META_FILE_ABS_PATH; + argv[5] = len_str; + + + /* write back t_bootctl */ + ret = do_ext4_write(NULL, 0, 6, argv); + if (ret) { + printf("!!! do_ext4_write %s failed, ret %d\n", argv[4], ret); + return ret; + } + + /* back up */ + argv[4] = META_BAK_FILE_ABS_PATH; + ret = do_ext4_write(NULL, 0, 6, argv); + if (ret) { + printf("!!! do_ext4_write %s failed, ret %d\n", argv[4], ret); + return ret; + } + + return ret; +} + + +char *select_slot(void) +{ + int i = 0; + int ret = 0; + unsigned int slot; + struct boot_ctl t_bootctl; + bool b_need_write = false; + + ret = read_bootctl(&t_bootctl); + if (ret) { + printf("read_bootctl failed, ret %d\n", ret); + return NULL; + } + + dump_slotmeta(&t_bootctl); + + slot = slot_find(&t_bootctl); + if (slot >= SLOT_NUM) { + printf("!!! select_slot, no valid slot\n"); + return NULL; + } + + /* invalid slot, set priority to 0 */ + for (i = 0; i < SLOT_NUM; i++) { + struct slot_meta *pslot_meta = &(t_bootctl.a_slot_meta[i]); + if ((pslot_meta->bootsuc == 0) && + (pslot_meta->tryremain == 0) && + (pslot_meta->priority > 0)) { + pslot_meta->priority = 0; + b_need_write = true; + } + } + + if (t_bootctl.recovery_tryremain != 7) { + b_need_write = true; + t_bootctl.recovery_tryremain = 7; + } + + if ((t_bootctl.a_slot_meta[slot].bootsuc == 0) && + (t_bootctl.a_slot_meta[slot].tryremain > 0)) { + b_need_write = true; + t_bootctl.a_slot_meta[slot].tryremain--; + } + + if (b_need_write) { + ret = write_bootctl(&t_bootctl); + if (ret) + printf("!!! write_bootctl failed, ret %d\n", ret); + } + + g_slot_selected = slot; + + if (slot == 0) + return FASTBOOT_PARTITION_BOOT_A; + else + return FASTBOOT_PARTITION_BOOT_B; +} + +static unsigned int slotidx_from_suffix(char *suffix) +{ + unsigned int slot = -1; + + if (!strcmp(suffix, "_a")) + slot = 0; + else if (!strcmp(suffix, "_b")) + slot = 1; + + return slot; +} + +bool is_sotvar(char *cmd) +{ + if (!strcmp_l1("has-slot:", cmd) || + !strcmp_l1("slot-successful:", cmd) || + !strcmp_l1("slot-suffixes", cmd) || + !strcmp_l1("current-slot", cmd) || + !strcmp_l1("slot-unbootable:", cmd) || + !strcmp_l1("slot-retry-count:", cmd)) { + return true; + } + + return false; +} + +void get_slotvar(char *cmd, char *response, size_t chars_left) +{ + int ret; + struct boot_ctl t_bootctl; + memset(&t_bootctl, 0, sizeof(t_bootctl)); + + ret = read_bootctl(&t_bootctl); + if (ret) { + error("get_slotvar, read_bootctl failed\n"); + strcpy(response, "get_slotvar read_bootctl failed"); + return; + } + + if (!strcmp_l1("has-slot:", cmd)) { + char *ptnname = NULL; + ptnname = strchr(cmd, ':') + 1; + if (!strcmp(ptnname, "system") || !strcmp(ptnname, "boot")) + strncat(response, "yes", chars_left); + else + strncat(response, "no", chars_left); + } else if (!strcmp_l1("current-slot", cmd)) { + unsigned int slot = slot_find(&t_bootctl); + if (slot < SLOT_NUM) + strncat(response, g_slot_suffix[slot], chars_left); + else + strncat(response, "no valid slot", chars_left); + } else if (!strcmp_l1("slot-suffixes", cmd)) { + strncat(response, "_a,_b", chars_left); + } else if (!strcmp_l1("slot-successful:", cmd)) { + char *suffix = strchr(cmd, ':') + 1; + unsigned int slot = slotidx_from_suffix(suffix); + if (slot >= SLOT_NUM) { + strncat(response, "no such slot", chars_left); + } else { + bool suc = t_bootctl.a_slot_meta[slot].bootsuc; + strncat(response, suc ? "yes" : "no", chars_left); + } + } else if (!strcmp_l1("slot-unbootable:", cmd)) { + char *suffix = strchr(cmd, ':') + 1; + unsigned int slot = slotidx_from_suffix(suffix); + if (slot >= SLOT_NUM) { + strncat(response, "no such slot", chars_left); + } else { + unsigned int pri = t_bootctl.a_slot_meta[slot].priority; + strncat(response, pri ? "no" : "yes", chars_left); + } + } else if (!strcmp_l1("slot-retry-count:", cmd)) { + char *suffix = strchr(cmd, ':') + 1; + unsigned int slot = slotidx_from_suffix(suffix); + if (slot >= SLOT_NUM) + strncat(response, "no such slot", chars_left); + else + sprintf(response, "OKAY%d", + t_bootctl.a_slot_meta[slot].tryremain); + } else { + strncat(response, "no such slot command", chars_left); + } + + return; +} + + +void cb_set_active(struct usb_ep *ep, struct usb_request *req) +{ + int ret; + int i; + unsigned int slot = 0; + char *cmd = req->buf; + struct boot_ctl t_bootctl; + + memset(&t_bootctl, 0, sizeof(t_bootctl)); + + strsep(&cmd, ":"); + if (!cmd) { + error("missing slot suffix\n"); + fastboot_tx_write_str("FAILmissing slot suffix"); + return; + } + + slot = slotidx_from_suffix(cmd); + if (slot >= SLOT_NUM) { + fastboot_tx_write_str("FAILerr slot suffix"); + return; + } + + ret = read_bootctl(&t_bootctl); + if (ret) + fastboot_tx_write_str("FAILReadBootCtl failed"); + + t_bootctl.a_slot_meta[slot].bootsuc = 0; + t_bootctl.a_slot_meta[slot].priority = 15; + t_bootctl.a_slot_meta[slot].tryremain = 7; + + /* low other slot priority */ + for (i = 0; i < SLOT_NUM; i++) { + if (i == slot) + continue; + + if (t_bootctl.a_slot_meta[i].priority >= 15) + t_bootctl.a_slot_meta[i].priority = 14; + } + + ret = write_bootctl(&t_bootctl); + if (ret) + fastboot_tx_write_str("write_bootctl failed"); + else + fastboot_tx_write_str("OKAY"); + + return; +} diff --git a/drivers/usb/gadget/bootctrl.h b/drivers/usb/gadget/bootctrl.h new file mode 100644 index 0000000..2153103 --- /dev/null +++ b/drivers/usb/gadget/bootctrl.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef BOOTCTRL_H +#define BOOTCTRL_H + +void set_mmc_id(unsigned int id); +char *select_slot(void); +bool is_sotvar(char *cmd); +void get_slotvar(char *cmd, char *response, size_t chars_left); +void cb_set_active(struct usb_ep *ep, struct usb_request *req); +const char *get_slot_suffix(void); + +#endif diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 88c648f..400f941 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -36,6 +36,10 @@ #endif #endif +#ifdef CONFIG_BRILLO_SUPPORT +#include "bootctrl.h" +#endif + #define FASTBOOT_VERSION "0.4" #define FASTBOOT_INTERFACE_CLASS 0xff @@ -155,13 +159,19 @@ static struct usb_gadget_strings *fastboot_strings[] = { /*pentry index internally*/ enum { - PTN_MBR_INDEX = 0, - PTN_BOOTLOADER_INDEX, - PTN_KERNEL_INDEX, - PTN_URAMDISK_INDEX, - PTN_SYSTEM_INDEX, - PTN_RECOVERY_INDEX, - PTN_DATA_INDEX + PTN_MBR_INDEX = 0, + PTN_BOOTLOADER_INDEX, + PTN_KERNEL_INDEX, + PTN_URAMDISK_INDEX, + PTN_SYSTEM_INDEX, + PTN_RECOVERY_INDEX, + PTN_DATA_INDEX, +#ifdef CONFIG_BRILLO_SUPPORT + PTN_KERNEL_B_INDEX, + PTN_SYSTEM_B_INDEX, + PTN_SLOTMETA_INDEX, +#endif + PTN_NUM }; static unsigned int download_bytes_unpadded; @@ -811,10 +821,19 @@ static void process_flash_sata(const char *cmdbuf, char *response) #if defined(CONFIG_FASTBOOT_STORAGE_MMC) static int is_sparse_partition(struct fastboot_ptentry *ptn) { +#ifdef CONFIG_BRILLO_SUPPORT + if (ptn && (!strncmp(ptn->name, FASTBOOT_PARTITION_SYSTEM_A, + strlen(FASTBOOT_PARTITION_SYSTEM_A)) || + !strncmp(ptn->name, FASTBOOT_PARTITION_SYSTEM_B, + strlen(FASTBOOT_PARTITION_SYSTEM_B)) || + !strncmp(ptn->name, FASTBOOT_PARTITION_DATA, + strlen(FASTBOOT_PARTITION_DATA)))) { +#else if (ptn && (!strncmp(ptn->name, FASTBOOT_PARTITION_SYSTEM, strlen(FASTBOOT_PARTITION_SYSTEM)) || !strncmp(ptn->name, FASTBOOT_PARTITION_DATA, strlen(FASTBOOT_PARTITION_DATA)))) { +#endif printf("support sparse flash partition for %s\n", ptn->name); return 1; } else @@ -1078,6 +1097,9 @@ static int _fastboot_setup_dev(void) } else if (!strncmp(fastboot_env, "mmc", 3)) { fastboot_devinfo.type = DEV_MMC; fastboot_devinfo.dev_id = _fastboot_get_mmc_no(fastboot_env); +#ifdef CONFIG_BRILLO_SUPPORT + set_mmc_id(fastboot_devinfo.dev_id); +#endif } } else { return 1; @@ -1131,7 +1153,7 @@ static int _fastboot_parts_load_from_ptable(void) struct mmc *mmc; block_dev_desc_t *dev_desc; - struct fastboot_ptentry ptable[PTN_DATA_INDEX + 1]; + struct fastboot_ptentry ptable[PTN_NUM]; /* sata case in env */ if (fastboot_devinfo.type == DEV_SATA) { @@ -1178,7 +1200,7 @@ static int _fastboot_parts_load_from_ptable(void) } memset((char *)ptable, 0, - sizeof(struct fastboot_ptentry) * (PTN_DATA_INDEX + 1)); + sizeof(struct fastboot_ptentry) * (PTN_NUM)); /* MBR */ strcpy(ptable[PTN_MBR_INDEX].name, "mbr"); ptable[PTN_MBR_INDEX].start = ANDROID_MBR_OFFSET / dev_desc->blksz; @@ -1192,24 +1214,75 @@ static int _fastboot_parts_load_from_ptable(void) ANDROID_BOOTLOADER_SIZE / dev_desc->blksz; ptable[PTN_BOOTLOADER_INDEX].partition_id = boot_partition; +#ifdef CONFIG_BRILLO_SUPPORT _fastboot_parts_add_ptable_entry(PTN_KERNEL_INDEX, - CONFIG_ANDROID_BOOT_PARTITION_MMC, - user_partition, - FASTBOOT_PARTITION_BOOT , dev_desc, ptable); + CONFIG_ANDROID_BOOT_PARTITION_MMC, + user_partition, + FASTBOOT_PARTITION_BOOT_A, + dev_desc, ptable); + + _fastboot_parts_add_ptable_entry(PTN_RECOVERY_INDEX, + CONFIG_ANDROID_RECOVERY_PARTITION_MMC, + user_partition, + FASTBOOT_PARTITION_RECOVERY, + dev_desc, ptable); + + _fastboot_parts_add_ptable_entry(PTN_SYSTEM_INDEX, + CONFIG_ANDROID_SYSTEM_PARTITION_MMC, + user_partition, + FASTBOOT_PARTITION_SYSTEM_A, + dev_desc, ptable); + + _fastboot_parts_add_ptable_entry(PTN_DATA_INDEX, + CONFIG_ANDROID_DATA_PARTITION_MMC, + user_partition, + FASTBOOT_PARTITION_DATA, + dev_desc, ptable); + + _fastboot_parts_add_ptable_entry(PTN_KERNEL_B_INDEX, + CONFIG_ANDROID_BOOT_B_PARTITION_MMC, + user_partition, + FASTBOOT_PARTITION_BOOT_B, + dev_desc, ptable); + + _fastboot_parts_add_ptable_entry(PTN_SYSTEM_B_INDEX, + CONFIG_ANDROID_SYSTEM_B_PARTITION_MMC, + user_partition, + FASTBOOT_PARTITION_SYSTEM_B, + dev_desc, ptable); + + _fastboot_parts_add_ptable_entry(PTN_SLOTMETA_INDEX, + CONFIG_ANDROID_SLOTMETA_PARTITION_MMC, + user_partition, + FASTBOOT_PARTITION_SLOTMETA, + dev_desc, ptable); +#else + _fastboot_parts_add_ptable_entry(PTN_KERNEL_INDEX, + CONFIG_ANDROID_BOOT_PARTITION_MMC, + user_partition, + FASTBOOT_PARTITION_BOOT, + dev_desc, ptable); + _fastboot_parts_add_ptable_entry(PTN_RECOVERY_INDEX, - CONFIG_ANDROID_RECOVERY_PARTITION_MMC, - user_partition, - FASTBOOT_PARTITION_RECOVERY, dev_desc, ptable); + CONFIG_ANDROID_RECOVERY_PARTITION_MMC, + user_partition, + FASTBOOT_PARTITION_RECOVERY, + dev_desc, ptable); + _fastboot_parts_add_ptable_entry(PTN_SYSTEM_INDEX, - CONFIG_ANDROID_SYSTEM_PARTITION_MMC, - user_partition, - FASTBOOT_PARTITION_SYSTEM, dev_desc, ptable); + CONFIG_ANDROID_SYSTEM_PARTITION_MMC, + user_partition, + FASTBOOT_PARTITION_SYSTEM, + dev_desc, ptable); + _fastboot_parts_add_ptable_entry(PTN_DATA_INDEX, - CONFIG_ANDROID_DATA_PARTITION_MMC, - user_partition, - FASTBOOT_PARTITION_DATA, dev_desc, ptable); + CONFIG_ANDROID_DATA_PARTITION_MMC, + user_partition, + FASTBOOT_PARTITION_DATA, + dev_desc, ptable); +#endif - for (i = 0; i <= PTN_DATA_INDEX; i++) + for (i = 0; i < PTN_NUM; i++) fastboot_flash_add_ptn(&ptable[i]); return 0; @@ -1553,7 +1626,16 @@ int do_boota(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (argc > 2) ptn = argv[2]; - +#ifdef CONFIG_BRILLO_SUPPORT + else { + ptn = select_slot(); + if (ptn == NULL) { + printf("no valid slot found, enter to recovery\n"); + ptn = "recovery"; + } + printf("use slot %s\n", ptn); + } +#endif if (mmcc != -1) { #ifdef CONFIG_MMC struct fastboot_ptentry *pte; @@ -1997,7 +2079,7 @@ static int fastboot_tx_write(const char *buffer, unsigned int buffer_size) return 0; } -static int fastboot_tx_write_str(const char *buffer) +int fastboot_tx_write_str(const char *buffer) { return fastboot_tx_write(buffer, strlen(buffer)); } @@ -2037,6 +2119,13 @@ static void cb_getvar(struct usb_ep *ep, struct usb_request *req) return; } +#ifdef CONFIG_BRILLO_SUPPORT + if (is_sotvar(cmd)) { + get_slotvar(cmd, response, chars_left); + fastboot_tx_write_str(response); + return; + } +#endif if (!strcmp_l1("version", cmd)) { strncat(response, FASTBOOT_VERSION, chars_left); } else if (!strcmp_l1("bootloader-version", cmd)) { @@ -2361,6 +2450,12 @@ static const struct cmd_dispatch_info cmd_dispatch_info[] = { .cmd = "oem", .cb = cb_oem, }, +#ifdef CONFIG_BRILLO_SUPPORT + { + .cmd = "set_active", + .cb = cb_set_active, + }, +#endif }; static void rx_handler_command(struct usb_ep *ep, struct usb_request *req) |