summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJun Yu <yujun@marvell.com>2015-10-16 02:11:19 -0700
committerMohammed Habibulla <moch@google.com>2015-11-04 23:20:02 -0800
commit6fec13014701b9335f14c3689726e9522b7ac88a (patch)
treeaa8e87ea0eb66aba4ad312caaf22879d497ae16f
parent999988065d4c152f37b4393a791f90b3a8a1f296 (diff)
downloadabox_edge-6fec13014701b9335f14c3689726e9522b7ac88a.tar.gz
Boot control HAL for Marvell platform.
Marvell specific boot control hal implementation: switch the boot_a.img system_a.img and boot_b.img system_b.img back and forth in terms of the boot control setting. Change-Id: I29eee0e83cf201233729e0f32114ffe0f06243be
-rw-r--r--base_product/abox_edge.mk2
-rw-r--r--base_product/boot_control/Android.mk28
-rw-r--r--base_product/boot_control/boot_control.c215
-rw-r--r--base_product/boot_control/bootinfo.c164
-rw-r--r--base_product/boot_control/bootinfo.h65
5 files changed, 474 insertions, 0 deletions
diff --git a/base_product/abox_edge.mk b/base_product/abox_edge.mk
index 658a6a6..dff327f 100644
--- a/base_product/abox_edge.mk
+++ b/base_product/abox_edge.mk
@@ -25,3 +25,5 @@ PRODUCT_DEVICE := abox_edge
PRODUCT_COPY_FILES += \
device/marvell/abox_edge/base_product/weaved.conf:system/etc/weaved/weaved.conf
+PRODUCT_PACKAGES += \
+ bootctrl.mrvl
diff --git a/base_product/boot_control/Android.mk b/base_product/boot_control/Android.mk
new file mode 100644
index 0000000..80f25fc
--- /dev/null
+++ b/base_product/boot_control/Android.mk
@@ -0,0 +1,28 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := bootctrl.mrvl
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := boot_control.c bootinfo.h bootinfo.c
+LOCAL_C_INCLUDES := system/core/mkbootimg bootable/recovery
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_STATIC_LIBRARIES := libfs_mgr
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/base_product/boot_control/boot_control.c b/base_product/boot_control/boot_control.c
new file mode 100644
index 0000000..fe40373
--- /dev/null
+++ b/base_product/boot_control/boot_control.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <fs_mgr.h>
+#include <hardware/hardware.h>
+#include <hardware/boot_control.h>
+#include <cutils/properties.h>
+
+#include "bootinfo.h"
+
+
+void boot_control_init(struct boot_control_module *module)
+{
+ return;
+}
+
+unsigned get_number_slots(struct boot_control_module *module)
+{
+ return 2;
+}
+
+unsigned get_current_slot(struct boot_control_module *module)
+{
+ char propbuf[PROPERTY_VALUE_MAX];
+ const char* suffix[2] = {"_a", "_b"};
+ int i;
+
+ property_get("ro.boot.slot_suffix", propbuf, "");
+
+ if (propbuf[0] != '\0') {
+ for (i = 0; i < 2; i++) {
+ if (strncmp(propbuf, suffix[i], 2) == 0)
+ return i;
+ }
+
+ if (i == 2)
+ fprintf(stderr, "WARNING: androidboot.slot_suffix is invalid\n");
+ } else {
+ fprintf(stderr, "WARNING: androidboot.slot_suffix is NULL\n");
+ }
+
+ return 0;
+}
+
+int mark_boot_successful(struct boot_control_module *module)
+{
+ BrilloBootInfo info;
+ unsigned current_slot;
+ int i;
+
+ if (!boot_info_load(&info)) {
+ fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
+ boot_info_reset(&info);
+ } else {
+ if (!boot_info_validate(&info)) {
+ fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
+ boot_info_reset(&info);
+ }
+ }
+
+ current_slot = get_current_slot(module);
+
+ info.slot_info[current_slot].boot_successful = true;
+ info.slot_info[current_slot].tries_remaining = 0;
+
+ if (!boot_info_save(&info)) {
+ fprintf(stderr, "WARNING: Error saving boot-info.\n");
+ return -errno;
+ }
+
+ return 0;
+}
+
+int set_active_boot_slot(struct boot_control_module *module, unsigned slot)
+{
+ BrilloBootInfo info;
+ unsigned other_slot;
+ int i;
+
+ if (slot >= 2)
+ return -EINVAL;
+
+ if (!boot_info_load(&info)) {
+ fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
+ boot_info_reset(&info);
+ } else {
+ if (!boot_info_validate(&info)) {
+ fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
+ boot_info_reset(&info);
+ }
+ }
+
+ other_slot = 1 - slot;
+ if (info.slot_info[other_slot].priority == 15)
+ info.slot_info[other_slot].priority = 14;
+
+ info.slot_info[slot].bootable = true;
+ info.slot_info[slot].priority = 15;
+ info.slot_info[slot].tries_remaining = 7;
+ info.slot_info[slot].boot_successful = false;
+
+ if (!boot_info_save(&info)) {
+ fprintf(stderr, "WARNING: Error saving boot-info.\n");
+ return -errno;
+ }
+
+ return 0;
+}
+
+int set_slot_as_unbootable(struct boot_control_module *module, unsigned slot)
+{
+ BrilloBootInfo info;
+
+ if (slot >= 2)
+ return -EINVAL;
+
+ if (!boot_info_load(&info)) {
+ fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
+ boot_info_reset(&info);
+ } else {
+ if (!boot_info_validate(&info)) {
+ fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
+ boot_info_reset(&info);
+ }
+ }
+
+ info.slot_info[slot].bootable = false;
+ info.slot_info[slot].priority = 0;
+ info.slot_info[slot].tries_remaining = 0;
+ info.slot_info[slot].boot_successful = false;
+
+ if (!boot_info_save(&info)) {
+ fprintf(stderr, "WARNING: Error saving boot-info.\n");
+ return -errno;
+ }
+
+ return 0;
+}
+
+int is_slot_bootable(struct boot_control_module *module, unsigned slot)
+{
+ BrilloBootInfo info;
+
+ if (slot >= 2)
+ return -EINVAL;
+
+ if (!boot_info_load(&info)) {
+ fprintf(stderr, "WARNING: Error loading boot-info. Resetting.\n");
+ boot_info_reset(&info);
+ } else {
+ if (!boot_info_validate(&info)) {
+ fprintf(stderr, "WARNING: boot-info is invalid. Resetting.\n");
+ boot_info_reset(&info);
+ }
+ }
+
+ return info.slot_info[slot].bootable;
+}
+
+const char* get_suffix(struct boot_control_module *module, unsigned slot)
+{
+ static const char* suffix[2] = {"_a", "_b"};
+
+ if (slot >= 2)
+ return NULL;
+
+ return suffix[slot];
+}
+
+static struct hw_module_methods_t boot_control_module_methods = {
+ .open = NULL,
+};
+
+struct boot_control_module HAL_MODULE_INFO_SYM = {
+ .common = {
+ .tag = HARDWARE_MODULE_TAG,
+ .module_api_version = BOOT_CONTROL_MODULE_API_VERSION_0_1,
+ .hal_api_version = HARDWARE_HAL_API_VERSION,
+ .id = BOOT_CONTROL_HARDWARE_MODULE_ID,
+ .name = "Marvell Boot Control HAL",
+ .author = "Marvell SEEDS",
+ .methods = &boot_control_module_methods,
+ },
+
+ .init = boot_control_init,
+ .getNumberSlots = get_number_slots,
+ .getCurrentSlot = get_current_slot,
+ .markBootSuccessful = mark_boot_successful,
+ .setActiveBootSlot = set_active_boot_slot,
+ .setSlotAsUnbootable = set_slot_as_unbootable,
+ .isSlotBootable = is_slot_bootable,
+ .getSuffix = get_suffix,
+};
diff --git a/base_product/boot_control/bootinfo.c b/base_product/boot_control/bootinfo.c
new file mode 100644
index 0000000..8f5b214
--- /dev/null
+++ b/base_product/boot_control/bootinfo.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cutils/properties.h>
+
+#include <bootloader.h>
+#include <fs_mgr.h>
+
+#include "bootinfo.h"
+
+// Open the appropriate fstab file and fallback to /fstab.device if
+// that's what's being used.
+static struct fstab *open_fstab(void)
+{
+ char propbuf[PROPERTY_VALUE_MAX];
+ char fstab_name[PROPERTY_VALUE_MAX + 32];
+ struct fstab *fstab;
+
+ property_get("ro.hardware", propbuf, "");
+ snprintf(fstab_name, sizeof(fstab_name), "/fstab.%s", propbuf);
+ fstab = fs_mgr_read_fstab(fstab_name);
+
+ if (fstab != NULL) {
+ return fstab;
+ } else {
+ fstab = fs_mgr_read_fstab("/fstab.device");
+ if (fstab != NULL)
+ return fstab;
+ }
+
+ return NULL;
+}
+
+static int boot_info_open_misc(int flags)
+{
+ char *path;
+ int fd;
+ struct fstab *fstab;
+ struct fstab_rec *record;
+
+ fstab = open_fstab();
+ if (fstab == NULL)
+ return -1;
+
+ record = fs_mgr_get_entry_for_mount_point(fstab, "/misc");
+ if (record == NULL) {
+ fs_mgr_free_fstab(fstab);
+ return -1;
+ }
+
+ path = strdup(record->blk_device);
+ fs_mgr_free_fstab(fstab);
+
+ fd = open(path, flags);
+ free(path);
+
+ return fd;
+}
+
+// As per struct bootloader_message which is defined in
+// bootable/recovery/bootloader.h we can use the 32 bytes in the
+// bootctrl_suffix field provided that they start with the active slot
+// suffix terminated by NUL. It just so happens that BrilloBootInfo is
+// laid out this way.
+#define BOOTINFO_OFFSET offsetof(struct bootloader_message, slot_suffix)
+
+bool boot_info_load(BrilloBootInfo *out_info)
+{
+ int fd;
+
+ memset(out_info, '\0', sizeof(BrilloBootInfo));
+
+ fd = boot_info_open_misc(O_RDONLY);
+ if (fd == -1)
+ return false;
+
+ if (lseek(fd, BOOTINFO_OFFSET, SEEK_SET) != BOOTINFO_OFFSET) {
+ close(fd);
+ return false;
+ }
+
+ ssize_t num_read;
+ do {
+ num_read = read(fd, (void*) out_info, sizeof(BrilloBootInfo));
+ } while (num_read == -1 && errno == EINTR);
+
+ close(fd);
+
+ if (num_read != sizeof(BrilloBootInfo))
+ return false;
+
+ return true;
+}
+
+bool boot_info_save(BrilloBootInfo *info)
+{
+ int fd;
+
+ fd = boot_info_open_misc(O_RDWR);
+ if (fd == -1)
+ return false;
+
+ if (lseek(fd, BOOTINFO_OFFSET, SEEK_SET) != BOOTINFO_OFFSET) {
+ close(fd);
+ return false;
+ }
+
+ ssize_t num_written;
+ do {
+ num_written = write(fd, (void*) info, sizeof(BrilloBootInfo));
+ } while (num_written == -1 && errno == EINTR);
+
+ close(fd);
+
+ if (num_written != sizeof(BrilloBootInfo))
+ return false;
+
+ return true;
+}
+
+bool boot_info_validate(BrilloBootInfo* info)
+{
+ if (info->magic[0] != '\0' ||
+ info->magic[1] != 'B' ||
+ info->magic[2] != 'C')
+ return false;
+
+ return true;
+}
+
+void boot_info_reset(BrilloBootInfo* info)
+{
+ memset(info, '\0', sizeof(BrilloBootInfo));
+ info->magic[1] = 'B';
+ info->magic[2] = 'C';
+
+ return;
+}
diff --git a/base_product/boot_control/bootinfo.h b/base_product/boot_control/bootinfo.h
new file mode 100644
index 0000000..f3e6b41
--- /dev/null
+++ b/base_product/boot_control/bootinfo.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef BOOTINFO_H_
+#define BOOTINFO_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef struct brillo_slot_info {
+ // Flag mean that the slot can bootable or not.
+ uint8_t bootable :1;
+
+ // Set to true when the OS has successfully booted.
+ uint8_t boot_successful :1;
+
+ // Priorty number range [0:15], with 15 meaning highest priortiy,
+ // 1 meaning lowest priority and 0 mean that the slot is unbootable.
+ uint8_t priority;
+
+ // Boot times left range [0:7].
+ uint8_t tries_remaining;
+
+ uint8_t reserved[1];
+} BrilloSlotInfo;
+
+typedef struct BrilloBootInfo {
+ // Magic for identification
+ uint8_t magic[3];
+
+ // Version of BrilloBootInfo struct, must be 0 or larger.
+ uint8_t version;
+
+ // Information about each slot.
+ BrilloSlotInfo slot_info[2];
+
+ uint8_t reserved[20];
+} BrilloBootInfo;
+
+// Loading and saving BrillBootInfo instances.
+bool boot_info_load(BrilloBootInfo *out_info);
+bool boot_info_save(BrilloBootInfo *info);
+
+// Returns non-zero if valid.
+bool boot_info_validate(BrilloBootInfo* info);
+void boot_info_reset(BrilloBootInfo* info);
+
+#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6
+_Static_assert(sizeof(BrilloBootInfo) == 32, "BrilloBootInfo has wrong size");
+#endif
+
+#endif // BOOTINFO_H