5 Commits
0.1.0 ... 0.1.2

Author SHA1 Message Date
Caleb Connolly
77b48f092a Merge branch 'emmc' into 'main'
Support eMMC-backed A/B

See merge request sdm845-mainline/qbootctl!1
2022-09-21 16:25:40 +00:00
Richard Acayan
17ee1b8e65 detect and handle emmc-backed xbl partitions when switching slots 2022-08-31 17:49:18 -04:00
Richard Acayan
c1f24adfb6 properly remove the partition number and separator 2022-08-31 17:10:31 -04:00
Caleb Connolly
50ef0328af minor cleanups, improve error handling
gracefully handle UFS_BSG not being enabled in the kernel, rather than
putting the device into a semi-bricked state (oops).
2022-06-10 19:18:13 +01:00
Caleb Connolly
487a96f663 gpt-utils: drop unused function
it also called strlcpy which only exists on musl and bionic, dropping it
lets this build on glibc too.
2022-06-05 22:30:34 +01:00
6 changed files with 65 additions and 92 deletions

View File

@@ -39,3 +39,8 @@ qbootctl [-c|-m|-s|-u|-b|-n|-x] [SLOT]
## Debugging
Set `DEBUG` to 1 in `utils.h` to enable debug logging.
## Documentation
A more details explanation and a list of devices where qbootctl has been
validated can be found [on the postmarketOS wiki](https://wiki.postmarketos.org/wiki/Android_AB_Slots):

View File

@@ -33,6 +33,7 @@
#include "utils.h"
#include "gpt-utils.h"
#include "ufs-bsg.h"
#include "bootctrl.h"
@@ -601,19 +602,26 @@ int set_active_boot_slot(unsigned slot)
uint32_t i;
int rc = -1;
map<string, vector<string> >::iterator map_iter;
bool ismmc;
if (boot_control_check_slot_sanity(slot)) {
fprintf(stderr, "%s: Bad arguments\n", __func__);
goto error;
}
ismmc = gpt_utils_is_partition_backed_by_emmc(PTN_XBL AB_SLOT_A_SUFFIX);
if (!ismmc && ufs_bsg_dev_open() < 0) {
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 is handled differrently for ufs devices so ignore it
if (!strncmp(ptn_list[i], PTN_XBL, strlen(PTN_XBL)))
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];
@@ -645,6 +653,10 @@ int set_active_boot_slot(unsigned slot)
}
}
// EMMC doesn't need attributes to be set.
if (ismmc)
return 0;
if (!strncmp(slot_suffix_arr[slot], AB_SLOT_A_SUFFIX,
strlen(AB_SLOT_A_SUFFIX))) {
//Set xbl_a as the boot lun

View File

@@ -300,8 +300,6 @@ int gpt_utils_set_xbl_boot_partition(enum boot_chain chain)
LOGD("%s: setting %s lun as boot lun\n", __func__, boot_dev);
if (set_boot_lun(boot_lun_id)) {
fprintf(stderr, "%s: Failed to set xblbak as boot partition\n",
__func__);
goto error;
}
return 0;
@@ -309,47 +307,6 @@ error:
return -1;
}
int add_lun_to_update_list(char *lun_path, struct update_data *dat)
{
uint32_t i = 0;
struct stat st;
if (!lun_path || !dat) {
fprintf(stderr, "%s: Invalid data\n", __func__);
return -1;
}
if (stat(lun_path, &st)) {
fprintf(stderr,
"%s: Unable to access %s. Skipping adding to list\n",
__func__, lun_path);
return -1;
}
if (dat->num_valid_entries == 0) {
fprintf(stderr, "%s: Copying %s into lun_list[%d]\n", __func__,
lun_path, i);
strlcpy(dat->lun_list[0], lun_path, PATH_MAX * sizeof(char));
dat->num_valid_entries = 1;
} else {
for (i = 0; (i < dat->num_valid_entries) &&
(dat->num_valid_entries < MAX_LUNS - 1);
i++) {
//Check if the current LUN is not already part
//of the lun list
if (!strncmp(lun_path, dat->lun_list[i],
strlen(dat->lun_list[i]))) {
//LUN already in list..Return
return 0;
}
}
fprintf(stderr, "%s: Copying %s into lun_list[%d]\n", __func__,
lun_path, dat->num_valid_entries);
//Add LUN path lun list
strlcpy(dat->lun_list[dat->num_valid_entries], lun_path,
PATH_MAX * sizeof(char));
dat->num_valid_entries++;
}
return 0;
}
//Given a parttion name(eg: rpm) get the path to the block device that
//represents the GPT disk the partition resides on. In the case of emmc it
//would be the default emmc dev(/dev/mmcblk0). In the case of UFS we look
@@ -360,6 +317,7 @@ static int get_dev_path_from_partition_name(const char *partname, char *buf,
{
struct stat st;
char path[PATH_MAX] = { 0 };
int i;
(void)st;
@@ -377,7 +335,14 @@ static int get_dev_path_from_partition_name(const char *partname, char *buf,
if (!buf) {
return -1;
} else {
buf[PATH_TRUNCATE_LOC] = '\0';
for (i = strlen(buf); i > 0; i--)
if (!isdigit(buf[i - 1]))
break;
if (i >= 2 && buf[i - 1] == 'p' && isdigit(buf[i - 2]))
i--;
buf[i] = 0;
}
return 0;
}
@@ -816,3 +781,18 @@ error:
close(fd);
return -1;
}
//Determine whether to handle the given partition as eMMC or UFS, using the
//name of the backing device.
//
//Note: In undefined cases (i.e. /dev/mmcblk1 and unresolvable), this function
//will tend to prefer UFS behavior. If it incorrectly reports this, then the
//program should exit (e.g. by failing) before making any changes.
bool gpt_utils_is_partition_backed_by_emmc(const char *part) {
char devpath[PATH_MAX] = { '\0' };
if (get_dev_path_from_partition_name(part, devpath, sizeof(devpath)))
return false;
return !strcmp(devpath, EMMC_DEVICE);
}

View File

@@ -84,6 +84,8 @@ extern "C" {
"product"
#define BOOT_DEV_DIR "/dev/disk/by-partlabel"
#define EMMC_DEVICE "/dev/mmcblk0"
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
enum gpt_instance { PRIMARY_GPT = 0, SECONDARY_GPT };
@@ -163,6 +165,8 @@ int gpt_utils_set_xbl_boot_partition(enum boot_chain chain);
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);
#ifdef __cplusplus
}
#endif

View File

@@ -45,52 +45,30 @@
#include "utils.h"
#include "ufs-bsg.h"
// FIXME: replace this with something that actually works
// static int get_ufs_bsg_dev(void)
// {
// DIR *dir;
// struct dirent *ent;
// int ret = -ENODEV;
/* UFS BSG device node */
static char ufs_bsg_dev[FNAME_SZ] = "/dev/bsg/ufs-bsg0";
// if ((dir = opendir ("/dev")) != NULL) {
// /* read all the files and directories within directory */
// while ((ent = readdir(dir)) != NULL) {
// if (!strcmp(ent->d_name, "bsg") ||
// !strcmp(ent->d_name, "ufs-bsg0")) {
// snprintf(ufs_bsg_dev, FNAME_SZ, "/dev/%s", ent->d_name);
// ret = 0;
// break;
// }
// }
// if (ret)
// fprintf(stderr, "could not find the ufs-bsg dev\n");
// closedir (dir);
// } else {
// /* could not open directory */
// fprintf(stderr, "could not open /dev (error no: %d)\n", errno);
// ret = -EINVAL;
// }
static int fd_ufs_bsg = 0;
// return ret;
// }
int ufs_bsg_dev_open(void)
int ufs_bsg_dev_open()
{
int ret;
if (!fd_ufs_bsg) {
fd_ufs_bsg = open(ufs_bsg_dev, O_RDWR);
ret = errno;
if (fd_ufs_bsg < 0) {
fprintf(stderr, "Unable to open %s (error no: %d)",
ufs_bsg_dev, errno);
fd_ufs_bsg = 0;
return ret;
}
if (fd_ufs_bsg)
return 0;
fd_ufs_bsg = open(ufs_bsg_dev, O_RDWR);
if (fd_ufs_bsg < 0) {
fprintf(stderr, "Unable to open '%s': %s\n", ufs_bsg_dev,
strerror(errno));
fprintf(stderr,
"Is CONFIG_SCSI_UFS_BSG is enabled in your kernel?\n");
fd_ufs_bsg = 0;
return -1;
}
return 0;
}
void ufs_bsg_dev_close(void)
void ufs_bsg_dev_close()
{
if (fd_ufs_bsg) {
close(fd_ufs_bsg);
@@ -188,9 +166,6 @@ int32_t set_boot_lun(__u8 lun_id)
int32_t ret;
__u32 boot_lun_id = lun_id;
// ret = get_ufs_bsg_dev();
// if (ret)
// return ret;
LOGD("Using UFS bsg device: %s\n", ufs_bsg_dev);
ret = ufs_bsg_dev_open();

View File

@@ -36,11 +36,6 @@
#define DWORD(b3, b2, b1, b0) htobe32((b3 << 24) | (b2 << 16) | (b1 << 8) | b0)
/* UFS BSG device node */
char ufs_bsg_dev[FNAME_SZ] = "/dev/bsg/ufs-bsg0";
int fd_ufs_bsg;
/* UPIU Transaction Codes */
enum {
UTP_UPIU_NOP_OUT = 0x00,
@@ -91,4 +86,6 @@ enum query_attr_idn {
QUERY_ATTR_IDN_ACTIVE_ICC_LVL = 0x03,
};
int ufs_bsg_dev_open();
#endif /* __RECOVERY_UFS_BSG_H__ */