summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Wang <leozwang@google.com>2016-01-29 17:26:12 +0000
committerAndroid Partner Code Review <android-gerrit-partner@google.com>2016-01-29 17:26:12 +0000
commit0af041c0ad930a2173803a780158e0186f4b0f85 (patch)
treea010d62112eab0e4cbff98c28c3edce91aa78e8d
parent5849b430b84cc2deec30f1baff3440e15c954e65 (diff)
parent57025cebf42022966bfcce7df7c010257bbcfe41 (diff)
downloadrockchip-0af041c0ad930a2173803a780158e0186f4b0f85.tar.gz
Merge "kylin: Add boot_control, base on qcom" into m-brillo-dev-kylin
-rw-r--r--boot_control/Android.mk18
-rw-r--r--boot_control/boot_control_rockchip.cpp277
-rw-r--r--boot_control/boot_control_rockchip.h51
-rw-r--r--boot_control/gpt.cpp357
-rw-r--r--boot_control/gpt.h137
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