diff options
author | Jun Yu <yujun@marvell.com> | 2015-10-16 02:11:19 -0700 |
---|---|---|
committer | Mohammed Habibulla <moch@google.com> | 2015-11-04 23:20:02 -0800 |
commit | 6fec13014701b9335f14c3689726e9522b7ac88a (patch) | |
tree | aa8e87ea0eb66aba4ad312caaf22879d497ae16f | |
parent | 999988065d4c152f37b4393a791f90b3a8a1f296 (diff) | |
download | abox_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.mk | 2 | ||||
-rw-r--r-- | base_product/boot_control/Android.mk | 28 | ||||
-rw-r--r-- | base_product/boot_control/boot_control.c | 215 | ||||
-rw-r--r-- | base_product/boot_control/bootinfo.c | 164 | ||||
-rw-r--r-- | base_product/boot_control/bootinfo.h | 65 |
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 |