corfur: Add A/B support

bootctrl& gpt-utils modified from http://github.com/LineageOS/android_device_motorola_sm7325-common
This commit is contained in:
Venkat Yadlapati 2022-10-23 02:47:46 +05:30
parent ea5f352643
commit 63af62a6f1
17 changed files with 4145 additions and 0 deletions

View File

@ -0,0 +1,24 @@
filegroup {
name: "android.hardware.boot@1.1-impl-qti_src",
srcs: ["BootControl.cpp"],
}
cc_defaults {
name: "android.hardware.boot@1.1-impl-qti_defaults",
defaults: [
"hidl_defaults",
"libboot_control_qti_defaults",
],
relative_install_path: "hw",
vendor: true,
recovery_available: true,
srcs: [":android.hardware.boot@1.1-impl-qti_src"],
shared_libs: [
"liblog",
"libhidlbase",
"libhardware",
"libutils",
"android.hardware.boot@1.0",
"android.hardware.boot@1.1",
],
}

View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 2020, 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 "android.hardware.boot@1.1-impl-qti"
#include <memory>
#include <log/log.h>
#include "BootControl.h"
namespace android {
namespace hardware {
namespace boot {
namespace V1_1 {
namespace implementation {
using ::android::hardware::boot::V1_0::CommandResult;
bool BootControl::Init() {
return bootcontrol_init();
}
Return<uint32_t> BootControl::getNumberSlots() {
return get_number_slots();
}
Return<uint32_t> BootControl::getCurrentSlot() {
return get_current_slot();
}
Return<void> BootControl::markBootSuccessful(markBootSuccessful_cb _hidl_cb) {
int ret = mark_boot_successful();
struct CommandResult cr;
cr.success = (ret == 0);
cr.errMsg = strerror(-ret);
_hidl_cb(cr);
return Void();
}
Return<void> BootControl::setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) {
int ret = set_active_boot_slot(slot);
struct CommandResult cr;
cr.success = (ret == 0);
cr.errMsg = strerror(-ret);
_hidl_cb(cr);
return Void();
}
Return<void> BootControl::setSlotAsUnbootable(uint32_t slot, setSlotAsUnbootable_cb _hidl_cb) {
int ret = set_slot_as_unbootable(slot);
struct CommandResult cr;
cr.success = (ret == 0);
cr.errMsg = strerror(-ret);
_hidl_cb(cr);
return Void();
}
Return<BoolResult> BootControl::isSlotBootable(uint32_t slot) {
int32_t ret = is_slot_bootable(slot);
if (ret < 0) {
return BoolResult::INVALID_SLOT;
}
return ret ? BoolResult::TRUE : BoolResult::FALSE;
}
Return<BoolResult> BootControl::isSlotMarkedSuccessful(uint32_t slot) {
int32_t ret = is_slot_marked_successful(slot);
if (ret < 0) {
return BoolResult::INVALID_SLOT;
}
return ret ? BoolResult::TRUE : BoolResult::FALSE;
}
Return<void> BootControl::getSuffix(uint32_t slot, getSuffix_cb _hidl_cb) {
hidl_string ans;
const char* suffix = get_suffix(slot);
if (suffix) {
ans = suffix;
}
_hidl_cb(ans);
return Void();
}
Return<bool> BootControl::setSnapshotMergeStatus(MergeStatus status) {
return set_snapshot_merge_status(status);
}
Return<MergeStatus> BootControl::getSnapshotMergeStatus() {
return get_snapshot_merge_status();
}
IBootControl* HIDL_FETCH_IBootControl(const char* /* hal */) {
auto module = std::make_unique<BootControl>();
if (!module->Init()) {
ALOGE("Could not initialize BootControl module");
return nullptr;
}
return module.release();
}
} // namespace implementation
} // namespace V1_1
} // namespace boot
} // namespace hardware
} // namespace android

View File

@ -0,0 +1,75 @@
/*
* Copyright (c) 2020, 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.
*/
#pragma once
#include <android/hardware/boot/1.1/IBootControl.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include <libboot_control_qti.h>
namespace android {
namespace hardware {
namespace boot {
namespace V1_1 {
namespace implementation {
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::boot::V1_0::BoolResult;
using ::android::hardware::boot::V1_1::IBootControl;
using ::android::hardware::boot::V1_1::MergeStatus;
class BootControl : public IBootControl {
public:
bool Init();
// Methods from ::android::hardware::boot::V1_0::IBootControl follow.
Return<uint32_t> getNumberSlots() override;
Return<uint32_t> getCurrentSlot() override;
Return<void> markBootSuccessful(markBootSuccessful_cb _hidl_cb) override;
Return<void> setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) override;
Return<void> setSlotAsUnbootable(uint32_t slot, setSlotAsUnbootable_cb _hidl_cb) override;
Return<BoolResult> isSlotBootable(uint32_t slot) override;
Return<BoolResult> isSlotMarkedSuccessful(uint32_t slot) override;
Return<void> getSuffix(uint32_t slot, getSuffix_cb _hidl_cb) override;
// Methods from ::android::hardware::boot::V1_1::IBootControl follow.
Return<bool> setSnapshotMergeStatus(MergeStatus status) override;
Return<MergeStatus> getSnapshotMergeStatus() override;
};
extern "C" IBootControl* HIDL_FETCH_IBootControl(const char* name);
} // namespace implementation
} // namespace V1_1
} // namespace boot
} // namespace hardware
} // namespace android

View File

@ -0,0 +1,38 @@
filegroup {
name: "libboot_control_qti_src",
srcs: ["libboot_control_qti.cpp"],
}
cc_library_headers {
name: "libboot_control_qti_headers",
vendor: true,
recovery_available: true,
export_include_dirs: ["."],
}
cc_defaults {
name: "libboot_control_qti_defaults",
vendor: true,
recovery_available: true,
shared_libs: [
"android.hardware.boot@1.1",
"libbase",
"libcutils",
"liblog",
"libz",
],
static_libs: [
"libboot_control",
"libbootloader_message_vendor",
"libfstab",
],
owner: "qti",
cflags: [
"-Wall",
"-Werror",
],
srcs: [
":libboot_control_qti_src",
],
header_libs: ["libboot_control_qti_headers"],
}

View File

@ -0,0 +1,754 @@
/*
* Copyright (c) 2016,2020, 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_NDEBUG 0
#define LOG_TAG "bootcontrolhal"
#include <libboot_control_qti.h>
#include <map>
#include <list>
#include <string>
#include <vector>
#include <errno.h>
#include <cutils/log.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <cutils/properties.h>
#include <gpt-utils.h>
#include <bootloader_message/bootloader_message.h>
#include <libboot_control/libboot_control.h>
#define BOOTDEV_DIR "/dev/block/bootdevice/by-name"
#define BOOT_IMG_PTN_NAME "boot"
#define LUN_NAME_END_LOC 14
#define BOOT_SLOT_PROP "ro.boot.slot_suffix"
#define BOARD_PLATFORM_PROP "ro.build.product"
#define GVMQ_PLATFORM "msmnile_gvmq"
#define SLOT_ACTIVE 1
#define SLOT_INACTIVE 2
#define UPDATE_SLOT(pentry, guid, slot_state) ({ \
memcpy(pentry, guid, TYPE_GUID_SIZE); \
if (slot_state == SLOT_ACTIVE)\
*(pentry + AB_FLAG_OFFSET) = AB_SLOT_ACTIVE_VAL; \
else if (slot_state == SLOT_INACTIVE) \
*(pentry + AB_FLAG_OFFSET) = (*(pentry + AB_FLAG_OFFSET)& \
~AB_PARTITION_ATTR_SLOT_ACTIVE); \
})
using namespace std;
const char *slot_suffix_arr[] = {
AB_SLOT_A_SUFFIX,
AB_SLOT_B_SUFFIX,
NULL};
enum part_attr_type {
ATTR_SLOT_ACTIVE = 0,
ATTR_BOOT_SUCCESSFUL,
ATTR_UNBOOTABLE,
};
bool mGvmqPlatform = false;
using ::android::bootable::GetMiscVirtualAbMergeStatus;
using ::android::bootable::InitMiscVirtualAbMessageIfNeeded;
using ::android::bootable::SetMiscVirtualAbMergeStatus;
using ::android::hardware::boot::V1_1::MergeStatus;
//Get the value of one of the attribute fields for a partition.
static int get_partition_attribute(char *partname,
enum part_attr_type part_attr)
{
struct gpt_disk *disk = NULL;
uint8_t *pentry = NULL;
int retval = -1;
uint8_t *attr = NULL;
if (!partname)
goto error;
disk = gpt_disk_alloc();
if (!disk) {
ALOGE("%s: Failed to alloc disk struct", __func__);
goto error;
}
if (gpt_disk_get_disk_info(partname, disk)) {
ALOGE("%s: Failed to get disk info", __func__);
goto error;
}
pentry = gpt_disk_get_pentry(disk, partname, PRIMARY_GPT);
if (!pentry) {
ALOGE("%s: pentry does not exist in disk struct",
__func__);
goto error;
}
attr = pentry + AB_FLAG_OFFSET;
if (part_attr == ATTR_SLOT_ACTIVE)
retval = !!(*attr & AB_PARTITION_ATTR_SLOT_ACTIVE);
else if (part_attr == ATTR_BOOT_SUCCESSFUL)
retval = !!(*attr & AB_PARTITION_ATTR_BOOT_SUCCESSFUL);
else if (part_attr == ATTR_UNBOOTABLE)
retval = !!(*attr & AB_PARTITION_ATTR_UNBOOTABLE);
else
retval = -1;
gpt_disk_free(disk);
return retval;
error:
if (disk)
gpt_disk_free(disk);
return retval;
}
//Set a particular attribute for all the partitions in a
//slot
static int update_slot_attribute(const char *slot,
enum part_attr_type ab_attr)
{
unsigned int i = 0;
char buf[PATH_MAX];
struct stat st;
struct gpt_disk *disk = NULL;
uint8_t *pentry = NULL;
uint8_t *pentry_bak = NULL;
int rc = -1;
uint8_t *attr = NULL;
uint8_t *attr_bak = NULL;
char partName[MAX_GPT_NAME_SIZE + 1] = {0};
const char ptn_list[][MAX_GPT_NAME_SIZE] = { AB_PTN_LIST };
int slot_name_valid = 0;
if (!slot) {
ALOGE("%s: Invalid argument", __func__);
goto error;
}
for (i = 0; slot_suffix_arr[i] != NULL; i++)
{
if (!strncmp(slot, slot_suffix_arr[i],
strlen(slot_suffix_arr[i])))
slot_name_valid = 1;
}
if (!slot_name_valid) {
ALOGE("%s: Invalid slot name", __func__);
goto error;
}
for (i=0; i < ARRAY_SIZE(ptn_list); i++) {
memset(buf, '\0', sizeof(buf));
//Check if A/B versions of this ptn exist
snprintf(buf, sizeof(buf) - 1,
"%s/%s%s",
BOOT_DEV_DIR,
ptn_list[i],
AB_SLOT_A_SUFFIX
);
if (stat(buf, &st)) {
//partition does not have _a version
continue;
}
memset(buf, '\0', sizeof(buf));
snprintf(buf, sizeof(buf) - 1,
"%s/%s%s",
BOOT_DEV_DIR,
ptn_list[i],
AB_SLOT_B_SUFFIX
);
if (stat(buf, &st)) {
//partition does not have _a version
continue;
}
memset(partName, '\0', sizeof(partName));
snprintf(partName,
sizeof(partName) - 1,
"%s%s",
ptn_list[i],
slot);
disk = gpt_disk_alloc();
if (!disk) {
ALOGE("%s: Failed to alloc disk struct",
__func__);
goto error;
}
rc = gpt_disk_get_disk_info(partName, disk);
if (rc != 0) {
ALOGE("%s: Failed to get disk info for %s",
__func__,
partName);
goto error;
}
pentry = gpt_disk_get_pentry(disk, partName, PRIMARY_GPT);
pentry_bak = gpt_disk_get_pentry(disk, partName, SECONDARY_GPT);
if (!pentry || !pentry_bak) {
ALOGE("%s: Failed to get pentry/pentry_bak for %s",
__func__,
partName);
goto error;
}
attr = pentry + AB_FLAG_OFFSET;
attr_bak = pentry_bak + AB_FLAG_OFFSET;
if (ab_attr == ATTR_BOOT_SUCCESSFUL) {
*attr = (*attr) | AB_PARTITION_ATTR_BOOT_SUCCESSFUL;
*attr_bak = (*attr_bak) |
AB_PARTITION_ATTR_BOOT_SUCCESSFUL;
} else if (ab_attr == ATTR_UNBOOTABLE) {
*attr = (*attr) | AB_PARTITION_ATTR_UNBOOTABLE;
*attr_bak = (*attr_bak) | AB_PARTITION_ATTR_UNBOOTABLE;
} else if (ab_attr == ATTR_SLOT_ACTIVE) {
*attr = (*attr) | AB_PARTITION_ATTR_SLOT_ACTIVE;
*attr_bak = (*attr) | AB_PARTITION_ATTR_SLOT_ACTIVE;
} else {
ALOGE("%s: Unrecognized attr", __func__);
goto error;
}
if (gpt_disk_update_crc(disk)) {
ALOGE("%s: Failed to update crc for %s",
__func__,
partName);
goto error;
}
if (gpt_disk_commit(disk)) {
ALOGE("%s: Failed to write back entry for %s",
__func__,
partName);
goto error;
}
gpt_disk_free(disk);
disk = NULL;
}
return 0;
error:
if (disk)
gpt_disk_free(disk);
return -1;
}
static int boot_control_check_slot_sanity(unsigned slot)
{
uint32_t num_slots = get_number_slots();
if ((num_slots < 1) || (slot > num_slots - 1)) {
ALOGE("Invalid slot number");
return -1;
}
return 0;
}
//Return a gpt disk structure representing the disk that holds
//partition.
static struct gpt_disk* boot_ctl_get_disk_info(char *partition)
{
struct gpt_disk *disk = NULL;
if (!partition)
return NULL;
disk = gpt_disk_alloc();
if (!disk) {
ALOGE("%s: Failed to alloc disk",
__func__);
goto error;
}
if (gpt_disk_get_disk_info(partition, disk)) {
ALOGE("failed to get disk info for %s",
partition);
goto error;
}
return disk;
error:
if (disk)
gpt_disk_free(disk);
return NULL;
}
//The argument here is a vector of partition names(including the slot suffix)
//that lie on a single disk
static int boot_ctl_set_active_slot_for_partitions(vector<string> part_list,
unsigned slot)
{
char buf[PATH_MAX] = {0};
struct gpt_disk *diskA = NULL;
struct gpt_disk *diskB = NULL;
char slotA[MAX_GPT_NAME_SIZE + 1] = {0};
char slotB[MAX_GPT_NAME_SIZE + 1] = {0};
char active_guid[TYPE_GUID_SIZE + 1] = {0};
char inactive_guid[TYPE_GUID_SIZE + 1] = {0};
//Pointer to the partition entry of current 'A' partition
uint8_t *pentryA = NULL;
uint8_t *pentryA_bak = NULL;
//Pointer to partition entry of current 'B' partition
uint8_t *pentryB = NULL;
uint8_t *pentryB_bak = NULL;
struct stat st;
vector<string>::iterator partition_iterator;
for (partition_iterator = part_list.begin();
partition_iterator != part_list.end();
partition_iterator++) {
//Chop off the slot suffix from the partition name to
//make the string easier to work with.
string prefix = *partition_iterator;
if (prefix.size() < (strlen(AB_SLOT_A_SUFFIX) + 1)) {
ALOGE("Invalid partition name: %s", prefix.c_str());
goto error;
}
prefix.resize(prefix.size() - strlen(AB_SLOT_A_SUFFIX));
//Check if A/B versions of this ptn exist
snprintf(buf, sizeof(buf) - 1, "%s/%s%s", BOOT_DEV_DIR,
prefix.c_str(),
AB_SLOT_A_SUFFIX);
if (stat(buf, &st))
continue;
memset(buf, '\0', sizeof(buf));
snprintf(buf, sizeof(buf) - 1, "%s/%s%s", BOOT_DEV_DIR,
prefix.c_str(),
AB_SLOT_B_SUFFIX);
if (stat(buf, &st))
continue;
memset(slotA, 0, sizeof(slotA));
memset(slotB, 0, sizeof(slotB));
snprintf(slotA, sizeof(slotA) - 1, "%s%s", prefix.c_str(),
AB_SLOT_A_SUFFIX);
snprintf(slotB, sizeof(slotB) - 1,"%s%s", prefix.c_str(),
AB_SLOT_B_SUFFIX);
//Get the disks containing the partitions that were passed in.
if (!diskA) {
diskA = boot_ctl_get_disk_info(slotA);
if (!diskA)
goto error;
}
if (!diskB) {
diskB = boot_ctl_get_disk_info(slotB);
if (!diskB)
goto error;
}
//Get partition entry for slot A & B from the primary
//and backup tables.
pentryA = gpt_disk_get_pentry(diskA, slotA, PRIMARY_GPT);
pentryA_bak = gpt_disk_get_pentry(diskA, slotA, SECONDARY_GPT);
pentryB = gpt_disk_get_pentry(diskB, slotB, PRIMARY_GPT);
pentryB_bak = gpt_disk_get_pentry(diskB, slotB, SECONDARY_GPT);
if ( !pentryA || !pentryA_bak || !pentryB || !pentryB_bak) {
//None of these should be NULL since we have already
//checked for A & B versions earlier.
ALOGE("Slot pentries for %s not found.",
prefix.c_str());
goto error;
}
memset(active_guid, '\0', sizeof(active_guid));
memset(inactive_guid, '\0', sizeof(inactive_guid));
if (get_partition_attribute(slotA, ATTR_SLOT_ACTIVE) == 1) {
//A is the current active slot
memcpy((void*)active_guid, (const void*)pentryA,
TYPE_GUID_SIZE);
memcpy((void*)inactive_guid,(const void*)pentryB,
TYPE_GUID_SIZE);
} else if (get_partition_attribute(slotB,
ATTR_SLOT_ACTIVE) == 1) {
//B is the current active slot
memcpy((void*)active_guid, (const void*)pentryB,
TYPE_GUID_SIZE);
memcpy((void*)inactive_guid, (const void*)pentryA,
TYPE_GUID_SIZE);
} else {
ALOGE("Both A & B for %s are inactive..Aborting",
prefix.c_str());
goto error;
}
if (!strncmp(slot_suffix_arr[slot], AB_SLOT_A_SUFFIX,
strlen(AB_SLOT_A_SUFFIX))){
//Mark A as active in primary table
UPDATE_SLOT(pentryA, active_guid, SLOT_ACTIVE);
//Mark A as active in backup table
UPDATE_SLOT(pentryA_bak, active_guid, SLOT_ACTIVE);
//Mark B as inactive in primary table
UPDATE_SLOT(pentryB, inactive_guid, SLOT_INACTIVE);
//Mark B as inactive in backup table
UPDATE_SLOT(pentryB_bak, inactive_guid, SLOT_INACTIVE);
} else if (!strncmp(slot_suffix_arr[slot], AB_SLOT_B_SUFFIX,
strlen(AB_SLOT_B_SUFFIX))){
//Mark B as active in primary table
UPDATE_SLOT(pentryB, active_guid, SLOT_ACTIVE);
//Mark B as active in backup table
UPDATE_SLOT(pentryB_bak, active_guid, SLOT_ACTIVE);
//Mark A as inavtive in primary table
UPDATE_SLOT(pentryA, inactive_guid, SLOT_INACTIVE);
//Mark A as inactive in backup table
UPDATE_SLOT(pentryA_bak, inactive_guid, SLOT_INACTIVE);
} else {
//Something has gone terribly terribly wrong
ALOGE("%s: Unknown slot suffix!", __func__);
goto error;
}
if (diskA) {
if (gpt_disk_update_crc(diskA) != 0) {
ALOGE("%s: Failed to update gpt_disk crc",
__func__);
goto error;
}
}
if (diskB) {
if (gpt_disk_update_crc(diskB) != 0) {
ALOGE("%s: Failed to update gpt_disk crc",
__func__);
goto error;
}
}
}
//write updated content to disk
if (diskA) {
if (gpt_disk_commit(diskA)) {
ALOGE("Failed to commit disk entry");
goto error;
}
gpt_disk_free(diskA);
}
if (diskB) {
if (gpt_disk_commit(diskB)) {
ALOGE("Failed to commit disk entry");
goto error;
}
gpt_disk_free(diskB);
}
return 0;
error:
if (diskA)
gpt_disk_free(diskA);
if (diskB)
gpt_disk_free(diskB);
return -1;
}
bool bootcontrol_init()
{
char platform[256];
property_get(BOARD_PLATFORM_PROP , platform, "");
if (!strncmp(platform, GVMQ_PLATFORM, strlen(GVMQ_PLATFORM)))
mGvmqPlatform = true;
return InitMiscVirtualAbMessageIfNeeded();
}
unsigned get_number_slots()
{
if (mGvmqPlatform)
return 2;
struct dirent *de = NULL;
DIR *dir_bootdev = NULL;
unsigned slot_count = 0;
dir_bootdev = opendir(BOOTDEV_DIR);
if (!dir_bootdev) {
ALOGE("%s: Failed to open bootdev dir (%s)",
__func__,
strerror(errno));
goto error;
}
while ((de = readdir(dir_bootdev))) {
if (de->d_name[0] == '.')
continue;
if (!strncmp(de->d_name, BOOT_IMG_PTN_NAME,
strlen(BOOT_IMG_PTN_NAME)))
slot_count++;
}
closedir(dir_bootdev);
return slot_count;
error:
if (dir_bootdev)
closedir(dir_bootdev);
return 0;
}
unsigned get_current_slot()
{
uint32_t num_slots = 0;
char bootSlotProp[PROPERTY_VALUE_MAX] = {'\0'};
unsigned i = 0;
num_slots = get_number_slots();
if (num_slots <= 1) {
//Slot 0 is the only slot around.
return 0;
}
property_get(BOOT_SLOT_PROP, bootSlotProp, "N/A");
if (!strncmp(bootSlotProp, "N/A", strlen("N/A"))) {
ALOGE("%s: Unable to read boot slot property",
__func__);
goto error;
}
//Iterate through a list of partitons named as boot+suffix
//and see which one is currently active.
for (i = 0; slot_suffix_arr[i] != NULL ; i++) {
if (!strncmp(bootSlotProp,
slot_suffix_arr[i],
strlen(slot_suffix_arr[i])))
return i;
}
error:
//The HAL spec requires that we return a number between
//0 to num_slots - 1. Since something went wrong here we
//are just going to return the default slot.
return 0;
}
int mark_boot_successful(){
if (mGvmqPlatform) {
std::string err;
std::string misc_blk_device = get_bootloader_message_blk_device(&err);
if (misc_blk_device.empty()) {
ALOGE("Could not find bootloader message block device: %s", err.c_str());
return -1;
}
bootloader_message boot;
if (!read_bootloader_message_from(&boot, misc_blk_device, &err)) {
ALOGE(" Failed to read from %s due to %s ", misc_blk_device.c_str(), err.c_str());
return -1;
}
ALOGV(" bootloader_message is : boot.reserved[0] = %c, boot.reserved[1] = %c",
boot.reserved[0], boot.reserved[1]);
boot.reserved[2] = 'y';
if (!write_bootloader_message_to(boot, misc_blk_device, &err)) {
ALOGE("Failed to write to %s because : %s", misc_blk_device.c_str(), err.c_str());
return -1;
}
bootloader_message boot_verify;
if (!read_bootloader_message_from(&boot_verify, misc_blk_device, &err)) {
ALOGE("Failed to read from %s due to %s ", misc_blk_device.c_str(), err.c_str());
return -1;
}
ALOGV(" bootloader_message : boot_verify.reserved[0] = %c, boot_verify.reserved[1] = %c,boot_verify.reserved[2] = %c",
boot_verify.reserved[0],boot_verify.reserved[1], boot_verify.reserved[2]);
}
unsigned cur_slot = 0;
cur_slot = get_current_slot();
if (update_slot_attribute(slot_suffix_arr[cur_slot],
ATTR_BOOT_SUCCESSFUL)) {
goto error;
}
return 0;
error:
ALOGE("%s: Failed to mark boot successful", __func__);
return -1;
}
int set_active_boot_slot(unsigned slot)
{
if (mGvmqPlatform) {
std::string err;
std::string misc_blk_device = get_bootloader_message_blk_device(&err);
if (misc_blk_device.empty()) {
ALOGE("Could not find bootloader message block device: %s", err.c_str());
return -1;
}
unsigned current_slot = get_current_slot();
uint32_t num_slots = get_number_slots();
if ((num_slots < 1) || (current_slot > num_slots - 1)) {
ALOGE("Invalid slot number");
return -1;
}
bootloader_message boot;
if(current_slot == 0)
boot.reserved[0] = 'a';
else
boot.reserved[0] = 'b';
if(slot == 0)
boot.reserved[1] = 'a';
else
boot.reserved[1] = 'b';
boot.reserved[2] = '\0';
if (!write_bootloader_message_to(boot, misc_blk_device, &err)) {
ALOGE("Failed to write to %s because : %s", misc_blk_device.c_str(), err.c_str());
return -1;
}
bootloader_message boot_verify;
if (!read_bootloader_message_from(&boot_verify, misc_blk_device, &err)) {
ALOGE("Failed to read from %s due to %s ", misc_blk_device.c_str(), err.c_str());
return -1;
}
ALOGV("bootloader_message is : boot_verify.reserved[0] = %c, boot_verify.reserved[1] = %c,boot_verify.reserved[2] = %c",
boot_verify.reserved[0],boot_verify.reserved[1], boot_verify.reserved[2]);
}
map<string, vector<string>> ptn_map;
vector<string> ptn_vec;
const char ptn_list[][MAX_GPT_NAME_SIZE] = { AB_PTN_LIST };
uint32_t i;
int rc = -1;
int is_ufs = gpt_utils_is_ufs_device();
map<string, vector<string>>::iterator map_iter;
if (boot_control_check_slot_sanity(slot)) {
ALOGE("%s: Bad arguments", __func__);
goto error;
}
//The partition list just contains prefixes(without the _a/_b) of the
//partitions that support A/B. In order to get the layout we need the
//actual names. To do this we append the slot suffix to every member
//in the list.
for (i = 0; i < ARRAY_SIZE(ptn_list); i++) {
//XBL & XBL_CFG are handled differrently for ufs devices so
//ignore them
if (is_ufs && (!strncmp(ptn_list[i],
PTN_XBL,
strlen(PTN_XBL))
|| !strncmp(ptn_list[i],
PTN_XBL_CFG,
strlen(PTN_XBL_CFG))))
continue;
//The partition list will be the list of partitions
//corresponding to the slot being set active
string cur_ptn = ptn_list[i];
cur_ptn.append(slot_suffix_arr[slot]);
ptn_vec.push_back(cur_ptn);
}
//The partition map gives us info in the following format:
// [path_to_block_device_1]--><partitions on device 1>
// [path_to_block_device_2]--><partitions on device 2>
// ...
// ...
// eg:
// [/dev/block/sdb]---><system, boot, rpm, tz,....>
if (gpt_utils_get_partition_map(ptn_vec, ptn_map)) {
ALOGE("%s: Failed to get partition map",
__func__);
goto error;
}
for (map_iter = ptn_map.begin(); map_iter != ptn_map.end(); map_iter++){
if (map_iter->second.size() < 1)
continue;
if (boot_ctl_set_active_slot_for_partitions(map_iter->second,
slot)) {
ALOGE("%s: Failed to set active slot", __func__);
goto error;
}
}
if (is_ufs) {
if (!strncmp(slot_suffix_arr[slot], AB_SLOT_A_SUFFIX,
strlen(AB_SLOT_A_SUFFIX))){
//Set xbl_a as the boot lun
rc = gpt_utils_set_xbl_boot_partition(NORMAL_BOOT);
} else if (!strncmp(slot_suffix_arr[slot], AB_SLOT_B_SUFFIX,
strlen(AB_SLOT_B_SUFFIX))){
//Set xbl_b as the boot lun
rc = gpt_utils_set_xbl_boot_partition(BACKUP_BOOT);
} else {
//Something has gone terribly terribly wrong
ALOGE("%s: Unknown slot suffix!", __func__);
goto error;
}
if (rc) {
ALOGE("%s: Failed to switch xbl boot partition",
__func__);
goto error;
}
}
return 0;
error:
return -1;
}
int set_slot_as_unbootable(unsigned slot)
{
if (boot_control_check_slot_sanity(slot) != 0) {
ALOGE("%s: Argument check failed", __func__);
goto error;
}
if (update_slot_attribute(slot_suffix_arr[slot],
ATTR_UNBOOTABLE)) {
goto error;
}
return 0;
error:
ALOGE("%s: Failed to mark slot unbootable", __func__);
return -1;
}
int is_slot_bootable(unsigned slot)
{
int attr = 0;
char bootPartition[MAX_GPT_NAME_SIZE + 1] = {0};
if (boot_control_check_slot_sanity(slot) != 0) {
ALOGE("%s: Argument check failed", __func__);
goto error;
}
snprintf(bootPartition,
sizeof(bootPartition) - 1, "boot%s",
slot_suffix_arr[slot]);
attr = get_partition_attribute(bootPartition, ATTR_UNBOOTABLE);
if (attr >= 0)
return !attr;
error:
return -1;
}
int is_slot_marked_successful(unsigned slot)
{
int attr = 0;
char bootPartition[MAX_GPT_NAME_SIZE + 1] = {0};
if (boot_control_check_slot_sanity(slot) != 0) {
ALOGE("%s: Argument check failed", __func__);
goto error;
}
snprintf(bootPartition,
sizeof(bootPartition) - 1,
"boot%s", slot_suffix_arr[slot]);
attr = get_partition_attribute(bootPartition, ATTR_BOOT_SUCCESSFUL);
if (attr >= 0)
return attr;
error:
return -1;
}
const char* get_suffix(unsigned slot)
{
if (boot_control_check_slot_sanity(slot) != 0)
return NULL;
else
return slot_suffix_arr[slot];
}
bool set_snapshot_merge_status(MergeStatus status)
{
bool retval = SetMiscVirtualAbMergeStatus(get_current_slot(), status);
ALOGI("%s: MergeStatus = %d, current_slot = %d, returning: %s \n", __func__,
status, get_current_slot(), retval ? "true" : "false");
return retval;
}
MergeStatus get_snapshot_merge_status()
{
MergeStatus status;
if (!GetMiscVirtualAbMergeStatus(get_current_slot(), &status)) {
ALOGI("%s: MergeStatus read from misc failed, returning unknown\n", __func__);
return MergeStatus::UNKNOWN;
}
ALOGI("%s: Returning MergeStatus = %d\n", __func__, status);
return status;
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2020, 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.
*/
#pragma once
#include <string>
#include <android/hardware/boot/1.1/IBootControl.h>
using MergeStatus = ::android::hardware::boot::V1_1::MergeStatus;
// IBootControl 1.0 methods
bool bootcontrol_init();
unsigned get_number_slots();
unsigned get_current_slot();
int mark_boot_successful();
int set_active_boot_slot(unsigned slot);
int set_slot_as_unbootable(unsigned slot);
int is_slot_bootable(unsigned slot);
int is_slot_marked_successful(unsigned slot);
const char* get_suffix(unsigned slot);
// IBootControl 1.1 methods
bool set_snapshot_merge_status(MergeStatus status);
MergeStatus get_snapshot_merge_status();

44
bootctrl/Android.bp Normal file
View File

@ -0,0 +1,44 @@
filegroup {
name: "bootctrl_hal_src",
srcs: [
"boot_control.cpp",
],
}
cc_defaults {
name: "bootctrl_hal_defaults",
proprietary: true,
recovery_available: true,
header_libs: [
"libhardware_headers",
"libsystem_headers",
],
shared_libs: [
"libcutils",
"liblog",
"libz",
],
owner: "qti",
relative_install_path: "hw",
cflags: [
"-Wall",
"-Werror",
],
srcs: [
":bootctrl_hal_src",
],
}
cc_library {
name: "bootctrl.holi",
defaults: ["bootctrl_hal_defaults"],
static_libs: ["libgptutils.corfur"],
}
cc_library_shared {
name: "android.hardware.boot@1.1-impl-qti",
stem: "android.hardware.boot@1.0-impl-1.1-qti",
defaults: ["android.hardware.boot@1.1-impl-qti_defaults"],
static_libs: ["libgptutils.corfur"],
}

26
bootctrl/NOTICE Normal file
View File

@ -0,0 +1,26 @@
Copyright (c) 2016, 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.

703
bootctrl/boot_control.cpp Normal file
View File

@ -0,0 +1,703 @@
/*
* Copyright (c) 2016, 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.
*/
#include <map>
#include <list>
#include <string>
#include <vector>
#ifdef __cplusplus
extern "C" {
#endif
#include <errno.h>
#define LOG_TAG "bootcontrolhal"
#include <cutils/log.h>
#include <hardware/boot_control.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <cutils/properties.h>
#include "gpt-utils.h"
#define BOOTDEV_DIR "/dev/block/bootdevice/by-name"
#define BOOT_IMG_PTN_NAME "boot"
#define LUN_NAME_END_LOC 14
#define BOOT_SLOT_PROP "ro.boot.slot_suffix"
#define SLOT_ACTIVE 1
#define SLOT_INACTIVE 2
#define UPDATE_SLOT(pentry, guid, slot_state) ({ \
memcpy(pentry, guid, TYPE_GUID_SIZE); \
if (slot_state == SLOT_ACTIVE)\
*(pentry + AB_FLAG_OFFSET) = AB_SLOT_ACTIVE_VAL; \
else if (slot_state == SLOT_INACTIVE) \
*(pentry + AB_FLAG_OFFSET) = (*(pentry + AB_FLAG_OFFSET)& \
~AB_PARTITION_ATTR_SLOT_ACTIVE); \
})
using namespace std;
const char *slot_suffix_arr[] = {
AB_SLOT_A_SUFFIX,
AB_SLOT_B_SUFFIX,
NULL};
enum part_attr_type {
ATTR_SLOT_ACTIVE = 0,
ATTR_BOOT_SUCCESSFUL,
ATTR_UNBOOTABLE,
};
void boot_control_init(struct boot_control_module *module)
{
if (!module) {
ALOGE("Invalid argument passed to %s", __func__);
return;
}
return;
}
//Get the value of one of the attribute fields for a partition.
static int get_partition_attribute(char *partname,
enum part_attr_type part_attr)
{
struct gpt_disk *disk = NULL;
uint8_t *pentry = NULL;
int retval = -1;
uint8_t *attr = NULL;
if (!partname)
goto error;
disk = gpt_disk_alloc();
if (!disk) {
ALOGE("%s: Failed to alloc disk struct", __func__);
goto error;
}
if (gpt_disk_get_disk_info(partname, disk)) {
ALOGE("%s: Failed to get disk info", __func__);
goto error;
}
pentry = gpt_disk_get_pentry(disk, partname, PRIMARY_GPT);
if (!pentry) {
ALOGE("%s: pentry does not exist in disk struct",
__func__);
goto error;
}
attr = pentry + AB_FLAG_OFFSET;
if (part_attr == ATTR_SLOT_ACTIVE)
retval = !!(*attr & AB_PARTITION_ATTR_SLOT_ACTIVE);
else if (part_attr == ATTR_BOOT_SUCCESSFUL)
retval = !!(*attr & AB_PARTITION_ATTR_BOOT_SUCCESSFUL);
else if (part_attr == ATTR_UNBOOTABLE)
retval = !!(*attr & AB_PARTITION_ATTR_UNBOOTABLE);
else
retval = -1;
gpt_disk_free(disk);
return retval;
error:
if (disk)
gpt_disk_free(disk);
return retval;
}
//Set a particular attribute for all the partitions in a
//slot
static int update_slot_attribute(const char *slot,
enum part_attr_type ab_attr)
{
unsigned int i = 0;
char buf[PATH_MAX];
struct stat st;
struct gpt_disk *disk = NULL;
uint8_t *pentry = NULL;
uint8_t *pentry_bak = NULL;
int rc = -1;
uint8_t *attr = NULL;
uint8_t *attr_bak = NULL;
char partName[MAX_GPT_NAME_SIZE + 1] = {0};
const char ptn_list[][MAX_GPT_NAME_SIZE] = { AB_PTN_LIST };
int slot_name_valid = 0;
if (!slot) {
ALOGE("%s: Invalid argument", __func__);
goto error;
}
for (i = 0; slot_suffix_arr[i] != NULL; i++)
{
if (!strncmp(slot, slot_suffix_arr[i],
strlen(slot_suffix_arr[i])))
slot_name_valid = 1;
}
if (!slot_name_valid) {
ALOGE("%s: Invalid slot name", __func__);
goto error;
}
for (i=0; i < ARRAY_SIZE(ptn_list); i++) {
memset(buf, '\0', sizeof(buf));
//Check if A/B versions of this ptn exist
snprintf(buf, sizeof(buf) - 1,
"%s/%s%s",
BOOT_DEV_DIR,
ptn_list[i],
AB_SLOT_A_SUFFIX
);
if (stat(buf, &st)) {
//partition does not have _a version
continue;
}
memset(buf, '\0', sizeof(buf));
snprintf(buf, sizeof(buf) - 1,
"%s/%s%s",
BOOT_DEV_DIR,
ptn_list[i],
AB_SLOT_B_SUFFIX
);
if (stat(buf, &st)) {
//partition does not have _a version
continue;
}
memset(partName, '\0', sizeof(partName));
snprintf(partName,
sizeof(partName) - 1,
"%s%s",
ptn_list[i],
slot);
disk = gpt_disk_alloc();
if (!disk) {
ALOGE("%s: Failed to alloc disk struct",
__func__);
goto error;
}
rc = gpt_disk_get_disk_info(partName, disk);
if (rc != 0) {
ALOGE("%s: Failed to get disk info for %s",
__func__,
partName);
goto error;
}
pentry = gpt_disk_get_pentry(disk, partName, PRIMARY_GPT);
pentry_bak = gpt_disk_get_pentry(disk, partName, SECONDARY_GPT);
if (!pentry || !pentry_bak) {
ALOGE("%s: Failed to get pentry/pentry_bak for %s",
__func__,
partName);
goto error;
}
attr = pentry + AB_FLAG_OFFSET;
attr_bak = pentry_bak + AB_FLAG_OFFSET;
if (ab_attr == ATTR_BOOT_SUCCESSFUL) {
*attr = (*attr) | AB_PARTITION_ATTR_BOOT_SUCCESSFUL;
*attr_bak = (*attr_bak) |
AB_PARTITION_ATTR_BOOT_SUCCESSFUL;
} else if (ab_attr == ATTR_UNBOOTABLE) {
*attr = (*attr) | AB_PARTITION_ATTR_UNBOOTABLE;
*attr_bak = (*attr_bak) | AB_PARTITION_ATTR_UNBOOTABLE;
} else if (ab_attr == ATTR_SLOT_ACTIVE) {
*attr = (*attr) | AB_PARTITION_ATTR_SLOT_ACTIVE;
*attr_bak = (*attr) | AB_PARTITION_ATTR_SLOT_ACTIVE;
} else {
ALOGE("%s: Unrecognized attr", __func__);
goto error;
}
if (gpt_disk_update_crc(disk)) {
ALOGE("%s: Failed to update crc for %s",
__func__,
partName);
goto error;
}
if (gpt_disk_commit(disk)) {
ALOGE("%s: Failed to write back entry for %s",
__func__,
partName);
goto error;
}
gpt_disk_free(disk);
disk = NULL;
}
return 0;
error:
if (disk)
gpt_disk_free(disk);
return -1;
}
unsigned get_number_slots(struct boot_control_module *module)
{
struct dirent *de = NULL;
DIR *dir_bootdev = NULL;
unsigned slot_count = 0;
if (!module) {
ALOGE("%s: Invalid argument", __func__);
goto error;
}
dir_bootdev = opendir(BOOTDEV_DIR);
if (!dir_bootdev) {
ALOGE("%s: Failed to open bootdev dir (%s)",
__func__,
strerror(errno));
goto error;
}
while ((de = readdir(dir_bootdev))) {
if (de->d_name[0] == '.')
continue;
if (!strncmp(de->d_name, BOOT_IMG_PTN_NAME,
strlen(BOOT_IMG_PTN_NAME)))
slot_count++;
}
closedir(dir_bootdev);
return slot_count;
error:
if (dir_bootdev)
closedir(dir_bootdev);
return 0;
}
unsigned get_current_slot(struct boot_control_module *module)
{
uint32_t num_slots = 0;
char bootSlotProp[PROPERTY_VALUE_MAX] = {'\0'};
unsigned i = 0;
if (!module) {
ALOGE("%s: Invalid argument", __func__);
goto error;
}
num_slots = get_number_slots(module);
if (num_slots <= 1) {
//Slot 0 is the only slot around.
return 0;
}
property_get(BOOT_SLOT_PROP, bootSlotProp, "N/A");
if (!strncmp(bootSlotProp, "N/A", strlen("N/A"))) {
ALOGE("%s: Unable to read boot slot property",
__func__);
goto error;
}
//Iterate through a list of partitons named as boot+suffix
//and see which one is currently active.
for (i = 0; slot_suffix_arr[i] != NULL ; i++) {
if (!strncmp(bootSlotProp,
slot_suffix_arr[i],
strlen(slot_suffix_arr[i])))
return i;
}
error:
//The HAL spec requires that we return a number between
//0 to num_slots - 1. Since something went wrong here we
//are just going to return the default slot.
return 0;
}
static int boot_control_check_slot_sanity(struct boot_control_module *module,
unsigned slot)
{
if (!module)
return -1;
uint32_t num_slots = get_number_slots(module);
if ((num_slots < 1) || (slot > num_slots - 1)) {
ALOGE("Invalid slot number");
return -1;
}
return 0;
}
int mark_boot_successful(struct boot_control_module *module)
{
unsigned cur_slot = 0;
if (!module) {
ALOGE("%s: Invalid argument", __func__);
goto error;
}
cur_slot = get_current_slot(module);
if (update_slot_attribute(slot_suffix_arr[cur_slot],
ATTR_BOOT_SUCCESSFUL)) {
goto error;
}
return 0;
error:
ALOGE("%s: Failed to mark boot successful", __func__);
return -1;
}
const char *get_suffix(struct boot_control_module *module, unsigned slot)
{
if (boot_control_check_slot_sanity(module, slot) != 0)
return NULL;
else
return slot_suffix_arr[slot];
}
//Return a gpt disk structure representing the disk that holds
//partition.
static struct gpt_disk* boot_ctl_get_disk_info(char *partition)
{
struct gpt_disk *disk = NULL;
if (!partition)
return NULL;
disk = gpt_disk_alloc();
if (!disk) {
ALOGE("%s: Failed to alloc disk",
__func__);
goto error;
}
if (gpt_disk_get_disk_info(partition, disk)) {
ALOGE("failed to get disk info for %s",
partition);
goto error;
}
return disk;
error:
if (disk)
gpt_disk_free(disk);
return NULL;
}
//The argument here is a vector of partition names(including the slot suffix)
//that lie on a single disk
static int boot_ctl_set_active_slot_for_partitions(vector<string> part_list,
unsigned slot)
{
char buf[PATH_MAX] = {0};
struct gpt_disk *diskA = NULL;
struct gpt_disk *diskB = NULL;
char slotA[MAX_GPT_NAME_SIZE + 1] = {0};
char slotB[MAX_GPT_NAME_SIZE + 1] = {0};
char active_guid[TYPE_GUID_SIZE + 1] = {0};
char inactive_guid[TYPE_GUID_SIZE + 1] = {0};
//Pointer to the partition entry of current 'A' partition
uint8_t *pentryA = NULL;
uint8_t *pentryA_bak = NULL;
//Pointer to partition entry of current 'B' partition
uint8_t *pentryB = NULL;
uint8_t *pentryB_bak = NULL;
struct stat st;
vector<string>::iterator partition_iterator;
for (partition_iterator = part_list.begin();
partition_iterator != part_list.end();
partition_iterator++) {
//Chop off the slot suffix from the partition name to
//make the string easier to work with.
string prefix = *partition_iterator;
if (prefix.size() < (strlen(AB_SLOT_A_SUFFIX) + 1)) {
ALOGE("Invalid partition name: %s", prefix.c_str());
goto error;
}
prefix.resize(prefix.size() - strlen(AB_SLOT_A_SUFFIX));
//Check if A/B versions of this ptn exist
snprintf(buf, sizeof(buf) - 1, "%s/%s%s", BOOT_DEV_DIR,
prefix.c_str(),
AB_SLOT_A_SUFFIX);
if (stat(buf, &st))
continue;
memset(buf, '\0', sizeof(buf));
snprintf(buf, sizeof(buf) - 1, "%s/%s%s", BOOT_DEV_DIR,
prefix.c_str(),
AB_SLOT_B_SUFFIX);
if (stat(buf, &st))
continue;
memset(slotA, 0, sizeof(slotA));
memset(slotB, 0, sizeof(slotB));
snprintf(slotA, sizeof(slotA) - 1, "%s%s", prefix.c_str(),
AB_SLOT_A_SUFFIX);
snprintf(slotB, sizeof(slotB) - 1,"%s%s", prefix.c_str(),
AB_SLOT_B_SUFFIX);
//Get the disks containing the partitions that were passed in.
if (!diskA) {
diskA = boot_ctl_get_disk_info(slotA);
if (!diskA)
goto error;
}
if (!diskB) {
diskB = boot_ctl_get_disk_info(slotB);
if (!diskB)
goto error;
}
//Get partition entry for slot A & B from the primary
//and backup tables.
pentryA = gpt_disk_get_pentry(diskA, slotA, PRIMARY_GPT);
pentryA_bak = gpt_disk_get_pentry(diskA, slotA, SECONDARY_GPT);
pentryB = gpt_disk_get_pentry(diskB, slotB, PRIMARY_GPT);
pentryB_bak = gpt_disk_get_pentry(diskB, slotB, SECONDARY_GPT);
if ( !pentryA || !pentryA_bak || !pentryB || !pentryB_bak) {
//None of these should be NULL since we have already
//checked for A & B versions earlier.
ALOGE("Slot pentries for %s not found.",
prefix.c_str());
goto error;
}
memset(active_guid, '\0', sizeof(active_guid));
memset(inactive_guid, '\0', sizeof(inactive_guid));
if (get_partition_attribute(slotA, ATTR_SLOT_ACTIVE) == 1) {
//A is the current active slot
memcpy((void*)active_guid, (const void*)pentryA,
TYPE_GUID_SIZE);
memcpy((void*)inactive_guid,(const void*)pentryB,
TYPE_GUID_SIZE);
} else if (get_partition_attribute(slotB,
ATTR_SLOT_ACTIVE) == 1) {
//B is the current active slot
memcpy((void*)active_guid, (const void*)pentryB,
TYPE_GUID_SIZE);
memcpy((void*)inactive_guid, (const void*)pentryA,
TYPE_GUID_SIZE);
} else {
ALOGE("Both A & B for %s are inactive..Aborting",
prefix.c_str());
goto error;
}
if (!strncmp(slot_suffix_arr[slot], AB_SLOT_A_SUFFIX,
strlen(AB_SLOT_A_SUFFIX))){
//Mark A as active in primary table
UPDATE_SLOT(pentryA, active_guid, SLOT_ACTIVE);
//Mark A as active in backup table
UPDATE_SLOT(pentryA_bak, active_guid, SLOT_ACTIVE);
//Mark B as inactive in primary table
UPDATE_SLOT(pentryB, inactive_guid, SLOT_INACTIVE);
//Mark B as inactive in backup table
UPDATE_SLOT(pentryB_bak, inactive_guid, SLOT_INACTIVE);
} else if (!strncmp(slot_suffix_arr[slot], AB_SLOT_B_SUFFIX,
strlen(AB_SLOT_B_SUFFIX))){
//Mark B as active in primary table
UPDATE_SLOT(pentryB, active_guid, SLOT_ACTIVE);
//Mark B as active in backup table
UPDATE_SLOT(pentryB_bak, active_guid, SLOT_ACTIVE);
//Mark A as inavtive in primary table
UPDATE_SLOT(pentryA, inactive_guid, SLOT_INACTIVE);
//Mark A as inactive in backup table
UPDATE_SLOT(pentryA_bak, inactive_guid, SLOT_INACTIVE);
} else {
//Something has gone terribly terribly wrong
ALOGE("%s: Unknown slot suffix!", __func__);
goto error;
}
if (diskA) {
if (gpt_disk_update_crc(diskA) != 0) {
ALOGE("%s: Failed to update gpt_disk crc",
__func__);
goto error;
}
}
if (diskB) {
if (gpt_disk_update_crc(diskB) != 0) {
ALOGE("%s: Failed to update gpt_disk crc",
__func__);
goto error;
}
}
}
//write updated content to disk
if (diskA) {
if (gpt_disk_commit(diskA)) {
ALOGE("Failed to commit disk entry");
goto error;
}
gpt_disk_free(diskA);
}
if (diskB) {
if (gpt_disk_commit(diskB)) {
ALOGE("Failed to commit disk entry");
goto error;
}
gpt_disk_free(diskB);
}
return 0;
error:
if (diskA)
gpt_disk_free(diskA);
if (diskB)
gpt_disk_free(diskB);
return -1;
}
int set_active_boot_slot(struct boot_control_module *module, unsigned slot)
{
map<string, vector<string>> ptn_map;
vector<string> ptn_vec;
const char ptn_list[][MAX_GPT_NAME_SIZE] = { AB_PTN_LIST };
uint32_t i;
int rc = -1;
int is_ufs = gpt_utils_is_ufs_device();
map<string, vector<string>>::iterator map_iter;
if (boot_control_check_slot_sanity(module, slot)) {
ALOGE("%s: Bad arguments", __func__);
goto error;
}
//The partition list just contains prefixes(without the _a/_b) of the
//partitions that support A/B. In order to get the layout we need the
//actual names. To do this we append the slot suffix to every member
//in the list.
for (i = 0; i < ARRAY_SIZE(ptn_list); i++) {
//XBL & XBL_CFG are handled differrently for ufs devices so
//ignore them
if (is_ufs && (!strncmp(ptn_list[i],
PTN_XBL,
strlen(PTN_XBL))
|| !strncmp(ptn_list[i],
PTN_XBL_CFG,
strlen(PTN_XBL_CFG))))
continue;
//The partition list will be the list of partitions
//corresponding to the slot being set active
string cur_ptn = ptn_list[i];
cur_ptn.append(slot_suffix_arr[slot]);
ptn_vec.push_back(cur_ptn);
}
//The partition map gives us info in the following format:
// [path_to_block_device_1]--><partitions on device 1>
// [path_to_block_device_2]--><partitions on device 2>
// ...
// ...
// eg:
// [/dev/block/sdb]---><system, boot, rpm, tz,....>
if (gpt_utils_get_partition_map(ptn_vec, ptn_map)) {
ALOGE("%s: Failed to get partition map",
__func__);
goto error;
}
for (map_iter = ptn_map.begin(); map_iter != ptn_map.end(); map_iter++){
if (map_iter->second.size() < 1)
continue;
if (boot_ctl_set_active_slot_for_partitions(map_iter->second,
slot)) {
ALOGE("%s: Failed to set active slot", __func__);
goto error;
}
}
if (is_ufs) {
if (!strncmp(slot_suffix_arr[slot], AB_SLOT_A_SUFFIX,
strlen(AB_SLOT_A_SUFFIX))){
//Set xbl_a as the boot lun
rc = gpt_utils_set_xbl_boot_partition(NORMAL_BOOT);
} else if (!strncmp(slot_suffix_arr[slot], AB_SLOT_B_SUFFIX,
strlen(AB_SLOT_B_SUFFIX))){
//Set xbl_b as the boot lun
rc = gpt_utils_set_xbl_boot_partition(BACKUP_BOOT);
} else {
//Something has gone terribly terribly wrong
ALOGE("%s: Unknown slot suffix!", __func__);
goto error;
}
if (rc) {
ALOGE("%s: Failed to switch xbl boot partition",
__func__);
goto error;
}
}
return 0;
error:
return -1;
}
int set_slot_as_unbootable(struct boot_control_module *module, unsigned slot)
{
if (boot_control_check_slot_sanity(module, slot) != 0) {
ALOGE("%s: Argument check failed", __func__);
goto error;
}
if (update_slot_attribute(slot_suffix_arr[slot],
ATTR_UNBOOTABLE)) {
goto error;
}
return 0;
error:
ALOGE("%s: Failed to mark slot unbootable", __func__);
return -1;
}
int is_slot_bootable(struct boot_control_module *module, unsigned slot)
{
int attr = 0;
char bootPartition[MAX_GPT_NAME_SIZE + 1] = {0};
if (boot_control_check_slot_sanity(module, slot) != 0) {
ALOGE("%s: Argument check failed", __func__);
goto error;
}
snprintf(bootPartition,
sizeof(bootPartition) - 1, "boot%s",
slot_suffix_arr[slot]);
attr = get_partition_attribute(bootPartition, ATTR_UNBOOTABLE);
if (attr >= 0)
return !attr;
error:
return -1;
}
int is_slot_marked_successful(struct boot_control_module *module, unsigned slot)
{
int attr = 0;
char bootPartition[MAX_GPT_NAME_SIZE + 1] = {0};
if (boot_control_check_slot_sanity(module, slot) != 0) {
ALOGE("%s: Argument check failed", __func__);
goto error;
}
snprintf(bootPartition,
sizeof(bootPartition) - 1,
"boot%s", slot_suffix_arr[slot]);
attr = get_partition_attribute(bootPartition, ATTR_BOOT_SUCCESSFUL);
if (attr >= 0)
return attr;
error:
return -1;
}
static hw_module_methods_t boot_control_module_methods = {
.open = NULL,
};
boot_control_module_t HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = 1,
.hal_api_version = 0,
.id = BOOT_CONTROL_HARDWARE_MODULE_ID,
.name = "Boot control HAL",
.author = "Code Aurora Forum",
.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,
.isSlotMarkedSuccessful = is_slot_marked_successful,
};
#ifdef __cplusplus
}
#endif

View File

@ -10,6 +10,47 @@ $(call inherit-product, $(SRC_TARGET_DIR)/product/emulated_storage.mk)
# Installs gsi keys into ramdisk, to boot a GSI with verified boot.
$(call inherit-product, $(SRC_TARGET_DIR)/product/gsi_keys.mk)
# A/B
AB_OTA_UPDATER := true
TARGET_ENFORCE_AB_OTA_PARTITION_LIST := true
AB_OTA_PARTITIONS += \
boot \
dtbo \
product \
system \
system_ext \
vbmeta \
vbmeta_system \
vendor
AB_OTA_POSTINSTALL_CONFIG += \
RUN_POSTINSTALL_system=true \
POSTINSTALL_PATH_system=system/bin/otapreopt_script \
FILESYSTEM_TYPE_system=ext4 \
POSTINSTALL_OPTIONAL_system=true
AB_OTA_POSTINSTALL_CONFIG += \
RUN_POSTINSTALL_vendor=true \
POSTINSTALL_PATH_vendor=bin/checkpoint_gc \
FILESYSTEM_TYPE_vendor=ext4 \
POSTINSTALL_OPTIONAL_vendor=true
PRODUCT_PACKAGES += \
checkpoint_gc \
otapreopt_script
# Boot control
PRODUCT_PACKAGES += \
android.hardware.boot@1.1-impl-qti.recovery \
bootctrl.holi.recovery
# Update engine
PRODUCT_PACKAGES += \
update_engine \
update_engine_sideload \
update_verifier
# Display
TARGET_RECOVERY_DEVICE_MODULES += \
libion \

38
gpt-utils/Android.bp Normal file
View File

@ -0,0 +1,38 @@
//
// Copyright (C) 2018 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.
//
cc_library {
name: "libgptutils.corfur",
vendor: true,
recovery_available: true,
shared_libs: [
"libcutils",
"liblog",
"libz",
],
cflags: [
"-Wall",
"-Werror",
"-D_BSG_FRAMEWORK_KERNEL_HEADERS",
],
srcs: [
"gpt-utils.cpp",
"recovery-ufs-bsg.cpp",
],
owner: "qti",
export_include_dirs: ["."],
}

1520
gpt-utils/gpt-utils.cpp Normal file

File diff suppressed because it is too large Load Diff

193
gpt-utils/gpt-utils.h Normal file
View File

@ -0,0 +1,193 @@
/*
* Copyright (c) 2013,2016, 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 __GPT_UTILS_H__
#define __GPT_UTILS_H__
#include <vector>
#include <string>
#include <map>
#ifdef __cplusplus
extern "C" {
#endif
#include <unistd.h>
#include <stdlib.h>
/******************************************************************************
* GPT HEADER DEFINES
******************************************************************************/
#define GPT_SIGNATURE "EFI PART"
#define HEADER_SIZE_OFFSET 12
#define HEADER_CRC_OFFSET 16
#define PRIMARY_HEADER_OFFSET 24
#define BACKUP_HEADER_OFFSET 32
#define FIRST_USABLE_LBA_OFFSET 40
#define LAST_USABLE_LBA_OFFSET 48
#define PENTRIES_OFFSET 72
#define PARTITION_COUNT_OFFSET 80
#define PENTRY_SIZE_OFFSET 84
#define PARTITION_CRC_OFFSET 88
#define TYPE_GUID_OFFSET 0
#define TYPE_GUID_SIZE 16
#define PTN_ENTRY_SIZE 128
#define UNIQUE_GUID_OFFSET 16
#define FIRST_LBA_OFFSET 32
#define LAST_LBA_OFFSET 40
#define ATTRIBUTE_FLAG_OFFSET 48
#define PARTITION_NAME_OFFSET 56
#define MAX_GPT_NAME_SIZE 72
/******************************************************************************
* AB RELATED DEFINES
******************************************************************************/
//Bit 48 onwords in the attribute field are the ones where we are allowed to
//store our AB attributes.
#define AB_FLAG_OFFSET (ATTRIBUTE_FLAG_OFFSET + 6)
#define GPT_DISK_INIT_MAGIC 0xABCD
#define AB_PARTITION_ATTR_SLOT_ACTIVE (0x1<<2)
#define AB_PARTITION_ATTR_BOOT_SUCCESSFUL (0x1<<6)
#define AB_PARTITION_ATTR_UNBOOTABLE (0x1<<7)
#define AB_SLOT_ACTIVE_VAL 0x3F
#define AB_SLOT_INACTIVE_VAL 0x0
#define AB_SLOT_ACTIVE 1
#define AB_SLOT_INACTIVE 0
#define AB_SLOT_A_SUFFIX "_a"
#define AB_SLOT_B_SUFFIX "_b"
#define PTN_XBL "xbl"
#define PTN_XBL_CFG "xbl_config"
#define PTN_SWAP_LIST PTN_XBL, PTN_XBL_CFG, "sbl1", "rpm", "tz", "aboot", "abl", "hyp", "lksecapp", "keymaster", "cmnlib", "cmnlib32", "cmnlib64", "pmic", "apdp", "devcfg", "hosd", "keystore", "msadp", "mdtp", "mdtpsecapp", "dsp", "aop", "qupfw", "vbmeta", "dtbo", "imagefv", "ImageFv", "multiimgoem", "multiimgqti", "uefisecapp", "shrm", "cpucp"
#define AB_PTN_LIST PTN_SWAP_LIST, "boot", "system", "vendor", "odm", "modem", "bluetooth", "fsg", "logo", "mdm1m9kefs3", "prov", "spss", "storsec", "vbmeta_system", "vendor_boot"
#define BOOT_DEV_DIR "/dev/block/bootdevice/by-name"
/******************************************************************************
* HELPER MACROS
******************************************************************************/
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
/******************************************************************************
* TYPES
******************************************************************************/
enum boot_update_stage {
UPDATE_MAIN = 1,
UPDATE_BACKUP,
UPDATE_FINALIZE
};
enum gpt_instance {
PRIMARY_GPT = 0,
SECONDARY_GPT
};
enum boot_chain {
NORMAL_BOOT = 0,
BACKUP_BOOT
};
struct gpt_disk {
//GPT primary header
uint8_t *hdr;
//primary header crc
uint32_t hdr_crc;
//GPT backup header
uint8_t *hdr_bak;
//backup header crc
uint32_t hdr_bak_crc;
//Partition entries array
uint8_t *pentry_arr;
//Partition entries array for backup table
uint8_t *pentry_arr_bak;
//Size of the pentry array
uint32_t pentry_arr_size;
//Size of each element in the pentry array
uint32_t pentry_size;
//CRC of the partition entry array
uint32_t pentry_arr_crc;
//CRC of the backup partition entry array
uint32_t pentry_arr_bak_crc;
//Path to block dev representing the disk
char devpath[PATH_MAX];
//Block size of disk
uint32_t block_size;
uint32_t is_initialized;
};
/******************************************************************************
* FUNCTION PROTOTYPES
******************************************************************************/
int prepare_boot_update(enum boot_update_stage stage);
//GPT disk methods
struct gpt_disk* gpt_disk_alloc();
//Free previously allocated gpt_disk struct
void gpt_disk_free(struct gpt_disk *disk);
//Get the details of the disk holding the partition whose name
//is passed in via dev
int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *disk);
//Get pointer to partition entry from a allocated gpt_disk structure
uint8_t* gpt_disk_get_pentry(struct gpt_disk *disk,
const char *partname,
enum gpt_instance instance);
//Update the crc fields of the modified disk structure
int gpt_disk_update_crc(struct gpt_disk *disk);
//Write the contents of struct gpt_disk back to the actual disk
int gpt_disk_commit(struct gpt_disk *disk);
//Return if the current device is UFS based or not
int gpt_utils_is_ufs_device();
//Swtich betwieen using either the primary or the backup
//boot LUN for boot. This is required since UFS boot partitions
//cannot have a backup GPT which is what we use for failsafe
//updates of the other 'critical' partitions. This function will
//not be invoked for emmc targets and on UFS targets is only required
//to be invoked for XBL.
//
//The algorithm to do this is as follows:
//- Find the real block device(eg: /dev/block/sdb) that corresponds
// to the /dev/block/bootdevice/by-name/xbl(bak) symlink
//
//- Once we have the block device 'node' name(sdb in the above example)
// use this node to to locate the scsi generic device that represents
// it by checking the file /sys/block/sdb/device/scsi_generic/sgY
//
//- Once we locate sgY we call the query ioctl on /dev/sgy to switch
//the boot lun to either LUNA or LUNB
int gpt_utils_set_xbl_boot_partition(enum boot_chain chain);
//Given a vector of partition names as a input and a reference to a map,
//populate the map to indicate which physical disk each of the partitions
//sits on. The key in the map is the path to the block device where the
//partiton lies and the value is a vector of strings indicating which of
//the passed in partiton names sits on that device.
int gpt_utils_get_partition_map(std::vector<std::string>& partition_list,
std::map<std::string,std::vector<std::string>>& partition_map);
#ifdef __cplusplus
}
#endif
#endif /* __GPT_UTILS_H__ */

View File

@ -0,0 +1,255 @@
/*
* Copyright (c) 2020 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 "recovery_ufs"
#include "recovery-ufs-bsg.h"
#ifndef _BSG_FRAMEWORK_KERNEL_HEADERS
#ifndef _GENERIC_KERNEL_HEADERS
#include <scsi/ufs/ioctl.h>
#include <scsi/ufs/ufs.h>
#endif
#endif
//Size of the buffer that needs to be passed to the UFS ioctl
#define UFS_ATTR_DATA_SIZE 32
#ifdef _BSG_FRAMEWORK_KERNEL_HEADERS
static int get_ufs_bsg_dev(void)
{
DIR *dir;
struct dirent *ent;
int ret = -ENODEV;
if ((dir = opendir ("/dev")) != NULL) {
/* read all the files and directories within directory */
while ((ent = readdir(dir)) != NULL) {
if (!strcmp(ent->d_name, "ufs-bsg") ||
!strcmp(ent->d_name, "ufs-bsg0")) {
snprintf(ufs_bsg_dev, FNAME_SZ, "/dev/%s", ent->d_name);
ret = 0;
break;
}
}
if (ret)
ALOGE("could not find the ufs-bsg dev\n");
closedir (dir);
} else {
/* could not open directory */
ALOGE("could not open /dev (error no: %d)\n", errno);
ret = -EINVAL;
}
return ret;
}
int ufs_bsg_dev_open(void)
{
int ret;
if (!fd_ufs_bsg) {
fd_ufs_bsg = open(ufs_bsg_dev, O_RDWR);
ret = errno;
if (fd_ufs_bsg < 0) {
ALOGE("Unable to open %s (error no: %d)",
ufs_bsg_dev, errno);
fd_ufs_bsg = 0;
return ret;
}
}
return 0;
}
void ufs_bsg_dev_close(void)
{
if (fd_ufs_bsg) {
close(fd_ufs_bsg);
fd_ufs_bsg = 0;
}
}
static int ufs_bsg_ioctl(int fd, struct ufs_bsg_request *req,
struct ufs_bsg_reply *rsp, __u8 *buf, __u32 buf_len,
enum bsg_ioctl_dir dir)
{
int ret;
struct sg_io_v4 sg_io{};
sg_io.guard = 'Q';
sg_io.protocol = BSG_PROTOCOL_SCSI;
sg_io.subprotocol = BSG_SUB_PROTOCOL_SCSI_TRANSPORT;
sg_io.request_len = sizeof(*req);
sg_io.request = (__u64)req;
sg_io.response = (__u64)rsp;
sg_io.max_response_len = sizeof(*rsp);
if (dir == BSG_IOCTL_DIR_FROM_DEV) {
sg_io.din_xfer_len = buf_len;
sg_io.din_xferp = (__u64)(buf);
} else {
sg_io.dout_xfer_len = buf_len;
sg_io.dout_xferp = (__u64)(buf);
}
ret = ioctl(fd, SG_IO, &sg_io);
if (ret)
ALOGE("%s: Error from sg_io ioctl (return value: %d, error no: %d, reply result from LLD: %d\n)",
__func__, ret, errno, rsp->result);
if (sg_io.info || rsp->result) {
ALOGE("%s: Error from sg_io info (check sg info: device_status: 0x%x, transport_status: 0x%x, driver_status: 0x%x, reply result from LLD: %d\n)",
__func__, sg_io.device_status, sg_io.transport_status,
sg_io.driver_status, rsp->result);
ret = -EAGAIN;
}
return ret;
}
static void compose_ufs_bsg_query_req(struct ufs_bsg_request *req, __u8 func,
__u8 opcode, __u8 idn, __u8 index, __u8 sel,
__u16 length)
{
struct utp_upiu_header *hdr = &req->upiu_req.header;
struct utp_upiu_query *qr = &req->upiu_req.qr;
req->msgcode = UTP_UPIU_QUERY_REQ;
hdr->dword_0 = DWORD(UTP_UPIU_QUERY_REQ, 0, 0, 0);
hdr->dword_1 = DWORD(0, func, 0, 0);
hdr->dword_2 = DWORD(0, 0, length >> 8, (__u8)length);
qr->opcode = opcode;
qr->idn = idn;
qr->index = index;
qr->selector = sel;
qr->length = htobe16(length);
}
static int ufs_query_attr(int fd, __u32 value,
__u8 func, __u8 opcode, __u8 idn,
__u8 index, __u8 sel)
{
struct ufs_bsg_request req{};
struct ufs_bsg_reply rsp{};
enum bsg_ioctl_dir dir = BSG_IOCTL_DIR_FROM_DEV;
int ret = 0;
if (opcode == QUERY_REQ_OP_WRITE_DESC || opcode == QUERY_REQ_OP_WRITE_ATTR)
dir = BSG_IOCTL_DIR_TO_DEV;
req.upiu_req.qr.value = htobe32(value);
compose_ufs_bsg_query_req(&req, func, opcode, idn, index, sel, 0);
ret = ufs_bsg_ioctl(fd, &req, &rsp, 0, 0, dir);
if (ret)
ALOGE("%s: Error from ufs_bsg_ioctl (return value: %d, error no: %d\n)",
__func__, ret, errno);
return ret;
}
int32_t set_boot_lun(char *sg_dev __unused,uint8_t lun_id)
{
int32_t ret;
__u32 boot_lun_id = lun_id;
ret = get_ufs_bsg_dev();
if (ret)
return ret;
ALOGV("Found the ufs bsg dev: %s\n", ufs_bsg_dev);
ret = ufs_bsg_dev_open();
if (ret)
return ret;
ALOGV("Opened ufs bsg dev: %s\n", ufs_bsg_dev);
ret = ufs_query_attr(fd_ufs_bsg, boot_lun_id, QUERY_REQ_FUNC_STD_WRITE,
QUERY_REQ_OP_WRITE_ATTR, QUERY_ATTR_IDN_BOOT_LU_EN, 0, 0);
if (ret) {
ALOGE("Error requesting ufs attr idn %d via query ioctl (return value: %d, error no: %d)",
QUERY_ATTR_IDN_BOOT_LU_EN, ret, errno);
goto out;
}
out:
ufs_bsg_dev_close();
return ret;
}
#endif
#ifndef _BSG_FRAMEWORK_KERNEL_HEADERS
int32_t set_boot_lun(char *sg_dev, uint8_t boot_lun_id)
{
#ifndef _GENERIC_KERNEL_HEADERS
int fd = -1;
int rc;
struct ufs_ioctl_query_data *data = NULL;
size_t ioctl_data_size = sizeof(struct ufs_ioctl_query_data) + UFS_ATTR_DATA_SIZE;
data = (struct ufs_ioctl_query_data*)malloc(ioctl_data_size);
if (!data) {
fprintf(stderr, "%s: Failed to alloc query data struct\n",
__func__);
goto error;
}
memset(data, 0, ioctl_data_size);
data->opcode = UPIU_QUERY_OPCODE_WRITE_ATTR;
data->idn = QUERY_ATTR_IDN_BOOT_LU_EN;
data->buf_size = UFS_ATTR_DATA_SIZE;
data->buffer[0] = boot_lun_id;
fd = open(sg_dev, O_RDWR);
if (fd < 0) {
fprintf(stderr, "%s: Failed to open %s(%s)\n",
__func__,
sg_dev,
strerror(errno));
goto error;
}
rc = ioctl(fd, UFS_IOCTL_QUERY, data);
if (rc) {
fprintf(stderr, "%s: UFS query ioctl failed(%s)\n",
__func__,
strerror(errno));
goto error;
}
close(fd);
free(data);
return 0;
error:
if (fd >= 0)
close(fd);
if (data)
free(data);
return -1;
#else
return 0;
#endif
}
#endif

View File

@ -0,0 +1,131 @@
#ifndef __RECOVERY_UFS_BSG_H__
#define __RECOVERY_UFS_BSG_H__
/*
* Copyright (c) 2020 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.
*/
#include <linux/bsg.h>
#include <scsi/scsi_bsg_ufs.h>
#include <endian.h>
#include <dirent.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#ifdef ANDROID
#include "cutils/log.h"
#endif
#ifdef OE
#include <syslog.h>
#define LOGI(...) syslog(LOG_NOTICE, "INFO:" __VA_ARGS__)
#define LOGV(...) syslog(LOG_NOTICE,"VERB:" __VA_ARGS__)
#define LOGD(...) syslog(LOG_DEBUG,"DBG:" __VA_ARGS__)
#define LOGE(...) syslog(LOG_ERR,"ERR:" __VA_ARGS__)
#define LOGW(...) syslog(LOG_WARNING,"WRN:" __VA_ARGS__)
#define strlcat(d,s,l) snprintf(d+strlen(d),l,"%s",s)
#endif
#define FNAME_SZ 64
#define SG_IO 0x2285
#define DWORD(b3, b2, b1, b0) htobe32((b3 << 24) | (b2 << 16) |\
(b1 << 8) | b0)
/* UFS BSG device nodes */
char ufs_bsg_dev[FNAME_SZ] = "/dev/ufs-bsg";
int fd_ufs_bsg;
int32_t set_ufs_lun(uint8_t lun_id);
#ifdef _BSG_FRAMEWORK_KERNEL_HEADERS
/* UPIU Transaction Codes */
enum {
UTP_UPIU_NOP_OUT = 0x00,
UTP_UPIU_COMMAND = 0x01,
UTP_UPIU_DATA_OUT = 0x02,
UTP_UPIU_TASK_REQ = 0x04,
UTP_UPIU_QUERY_REQ = 0x16,
};
/* UPIU Query Function field */
enum {
QUERY_REQ_FUNC_STD_READ = 0x01,
QUERY_REQ_FUNC_STD_WRITE = 0x81,
};
enum query_req_opcode {
QUERY_REQ_OP_READ_DESC = 0x1,
QUERY_REQ_OP_WRITE_DESC = 0x2,
QUERY_REQ_OP_READ_ATTR = 0x3,
QUERY_REQ_OP_WRITE_ATTR = 0x4,
QUERY_REQ_OP_READ_FLAG = 0x5,
QUERY_REQ_OP_SET_FLAG = 0x6,
QUERY_REQ_OP_CLEAR_FLAG = 0x7,
QUERY_REQ_OP_TOGGLE_FLAG = 0x8,
};
enum query_desc_idn {
QUERY_DESC_IDN_DEVICE = 0x0,
QUERY_DESC_IDN_UNIT = 0x2,
QUERY_DESC_IDN_GEOMETRY = 0x7,
};
enum query_desc_size {
QUERY_DESC_SIZE_DEVICE = 0x40,
QUERY_DESC_SIZE_GEOMETRY = 0x48,
QUERY_DESC_SIZE_UNIT = 0x23,
};
enum bsg_ioctl_dir {
BSG_IOCTL_DIR_TO_DEV,
BSG_IOCTL_DIR_FROM_DEV,
};
enum query_attr_idn {
QUERY_ATTR_IDN_BOOT_LU_EN = 0x00,
QUERY_ATTR_IDN_RESERVED = 0x01,
QUERY_ATTR_IDN_POWER_MODE = 0x02,
QUERY_ATTR_IDN_ACTIVE_ICC_LVL = 0x03,
};
#endif /* _BSG_FRAMEWORK_KERNEL_HEADERS */
#endif /* __RECOVERY_UFS_BSG_H__ */

View File

@ -0,0 +1,97 @@
/*-
* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
* code or tables extracted from it, as desired without restriction.
*/
/*
* First, the polynomial itself and its table of feedback terms. The
* polynomial is
* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
*
* Note that we take it "backwards" and put the highest-order term in
* the lowest-order bit. The X^32 term is "implied"; the LSB is the
* X^31 term, etc. The X^0 term (usually shown as "+1") results in
* the MSB being 1
*
* Note that the usual hardware shift register implementation, which
* is what we're using (we're merely optimizing it by doing eight-bit
* chunks at a time) shifts bits into the lowest-order term. In our
* implementation, that means shifting towards the right. Why do we
* do it this way? Because the calculated CRC must be transmitted in
* order from highest-order term to lowest-order term. UARTs transmit
* characters in order from LSB to MSB. By storing the CRC this way
* we hand it to the UART in the order low-byte to high-byte; the UART
* sends each low-bit to hight-bit; and the result is transmission bit
* by bit from highest- to lowest-order term without requiring any bit
* shuffling on our part. Reception works similarly
*
* The feedback terms table consists of 256, 32-bit entries. Notes
*
* The table can be generated at runtime if desired; code to do so
* is shown later. It might not be obvious, but the feedback
* terms simply represent the results of eight shift/xor opera
* tions for all combinations of data and CRC register values
*
* The values must be right-shifted by eight bits by the "updcrc
* logic; the shift must be unsigned (bring in zeroes). On some
* hardware you could probably optimize the shift in assembler by
* using byte-swap instructions
* polynomial $edb88320
*
*
* CRC32 code derived from work by Gary S. Brown.
*/
/* Code taken from FreeBSD 8 */
#include <stdint.h>
#include <stdio.h>
static uint32_t crc32_tab[] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
/*
* A function that calculates the CRC-32 based on the table above is
* given below for documentation purposes. An equivalent implementation
* of this function that's actually used in the kernel can be found
* in sys/libkern.h, where it can be inlined.
*/
uint32_t sparse_crc32(uint32_t crc_in, const void* buf, size_t size) {
const uint8_t* p = reinterpret_cast<const uint8_t*>(buf);
uint32_t crc;
crc = crc_in ^ ~0U;
while (size--) crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
return crc ^ ~0U;
}

24
gpt-utils/sparse_crc32.h Normal file
View File

@ -0,0 +1,24 @@
/*
* Copyright (C) 2010 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 _LIBSPARSE_SPARSE_CRC32_H_
#define _LIBSPARSE_SPARSE_CRC32_H_
#include <stdint.h>
uint32_t sparse_crc32(uint32_t crc, const void* buf, size_t size);
#endif