summaryrefslogtreecommitdiff
path: root/lib/avb/fsl/fsl_bootctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/avb/fsl/fsl_bootctl.c')
-rw-r--r--lib/avb/fsl/fsl_bootctl.c176
1 files changed, 176 insertions, 0 deletions
diff --git a/lib/avb/fsl/fsl_bootctl.c b/lib/avb/fsl/fsl_bootctl.c
new file mode 100644
index 0000000..26ff7da
--- /dev/null
+++ b/lib/avb/fsl/fsl_bootctl.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <stdlib.h>
+#include <linux/string.h>
+
+#include <fsl_avb.h>
+
+/* as libavb's bootctl doesn't have the get_var support
+ * we add the getvar support on our side ...*/
+#define SLOT_NUM 2
+static char *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));
+}
+
+static bool slot_is_bootable(AvbABSlotData* slot) {
+ return slot->priority > 0 &&
+ (slot->successful_boot || (slot->tries_remaining > 0));
+}
+
+int slotidx_from_suffix(char *suffix) {
+ int slot = -1;
+
+ if (!strcmp(suffix, "_a") ||
+ !strcmp(suffix, "a"))
+ slot = 0;
+ else if (!strcmp(suffix, "_b") ||
+ !strcmp(suffix, "b"))
+ slot = 1;
+
+ return slot;
+}
+
+bool is_slotvar_avb(char *cmd) {
+
+ assert(cmd != NULL);
+ if (!strcmp_l1("has-slot:", cmd) ||
+ !strcmp_l1("slot-successful:", cmd) ||
+ !strcmp_l1("slot-count", 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;
+}
+
+static int get_curr_slot(AvbABData *ab_data) {
+ if (slot_is_bootable(&ab_data->slots[0]) &&
+ slot_is_bootable(&ab_data->slots[1])) {
+ if (ab_data->slots[1].priority > ab_data->slots[0].priority)
+ return 1;
+ else
+ return 0;
+ } else if (slot_is_bootable(&ab_data->slots[0]))
+ return 0;
+ else if (slot_is_bootable(&ab_data->slots[1]))
+ return 1;
+ else
+ return -1;
+}
+
+int get_slotvar_avb(AvbABOps *ab_ops, char *cmd, char *buffer, size_t size) {
+
+ AvbABData ab_data;
+ AvbABSlotData *slot_data;
+ int slot;
+
+ assert(ab_ops != NULL && cmd != NULL && buffer != NULL);
+
+ char *str = cmd;
+ if (!strcmp_l1("has-slot:", cmd)) {
+ str += strlen("has-slot:");
+ if (!strcmp(str, "system") || !strcmp(str, "boot"))
+ strlcpy(buffer, "yes", size);
+ else
+ strlcpy(buffer, "no", size);
+ return 0;
+
+ } else if (!strcmp_l1("slot-suffixes", cmd)) {
+ strlcpy(buffer, "_a,_b", size);
+ return 0 ;
+
+ } else if (!strcmp_l1("slot-count", cmd)) {
+ strlcpy(buffer, "2", size);
+ return 0 ;
+ }
+
+ /* load ab meta */
+ if (ab_ops->read_ab_metadata == NULL ||
+ ab_ops->read_ab_metadata(ab_ops, &ab_data) != AVB_IO_RESULT_OK) {
+ strlcpy(buffer, "ab data read error", size);
+ return -1 ;
+ }
+
+ if (!strcmp_l1("current-slot", cmd)) {
+ int curr = get_curr_slot(&ab_data);
+ if (curr >= 0 && curr < SLOT_NUM)
+ strlcpy(buffer, slot_suffix[curr], size);
+ else {
+ strlcpy(buffer, "no bootable slot", size);
+ return -1;
+ }
+
+ } else if (!strcmp_l1("slot-successful:", cmd)) {
+ str += strlen("slot-successful:");
+ slot = slotidx_from_suffix(str);
+ if (slot < 0) {
+ strlcpy(buffer, "no such slot", size);
+ return -1;
+ } else {
+ slot_data = &ab_data.slots[slot];
+ bool succ = (slot_data->successful_boot != 0);
+ strlcpy(buffer, succ ? "yes" : "no", size);
+ }
+
+ } else if (!strcmp_l1("slot-unbootable:", cmd)) {
+ str += strlen("slot-unbootable:");
+ slot = slotidx_from_suffix(str);
+ if (slot < 0) {
+ strlcpy(buffer, "no such slot", size);
+ return -1;
+ } else {
+ slot_data = &ab_data.slots[slot];
+ bool bootable = slot_is_bootable(slot_data);
+ strlcpy(buffer, bootable ? "no" : "yes", size);
+ }
+
+ } else if (!strcmp_l1("slot-retry-count:", cmd)) {
+ str += strlen("slot-retry-count:");
+ slot = slotidx_from_suffix(str);
+ if (slot < 0) {
+ strlcpy(buffer, "no such slot", size);
+ return -1;
+ }
+ else {
+ slot_data = &ab_data.slots[slot];
+ char var[7];
+ sprintf(var, "%d",
+ slot_data->tries_remaining);
+ strlcpy(buffer, var, size);
+ }
+
+ } else {
+ strlcpy(buffer, "no such slot command", size);
+ return -1;
+ }
+
+ return 0;
+}
+
+char *select_slot(AvbABOps *ab_ops) {
+ AvbABData ab_data;
+ int curr;
+
+ assert(ab_ops != NULL);
+
+ /* load ab meta */
+ if (ab_ops->read_ab_metadata == NULL ||
+ ab_ops->read_ab_metadata(ab_ops, &ab_data) != AVB_IO_RESULT_OK) {
+ return NULL;
+ }
+ curr = get_curr_slot(&ab_data);
+ if (curr >= 0 && curr < SLOT_NUM)
+ return slot_suffix[curr];
+ else
+ return NULL;
+}