From 9c723a7d146018be07f49f6162ba761973049b9b Mon Sep 17 00:00:00 2001 From: fang hui Date: Thu, 12 Nov 2015 14:52:39 +0800 Subject: MA-7251 - [evk_6ul]: Support boot conctrol for brillo brillo need bootlader support boot control. bootlader can choose which slot(partition) to boot based on it's tactic. The commit support boot control for evk6ul Signed-off-by: fang hui --- drivers/usb/gadget/bootctrl.c | 403 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 403 insertions(+) create mode 100644 drivers/usb/gadget/bootctrl.c (limited to 'drivers/usb/gadget/bootctrl.c') diff --git a/drivers/usb/gadget/bootctrl.c b/drivers/usb/gadget/bootctrl.c new file mode 100644 index 0000000..0f979f2 --- /dev/null +++ b/drivers/usb/gadget/bootctrl.c @@ -0,0 +1,403 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#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; +} -- cgit v1.1