summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSourabh Banerjee <sbanerje@codeaurora.org>2015-10-20 06:42:03 +0530
committerMohammed Habibulla <moch@google.com>2015-11-05 12:04:29 -0800
commitcdbd9ece90cfa6bb29ec346a575e60807fe4c565 (patch)
tree45de9c7d2877c79d4d577f63b5979c3c320ba336
parent64bec02f0d5c2405b5609e97ad5a4102ac083d90 (diff)
downloadqcom-cdbd9ece90cfa6bb29ec346a575e60807fe4c565.tar.gz
boot control HAL for Qualcomm MSM platform
qcom boot control HAL uses GPT attribute flags to manage the slots. Properties success, priority and try count are used for a given slot. Current implementation supports maximum 2 slots, 'boot_a' and 'boot_b'. BUG=24675877 Change-Id: Ic4aa49ee1221ff17a1ddf566ea283d9b37b76530 Signed-off-by: Sourabh Banerjee <sbanerje@codeaurora.org>
-rw-r--r--boot_control/Android.mk18
-rw-r--r--boot_control/boot_control_qcom.cpp256
-rw-r--r--boot_control/boot_control_qcom.h55
-rw-r--r--boot_control/gpt.cpp357
-rw-r--r--boot_control/gpt.h143
5 files changed, 829 insertions, 0 deletions
diff --git a/boot_control/Android.mk b/boot_control/Android.mk
new file mode 100644
index 0000000..31344b6
--- /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_qcom.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.msm8916
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_SHARED_LIBRARY)
diff --git a/boot_control/boot_control_qcom.cpp b/boot_control/boot_control_qcom.cpp
new file mode 100644
index 0000000..c578578
--- /dev/null
+++ b/boot_control/boot_control_qcom.cpp
@@ -0,0 +1,256 @@
+/*
+ * 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_qcom.h"
+#include "gpt.h"
+
+using namespace std;
+
+/* Qualcomm 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 = "Qualcomm boot_control HAL",
+ .author = "CodeAurora Forum",
+ .methods = &module_methods,
+ },
+ .init = qcom_boot_control::init,
+ .getNumberSlots = qcom_boot_control::getNumberSlots,
+ .getCurrentSlot = qcom_boot_control::getCurrentSlot,
+ .markBootSuccessful = qcom_boot_control::markBootSuccessful,
+ .setActiveBootSlot = qcom_boot_control::setActiveBootSlot,
+ .setSlotAsUnbootable = qcom_boot_control::setSlotAsUnbootable,
+ .isSlotBootable = qcom_boot_control::isSlotBootable,
+ .getSuffix = qcom_boot_control::getSuffix,
+};
+
+namespace qcom_boot_control {
+
+void init(boot_control_module_t *module)
+{
+ ALOGV("QCOM 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].attribute_flag |=
+ PART_ATT_SUCCESS_MASK;
+ gpt->partition_array[partition_index].attribute_flag &=
+ ~PART_ATT_TRIES_MASK;
+
+ 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 */
+ attribute_flags =
+ ((15ULL << PART_ATT_PRIORITY_OFFSET) & PART_ATT_PRIORITY_MASK) |
+ ((7ULL << PART_ATT_TRIES_OFFSET) & PART_ATT_TRIES_MASK);
+
+ gpt->partition_array[partition_index].attribute_flag &= ~PART_ATT_ALL_MASK;
+ gpt->partition_array[partition_index].attribute_flag |= attribute_flags;
+
+ 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].attribute_flag &
+ PART_ATT_PRIORITY_MASK) {
+ gpt->partition_array[partition_index].attribute_flag &=
+ ~PART_ATT_PRIORITY_MASK;
+ gpt->partition_array[partition_index].attribute_flag |=
+ (14ULL << PART_ATT_PRIORITY_OFFSET) & PART_ATT_PRIORITY_MASK;
+ }
+
+ 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].attribute_flag &= ~PART_ATT_ALL_MASK;
+
+ 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].attribute_flag &
+ PART_ATT_SUCCESS_MASK)
+ ret = 1;
+
+ ALOGV("isSlotBootable: Slot: %d attribute: %llx, ret: %d",
+ slot, gpt->partition_array[partition_index].attribute_flag, 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];
+}
+
+}; //namespace qcom_boot_control
diff --git a/boot_control/boot_control_qcom.h b/boot_control/boot_control_qcom.h
new file mode 100644
index 0000000..812d2ed
--- /dev/null
+++ b/boot_control/boot_control_qcom.h
@@ -0,0 +1,55 @@
+/*
+ * 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_QCOM_BOOTCTL_HAL_H
+#define HARDWARE_QCOM_BOOTCTL_HAL_H
+
+#include <hardware/hardware.h>
+#include <hardware/boot_control.h>
+
+namespace qcom_boot_control {
+
+#define BLK_DEV_NODE "/dev/block/mmcblk0"
+
+typedef enum {
+ SLOT_PROPERTY_ATTRIBUTE_FLAGS,
+ SLOT_PROPERTY_PARTITION_INDEX,
+} slot_prop_t;
+
+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);
+
+}; //namespace qcom_boot_control
+#endif
diff --git a/boot_control/gpt.cpp b/boot_control/gpt.cpp
new file mode 100644
index 0000000..962a61c
--- /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 qcom_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.curr_lba = num_lbas - 1;
+ header.backup_lba = 1;
+ header.start_lba_part_array = num_lbas - 33;
+
+ /* Calculate CRCs for secondary header */
+ header.hdr_crc32 = 0;
+ header.part_arr_crc32 = calculate_crc32(partition_array,
+ header.num_parts *
+ sizeof(gpt_partition_entry_t));
+ header.hdr_crc32 = calculate_crc32(&header, header.hdr_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_t), &header)) < 0)
+ return ret;
+
+ /* Set header's fields for primary partition */
+ header.curr_lba = 1;
+ header.backup_lba = num_lbas - 1;
+ header.start_lba_part_array = 2;
+
+ /* Calculate CRCs for primary header */
+ header.hdr_crc32 = 0;
+ header.part_arr_crc32 = calculate_crc32(partition_array,
+ header.num_parts *
+ sizeof(gpt_partition_entry_t));
+ header.hdr_crc32 = calculate_crc32(&header, header.hdr_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_t), &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_t), &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_t), &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_t tmp_hdr;
+
+ if (header.signature != GPT_HDR_SIGNATURE)
+ return false;
+
+ if (header.hdr_size != 92)
+ return false;
+
+ /*
+ * Calculate header's CRC32 and compare against the CRC32 read from disk
+ */
+ memcpy(&tmp_hdr, &header, header.hdr_size);
+ tmp_hdr.hdr_crc32 = 0;
+ if (header.hdr_crc32 != calculate_crc32(&tmp_hdr, tmp_hdr.hdr_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_parts; i++) {
+ if (0 == strcmp16(partition_array[i].name, boot_partition_for_slot)) {
+ partition_index = i;
+ return 0;
+ }
+ }
+
+ ALOGV("getIndexForSlottedBootPartition: partition %s does not exist",
+ boot_partition_for_slot);
+
+ return -EINVAL;
+}
+
+}; //qcom_boot_control
+
diff --git a/boot_control/gpt.h b/boot_control/gpt.h
new file mode 100644
index 0000000..30f9d6f
--- /dev/null
+++ b/boot_control/gpt.h
@@ -0,0 +1,143 @@
+/*
+ * 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_QCOM_BOOTCTL_HAL_GPT_H
+#define HARDWARE_QCOM_BOOTCTL_HAL_GPT_H
+
+#include <string>
+#include <assert.h>
+
+#define GPT_HDR_SIGNATURE 0x5452415020494645ULL
+#define MAX_GPT_ENTRIES 128
+#define GPT_NAME_NUM_CHARS 36
+#define MAX_SLOTS 2
+
+#define PART_ATT_SUCCESS_OFFSET 56
+#define PART_ATT_TRIES_OFFSET 52
+#define PART_ATT_PRIORITY_OFFSET 48
+
+#define PART_ATT_SUCCESS_MASK (((uint64_t)0x1) << PART_ATT_SUCCESS_OFFSET)
+#define PART_ATT_TRIES_MASK (((uint64_t)0xF) << PART_ATT_TRIES_OFFSET)
+#define PART_ATT_PRIORITY_MASK (((uint64_t)0xF) << PART_ATT_PRIORITY_OFFSET)
+#define PART_ATT_ALL_MASK (PART_ATT_SUCCESS_MASK | \
+ PART_ATT_PRIORITY_MASK | \
+ PART_ATT_TRIES_MASK)
+
+namespace qcom_boot_control {
+
+typedef struct
+{
+ uint32_t data1;
+ uint16_t data2;
+ uint16_t data3;
+ uint8_t data4[8];
+} __attribute__((packed)) guid_t;
+
+typedef struct gpt_header {
+ uint64_t signature;
+ uint32_t rev;
+ uint32_t hdr_size;
+ uint32_t hdr_crc32;
+ uint32_t reserved;
+ uint64_t curr_lba;
+ uint64_t backup_lba;
+ uint64_t first_usable_lba;
+ uint64_t last_usable_lba;
+ guid_t disk_guid;
+ uint64_t start_lba_part_array;
+ uint32_t num_parts;
+ uint32_t part_size;
+ uint32_t part_arr_crc32;
+ uint8_t reserved_zeros[420];
+} __attribute__((packed)) gpt_header_t;
+
+typedef struct gpt_partition_entry {
+ guid_t type_guid;
+ guid_t unique_partition_guid;
+ uint64_t first_lba;
+ uint64_t last_lba;
+ uint64_t attribute_flag;
+ char16_t name[GPT_NAME_NUM_CHARS];
+} __attribute__((packed)) gpt_partition_entry_t;
+
+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_t header;
+ gpt_partition_entry_t partition_array[MAX_GPT_ENTRIES];
+
+private:
+ std::string disk_device = "";
+};
+
+#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6
+static_assert(sizeof(guid_t) == 16, "struct guid_t has wrong size");
+static_assert(sizeof(gpt_header_t) == 512,
+ "struct gpt_header_t has wrong size");
+static_assert(sizeof(gpt_partition_entry_t) == 128,
+ "struct gpt_partition_entry_t has wrong size");
+#endif
+
+}; //qcom_boot_control
+
+#endif