diff options
author | Leo Wang <leozwang@google.com> | 2016-01-29 17:26:12 +0000 |
---|---|---|
committer | Android Partner Code Review <android-gerrit-partner@google.com> | 2016-01-29 17:26:12 +0000 |
commit | 0af041c0ad930a2173803a780158e0186f4b0f85 (patch) | |
tree | a010d62112eab0e4cbff98c28c3edce91aa78e8d | |
parent | 5849b430b84cc2deec30f1baff3440e15c954e65 (diff) | |
parent | 57025cebf42022966bfcce7df7c010257bbcfe41 (diff) | |
download | rockchip-0af041c0ad930a2173803a780158e0186f4b0f85.tar.gz |
Merge "kylin: Add boot_control, base on qcom" into m-brillo-dev-kylin
-rw-r--r-- | boot_control/Android.mk | 18 | ||||
-rw-r--r-- | boot_control/boot_control_rockchip.cpp | 277 | ||||
-rw-r--r-- | boot_control/boot_control_rockchip.h | 51 | ||||
-rw-r--r-- | boot_control/gpt.cpp | 357 | ||||
-rw-r--r-- | boot_control/gpt.h | 137 |
5 files changed, 840 insertions, 0 deletions
diff --git a/boot_control/Android.mk b/boot_control/Android.mk new file mode 100644 index 0000000..7266d64 --- /dev/null +++ b/boot_control/Android.mk @@ -0,0 +1,18 @@ +# Copyright 2015 The Android Open Source Project + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + gpt.cpp \ + boot_control_rockchip.cpp + +LOCAL_CFLAGS := -Wall -Wno-missing-field-initializers +LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include + +LOCAL_SHARED_LIBRARIES := libcutils libutils + +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_MODULE:= bootctrl.$(TARGET_BOARD_PLATFORM) +LOCAL_MODULE_TAGS := optional +include $(BUILD_SHARED_LIBRARY) diff --git a/boot_control/boot_control_rockchip.cpp b/boot_control/boot_control_rockchip.cpp new file mode 100644 index 0000000..5b6e2d4 --- /dev/null +++ b/boot_control/boot_control_rockchip.cpp @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define LOG_TAG "boot_control_hw" +#define LOG_NDEBUG 0 + +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <cutils/log.h> +#include <hardware/hardware.h> +#include <cutils/properties.h> +#include <hardware/boot_control.h> + +#include "boot_control_rockchip.h" +#include "gpt.h" + +using namespace std; + +/* Rockchip boot_control HAL implements reading A/B slot information + * from the contents of GPT. + */ +static struct hw_module_methods_t module_methods = { + .open = nullptr, +}; + +boot_control_module_t 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 = "Rockchip boot_control HAL", + .author = "jeffy.chen@rock-chips.com", + .methods = &module_methods, + }, + .init = rockchip_boot_control::init, + .getNumberSlots = rockchip_boot_control::getNumberSlots, + .getCurrentSlot = rockchip_boot_control::getCurrentSlot, + .markBootSuccessful = rockchip_boot_control::markBootSuccessful, + .setActiveBootSlot = rockchip_boot_control::setActiveBootSlot, + .setSlotAsUnbootable = rockchip_boot_control::setSlotAsUnbootable, + .isSlotBootable = rockchip_boot_control::isSlotBootable, + .getSuffix = rockchip_boot_control::getSuffix, + .isSlotMarkedSuccessful = rockchip_boot_control::isSlotMarkedSuccessful, +}; + +namespace rockchip_boot_control { + +void init(boot_control_module_t *module) +{ + ALOGV("boot control HAL."); +} + +unsigned getNumberSlots(boot_control_module_t *module) +{ + return MAX_SLOTS; +} + +unsigned getCurrentSlot(boot_control_module_t *module) +{ + char propbuf[PROPERTY_VALUE_MAX]; + + property_get("ro.boot.slot_suffix", propbuf, ""); + ALOGV("getCurrentSlot: slot suffix %s", propbuf); + + if (!strcmp(propbuf, "_a")) { + return 0; + } else if (!strcmp(propbuf, "_b")) { + return 1; + } else { + ALOGE("ERROR: unsupported slot suffix"); + return 0; + } + return 0; +} + +int markBootSuccessful(boot_control_module_t *module) +{ + std::unique_ptr<PartitionTables> gpt = + PartitionTables::read_partitions(BLK_DEV_NODE); + uint32_t partition_index; + unsigned slot; + int ret; + + if (gpt == nullptr) { + ALOGE("markBootSuccessful: read partition returns %d", errno); + return -errno; + } + + slot = getCurrentSlot(module); + + if (slot >= MAX_SLOTS) + return -EINVAL; + + if ((ret = gpt->getIndexForSlottedBootPartition(slot, partition_index))) + return ret; + + /*Clear set success and clear tries count.*/ + gpt->partition_array[partition_index].attributes.fields.successful = 1; + gpt->partition_array[partition_index].attributes.fields.tries = 0; + + if ((ret = gpt->write_partitions())) { + ALOGE("markBootSuccessful: write partition returns %d", ret); + return ret; + } + + ALOGV("markBootSuccessful: slot:%d partition:%ld", slot, partition_index); + + return 0; +} + +int setActiveBootSlot(boot_control_module_t *module, unsigned slot) +{ + std::unique_ptr<PartitionTables> gpt = + PartitionTables::read_partitions(BLK_DEV_NODE); + uint32_t partition_index; + unsigned other_slot = 1 - slot; + uint64_t attribute_flags; + int ret; + + if (gpt == nullptr) { + ALOGE("setActiveBootSlot: read partition returns %d", errno); + return -errno; + } + + if (slot >= MAX_SLOTS) + return -EINVAL; + + if ((ret = gpt->getIndexForSlottedBootPartition( slot, partition_index))) + return ret; + + /*Set priority = 15 and try count = 7 for the target slot */ + gpt->partition_array[partition_index].attributes.fields.priority = 15; + gpt->partition_array[partition_index].attributes.fields.tries = 7; + gpt->partition_array[partition_index].attributes.fields.successful = 0; + + if ((ret = gpt->getIndexForSlottedBootPartition(other_slot, partition_index))) + return ret; + + /*Modify priority for other slot if it has a non-zero priority */ + if (gpt->partition_array[partition_index].attributes.fields.priority) + gpt->partition_array[partition_index].attributes.fields.priority = 14; + + if ((ret = gpt->write_partitions())) { + ALOGE("setActiveBootSlot: write partition returns %d", ret); + return ret; + } + + ALOGV("setActiveBootSlot: slot %d", slot); + return 0; +} + +int setSlotAsUnbootable(struct boot_control_module *module, unsigned slot) +{ + std::unique_ptr<PartitionTables> gpt = + PartitionTables::read_partitions(BLK_DEV_NODE); + uint32_t partition_index; + int ret = 0; + + if (gpt == nullptr) { + ALOGV("setSlotAsUnbootable: read partition returns %d", -errno); + return -errno; + } + + if (slot >= MAX_SLOTS) + return -EINVAL; + + if ((ret = gpt->getIndexForSlottedBootPartition(slot, partition_index))) + return ret; + + gpt->partition_array[partition_index].attributes.raw = 0; + + if ((ret = gpt->write_partitions())) { + ALOGE("setSlotAsUnbootable: write partition returns %d", ret); + return ret; + } + + ALOGV("setSlotAsUnbootable: partition index: %d, ret: %d", + partition_index, ret); + + return 0; +} + +int isSlotBootable(struct boot_control_module *module, unsigned slot) +{ + std::unique_ptr<PartitionTables> gpt = + PartitionTables::read_partitions(BLK_DEV_NODE); + uint32_t partition_index = 0; + int ret = 0; + + if (gpt == nullptr) { + ALOGE("isSlotBootable: read partition returns %d", -errno); + return -errno; + } + + if (slot >= MAX_SLOTS) + return -EINVAL; + + if ((ret = gpt->getIndexForSlottedBootPartition(slot, partition_index))) + return ret; + + if (gpt->partition_array[partition_index].attributes.fields.successful || + gpt->partition_array[partition_index].attributes.fields.tries) + ret = 1; + + if (!gpt->partition_array[partition_index].attributes.fields.priority) + ret = 0; + + ALOGV("isSlotBootable: Slot: %d attribute: %llx, ret: %d", + slot, gpt->partition_array[partition_index].attributes.raw, ret); + + return ret; +} + +const char* getSuffix(boot_control_module_t *module, unsigned slot) +{ + static const char* suffix[2] = {"_a", "_b"}; + if (slot >= MAX_SLOTS) + return nullptr; + return suffix[slot]; +} + +int isSlotMarkedSuccessful(boot_control_module_t *module, unsigned slot) +{ + std::unique_ptr<PartitionTables> gpt = + PartitionTables::read_partitions(BLK_DEV_NODE); + uint32_t partition_index = 0; + int ret = 0; + + if (gpt == nullptr) { + ALOGE("isSlotMarkedSuccessful: read partition returns %d", -errno); + return -errno; + } + + if (slot >= MAX_SLOTS) + return -EINVAL; + + if ((ret = gpt->getIndexForSlottedBootPartition(slot, partition_index))) + return ret; + + if (gpt->partition_array[partition_index].attributes.fields.successful) + ret = 1; + + ALOGV("isSlotMarkedSuccessful: Slot: %d attribute: %llx, ret: %d", + slot, gpt->partition_array[partition_index].attributes.raw, ret); + + return ret; +} + +}; //namespace rockchip_boot_control diff --git a/boot_control/boot_control_rockchip.h b/boot_control/boot_control_rockchip.h new file mode 100644 index 0000000..a1b2c4e --- /dev/null +++ b/boot_control/boot_control_rockchip.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HARDWARE_ROCKCHIP_BOOTCTL_HAL_H +#define HARDWARE_ROCKCHIP_BOOTCTL_HAL_H + +#include <hardware/hardware.h> +#include <hardware/boot_control.h> + +namespace rockchip_boot_control { + +#define BLK_DEV_NODE "/dev/block/mmcblk0" + +void init(boot_control_module_t *module); +unsigned getNumberSlots(boot_control_module_t *module); +unsigned getCurrentSlot(boot_control_module_t *module); +int markBootSuccessful(boot_control_module_t *module); +int setActiveBootSlot(boot_control_module_t *module, unsigned slot); +int setSlotAsUnbootable(struct boot_control_module *module, unsigned slot); +int isSlotBootable(struct boot_control_module *module, unsigned slot); +const char* getSuffix(boot_control_module_t *module, unsigned slot); +int isSlotMarkedSuccessful(boot_control_module_t *module, unsigned slot); + +}; //namespace rockchip_boot_control +#endif diff --git a/boot_control/gpt.cpp b/boot_control/gpt.cpp new file mode 100644 index 0000000..777d1ae --- /dev/null +++ b/boot_control/gpt.cpp @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define LOG_TAG "boot_control_hw" +#define LOG_NDEBUG 0 + +#include <string> +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/stat.h> +#include <linux/fs.h> +#include <sys/types.h> +#include <cutils/log.h> +#include <utils/Unicode.h> + +#include "gpt.h" + +using namespace std; + +namespace { + +static uint64_t lba_to_offset(uint64_t lba) +{ + return lba * 512; +} + +/* + * A8h reflected is 15h, i.e. 10101000 <--> 00010101 + */ +int reflect(int data, int len) +{ + int ref = 0; + int i; + for (i = 0; i < len; i++) { + if (data & 0x1) { + ref |= (1 << ((len - 1) - i)); + } + data = (data >> 1); + } + return ref; +} + +uint32_t calculate_crc32(void *buf, uint32_t len) +{ + uint32_t i, j; + uint32_t byte_length = 8; /*length of unit (i.e. byte) */ + int msb = 0; + int polynomial = 0x04C11DB7; /* IEEE 32bit polynomial */ + unsigned int regs = 0xFFFFFFFF; /* init to all ones */ + int regs_mask = 0xFFFFFFFF; /* ensure only 32 bit answer */ + int regs_msb = 0; + unsigned int reflected_regs; + + for (i = 0; i < len; i++) { + int data_byte = *((uint8_t *)buf + i); + data_byte = reflect(data_byte, 8); + for (j = 0; j < byte_length; j++) { + msb = data_byte >> (byte_length - 1); /* get MSB */ + msb &= 1; /* ensure just 1 bit */ + regs_msb = (regs >> 31) & 1; /* MSB of regs */ + regs = regs << 1; /* shift regs for CRC-CCITT */ + if (regs_msb ^ msb) { /* MSB is a 1 */ + regs = regs ^ polynomial; /* XOR with generator poly */ + } + regs = regs & regs_mask; /* Mask off excess upper bits */ + data_byte <<= 1; /* get to next bit */ + } + } + regs = regs & regs_mask; + reflected_regs = reflect(regs, 32) ^ 0xFFFFFFFF; + + return reflected_regs; +} + +int open_disk(const std::string& device, bool open_for_write) +{ + int fd; + int oflag = open_for_write ? O_RDWR : O_RDONLY; + + fd = open (device.c_str(), oflag); + if (-1 == fd) + return -errno; + + ALOGV("open_disk: %s", device.c_str()); + return fd; +} + +ssize_t read_from_disk(const std::string& device, uint64_t offset, + size_t size, void *buf) +{ + ssize_t read_bytes; + ssize_t ret = 0; + int fd = open_disk(device, false); + + if (-1 == fd) + return fd; // fd is set to -errno from open_disk(bool) + + if (-1 == lseek64(fd, offset, SEEK_SET)) { + close(fd); + return -errno; + } + + do { + read_bytes = read(fd, buf, size); + } while (-1 == read_bytes && EINTR == errno); + + if (-1 == read_bytes) + ret = -errno; + else + ret = read_bytes; + + close(fd); + return ret; +} + +ssize_t write_to_disk(const std::string& device, uint64_t offset, + size_t size, void *buf) +{ + ssize_t written_bytes; + ssize_t ret = 0; + int fd = open_disk (device, true); + + if (-1 == fd) + return fd; // fd is set to -errno from open_disk(true) + + if (-1 == lseek64(fd, offset, SEEK_SET)) { + close(fd); + return -errno; + } + + do { + written_bytes = write(fd, buf, size); + } while(-1 == written_bytes && EINTR == errno); + + + if (-1 == written_bytes) + ret = -errno; + else + ret = written_bytes; + + close(fd); + return ret; +} + +}; + +namespace rockchip_boot_control { + +int PartitionTables::write_partitions() +{ + ssize_t ret = 0; + uint64_t size_num_bytes = 0; + uint64_t num_lbas = 0; + int fd = open(disk_device.c_str(), O_RDONLY); + + if (-1 == fd) + return -errno; + + ret = ioctl(fd, BLKGETSIZE64, &size_num_bytes); + + close(fd); + + if (-1 == ret) + return -errno; + + num_lbas = size_num_bytes / 512; + + ALOGV("Total disk LBAs %lld", num_lbas); + + /* Set header's fields for secondary partition */ + header.my_lba = num_lbas - 1; + header.alternate_lba = 1; + header.partition_entry_lba = num_lbas - 33; + + /* Calculate CRCs for secondary header */ + header.header_crc32 = 0; + header.partition_entry_array_crc32 = calculate_crc32(partition_array, + header.num_partition_entries * + sizeof(gpt_entry)); + header.header_crc32 = calculate_crc32(&header, header.header_size); + + /* Write secondary partition array to disk*/ + if ((ret = write_to_disk(disk_device, lba_to_offset(num_lbas - 33), + sizeof(partition_array), partition_array)) < 0) + return ret; + + /* Write secondary header to disk*/ + if ((ret = write_to_disk(disk_device, lba_to_offset(num_lbas - 1), + sizeof(gpt_header), &header)) < 0) + return ret; + + /* Set header's fields for primary partition */ + header.my_lba = 1; + header.alternate_lba = num_lbas - 1; + header.partition_entry_lba = 2; + + /* Calculate CRCs for primary header */ + header.header_crc32 = 0; + header.partition_entry_array_crc32 = calculate_crc32(partition_array, + header.num_partition_entries * + sizeof(gpt_entry)); + header.header_crc32 = calculate_crc32(&header, header.header_size); + + /* Write primary partition array to disk*/ + if ((ret = write_to_disk(disk_device, lba_to_offset(2), + sizeof(partition_array), partition_array)) < 0) + return ret; + + /* Write primary header to disk*/ + if ((ret = write_to_disk(disk_device, lba_to_offset(1), + sizeof(gpt_header), &header)) < 0) + return ret; + + return 0; +} + +std::unique_ptr<PartitionTables> + PartitionTables::read_partitions(const std::string& device) +{ + std::unique_ptr<PartitionTables> gpt(new PartitionTables); + ssize_t ret; + uint64_t size_num_bytes = 0; + uint64_t num_lbas = 0; + int fd = open(device.c_str(), O_RDONLY); + + if (-1 == fd) + return nullptr; + + gpt->disk_device = device; + + ret = ioctl(fd, BLKGETSIZE64, &size_num_bytes); + + close(fd); + + if (-1 == ret) + return nullptr; + + num_lbas = size_num_bytes / 512; + + ALOGV("Total disk LBAs %lld", num_lbas); + + /* Read primary header*/ + if ((ret = read_from_disk(device, lba_to_offset(1), + sizeof(gpt_header), &gpt->header)) < 0) + return nullptr; + + if (gpt->gpt_sanity_check()) { + /* Read primary paritition array.*/ + if ((ret = read_from_disk(device, lba_to_offset(2), + sizeof(partition_array), + gpt->partition_array)) < 0) + return nullptr; + + /* Primary header and partiiton array read*/ + return gpt; + } + + /* + * The seconadary header and partition array is used only in case + * the primary header fails sanity check. + */ + ALOGE("Attempting to read secondary header and partition array."); + + /* Read secondary header. */ + if ((ret = read_from_disk(device, lba_to_offset(num_lbas - 1), + sizeof(gpt_header), &gpt->header)) < 0) + return nullptr; + + if (gpt->gpt_sanity_check()) { + /* Read secondary partition array.*/ + if ((ret = read_from_disk(device, lba_to_offset(num_lbas - 33), + sizeof(partition_array), + gpt->partition_array)) < 0) + return nullptr; + + /* Secondary header and partition array read*/ + return gpt; + } + + ALOGE("Sanity check failed for both headers."); + errno = EIO; + + return nullptr; +} + +bool PartitionTables::gpt_sanity_check() +{ + gpt_header tmp_hdr; + + if (header.signature != GPT_HDR_SIGNATURE) + return false; + + if (header.header_size != 92) + return false; + + /* + * Calculate header's CRC32 and compare against the CRC32 read from disk + */ + memcpy(&tmp_hdr, &header, header.header_size); + tmp_hdr.header_crc32 = 0; + if (header.header_crc32 != calculate_crc32(&tmp_hdr, tmp_hdr.header_size)) + return false; + + return true; +} + +int PartitionTables::getIndexForSlottedBootPartition(unsigned slot, + uint32_t& partition_index) const +{ + unsigned i; + const char16_t* boot_partition_for_slot = slot == 0 ? u"boot_a" : u"boot_b"; + + assert(slot <= MAX_SLOTS); + + for (i = 0; i < header.num_partition_entries; i++) { + if (0 == strcmp16(partition_array[i].partition_name, boot_partition_for_slot)) { + partition_index = i; + return 0; + } + } + + ALOGV("getIndexForSlottedBootPartition: partition %s does not exist", + boot_partition_for_slot); + + return -EINVAL; +} + +}; //rockchip_boot_control + diff --git a/boot_control/gpt.h b/boot_control/gpt.h new file mode 100644 index 0000000..68e66cf --- /dev/null +++ b/boot_control/gpt.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HARDWARE_ROCKCHIP_BOOTCTL_HAL_GPT_H +#define HARDWARE_ROCKCHIP_BOOTCTL_HAL_GPT_H + +#include <string> + +#define GPT_HDR_SIGNATURE 0x5452415020494645ULL +#define MAX_GPT_ENTRIES 128 +#define MAX_SLOTS 2 + +namespace rockchip_boot_control { + +/* linux/include/efi.h */ +typedef char16_t efi_char16_t; + +typedef struct +{ + uint8_t b[16]; +} efi_guid_t; + +/* based on linux/fs/partitions/efi.h */ +typedef struct _gpt_header { + uint64_t signature; + uint32_t revision; + uint32_t header_size; + uint32_t header_crc32; + uint32_t reserved1; + uint64_t my_lba; + uint64_t alternate_lba; + uint64_t first_usable_lba; + uint64_t last_usable_lba; + efi_guid_t disk_guid; + uint64_t partition_entry_lba; + uint32_t num_partition_entries; + uint32_t sizeof_partition_entry; + uint32_t partition_entry_array_crc32; +} __attribute__((packed)) gpt_header; + +typedef union _slot_attributes { + struct { + uint64_t required_to_function:1; + uint64_t no_block_io_protocol:1; + uint64_t legacy_bios_bootable:1; + uint64_t priority:4; + uint64_t tries:4; + uint64_t successful:1; + uint64_t reserved:36; + uint64_t type_guid_specific:16; + } fields; + uint64_t raw; +} __attribute__((packed)) slot_attributes; + +#define PARTNAME_SZ (72 / sizeof(efi_char16_t)) +typedef struct _gpt_entry { + efi_guid_t partition_type_guid; + efi_guid_t unique_partition_guid; + uint64_t starting_lba; + uint64_t ending_lba; + slot_attributes attributes; + efi_char16_t partition_name[PARTNAME_SZ]; +} __attribute__((packed)) gpt_entry; + +class PartitionTables { +public: + /* + * read_partitions() reads the header and partition array from + * primary or secondary GPT of the disk. Secondary GPT is read in case + * primary GPT fails sanity check, errni is set if both GPT copies + * fail sanity check. + * Returns pointer to allocated object on success, + * and 'nullptr' on error with errno set. + * On failure this method will log to stderr. + */ + static std::unique_ptr<PartitionTables> + read_partitions(const std::string& device); + + /* + * write_partitions() writes the header and partition array to + * primary and secondary GPT on the disk. + * Returns 0 on success, -errno on error. + */ + int write_partitions(); + + /* + * getIndexForSlottedBootPartition() gets the partition index associated + * with the slot parameter passed. + * Returns 0 on success, and partition_index value is valid. + * REtrns -errno on error, the partition_index value is invalid. + */ + int getIndexForSlottedBootPartition(unsigned slot, + uint32_t& partition_index) const; + + /* + * gpt_sanity_check() checks the header for correctness of signature, + * size and CRC. + * Returns 'true' on success, 'false' on error. + */ + bool gpt_sanity_check(); + + gpt_header header; + gpt_entry partition_array[MAX_GPT_ENTRIES]; + +private: + std::string disk_device = ""; +}; + +}; //rockchip_boot_control + +#endif |