mirror of
https://github.com/linux-msm/qbootctl
synced 2024-11-23 14:43:29 +08:00
more rework, cleanup, port to pure C
The only C++ was for handling discovering and iterating over the partitions PER block device, this was implemented in a really overcomplicated way. Simplify things, port everything over to c11 and drop the libstdc++ requirement entirely.
This commit is contained in:
parent
04f4ac81ea
commit
bca9aa5dd7
129
bootctrl.h
129
bootctrl.h
@ -19,85 +19,86 @@
|
|||||||
#ifndef __BOOTCTRL_H__
|
#ifndef __BOOTCTRL_H__
|
||||||
#define __BOOTCTRL_H__
|
#define __BOOTCTRL_H__
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
struct slot_info {
|
struct slot_info {
|
||||||
bool active;
|
bool active;
|
||||||
bool bootable;
|
bool bootable;
|
||||||
bool successful;
|
bool successful;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct boot_control_module {
|
struct boot_control_module {
|
||||||
|
/*
|
||||||
|
* (*getCurrentSlot)() returns the value letting the system know
|
||||||
|
* whether the current slot is A or B. The meaning of A and B is
|
||||||
|
* left up to the implementer. It is assumed that if the current slot
|
||||||
|
* is A, then the block devices underlying B can be accessed directly
|
||||||
|
* without any risk of corruption.
|
||||||
|
* The returned value is always guaranteed to be strictly less than the
|
||||||
|
* value returned by getNumberSlots. Slots start at 0 and
|
||||||
|
* finish at getNumberSlots() - 1
|
||||||
|
*/
|
||||||
|
unsigned (*getCurrentSlot)();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (*getCurrentSlot)() returns the value letting the system know
|
* (*markBootSuccessful)() marks the specified slot
|
||||||
* whether the current slot is A or B. The meaning of A and B is
|
* as boot successful
|
||||||
* left up to the implementer. It is assumed that if the current slot
|
*
|
||||||
* is A, then the block devices underlying B can be accessed directly
|
* Returns 0 on success, -errno on error.
|
||||||
* without any risk of corruption.
|
*/
|
||||||
* The returned value is always guaranteed to be strictly less than the
|
int (*markBootSuccessful)(unsigned slot);
|
||||||
* value returned by getNumberSlots. Slots start at 0 and
|
|
||||||
* finish at getNumberSlots() - 1
|
|
||||||
*/
|
|
||||||
unsigned (*getCurrentSlot)();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (*markBootSuccessful)() marks the specified slot
|
* (*setActiveBootSlot)() marks the slot passed in parameter as
|
||||||
* as boot successful
|
* the active boot slot (see getCurrentSlot for an explanation
|
||||||
*
|
* of the "slot" parameter). This overrides any previous call to
|
||||||
* Returns 0 on success, -errno on error.
|
* setSlotAsUnbootable.
|
||||||
*/
|
* Returns 0 on success, -errno on error.
|
||||||
int (*markBootSuccessful)(unsigned slot);
|
*/
|
||||||
|
int (*setActiveBootSlot)(unsigned slot);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (*setActiveBootSlot)() marks the slot passed in parameter as
|
* (*setSlotAsUnbootable)() marks the slot passed in parameter as
|
||||||
* the active boot slot (see getCurrentSlot for an explanation
|
* an unbootable. This can be used while updating the contents of the slot's
|
||||||
* of the "slot" parameter). This overrides any previous call to
|
* partitions, so that the system will not attempt to boot a known bad set up.
|
||||||
* setSlotAsUnbootable.
|
* Returns 0 on success, -errno on error.
|
||||||
* Returns 0 on success, -errno on error.
|
*/
|
||||||
*/
|
int (*setSlotAsUnbootable)(unsigned slot);
|
||||||
int (*setActiveBootSlot)(unsigned slot);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (*setSlotAsUnbootable)() marks the slot passed in parameter as
|
* (*isSlotBootable)() returns if the slot passed in parameter is
|
||||||
* an unbootable. This can be used while updating the contents of the slot's
|
* bootable. Note that slots can be made unbootable by both the
|
||||||
* partitions, so that the system will not attempt to boot a known bad set up.
|
* bootloader and by the OS using setSlotAsUnbootable.
|
||||||
* Returns 0 on success, -errno on error.
|
* Returns 1 if the slot is bootable, 0 if it's not, and -errno on
|
||||||
*/
|
* error.
|
||||||
int (*setSlotAsUnbootable)(unsigned slot);
|
*/
|
||||||
|
int (*isSlotBootable)(unsigned slot);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (*isSlotBootable)() returns if the slot passed in parameter is
|
* (*getSuffix)() returns the string suffix used by partitions that
|
||||||
* bootable. Note that slots can be made unbootable by both the
|
* correspond to the slot number passed in parameter. The returned string
|
||||||
* bootloader and by the OS using setSlotAsUnbootable.
|
* is expected to be statically allocated and not need to be freed.
|
||||||
* Returns 1 if the slot is bootable, 0 if it's not, and -errno on
|
* Returns NULL if slot does not match an existing slot.
|
||||||
* error.
|
*/
|
||||||
*/
|
const char *(*getSuffix)(unsigned slot);
|
||||||
int (*isSlotBootable)(unsigned slot);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (*getSuffix)() returns the string suffix used by partitions that
|
* (*isSlotMarkedSucessful)() returns if the slot passed in parameter has
|
||||||
* correspond to the slot number passed in parameter. The returned string
|
* been marked as successful using markBootSuccessful.
|
||||||
* is expected to be statically allocated and not need to be freed.
|
* Returns 1 if the slot has been marked as successful, 0 if it's
|
||||||
* Returns NULL if slot does not match an existing slot.
|
* not the case, and -errno on error.
|
||||||
*/
|
*/
|
||||||
const char* (*getSuffix)(unsigned slot);
|
int (*isSlotMarkedSuccessful)(unsigned slot);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* (*isSlotMarkedSucessful)() returns if the slot passed in parameter has
|
* Returns the active slot to boot into on the next boot. If
|
||||||
* been marked as successful using markBootSuccessful.
|
* setActiveBootSlot() has been called, the getter function should return
|
||||||
* Returns 1 if the slot has been marked as successful, 0 if it's
|
* the same slot as the one provided in the last setActiveBootSlot() call.
|
||||||
* not the case, and -errno on error.
|
*/
|
||||||
*/
|
unsigned (*getActiveBootSlot)();
|
||||||
int (*isSlotMarkedSuccessful)(unsigned slot);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the active slot to boot into on the next boot. If
|
|
||||||
* setActiveBootSlot() has been called, the getter function should return
|
|
||||||
* the same slot as the one provided in the last setActiveBootSlot() call.
|
|
||||||
*/
|
|
||||||
unsigned (*getActiveBootSlot)();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const struct boot_control_module bootctl;
|
extern const struct boot_control_module bootctl;
|
||||||
extern const struct boot_control_module bootctl_test;
|
extern const struct boot_control_module bootctl_test;
|
||||||
|
|
||||||
#endif // __BOOTCTRL_H__
|
#endif // __BOOTCTRL_H__
|
||||||
|
@ -16,21 +16,18 @@
|
|||||||
* along with this program. If not, see <http:// www.gnu.org/licenses/>.
|
* along with this program. If not, see <http:// www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <list>
|
#include <stdbool.h>
|
||||||
#include <map>
|
|
||||||
#include <regex>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <string>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "gpt-utils.h"
|
#include "gpt-utils.h"
|
||||||
#include "ufs-bsg.h"
|
#include "ufs-bsg.h"
|
||||||
@ -57,7 +54,6 @@
|
|||||||
(*(pentry + AB_FLAG_OFFSET) & ~AB_PARTITION_ATTR_SLOT_ACTIVE); \
|
(*(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 };
|
const char *slot_suffix_arr[] = { AB_SLOT_A_SUFFIX, AB_SLOT_B_SUFFIX, NULL };
|
||||||
|
|
||||||
enum part_attr_type {
|
enum part_attr_type {
|
||||||
@ -98,12 +94,12 @@ error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the value of one of the attribute fields for a partition.
|
// Get the value of one of the attribute fields for a partition.
|
||||||
static int get_partition_attribute(struct gpt_disk *disk, char *partname,
|
static int get_partition_attribute(struct gpt_disk *disk, const char *partname,
|
||||||
enum part_attr_type part_attr)
|
enum part_attr_type part_attr)
|
||||||
{
|
{
|
||||||
uint8_t *pentry = nullptr;
|
uint8_t *pentry = NULL;
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
uint8_t *attr = nullptr;
|
uint8_t *attr = NULL;
|
||||||
if (!partname)
|
if (!partname)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -151,13 +147,12 @@ static int update_slot_attribute(struct gpt_disk *disk, const char *slot,
|
|||||||
unsigned int i = 0;
|
unsigned int i = 0;
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX];
|
||||||
struct stat st;
|
struct stat st;
|
||||||
uint8_t *pentry = nullptr;
|
uint8_t *pentry = NULL;
|
||||||
uint8_t *pentry_bak = nullptr;
|
uint8_t *pentry_bak = NULL;
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
uint8_t *attr = nullptr;
|
uint8_t *attr = NULL;
|
||||||
uint8_t *attr_bak = nullptr;
|
uint8_t *attr_bak = NULL;
|
||||||
char partName[MAX_GPT_NAME_SIZE + 1] = { 0 };
|
char partName[MAX_GPT_NAME_SIZE + 1] = { 0 };
|
||||||
static const char ptn_list[][MAX_GPT_NAME_SIZE - 1] = { AB_PTN_LIST };
|
|
||||||
int slot_name_valid = 0;
|
int slot_name_valid = 0;
|
||||||
char devpath[PATH_MAX] = { 0 };
|
char devpath[PATH_MAX] = { 0 };
|
||||||
|
|
||||||
@ -166,7 +161,7 @@ static int update_slot_attribute(struct gpt_disk *disk, const char *slot,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; slot_suffix_arr[i] != nullptr; i++) {
|
for (i = 0; slot_suffix_arr[i] != NULL; i++) {
|
||||||
if (!strncmp(slot, slot_suffix_arr[i], strlen(slot_suffix_arr[i])))
|
if (!strncmp(slot, slot_suffix_arr[i], strlen(slot_suffix_arr[i])))
|
||||||
slot_name_valid = 1;
|
slot_name_valid = 1;
|
||||||
}
|
}
|
||||||
@ -176,10 +171,10 @@ static int update_slot_attribute(struct gpt_disk *disk, const char *slot,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(ptn_list); i++) {
|
for (i = 0; i < ARRAY_SIZE(g_all_ptns); i++) {
|
||||||
memset(buf, '\0', sizeof(buf));
|
memset(buf, '\0', sizeof(buf));
|
||||||
// Check if A/B versions of this ptn exist
|
// Check if A/B versions of this ptn exist
|
||||||
snprintf(buf, sizeof(buf) - 1, "%s/%s%s", BOOT_DEV_DIR, ptn_list[i],
|
snprintf(buf, sizeof(buf) - 1, "%s/%s%s", BOOT_DEV_DIR, g_all_ptns[i],
|
||||||
AB_SLOT_A_SUFFIX);
|
AB_SLOT_A_SUFFIX);
|
||||||
if (stat(buf, &st) < 0) {
|
if (stat(buf, &st) < 0) {
|
||||||
// partition does not have _a version
|
// partition does not have _a version
|
||||||
@ -187,7 +182,7 @@ static int update_slot_attribute(struct gpt_disk *disk, const char *slot,
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(buf, '\0', sizeof(buf));
|
memset(buf, '\0', sizeof(buf));
|
||||||
snprintf(buf, sizeof(buf) - 1, "%s/%s%s", BOOT_DEV_DIR, ptn_list[i],
|
snprintf(buf, sizeof(buf) - 1, "%s/%s%s", BOOT_DEV_DIR, g_all_ptns[i],
|
||||||
AB_SLOT_B_SUFFIX);
|
AB_SLOT_B_SUFFIX);
|
||||||
if (stat(buf, &st) < 0) {
|
if (stat(buf, &st) < 0) {
|
||||||
// partition does not have _b version
|
// partition does not have _b version
|
||||||
@ -195,11 +190,11 @@ static int update_slot_attribute(struct gpt_disk *disk, const char *slot,
|
|||||||
}
|
}
|
||||||
|
|
||||||
memset(partName, '\0', sizeof(partName));
|
memset(partName, '\0', sizeof(partName));
|
||||||
snprintf(partName, sizeof(partName) - 1, "%s%s", ptn_list[i], slot);
|
snprintf(partName, sizeof(partName) - 1, "%s%s", g_all_ptns[i], slot);
|
||||||
|
|
||||||
// If the current partition is for a different disk (e.g. /dev/sde when the current disk is /dev/sda)
|
// If the current partition is for a different disk (e.g. /dev/sde when the current disk is /dev/sda)
|
||||||
// Then commit the current disk
|
// Then commit the current disk
|
||||||
if (!partition_is_for_disk(partName, disk, devpath, sizeof(devpath))) {
|
if (partition_is_for_disk(disk, partName, devpath, sizeof(devpath)) != 0) {
|
||||||
if (!gpt_disk_commit(disk)) {
|
if (!gpt_disk_commit(disk)) {
|
||||||
fprintf(stderr, "%s: Failed to commit disk\n", __func__);
|
fprintf(stderr, "%s: Failed to commit disk\n", __func__);
|
||||||
return -1;
|
return -1;
|
||||||
@ -265,8 +260,8 @@ static int update_slot_attribute(struct gpt_disk *disk, const char *slot,
|
|||||||
*/
|
*/
|
||||||
unsigned get_number_slots()
|
unsigned get_number_slots()
|
||||||
{
|
{
|
||||||
struct dirent *de = nullptr;
|
struct dirent *de = NULL;
|
||||||
DIR *dir_bootdev = nullptr;
|
DIR *dir_bootdev = NULL;
|
||||||
static int slot_count = 0;
|
static int slot_count = 0;
|
||||||
|
|
||||||
// If we've already counted the slots, return the cached value.
|
// If we've already counted the slots, return the cached value.
|
||||||
@ -274,8 +269,8 @@ unsigned get_number_slots()
|
|||||||
if (slot_count > 0)
|
if (slot_count > 0)
|
||||||
return slot_count;
|
return slot_count;
|
||||||
|
|
||||||
static_assert(AB_SLOT_A_SUFFIX[0] == '_', "Breaking change to slot A suffix");
|
assert(AB_SLOT_A_SUFFIX[0] == '_');
|
||||||
static_assert(AB_SLOT_B_SUFFIX[0] == '_', "Breaking change to slot B suffix");
|
assert(AB_SLOT_B_SUFFIX[0] == '_');
|
||||||
|
|
||||||
dir_bootdev = opendir(BOOTDEV_DIR);
|
dir_bootdev = opendir(BOOTDEV_DIR);
|
||||||
// Shouldn't this be an assert?
|
// Shouldn't this be an assert?
|
||||||
@ -344,7 +339,7 @@ static unsigned int get_current_slot_from_kernel_cmdline()
|
|||||||
|
|
||||||
// Iterate through a list of partitons named as boot+suffix
|
// Iterate through a list of partitons named as boot+suffix
|
||||||
// and see which one is currently active.
|
// and see which one is currently active.
|
||||||
for (i = 0; slot_suffix_arr[i] != nullptr; i++) {
|
for (i = 0; slot_suffix_arr[i] != NULL; i++) {
|
||||||
if (!strncmp(bootSlotProp, slot_suffix_arr[i], strlen(slot_suffix_arr[i]))) {
|
if (!strncmp(bootSlotProp, slot_suffix_arr[i], strlen(slot_suffix_arr[i]))) {
|
||||||
// printf("%s current_slot = %d\n", __func__, i);
|
// printf("%s current_slot = %d\n", __func__, i);
|
||||||
return i;
|
return i;
|
||||||
@ -413,68 +408,66 @@ const char *get_suffix(unsigned slot)
|
|||||||
return slot_suffix_arr[slot];
|
return slot_suffix_arr[slot];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// The argument here is a vector of partition names(including the slot suffix)
|
// The argument here is a vector of partition names(including the slot suffix)
|
||||||
// that lie on a single disk
|
// that lie on a single disk
|
||||||
static int boot_ctl_set_active_slot_for_partitions(struct gpt_disk *disk, vector<string> part_list,
|
static int boot_ctl_set_active_slot_for_partitions(struct gpt_disk *disk, const char ptn_list[][MAX_GPT_NAME_SIZE], int len,
|
||||||
unsigned slot)
|
unsigned slot)
|
||||||
{
|
{
|
||||||
char buf[PATH_MAX] = { 0 };
|
char buf[PATH_MAX] = { 0 };
|
||||||
char slotA[MAX_GPT_NAME_SIZE + 1] = { 0 };
|
const char *slotA;
|
||||||
char slotB[MAX_GPT_NAME_SIZE + 1] = { 0 };
|
char slotB[MAX_GPT_NAME_SIZE] = { 0 };
|
||||||
char active_guid[TYPE_GUID_SIZE + 1] = { 0 };
|
char active_guid[TYPE_GUID_SIZE + 1] = { 0 };
|
||||||
char inactive_guid[TYPE_GUID_SIZE + 1] = { 0 };
|
char inactive_guid[TYPE_GUID_SIZE + 1] = { 0 };
|
||||||
int rc;
|
int rc, i;
|
||||||
// Pointer to the partition entry of current 'A' partition
|
// Pointer to the partition entry of current 'A' partition
|
||||||
uint8_t *pentryA = nullptr;
|
uint8_t *pentryA = NULL;
|
||||||
uint8_t *pentryA_bak = nullptr;
|
uint8_t *pentryA_bak = NULL;
|
||||||
// Pointer to partition entry of current 'B' partition
|
// Pointer to partition entry of current 'B' partition
|
||||||
uint8_t *pentryB = nullptr;
|
uint8_t *pentryB = NULL;
|
||||||
uint8_t *pentryB_bak = nullptr;
|
uint8_t *pentryB_bak = NULL;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
vector<string>::iterator partition_iterator;
|
|
||||||
|
|
||||||
LOGD("Marking slot %s as active:\n", slot_suffix_arr[slot]);
|
LOGD("Marking slot %s as active:\n", slot_suffix_arr[slot]);
|
||||||
|
|
||||||
for (partition_iterator = part_list.begin(); partition_iterator != part_list.end();
|
for (i = 0, slotA = ptn_list[0]; i < len; slotA = ptn_list[++i]) {
|
||||||
partition_iterator++) {
|
|
||||||
// Chop off the slot suffix from the partition name to
|
// Chop off the slot suffix from the partition name to
|
||||||
// make the string easier to work with.
|
// make the string easier to work with.
|
||||||
string prefix = *partition_iterator;
|
LOGD("Part: %s\n", slotA);
|
||||||
LOGD("Part: %s\n", prefix.c_str());
|
int n = strlen(slotA) - strlen(AB_SLOT_A_SUFFIX);
|
||||||
if (prefix.size() < (strlen(AB_SLOT_A_SUFFIX) + 1)) {
|
if (n + 1 < 3 || n + 1 > MAX_GPT_NAME_SIZE) {
|
||||||
fprintf(stderr, "Invalid partition name: %s\n", prefix.c_str());
|
fprintf(stderr, "Invalid partition name: %s\n", slotA);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
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);
|
|
||||||
LOGD("\t_a Path: '%s'\n", buf);
|
|
||||||
rc = stat(buf, &st);
|
|
||||||
if (rc < 0) {
|
|
||||||
fprintf(stderr, "Failed to stat() path: %d: %s\n", rc, strerror(errno));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
memset(buf, '\0', sizeof(buf));
|
|
||||||
snprintf(buf, sizeof(buf) - 1, "%s/%s%s", BOOT_DEV_DIR, prefix.c_str(),
|
|
||||||
AB_SLOT_B_SUFFIX);
|
|
||||||
// LOGD("\t_b Path: '%s'\n", buf);
|
|
||||||
rc = stat(buf, &st);
|
|
||||||
if (rc < 0) {
|
|
||||||
fprintf(stderr, "Failed to stat() path: %d: %s\n", rc, strerror(errno));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
memset(slotA, 0, sizeof(slotA));
|
|
||||||
memset(slotB, 0, sizeof(slotA));
|
|
||||||
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 disk containing the partitions that were passed in.
|
memset(slotB, 0, sizeof(slotB));
|
||||||
// All partitions passed in must lie on the same disk.
|
strncat(slotB, slotA, n);
|
||||||
if (!gpt_disk_is_valid(disk)) {
|
strncat(slotB + n, AB_SLOT_B_SUFFIX, 3);
|
||||||
if (gpt_disk_get_disk_info(slotA, disk) < 0)
|
|
||||||
|
rc = snprintf(buf, sizeof(buf) - 1, "%s", BOOT_DEV_DIR);
|
||||||
|
snprintf(buf + rc, PATH_MAX - rc, "/%s", slotA);
|
||||||
|
LOGD("Checking for partition %s\n", buf);
|
||||||
|
if (stat(buf, &st)) {
|
||||||
|
if (!strcmp(slotA, "boot_a") || !strcmp(slotA, "dtbo_a")) {
|
||||||
|
fprintf(stderr, "Couldn't find required partition %s\n", slotA);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
// Not every device has every partition
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
snprintf(buf + rc, PATH_MAX - rc, "/%s", slotB);
|
||||||
|
if (stat(buf, &st)) {
|
||||||
|
fprintf(stderr, "Partition %s does not exist\n", slotB);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the disk containing this partition. This only
|
||||||
|
// actually re-initialises disk if this partition refers
|
||||||
|
// to a different block device than the last one.
|
||||||
|
if (gpt_disk_get_disk_info(slotA, disk) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
// Get partition entry for slot A & B from the primary
|
// Get partition entry for slot A & B from the primary
|
||||||
// and backup tables.
|
// and backup tables.
|
||||||
pentryA = gpt_disk_get_pentry(disk, slotA, PRIMARY_GPT);
|
pentryA = gpt_disk_get_pentry(disk, slotA, PRIMARY_GPT);
|
||||||
@ -484,7 +477,7 @@ static int boot_ctl_set_active_slot_for_partitions(struct gpt_disk *disk, vector
|
|||||||
if (!pentryA || !pentryA_bak || !pentryB || !pentryB_bak) {
|
if (!pentryA || !pentryA_bak || !pentryB || !pentryB_bak) {
|
||||||
// None of these should be NULL since we have already
|
// None of these should be NULL since we have already
|
||||||
// checked for A & B versions earlier.
|
// checked for A & B versions earlier.
|
||||||
fprintf(stderr, "Slot pentries for %s not found.\n", prefix.c_str());
|
fprintf(stderr, "Slot pentries for %s not found.\n", slotA);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
LOGD("\tAB attr (A): 0x%x (backup: 0x%x)\n", *(uint16_t *)(pentryA + AB_FLAG_OFFSET),
|
LOGD("\tAB attr (A): 0x%x (backup: 0x%x)\n", *(uint16_t *)(pentryA + AB_FLAG_OFFSET),
|
||||||
@ -558,86 +551,50 @@ unsigned get_active_boot_slot()
|
|||||||
|
|
||||||
int set_active_boot_slot(unsigned slot)
|
int set_active_boot_slot(unsigned slot)
|
||||||
{
|
{
|
||||||
map<string, vector<string>> ptn_map;
|
enum boot_chain chain = (enum boot_chain)slot;
|
||||||
vector<string> ptn_vec;
|
|
||||||
const char ptn_list[][MAX_GPT_NAME_SIZE] = { AB_PTN_LIST };
|
|
||||||
struct gpt_disk disk = { 0 };
|
struct gpt_disk disk = { 0 };
|
||||||
uint32_t i;
|
int rc;
|
||||||
int rc = -1;
|
|
||||||
map<string, vector<string>>::iterator map_iter;
|
|
||||||
bool ismmc;
|
bool ismmc;
|
||||||
|
|
||||||
if (boot_control_check_slot_sanity(slot)) {
|
if (boot_control_check_slot_sanity(slot)) {
|
||||||
fprintf(stderr, "%s: Bad arguments\n", __func__);
|
fprintf(stderr, "%s: Bad arguments\n", __func__);
|
||||||
goto out;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ismmc = gpt_utils_is_partition_backed_by_emmc(PTN_XBL AB_SLOT_A_SUFFIX);
|
ismmc = gpt_utils_is_partition_backed_by_emmc(PTN_XBL AB_SLOT_A_SUFFIX);
|
||||||
|
|
||||||
|
// Do this *before* updating all the slot attributes
|
||||||
|
// to make sure we can
|
||||||
if (!ismmc && ufs_bsg_dev_open() < 0) {
|
if (!ismmc && ufs_bsg_dev_open() < 0) {
|
||||||
goto out;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The partition list just contains prefixes(without the _a/_b) of the
|
rc = boot_ctl_set_active_slot_for_partitions(&disk, g_all_ptns, ARRAY_SIZE(g_all_ptns), slot);
|
||||||
// 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 is handled differrently for ufs devices so ignore it
|
|
||||||
if (!ismmc && !strncmp(ptn_list[i], PTN_XBL, strlen(PTN_XBL)))
|
|
||||||
continue;
|
|
||||||
// The partition list will be the list of _a partitions
|
|
||||||
string cur_ptn = ptn_list[i];
|
|
||||||
cur_ptn.append(AB_SLOT_A_SUFFIX);
|
|
||||||
ptn_vec.push_back(cur_ptn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The partition map gives us info in the following format:
|
if (rc) {
|
||||||
// [path_to_block_device_1]--><partitions on device 1>
|
fprintf(stderr, "%s: Failed to set active slot for partitions \n", __func__);
|
||||||
// [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)) {
|
|
||||||
fprintf(stderr, "%s: Failed to get partition map\n", __func__);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
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(&disk, map_iter->second, slot)) {
|
|
||||||
fprintf(stderr, "%s: Failed to set active slot for partitions \n", __func__);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// EMMC doesn't need attributes to be set.
|
// EMMC doesn't need attributes to be set.
|
||||||
if (ismmc)
|
if (ismmc)
|
||||||
return 0;
|
goto out;
|
||||||
|
|
||||||
if (slot == 0) {
|
if (chain > BACKUP_BOOT) {
|
||||||
// Set xbl_a as the boot lun
|
fprintf(stderr, "%s: Unknown slot %d!\n", __func__, slot);
|
||||||
rc = gpt_utils_set_xbl_boot_partition(NORMAL_BOOT);
|
rc = -1;
|
||||||
} else if (slot == 1) {
|
|
||||||
// Set xbl_b as the boot lun
|
|
||||||
rc = gpt_utils_set_xbl_boot_partition(BACKUP_BOOT);
|
|
||||||
} else {
|
|
||||||
// Something has gone terribly terribly wrong
|
|
||||||
fprintf(stderr, "%s: Unknown slot suffix!\n", __func__);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc = gpt_utils_set_xbl_boot_partition(chain);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
fprintf(stderr, "%s: Failed to switch xbl boot partition\n", __func__);
|
fprintf(stderr, "%s: Failed to switch xbl boot partition\n", __func__);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpt_disk_free(&disk);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
gpt_disk_free(&disk);
|
gpt_disk_free(&disk);
|
||||||
return -1;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_slot_as_unbootable(unsigned slot)
|
int set_slot_as_unbootable(unsigned slot)
|
@ -16,6 +16,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include "bootctrl.h"
|
#include "bootctrl.h"
|
||||||
|
|
||||||
struct test_state {
|
struct test_state {
|
@ -30,8 +30,10 @@
|
|||||||
|
|
||||||
#define _LARGEFILE64_SOURCE /* enable lseek64() */
|
#define _LARGEFILE64_SOURCE /* enable lseek64() */
|
||||||
|
|
||||||
#include "assert.h"
|
#include <assert.h>
|
||||||
#include <asm/byteorder.h>
|
#include <asm/byteorder.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <endian.h>
|
#include <endian.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -40,14 +42,11 @@
|
|||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <map>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <string>
|
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <vector>
|
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
#include "gpt-utils.h"
|
#include "gpt-utils.h"
|
||||||
@ -75,9 +74,6 @@
|
|||||||
#define LUN_NAME_START_LOC (sizeof("/dev/") - 1)
|
#define LUN_NAME_START_LOC (sizeof("/dev/") - 1)
|
||||||
#define BOOT_LUN_A_ID 1
|
#define BOOT_LUN_A_ID 1
|
||||||
#define BOOT_LUN_B_ID 2
|
#define BOOT_LUN_B_ID 2
|
||||||
/******************************************************************************
|
|
||||||
* MACROS
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
#define GET_4_BYTES(ptr) \
|
#define GET_4_BYTES(ptr) \
|
||||||
((uint32_t) * ((uint8_t *)(ptr)) | ((uint32_t) * ((uint8_t *)(ptr) + 1) << 8) | \
|
((uint32_t) * ((uint8_t *)(ptr)) | ((uint32_t) * ((uint8_t *)(ptr) + 1) << 8) | \
|
||||||
@ -97,10 +93,6 @@
|
|||||||
*((uint8_t *)(ptr) + 2) = ((y) >> 16) & 0xff; \
|
*((uint8_t *)(ptr) + 2) = ((y) >> 16) & 0xff; \
|
||||||
*((uint8_t *)(ptr) + 3) = ((y) >> 24) & 0xff;
|
*((uint8_t *)(ptr) + 3) = ((y) >> 24) & 0xff;
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
* TYPES
|
|
||||||
******************************************************************************/
|
|
||||||
using namespace std;
|
|
||||||
enum gpt_state { GPT_OK = 0, GPT_BAD_SIGNATURE, GPT_BAD_CRC };
|
enum gpt_state { GPT_OK = 0, GPT_BAD_SIGNATURE, GPT_BAD_CRC };
|
||||||
// List of LUN's containing boot critical images.
|
// List of LUN's containing boot critical images.
|
||||||
// Required in the case of UFS devices
|
// Required in the case of UFS devices
|
||||||
@ -109,9 +101,6 @@ struct update_data {
|
|||||||
uint32_t num_valid_entries;
|
uint32_t num_valid_entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
* FUNCTIONS
|
|
||||||
******************************************************************************/
|
|
||||||
void DumpHex(const void *data, size_t size)
|
void DumpHex(const void *data, size_t size)
|
||||||
{
|
{
|
||||||
char ascii[17];
|
char ascii[17];
|
||||||
@ -222,7 +211,7 @@ static uint8_t *gpt_pentry_seek(const char *ptn_name, const uint8_t *pentries_st
|
|||||||
return (uint8_t *)(pentry_name - PARTITION_NAME_OFFSET);
|
return (uint8_t *)(pentry_name - PARTITION_NAME_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defined in ufs-bsg.cpp
|
// Defined in ufs-bsg.cpp
|
||||||
@ -249,7 +238,7 @@ int gpt_utils_set_xbl_boot_partition(enum boot_chain chain)
|
|||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
uint8_t boot_lun_id = 0;
|
uint8_t boot_lun_id = 0;
|
||||||
const char *boot_dev = nullptr;
|
const char *boot_dev = NULL;
|
||||||
|
|
||||||
(void)st;
|
(void)st;
|
||||||
(void)boot_dev;
|
(void)boot_dev;
|
||||||
@ -332,42 +321,6 @@ static int get_dev_path_from_partition_name(const char *partname, char *buf, siz
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpt_utils_get_partition_map(vector<string> &ptn_list, map<string, vector<string>> &partition_map)
|
|
||||||
{
|
|
||||||
char devpath[PATH_MAX] = { '\0' };
|
|
||||||
map<string, vector<string>>::iterator it;
|
|
||||||
|
|
||||||
if (ptn_list.size() < 1) {
|
|
||||||
fprintf(stderr, "%s: Invalid ptn list\n", __func__);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go through the passed in list
|
|
||||||
for (uint32_t i = 0; i < ptn_list.size(); i++) {
|
|
||||||
// Key in the map is the path to the device that holds the
|
|
||||||
// partition
|
|
||||||
if (get_dev_path_from_partition_name(ptn_list[i].c_str(), devpath, sizeof(devpath))) {
|
|
||||||
// Not necessarily an error. The partition may just
|
|
||||||
// not be present.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
string path = devpath;
|
|
||||||
it = partition_map.find(path);
|
|
||||||
if (it != partition_map.end()) {
|
|
||||||
it->second.push_back(ptn_list[i]);
|
|
||||||
} else {
|
|
||||||
vector<string> str_vec;
|
|
||||||
str_vec.push_back(ptn_list[i]);
|
|
||||||
partition_map.insert(pair<string, vector<string>>(path, str_vec));
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(devpath, '\0', sizeof(devpath));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the block size of the disk represented by decsriptor fd
|
// Get the block size of the disk represented by decsriptor fd
|
||||||
static uint32_t gpt_get_block_size(int fd)
|
static uint32_t gpt_get_block_size(int fd)
|
||||||
{
|
{
|
||||||
@ -432,7 +385,7 @@ error:
|
|||||||
// Read out the GPT headers for the disk that contains the partition partname
|
// Read out the GPT headers for the disk that contains the partition partname
|
||||||
static int gpt_get_headers(const char *partname, uint8_t **primary, uint8_t **backup)
|
static int gpt_get_headers(const char *partname, uint8_t **primary, uint8_t **backup)
|
||||||
{
|
{
|
||||||
uint8_t *hdr = nullptr;
|
uint8_t *hdr = NULL;
|
||||||
char devpath[PATH_MAX] = { 0 };
|
char devpath[PATH_MAX] = { 0 };
|
||||||
off_t hdr_offset = 0;
|
off_t hdr_offset = 0;
|
||||||
uint32_t block_size = 0;
|
uint32_t block_size = 0;
|
||||||
@ -505,7 +458,7 @@ static uint8_t *gpt_get_pentry_arr(uint8_t *hdr, int fd)
|
|||||||
uint32_t pentry_size = 0;
|
uint32_t pentry_size = 0;
|
||||||
uint32_t block_size = 0;
|
uint32_t block_size = 0;
|
||||||
uint32_t pentries_arr_size = 0;
|
uint32_t pentries_arr_size = 0;
|
||||||
uint8_t *pentry_arr = nullptr;
|
uint8_t *pentry_arr = NULL;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
if (!hdr) {
|
if (!hdr) {
|
||||||
fprintf(stderr, "%s: Invalid header\n", __func__);
|
fprintf(stderr, "%s: Invalid header\n", __func__);
|
||||||
@ -537,7 +490,7 @@ static uint8_t *gpt_get_pentry_arr(uint8_t *hdr, int fd)
|
|||||||
error:
|
error:
|
||||||
if (pentry_arr)
|
if (pentry_arr)
|
||||||
free(pentry_arr);
|
free(pentry_arr);
|
||||||
return nullptr;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gpt_set_pentry_arr(uint8_t *hdr, int fd, uint8_t *arr)
|
static int gpt_set_pentry_arr(uint8_t *hdr, int fd, uint8_t *arr)
|
||||||
@ -586,19 +539,19 @@ void gpt_disk_free(struct gpt_disk *disk)
|
|||||||
|
|
||||||
if (disk->hdr) {
|
if (disk->hdr) {
|
||||||
free(disk->hdr);
|
free(disk->hdr);
|
||||||
disk->hdr = nullptr;
|
disk->hdr = NULL;
|
||||||
}
|
}
|
||||||
if (disk->hdr_bak) {
|
if (disk->hdr_bak) {
|
||||||
free(disk->hdr_bak);
|
free(disk->hdr_bak);
|
||||||
disk->hdr_bak = nullptr;
|
disk->hdr_bak = NULL;
|
||||||
}
|
}
|
||||||
if (disk->pentry_arr) {
|
if (disk->pentry_arr) {
|
||||||
free(disk->pentry_arr);
|
free(disk->pentry_arr);
|
||||||
disk->pentry_arr = nullptr;
|
disk->pentry_arr = NULL;
|
||||||
}
|
}
|
||||||
if (disk->pentry_arr_bak) {
|
if (disk->pentry_arr_bak) {
|
||||||
free(disk->pentry_arr_bak);
|
free(disk->pentry_arr_bak);
|
||||||
disk->pentry_arr_bak = nullptr;
|
disk->pentry_arr_bak = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
disk->is_initialized = 0;
|
disk->is_initialized = 0;
|
||||||
@ -616,14 +569,14 @@ bool gpt_disk_is_valid(struct gpt_disk *disk)
|
|||||||
* and populate the blockdev path.
|
* and populate the blockdev path.
|
||||||
* e.g. for /dev/disk/by-partlabel/system_a blockdev would be /dev/sda
|
* e.g. for /dev/disk/by-partlabel/system_a blockdev would be /dev/sda
|
||||||
*/
|
*/
|
||||||
bool partition_is_for_disk(const char *part, struct gpt_disk *disk, char *blockdev, int blockdev_len)
|
int partition_is_for_disk(const struct gpt_disk *disk, const char *part, char *blockdev, int blockdev_len)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = get_dev_path_from_partition_name(part, blockdev, blockdev_len);
|
ret = get_dev_path_from_partition_name(part, blockdev, blockdev_len);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
fprintf(stderr, "%s: Failed to resolve path for %s\n", __func__, part);
|
fprintf(stderr, "%s: Failed to resolve path for %s\n", __func__, part);
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(blockdev, disk->devpath)) {
|
if (!strcmp(blockdev, disk->devpath)) {
|
||||||
@ -639,7 +592,7 @@ bool partition_is_for_disk(const char *part, struct gpt_disk *disk, char *blockd
|
|||||||
*/
|
*/
|
||||||
int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *disk)
|
int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *disk)
|
||||||
{
|
{
|
||||||
int fd = -1;
|
int fd = -1, rc;
|
||||||
uint32_t gpt_header_size = 0;
|
uint32_t gpt_header_size = 0;
|
||||||
char devpath[PATH_MAX] = { 0 };
|
char devpath[PATH_MAX] = { 0 };
|
||||||
|
|
||||||
@ -648,8 +601,14 @@ int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *disk)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (partition_is_for_disk(dev, disk, devpath, sizeof(devpath))) {
|
rc = partition_is_for_disk(disk, dev, devpath, sizeof(devpath));
|
||||||
|
|
||||||
|
if (rc > 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "%s: Failed to resolve path for %s\n", __func__, dev);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (disk->is_initialized == GPT_DISK_INIT_MAGIC) {
|
if (disk->is_initialized == GPT_DISK_INIT_MAGIC) {
|
||||||
@ -666,8 +625,8 @@ int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *disk)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(disk->hdr != nullptr);
|
assert(disk->hdr != NULL);
|
||||||
assert(disk->hdr_bak != nullptr);
|
assert(disk->hdr_bak != NULL);
|
||||||
|
|
||||||
gpt_header_size = GET_4_BYTES(disk->hdr + HEADER_SIZE_OFFSET);
|
gpt_header_size = GET_4_BYTES(disk->hdr + HEADER_SIZE_OFFSET);
|
||||||
|
|
||||||
@ -683,14 +642,14 @@ int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *disk)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(disk->pentry_arr == nullptr);
|
assert(disk->pentry_arr == NULL);
|
||||||
disk->pentry_arr = gpt_get_pentry_arr(disk->hdr, fd);
|
disk->pentry_arr = gpt_get_pentry_arr(disk->hdr, fd);
|
||||||
if (!disk->pentry_arr) {
|
if (!disk->pentry_arr) {
|
||||||
fprintf(stderr, "%s: Failed to obtain partition entry array\n", __func__);
|
fprintf(stderr, "%s: Failed to obtain partition entry array\n", __func__);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(disk->pentry_arr_bak == nullptr);
|
assert(disk->pentry_arr_bak == NULL);
|
||||||
disk->pentry_arr_bak = gpt_get_pentry_arr(disk->hdr_bak, fd);
|
disk->pentry_arr_bak = gpt_get_pentry_arr(disk->hdr_bak, fd);
|
||||||
if (!disk->pentry_arr_bak) {
|
if (!disk->pentry_arr_bak) {
|
||||||
fprintf(stderr, "%s: Failed to obtain backup partition entry array\n", __func__);
|
fprintf(stderr, "%s: Failed to obtain backup partition entry array\n", __func__);
|
||||||
@ -714,10 +673,10 @@ error:
|
|||||||
// Get pointer to partition entry from a allocated gpt_disk structure
|
// 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)
|
uint8_t *gpt_disk_get_pentry(struct gpt_disk *disk, const char *partname, enum gpt_instance instance)
|
||||||
{
|
{
|
||||||
uint8_t *ptn_arr = nullptr;
|
uint8_t *ptn_arr = NULL;
|
||||||
if (!disk || !partname || disk->is_initialized != GPT_DISK_INIT_MAGIC) {
|
if (!disk || !partname || disk->is_initialized != GPT_DISK_INIT_MAGIC) {
|
||||||
fprintf(stderr, "%s: disk handle not initialised\n", __func__);
|
fprintf(stderr, "%s: disk handle not initialised\n", __func__);
|
||||||
return nullptr;
|
return NULL;
|
||||||
}
|
}
|
||||||
ptn_arr = (instance == PRIMARY_GPT) ? disk->pentry_arr : disk->pentry_arr_bak;
|
ptn_arr = (instance == PRIMARY_GPT) ? disk->pentry_arr : disk->pentry_arr_bak;
|
||||||
return (gpt_pentry_seek(partname, ptn_arr, ptn_arr + disk->pentry_arr_size,
|
return (gpt_pentry_seek(partname, ptn_arr, ptn_arr + disk->pentry_arr_size,
|
99
gpt-utils.h
99
gpt-utils.h
@ -29,13 +29,11 @@
|
|||||||
|
|
||||||
#ifndef __GPT_UTILS_H__
|
#ifndef __GPT_UTILS_H__
|
||||||
#define __GPT_UTILS_H__
|
#define __GPT_UTILS_H__
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <linux/limits.h>
|
#include <linux/limits.h>
|
||||||
@ -62,8 +60,8 @@ extern "C" {
|
|||||||
#define PARTITION_NAME_OFFSET 56
|
#define PARTITION_NAME_OFFSET 56
|
||||||
#define MAX_GPT_NAME_SIZE 72
|
#define MAX_GPT_NAME_SIZE 72
|
||||||
|
|
||||||
//Bit 48 onwords in the attribute field are the ones where we are allowed to
|
// Bit 48 onwords in the attribute field are the ones where we are allowed to
|
||||||
//store our AB attributes.
|
// store our AB attributes.
|
||||||
#define AB_FLAG_OFFSET (ATTRIBUTE_FLAG_OFFSET + 6)
|
#define AB_FLAG_OFFSET (ATTRIBUTE_FLAG_OFFSET + 6)
|
||||||
#define GPT_DISK_INIT_MAGIC 0xABCD
|
#define GPT_DISK_INIT_MAGIC 0xABCD
|
||||||
#define AB_PARTITION_ATTR_SLOT_ACTIVE (0x1 << 2)
|
#define AB_PARTITION_ATTR_SLOT_ACTIVE (0x1 << 2)
|
||||||
@ -76,14 +74,22 @@ extern "C" {
|
|||||||
#define AB_SLOT_A_SUFFIX "_a"
|
#define AB_SLOT_A_SUFFIX "_a"
|
||||||
#define AB_SLOT_B_SUFFIX "_b"
|
#define AB_SLOT_B_SUFFIX "_b"
|
||||||
#define PTN_XBL "xbl"
|
#define PTN_XBL "xbl"
|
||||||
#define PTN_SWAP_LIST \
|
// XBL is not included because the slot attributes are meaningless there
|
||||||
PTN_XBL, "abl", "aop", "apdp", "cmnlib", "cmnlib64", "devcfg", "dtbo", \
|
// *which* XBL partition is active is determined via the UFS bBootLunEn field
|
||||||
"hyp", "keymaster", "msadp", "qupfw", "storsec", "tz", \
|
// as it needs to be handled by PBL
|
||||||
"vbmeta", "vbmeta_system", "xbl_config"
|
#define PTN_SWAP_LIST \
|
||||||
|
"abl_a", "aop_a", "apdp_a", "cmnlib_a", "cmnlib64_a", "devcfg_a", "dtbo_a", \
|
||||||
|
"hyp_a", "keymaster_a", "msadp_a", "qupfw_a", "storsec_a", "tz_a", \
|
||||||
|
"vbmeta_a", "vbmeta_system_a"
|
||||||
|
|
||||||
|
static const char g_all_ptns[][MAX_GPT_NAME_SIZE] = {
|
||||||
|
PTN_SWAP_LIST, "boot_a", "system",
|
||||||
|
"vendor_a", "modem_a", "system_ext_a", "product_a"
|
||||||
|
};
|
||||||
|
|
||||||
|
// No more than /dev/sdk
|
||||||
|
#define MAX_BLOCK_DEVICES 10
|
||||||
|
|
||||||
#define AB_PTN_LIST \
|
|
||||||
PTN_SWAP_LIST, "boot", "system", "vendor", "modem", "system_ext", \
|
|
||||||
"product"
|
|
||||||
#define BOOT_DEV_DIR "/dev/disk/by-partlabel"
|
#define BOOT_DEV_DIR "/dev/disk/by-partlabel"
|
||||||
|
|
||||||
#define EMMC_DEVICE "/dev/mmcblk0"
|
#define EMMC_DEVICE "/dev/mmcblk0"
|
||||||
@ -95,78 +101,69 @@ enum gpt_instance { PRIMARY_GPT = 0, SECONDARY_GPT };
|
|||||||
enum boot_chain { NORMAL_BOOT = 0, BACKUP_BOOT };
|
enum boot_chain { NORMAL_BOOT = 0, BACKUP_BOOT };
|
||||||
|
|
||||||
struct gpt_disk {
|
struct gpt_disk {
|
||||||
//GPT primary header
|
// GPT primary header
|
||||||
uint8_t *hdr;
|
uint8_t *hdr;
|
||||||
//primary header crc
|
// primary header crc
|
||||||
uint32_t hdr_crc;
|
uint32_t hdr_crc;
|
||||||
//GPT backup header
|
// GPT backup header
|
||||||
uint8_t *hdr_bak;
|
uint8_t *hdr_bak;
|
||||||
//backup header crc
|
// backup header crc
|
||||||
uint32_t hdr_bak_crc;
|
uint32_t hdr_bak_crc;
|
||||||
//Partition entries array
|
// Partition entries array
|
||||||
uint8_t *pentry_arr;
|
uint8_t *pentry_arr;
|
||||||
//Partition entries array for backup table
|
// Partition entries array for backup table
|
||||||
uint8_t *pentry_arr_bak;
|
uint8_t *pentry_arr_bak;
|
||||||
//Size of the pentry array
|
// Size of the pentry array
|
||||||
uint32_t pentry_arr_size;
|
uint32_t pentry_arr_size;
|
||||||
//Size of each element in the pentry array
|
// Size of each element in the pentry array
|
||||||
uint32_t pentry_size;
|
uint32_t pentry_size;
|
||||||
//CRC of the partition entry array
|
// CRC of the partition entry array
|
||||||
uint32_t pentry_arr_crc;
|
uint32_t pentry_arr_crc;
|
||||||
//CRC of the backup partition entry array
|
// CRC of the backup partition entry array
|
||||||
uint32_t pentry_arr_bak_crc;
|
uint32_t pentry_arr_bak_crc;
|
||||||
//Path to block dev representing the disk
|
// Path to block dev representing the disk
|
||||||
char devpath[PATH_MAX];
|
char devpath[PATH_MAX];
|
||||||
//Block size of disk
|
// Block size of disk
|
||||||
uint32_t block_size;
|
uint32_t block_size;
|
||||||
uint32_t is_initialized;
|
uint32_t is_initialized;
|
||||||
};
|
};
|
||||||
|
|
||||||
//GPT disk methods
|
// GPT disk methods
|
||||||
bool gpt_disk_is_valid(struct gpt_disk *disk);
|
bool gpt_disk_is_valid(struct gpt_disk *disk);
|
||||||
//Free previously allocated gpt_disk struct
|
// Free previously allocated gpt_disk struct
|
||||||
void gpt_disk_free(struct gpt_disk *disk);
|
void gpt_disk_free(struct gpt_disk *disk);
|
||||||
//Get the details of the disk holding the partition whose name
|
// Get the details of the disk holding the partition whose name
|
||||||
//is passed in via dev
|
// is passed in via dev
|
||||||
int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *disk);
|
int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *disk);
|
||||||
|
|
||||||
bool partition_is_for_disk(const char *part, struct gpt_disk *disk, char *blockdev, int blockdev_len);
|
int partition_is_for_disk(const struct gpt_disk *disk, const char *part, char *blockdev, int blockdev_len);
|
||||||
|
|
||||||
//Get pointer to partition entry from a allocated gpt_disk structure
|
// Get pointer to partition entry from a allocated gpt_disk structure
|
||||||
uint8_t *gpt_disk_get_pentry(struct gpt_disk *disk, const char *partname,
|
uint8_t *gpt_disk_get_pentry(struct gpt_disk *disk, const char *partname,
|
||||||
enum gpt_instance instance);
|
enum gpt_instance instance);
|
||||||
|
|
||||||
//Write the contents of struct gpt_disk back to the actual disk
|
// Write the contents of struct gpt_disk back to the actual disk
|
||||||
int gpt_disk_commit(struct gpt_disk *disk);
|
int gpt_disk_commit(struct gpt_disk *disk);
|
||||||
|
|
||||||
//Swtich betwieen using either the primary or the backup
|
// Swtich betwieen using either the primary or the backup
|
||||||
//boot LUN for boot. This is required since UFS boot partitions
|
// boot LUN for boot. This is required since UFS boot partitions
|
||||||
//cannot have a backup GPT which is what we use for failsafe
|
// cannot have a backup GPT which is what we use for failsafe
|
||||||
//updates of the other 'critical' partitions. This function will
|
// updates of the other 'critical' partitions. This function will
|
||||||
//not be invoked for emmc targets and on UFS targets is only required
|
// not be invoked for emmc targets and on UFS targets is only required
|
||||||
//to be invoked for XBL.
|
// to be invoked for XBL.
|
||||||
//
|
//
|
||||||
//The algorithm to do this is as follows:
|
// The algorithm to do this is as follows:
|
||||||
//- Find the real block device(eg: /dev/block/sdb) that corresponds
|
// - Find the real block device(eg: /dev/block/sdb) that corresponds
|
||||||
// to the /dev/block/bootdevice/by-name/xbl(bak) symlink
|
// to the /dev/block/bootdevice/by-name/xbl(bak) symlink
|
||||||
//
|
//
|
||||||
//- Once we have the block device 'node' name(sdb in the above example)
|
// - 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
|
// use this node to to locate the scsi generic device that represents
|
||||||
// it by checking the file /sys/block/sdb/device/scsi_generic/sgY
|
// 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
|
// - Once we locate sgY we call the query ioctl on /dev/sgy to switch
|
||||||
//the boot lun to either LUNA or LUNB
|
// the boot lun to either LUNA or LUNB
|
||||||
int gpt_utils_set_xbl_boot_partition(enum boot_chain chain);
|
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
|
|
||||||
//partition lies and the value is a vector of strings indicating which of
|
|
||||||
//the passed in partition 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);
|
|
||||||
|
|
||||||
bool gpt_utils_is_partition_backed_by_emmc(const char *part);
|
bool gpt_utils_is_partition_backed_by_emmc(const char *part);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
14
meson.build
14
meson.build
@ -1,6 +1,6 @@
|
|||||||
project('qbootctl', 'cpp', default_options : ['c_std=c11', 'cpp_std=c++17'])
|
project('qbootctl', 'c', default_options : ['c_std=c11'])
|
||||||
|
|
||||||
cc = meson.get_compiler('cpp')
|
cc = meson.get_compiler('c')
|
||||||
|
|
||||||
deps = [
|
deps = [
|
||||||
dependency('zlib'),
|
dependency('zlib'),
|
||||||
@ -11,11 +11,11 @@ if not cc.has_header('linux/bsg.h')
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
src = [
|
src = [
|
||||||
'qbootctl.cpp',
|
'qbootctl.c',
|
||||||
'bootctrl_impl.cpp',
|
'bootctrl_impl.c',
|
||||||
'bootctrl_test.cpp',
|
'bootctrl_test.c',
|
||||||
'gpt-utils.cpp',
|
'gpt-utils.c',
|
||||||
'ufs-bsg.cpp',
|
'ufs-bsg.c',
|
||||||
]
|
]
|
||||||
|
|
||||||
inc = [
|
inc = [
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "bootctrl.h"
|
#include "bootctrl.h"
|
@ -81,16 +81,16 @@ static int ufs_bsg_ioctl(int fd, struct ufs_bsg_request *req,
|
|||||||
enum bsg_ioctl_dir dir)
|
enum bsg_ioctl_dir dir)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct sg_io_v4 sg_io {
|
struct sg_io_v4 sg_io = {
|
||||||
|
.guard = 'Q',
|
||||||
|
.protocol = BSG_PROTOCOL_SCSI,
|
||||||
|
.subprotocol = BSG_SUB_PROTOCOL_SCSI_TRANSPORT,
|
||||||
|
.request_len = sizeof(*req),
|
||||||
|
.request = (__u64)req,
|
||||||
|
.response = (__u64)rsp,
|
||||||
|
.max_response_len = sizeof(*rsp),
|
||||||
};
|
};
|
||||||
|
|
||||||
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) {
|
if (dir == BSG_IOCTL_DIR_FROM_DEV) {
|
||||||
sg_io.din_xfer_len = buf_len;
|
sg_io.din_xfer_len = buf_len;
|
||||||
sg_io.din_xferp = (__u64)(buf);
|
sg_io.din_xferp = (__u64)(buf);
|
||||||
@ -137,10 +137,8 @@ static void compose_ufs_bsg_query_req(struct ufs_bsg_request *req, __u8 func,
|
|||||||
static int ufs_query_attr(int fd, __u32 value, __u8 func, __u8 opcode, __u8 idn,
|
static int ufs_query_attr(int fd, __u32 value, __u8 func, __u8 opcode, __u8 idn,
|
||||||
__u8 index, __u8 sel)
|
__u8 index, __u8 sel)
|
||||||
{
|
{
|
||||||
struct ufs_bsg_request req {
|
struct ufs_bsg_request req = { 0 };
|
||||||
};
|
struct ufs_bsg_reply rsp = { 0 };
|
||||||
struct ufs_bsg_reply rsp {
|
|
||||||
};
|
|
||||||
enum bsg_ioctl_dir dir = BSG_IOCTL_DIR_FROM_DEV;
|
enum bsg_ioctl_dir dir = BSG_IOCTL_DIR_FROM_DEV;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user