mirror of
https://github.com/linux-msm/qbootctl.git
synced 2026-02-25 13:13:44 -08:00
its ALIIIIIIVE
not yet properly tested, but it seems to mostly work just fine. Slot switching and marking boot as successful at least just work!
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
.vscode/
|
||||
.push.settings.jsonc
|
||||
build/
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "boot_control.h"
|
||||
#include "BootControl.h"
|
||||
|
||||
BootControl::BootControl(boot_control_module *module) : mModule(module) {
|
||||
}
|
||||
|
||||
// Methods from ::android::hardware::boot::V1_0::IBootControl follow.
|
||||
unsigned int BootControl::getNumberSlots() {
|
||||
return mModule->getNumberSlots(mModule);
|
||||
}
|
||||
|
||||
unsigned int BootControl::getCurrentSlot() {
|
||||
return mModule->getCurrentSlot(mModule);
|
||||
}
|
||||
|
||||
int BootControl::markBootSuccessful() {
|
||||
int ret = mModule->markBootSuccessful(mModule);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int BootControl::setActiveBootSlot(unsigned int slot) {
|
||||
int ret = mModule->setActiveBootSlot(mModule, slot);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int BootControl::setSlotAsUnbootable(unsigned int slot) {
|
||||
int ret = mModule->setSlotAsUnbootable(mModule, slot);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BoolResult BootControl::isSlotBootable(unsigned int slot) {
|
||||
int32_t ret = mModule->isSlotBootable(mModule, slot);
|
||||
if (ret < 0) {
|
||||
return BoolResult::INVALID_SLOT;
|
||||
}
|
||||
return ret ? BoolResult::TRUE : BoolResult::FALSE;
|
||||
}
|
||||
|
||||
BoolResult BootControl::isSlotMarkedSuccessful(unsigned int slot) {
|
||||
int32_t ret = mModule->isSlotMarkedSuccessful(mModule, slot);
|
||||
if (ret < 0) {
|
||||
return BoolResult::INVALID_SLOT;
|
||||
}
|
||||
return ret ? BoolResult::TRUE : BoolResult::FALSE;
|
||||
}
|
||||
|
||||
std::string BootControl::getSuffix(unsigned int slot) {
|
||||
std::string ans;
|
||||
const char *suffix = mModule->getSuffix(mModule, slot);
|
||||
if (suffix) {
|
||||
ans = std::string(suffix);
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
BootControl* BootControlInit() {
|
||||
boot_control_module* module;
|
||||
|
||||
// For devices that don't build a standalone libhardware bootctrl impl for recovery,
|
||||
// we simulate the hw_get_module() by accessing it from the current process directly.
|
||||
const boot_control_module* hw_module = &HAL_MODULE_INFO_SYM;
|
||||
module = reinterpret_cast<boot_control_module*>(const_cast<boot_control_module*>(hw_module));
|
||||
module->init(module);
|
||||
return new BootControl(module);
|
||||
}
|
||||
|
||||
int main (int argc, char * argv []) {
|
||||
BootControl *bootctl = BootControlInit();
|
||||
printf("======= Current slot: %d\n", bootctl->getCurrentSlot());
|
||||
printf("======= isslotbootable: a = %d, b = %d\n", bootctl->isSlotBootable(0),
|
||||
bootctl->isSlotBootable(1));
|
||||
printf("======= markBootSuccessful\n", bootctl->markBootSuccessful());
|
||||
printf("======= isSlotMarkedSuccessful: a = %d, b = %d\n", bootctl->isSlotMarkedSuccessful(0),
|
||||
bootctl->isSlotMarkedSuccessful(1));
|
||||
// printf("\n\n\n trying to switch to slot b: %d\n",
|
||||
// bootctl->setActiveBootSlot(1));
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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 ANDROID_HARDWARE_BOOT_V1_0_BOOTCONTROL_H
|
||||
#define ANDROID_HARDWARE_BOOT_V1_0_BOOTCONTROL_H
|
||||
|
||||
/**
|
||||
* A result encapsulating whether a function returned true, false or
|
||||
* failed due to an invalid slot number
|
||||
*/
|
||||
enum class BoolResult : int {
|
||||
FALSE = 0,
|
||||
TRUE = 1,
|
||||
INVALID_SLOT = -1 /* -1 */,
|
||||
};
|
||||
|
||||
struct BootControl {
|
||||
BootControl(boot_control_module* module);
|
||||
// Methods from ::android::hardware::boot::V1_0::IBootControl follow.
|
||||
unsigned int getNumberSlots();
|
||||
unsigned int getCurrentSlot();
|
||||
int markBootSuccessful();
|
||||
int setActiveBootSlot(unsigned int slot);
|
||||
int setSlotAsUnbootable(unsigned int slot);
|
||||
BoolResult isSlotBootable(unsigned int slot);
|
||||
BoolResult isSlotMarkedSuccessful(unsigned int slot);
|
||||
std::string getSuffix(unsigned int slot);
|
||||
private:
|
||||
boot_control_module* mModule;
|
||||
};
|
||||
|
||||
|
||||
#endif // ANDROID_HARDWARE_BOOT_V1_0_BOOTCONTROL_H
|
||||
@@ -1,15 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
# set the project name
|
||||
project(qbootctl)
|
||||
|
||||
set(BootCtrl_Files BootControl.cpp
|
||||
boot_control_impl_qcom.cpp
|
||||
gpt-utils.cpp)
|
||||
|
||||
include_directories(include)
|
||||
|
||||
# add the executable
|
||||
add_executable(qbootctl ${BootCtrl_Files})
|
||||
|
||||
target_link_libraries(qbootctl libz.so)
|
||||
28
README.md
28
README.md
@@ -1,7 +1,29 @@
|
||||
Qualcomm bootctl HAL for Linux
|
||||
# Qualcomm bootctl HAL for Linux
|
||||
|
||||
This HAL was pulled from AOSP source code and bastardised to build and run on a musl/glibc system. This may or may not render any hardware you run it on unusable, you have been warned.
|
||||
|
||||
# Dependencies
|
||||
## Dependencies
|
||||
|
||||
* zlib-dev
|
||||
* zlib-dev
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
qbootctl: qcom bootctrl HAL port for Linux
|
||||
-------------------------------------------
|
||||
qbootctl [-c|-m|-s|-u|-b|-n|-x] [SLOT]
|
||||
|
||||
<no args> dump slot info (default)
|
||||
-h this help text
|
||||
-c get the current slot
|
||||
-b SLOT check if SLOT is marked as bootable
|
||||
-n SLOT check if SLOT is marked as successful
|
||||
-x [SLOT] get the slot suffix for SLOT (default: current)
|
||||
-s SLOT set to active slot to SLOT
|
||||
-m [SLOT] mark a boot as successful (default: current)
|
||||
-u [SLOT] mark SLOT as unbootable (default: current)
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
Set `DEBUG` to 1 in `utils.h` to enable debug logging.
|
||||
|
||||
136
boot_control.h
136
boot_control.h
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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 ANDROID_INCLUDE_HARDWARE_BOOT_CONTROL_H
|
||||
#define ANDROID_INCLUDE_HARDWARE_BOOT_CONTROL_H
|
||||
|
||||
#define BOOT_CONTROL_MODULE_API_VERSION_0_1 HARDWARE_MODULE_API_VERSION(0, 1)
|
||||
|
||||
/**
|
||||
* The id of this module
|
||||
*/
|
||||
#define BOOT_CONTROL_HARDWARE_MODULE_ID "bootctrl"
|
||||
|
||||
/*
|
||||
* The Boot Control HAL is designed to allow for managing sets of redundant
|
||||
* partitions, called slots, that can be booted from independantly. Slots
|
||||
* are sets of partitions whose names differ only by a given suffix.
|
||||
* They are identified here by a 0 indexed number, and associated with their
|
||||
* suffix, which can be appended to the base name for any particular partition
|
||||
* to find the one associated with that slot. The bootloader must pass the suffix
|
||||
* of the currently active slot either through a kernel command line property at
|
||||
* androidboot.slot_suffix, or the device tree at /firmware/android/slot_suffix.
|
||||
* The primary use of this set up is to allow for background updates while the
|
||||
* device is running, and to provide a fallback in the event that the update fails.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
|
||||
* and the fields of this data structure must begin with hw_module_t
|
||||
* followed by module specific information.
|
||||
*/
|
||||
struct boot_control_module {
|
||||
|
||||
/*
|
||||
* (*init)() perform any initialization tasks needed for the HAL.
|
||||
* This is called only once.
|
||||
*/
|
||||
void (*init)(struct boot_control_module *module);
|
||||
|
||||
/*
|
||||
* (*getNumberSlots)() returns the number of available slots.
|
||||
* For instance, a system with a single set of partitions would return
|
||||
* 1, a system with A/B would return 2, A/B/C -> 3...
|
||||
*/
|
||||
unsigned (*getNumberSlots)(struct boot_control_module *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)(struct boot_control_module *module);
|
||||
|
||||
/*
|
||||
* (*markBootSuccessful)() marks the current slot
|
||||
* as having booted successfully
|
||||
*
|
||||
* Returns 0 on success, -errno on error.
|
||||
*/
|
||||
int (*markBootSuccessful)(struct boot_control_module *module);
|
||||
|
||||
/*
|
||||
* (*setActiveBootSlot)() marks the slot passed in parameter as
|
||||
* the active boot slot (see getCurrentSlot for an explanation
|
||||
* of the "slot" parameter). This overrides any previous call to
|
||||
* setSlotAsUnbootable.
|
||||
* Returns 0 on success, -errno on error.
|
||||
*/
|
||||
int (*setActiveBootSlot)(struct boot_control_module *module, unsigned slot);
|
||||
|
||||
/*
|
||||
* (*setSlotAsUnbootable)() marks the slot passed in parameter as
|
||||
* an unbootable. This can be used while updating the contents of the slot's
|
||||
* partitions, so that the system will not attempt to boot a known bad set up.
|
||||
* Returns 0 on success, -errno on error.
|
||||
*/
|
||||
int (*setSlotAsUnbootable)(struct boot_control_module *module, unsigned slot);
|
||||
|
||||
/*
|
||||
* (*isSlotBootable)() returns if the slot passed in parameter is
|
||||
* bootable. Note that slots can be made unbootable by both the
|
||||
* bootloader and by the OS using setSlotAsUnbootable.
|
||||
* Returns 1 if the slot is bootable, 0 if it's not, and -errno on
|
||||
* error.
|
||||
*/
|
||||
int (*isSlotBootable)(struct boot_control_module *module, unsigned slot);
|
||||
|
||||
/*
|
||||
* (*getSuffix)() returns the string suffix used by partitions that
|
||||
* correspond to the slot number passed in parameter. The returned string
|
||||
* is expected to be statically allocated and not need to be freed.
|
||||
* Returns NULL if slot does not match an existing slot.
|
||||
*/
|
||||
const char* (*getSuffix)(struct boot_control_module *module, unsigned slot);
|
||||
|
||||
/*
|
||||
* (*isSlotMarkedSucessful)() returns if the slot passed in parameter has
|
||||
* been marked as successful using markBootSuccessful.
|
||||
* Returns 1 if the slot has been marked as successful, 0 if it's
|
||||
* not the case, and -errno on error.
|
||||
*/
|
||||
int (*isSlotMarkedSuccessful)(struct boot_control_module *module, 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)(struct boot_control_module *module);
|
||||
|
||||
void* reserved[30];
|
||||
};
|
||||
|
||||
extern const struct boot_control_module HAL_MODULE_INFO_SYM;
|
||||
|
||||
|
||||
#endif // ANDROID_INCLUDE_HARDWARE_BOOT_CONTROL_H
|
||||
202
gpt-utils.cpp
202
gpt-utils.cpp
@@ -38,8 +38,6 @@
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <scsi/ufs/ioctl.h>
|
||||
#include <scsi/ufs/ufs.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/fs.h>
|
||||
#include <limits.h>
|
||||
@@ -53,6 +51,7 @@
|
||||
#include <endian.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "gpt-utils.h"
|
||||
|
||||
|
||||
@@ -373,7 +372,7 @@ static int gpt2_set_boot_chain(int fd, enum boot_chain boot)
|
||||
if (r)
|
||||
goto EXIT;
|
||||
|
||||
crc = 0; // crc32(0, pentries, pentries_array_size);
|
||||
crc = crc32(0, pentries, pentries_array_size);
|
||||
if (GET_4_BYTES(gpt_header + PARTITION_CRC_OFFSET) != crc) {
|
||||
fprintf(stderr, "Primary GPT partition entries array CRC invalid\n");
|
||||
r = -1;
|
||||
@@ -396,12 +395,12 @@ static int gpt2_set_boot_chain(int fd, enum boot_chain boot)
|
||||
goto EXIT;
|
||||
}
|
||||
|
||||
crc = 0; // crc32(0, pentries, pentries_array_size);
|
||||
crc = crc32(0, pentries, pentries_array_size);
|
||||
PUT_4_BYTES(gpt_header + PARTITION_CRC_OFFSET, crc);
|
||||
|
||||
/* header CRC is calculated with this field cleared */
|
||||
PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, 0);
|
||||
crc = 0; // crc32(0, gpt_header, gpt_header_size);
|
||||
crc = crc32(0, gpt_header, gpt_header_size);
|
||||
PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, crc);
|
||||
|
||||
/* Write the modified GPT header back to block dev */
|
||||
@@ -542,7 +541,7 @@ static int gpt_set_state(int fd, enum gpt_instance gpt, enum gpt_state state)
|
||||
|
||||
/* header CRC is calculated with this field cleared */
|
||||
PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, 0);
|
||||
crc = 0; // crc32(0, gpt_header, gpt_header_size);
|
||||
crc = crc32(0, gpt_header, gpt_header_size);
|
||||
PUT_4_BYTES(gpt_header + HEADER_CRC_OFFSET, crc);
|
||||
|
||||
if (blk_rw(fd, 1, gpt_header_offset, gpt_header, blk_size)) {
|
||||
@@ -556,127 +555,9 @@ error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int get_scsi_node_from_bootdevice(const char *bootdev_path,
|
||||
char *sg_node_path,
|
||||
size_t buf_size)
|
||||
{
|
||||
char sg_dir_path[PATH_MAX] = {0};
|
||||
char real_path[PATH_MAX] = {0};
|
||||
DIR *scsi_dir = NULL;
|
||||
struct dirent *de;
|
||||
int node_found = 0;
|
||||
if (!bootdev_path || !sg_node_path) {
|
||||
fprintf(stderr, "%s : invalid argument\n",
|
||||
__func__);
|
||||
goto error;
|
||||
}
|
||||
if (realpath(bootdev_path, real_path) < 0) {
|
||||
fprintf(stderr, "failed to resolve link for %s(%s)\n",
|
||||
bootdev_path,
|
||||
strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
if(strlen(real_path) < PATH_TRUNCATE_LOC + 1){
|
||||
fprintf(stderr, "Unrecognized path :%s:\n",
|
||||
real_path);
|
||||
goto error;
|
||||
}
|
||||
//For the safe side in case there are additional partitions on
|
||||
//the XBL lun we truncate the name.
|
||||
real_path[PATH_TRUNCATE_LOC] = '\0';
|
||||
if(strlen(real_path) < LUN_NAME_START_LOC + 1){
|
||||
fprintf(stderr, "Unrecognized truncated path :%s:\n",
|
||||
real_path);
|
||||
goto error;
|
||||
}
|
||||
// snprintf(sg_node_path, PATH_MAX, "%s", real_path);
|
||||
// return 0;
|
||||
//This will give us /dev/disk/sdb/device/scsi_generic
|
||||
//which contains a file sgY whose name gives us the path
|
||||
//to /dev/sgY which we return
|
||||
snprintf(sg_dir_path, sizeof(sg_dir_path) - 1,
|
||||
"/sys/block/%s/device/scsi_generic",
|
||||
&real_path[LUN_NAME_START_LOC]);
|
||||
scsi_dir = opendir(sg_dir_path);
|
||||
if (!scsi_dir) {
|
||||
fprintf(stderr, "%s : Failed to open %s(%s)\n",
|
||||
__func__,
|
||||
sg_dir_path,
|
||||
strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
while((de = readdir(scsi_dir))) {
|
||||
if (de->d_name[0] == '.')
|
||||
continue;
|
||||
else if (!strncmp(de->d_name, "sg\n", 2)) {
|
||||
snprintf(sg_node_path,
|
||||
buf_size -1,
|
||||
"/dev/%s",
|
||||
de->d_name);
|
||||
fprintf(stderr, "%s:scsi generic node is :%s:\n",
|
||||
__func__,
|
||||
sg_node_path);
|
||||
node_found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!node_found) {
|
||||
fprintf(stderr,"%s: Unable to locate scsi generic node\n",
|
||||
__func__);
|
||||
goto error;
|
||||
}
|
||||
closedir(scsi_dir);
|
||||
return 0;
|
||||
error:
|
||||
if (scsi_dir)
|
||||
closedir(scsi_dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int set_boot_lun(char *sg_dev, uint8_t boot_lun_id)
|
||||
{
|
||||
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;
|
||||
}
|
||||
printf("%s(): sg_dev = %s\n", __func__, sg_dev);
|
||||
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;
|
||||
}
|
||||
// Defined in ufs-bsg.cpp
|
||||
int32_t set_boot_lun(uint8_t lun_id);
|
||||
|
||||
//Swtich betwieen using either the primary or the backup
|
||||
//boot LUN for boot. This is required since UFS boot partitions
|
||||
@@ -698,11 +579,12 @@ error:
|
||||
int gpt_utils_set_xbl_boot_partition(enum boot_chain chain)
|
||||
{
|
||||
struct stat st;
|
||||
///sys/block/sdX/device/scsi_generic/
|
||||
char sg_dev_node[PATH_MAX] = {0};
|
||||
uint8_t boot_lun_id = 0;
|
||||
const char *boot_dev = NULL;
|
||||
|
||||
(void)st;
|
||||
(void)boot_dev;
|
||||
|
||||
if (chain == BACKUP_BOOT) {
|
||||
boot_lun_id = BOOT_LUN_B_ID;
|
||||
if (!stat(XBL_BACKUP, &st))
|
||||
@@ -740,17 +622,10 @@ int gpt_utils_set_xbl_boot_partition(enum boot_chain chain)
|
||||
strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
fprintf(stderr, "%s: setting %s lun as boot lun\n",
|
||||
__func__,
|
||||
LOGD("%s: setting %s lun as boot lun\n", __func__,
|
||||
boot_dev);
|
||||
if (get_scsi_node_from_bootdevice(boot_dev,
|
||||
sg_dev_node,
|
||||
sizeof(sg_dev_node))) {
|
||||
fprintf(stderr, "%s: Failed to get scsi node path for xblbak\n",
|
||||
__func__);
|
||||
goto error;
|
||||
}
|
||||
if (set_boot_lun(sg_dev_node, boot_lun_id)) {
|
||||
|
||||
if (set_boot_lun(boot_lun_id)) {
|
||||
fprintf(stderr, "%s: Failed to set xblbak as boot partition\n",
|
||||
__func__);
|
||||
goto error;
|
||||
@@ -1050,7 +925,7 @@ int prepare_boot_update(enum boot_update_stage stage)
|
||||
if (stat(buf, &ufs_dir_stat)) {
|
||||
continue;
|
||||
}
|
||||
if (realpath(buf, real_path) < 0)
|
||||
if (!realpath(buf, real_path))
|
||||
{
|
||||
fprintf(stderr, "%s: realpath error. Skipping %s\n",
|
||||
__func__,
|
||||
@@ -1097,11 +972,13 @@ static int get_dev_path_from_partition_name(const char *partname,
|
||||
size_t buflen)
|
||||
{
|
||||
struct stat st;
|
||||
int rc;
|
||||
char path[PATH_MAX] = {0};
|
||||
|
||||
(void)st;
|
||||
|
||||
if (!partname || !buf || buflen < ((PATH_TRUNCATE_LOC) + 1)) {
|
||||
fprintf(stderr, "%s: Invalid argument\n", __func__);
|
||||
goto error;
|
||||
return -1;
|
||||
}
|
||||
if (gpt_utils_is_ufs_device()) {
|
||||
//Need to find the lun that holds partition partname
|
||||
@@ -1110,25 +987,20 @@ static int get_dev_path_from_partition_name(const char *partname,
|
||||
BOOT_DEV_DIR,
|
||||
partname);
|
||||
// if (rc = stat(path, &st)) {
|
||||
// printf("stat failed: errno=%d\n", errno);
|
||||
// LOGD("stat failed: errno=%d\n", errno);
|
||||
// goto error;
|
||||
// }
|
||||
buf = realpath(path, buf);
|
||||
if (!buf)
|
||||
{
|
||||
printf("realpath failed\n");
|
||||
goto error;
|
||||
return -1;
|
||||
} else {
|
||||
buf[PATH_TRUNCATE_LOC] = '\0';
|
||||
}
|
||||
printf("PATH: %s, realpath: %s\n", path, buf);
|
||||
} else {
|
||||
snprintf(buf, buflen, "/dev/mmcblk0");
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int gpt_utils_get_partition_map(vector<string>& ptn_list,
|
||||
@@ -1199,7 +1071,7 @@ static int gpt_set_header(uint8_t *gpt_header, int fd,
|
||||
goto error;
|
||||
}
|
||||
block_size = gpt_get_block_size(fd);
|
||||
printf("%s: Block size is : %d\n", __func__, block_size);
|
||||
LOGD("%s: Block size is : %d\n", __func__, block_size);
|
||||
if (block_size == 0) {
|
||||
fprintf(stderr, "%s: Failed to get block size\n", __func__);
|
||||
goto error;
|
||||
@@ -1212,7 +1084,7 @@ static int gpt_set_header(uint8_t *gpt_header, int fd,
|
||||
fprintf(stderr, "%s: Failed to get gpt header offset\n",__func__);
|
||||
goto error;
|
||||
}
|
||||
printf("%s: Writing back header to offset %ld\n", __func__,
|
||||
LOGD("%s: Writing back header to offset %ld\n", __func__,
|
||||
gpt_header_offset);
|
||||
if (blk_rw(fd, 1, gpt_header_offset, gpt_header, block_size)) {
|
||||
fprintf(stderr, "%s: Failed to write back GPT header\n", __func__);
|
||||
@@ -1359,16 +1231,16 @@ static int gpt_set_pentry_arr(uint8_t *hdr, int fd, uint8_t* arr)
|
||||
__func__);
|
||||
goto error;
|
||||
}
|
||||
printf("%s : Block size is %d\n", __func__, block_size);
|
||||
LOGD("%s : Block size is %d\n", __func__, block_size);
|
||||
pentries_start = GET_8_BYTES(hdr + PENTRIES_OFFSET) * block_size;
|
||||
pentry_size = GET_4_BYTES(hdr + PENTRY_SIZE_OFFSET);
|
||||
pentries_arr_size =
|
||||
GET_4_BYTES(hdr + PARTITION_COUNT_OFFSET) * pentry_size;
|
||||
printf("%s: Writing partition entry array of size %d to offset %" PRIu64 "\n",
|
||||
LOGD("%s: Writing partition entry array of size %d to offset %" PRIu64 "\n",
|
||||
__func__,
|
||||
pentries_arr_size,
|
||||
pentries_start);
|
||||
printf("pentries_start: %lu\n", pentries_start);
|
||||
LOGD("pentries_start: %lu\n", pentries_start);
|
||||
rc = blk_rw(fd, 1,
|
||||
pentries_start,
|
||||
arr,
|
||||
@@ -1436,13 +1308,13 @@ int gpt_disk_get_disk_info(const char *dev, struct gpt_disk *dsk)
|
||||
}
|
||||
gpt_header_size = GET_4_BYTES(disk->hdr + HEADER_SIZE_OFFSET);
|
||||
// FIXME: pointer offsets crc bleh
|
||||
disk->hdr_crc = 0; //crc32(0, disk->hdr, gpt_header_size);
|
||||
disk->hdr_crc = crc32(0, disk->hdr, gpt_header_size);
|
||||
disk->hdr_bak = gpt_get_header(dev, PRIMARY_GPT);
|
||||
if (!disk->hdr_bak) {
|
||||
fprintf(stderr, "%s: Failed to get backup header\n", __func__);
|
||||
goto error;
|
||||
}
|
||||
disk->hdr_bak_crc = 0; //crc32(0, disk->hdr_bak, gpt_header_size);
|
||||
disk->hdr_bak_crc = crc32(0, disk->hdr_bak, gpt_header_size);
|
||||
|
||||
//Descriptor for the block device. We will use this for further
|
||||
//modifications to the partition table
|
||||
@@ -1522,13 +1394,13 @@ int gpt_disk_update_crc(struct gpt_disk *disk)
|
||||
goto error;
|
||||
}
|
||||
//Recalculate the CRC of the primary partiton array
|
||||
disk->pentry_arr_crc = 0; // crc32(0,
|
||||
//disk->pentry_arr,
|
||||
//disk->pentry_arr_size);
|
||||
disk->pentry_arr_crc = crc32(0,
|
||||
disk->pentry_arr,
|
||||
disk->pentry_arr_size);
|
||||
//Recalculate the CRC of the backup partition array
|
||||
disk->pentry_arr_bak_crc = 0; // crc32(0,
|
||||
//disk->pentry_arr_bak,
|
||||
//disk->pentry_arr_size);
|
||||
disk->pentry_arr_bak_crc = crc32(0,
|
||||
disk->pentry_arr_bak,
|
||||
disk->pentry_arr_size);
|
||||
//Update the partition CRC value in the primary GPT header
|
||||
PUT_4_BYTES(disk->hdr + PARTITION_CRC_OFFSET, disk->pentry_arr_crc);
|
||||
//Update the partition CRC value in the backup GPT header
|
||||
@@ -1539,8 +1411,8 @@ int gpt_disk_update_crc(struct gpt_disk *disk)
|
||||
//Header CRC is calculated with its own CRC field set to 0
|
||||
PUT_4_BYTES(disk->hdr + HEADER_CRC_OFFSET, 0);
|
||||
PUT_4_BYTES(disk->hdr_bak + HEADER_CRC_OFFSET, 0);
|
||||
disk->hdr_crc = 0; // crc32(0, disk->hdr, gpt_header_size);
|
||||
disk->hdr_bak_crc = 0; // crc32(0, disk->hdr_bak, gpt_header_size);
|
||||
disk->hdr_crc = crc32(0, disk->hdr, gpt_header_size);
|
||||
disk->hdr_bak_crc = crc32(0, disk->hdr_bak, gpt_header_size);
|
||||
PUT_4_BYTES(disk->hdr + HEADER_CRC_OFFSET, disk->hdr_crc);
|
||||
PUT_4_BYTES(disk->hdr_bak + HEADER_CRC_OFFSET, disk->hdr_bak_crc);
|
||||
return 0;
|
||||
@@ -1564,14 +1436,14 @@ int gpt_disk_commit(struct gpt_disk *disk)
|
||||
strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
printf("%s: Writing back primary GPT header\n", __func__);
|
||||
LOGD("%s: Writing back primary GPT header\n", __func__);
|
||||
//Write the primary header
|
||||
if(gpt_set_header(disk->hdr, fd, PRIMARY_GPT) != 0) {
|
||||
fprintf(stderr, "%s: Failed to update primary GPT header\n",
|
||||
__func__);
|
||||
goto error;
|
||||
}
|
||||
printf("%s: Writing back primary partition array\n", __func__);
|
||||
LOGD("%s: Writing back primary partition array\n", __func__);
|
||||
//Write back the primary partition array
|
||||
if (gpt_set_pentry_arr(disk->hdr, fd, disk->pentry_arr)) {
|
||||
fprintf(stderr, "%s: Failed to write primary GPT partition arr\n",
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/****************************************************************************
|
||||
****************************************************************************
|
||||
***
|
||||
*** This header was automatically generated from a Linux kernel header
|
||||
*** of the same name, to make information necessary for userspace to
|
||||
*** call into the kernel available to libc. It contains only constants,
|
||||
*** structures, and macros generated from the original header, and thus,
|
||||
*** contains no copyrightable information.
|
||||
***
|
||||
*** To edit the content of this header, modify the corresponding
|
||||
*** source file (e.g. under external/kernel-headers/original/) then
|
||||
*** run bionic/libc/kernel/tools/update_all.py
|
||||
***
|
||||
*** Any manual change here will be lost the next time this script will
|
||||
*** be run. You've been warned!
|
||||
***
|
||||
****************************************************************************
|
||||
****************************************************************************/
|
||||
#ifndef UAPI_UFS_IOCTL_H_
|
||||
#define UAPI_UFS_IOCTL_H_
|
||||
#include <linux/types.h>
|
||||
#define UFS_IOCTL_QUERY 0x5388
|
||||
struct ufs_ioctl_query_data {
|
||||
__u32 opcode;
|
||||
__u8 idn;
|
||||
__u16 buf_size;
|
||||
__u8 buffer[0];
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
/****************************************************************************
|
||||
****************************************************************************
|
||||
***
|
||||
*** This header was automatically generated from a Linux kernel header
|
||||
*** of the same name, to make information necessary for userspace to
|
||||
*** call into the kernel available to libc. It contains only constants,
|
||||
*** structures, and macros generated from the original header, and thus,
|
||||
*** contains no copyrightable information.
|
||||
***
|
||||
*** To edit the content of this header, modify the corresponding
|
||||
*** source file (e.g. under external/kernel-headers/original/) then
|
||||
*** run bionic/libc/kernel/tools/update_all.py
|
||||
***
|
||||
*** Any manual change here will be lost the next time this script will
|
||||
*** be run. You've been warned!
|
||||
***
|
||||
****************************************************************************
|
||||
****************************************************************************/
|
||||
#ifndef UAPI_UFS_H_
|
||||
#define UAPI_UFS_H_
|
||||
#define MAX_QUERY_IDN 0x18
|
||||
enum flag_idn {
|
||||
QUERY_FLAG_IDN_FDEVICEINIT = 0x01,
|
||||
QUERY_FLAG_IDN_PERMANENT_WPE = 0x02,
|
||||
QUERY_FLAG_IDN_PWR_ON_WPE = 0x03,
|
||||
QUERY_FLAG_IDN_BKOPS_EN = 0x04,
|
||||
QUERY_FLAG_IDN_RESERVED1 = 0x05,
|
||||
QUERY_FLAG_IDN_PURGE_ENABLE = 0x06,
|
||||
QUERY_FLAG_IDN_RESERVED2 = 0x07,
|
||||
QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL = 0x08,
|
||||
QUERY_FLAG_IDN_BUSY_RTC = 0x09,
|
||||
QUERY_FLAG_IDN_MANUAL_GC_CONT = 0x0E,
|
||||
};
|
||||
enum 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,
|
||||
QUERY_ATTR_IDN_OOO_DATA_EN = 0x04,
|
||||
QUERY_ATTR_IDN_BKOPS_STATUS = 0x05,
|
||||
QUERY_ATTR_IDN_PURGE_STATUS = 0x06,
|
||||
QUERY_ATTR_IDN_MAX_DATA_IN = 0x07,
|
||||
QUERY_ATTR_IDN_MAX_DATA_OUT = 0x08,
|
||||
QUERY_ATTR_IDN_DYN_CAP_NEEDED = 0x09,
|
||||
QUERY_ATTR_IDN_REF_CLK_FREQ = 0x0A,
|
||||
QUERY_ATTR_IDN_CONF_DESC_LOCK = 0x0B,
|
||||
QUERY_ATTR_IDN_MAX_NUM_OF_RTT = 0x0C,
|
||||
QUERY_ATTR_IDN_EE_CONTROL = 0x0D,
|
||||
QUERY_ATTR_IDN_EE_STATUS = 0x0E,
|
||||
QUERY_ATTR_IDN_SECONDS_PASSED = 0x0F,
|
||||
QUERY_ATTR_IDN_CNTX_CONF = 0x10,
|
||||
QUERY_ATTR_IDN_CORR_PRG_BLK_NUM = 0x11,
|
||||
QUERY_ATTR_IDN_MANUAL_GC_STATUS = 0x17,
|
||||
};
|
||||
#define QUERY_ATTR_IDN_BOOT_LU_EN_MAX 0x02
|
||||
enum desc_idn {
|
||||
QUERY_DESC_IDN_DEVICE = 0x0,
|
||||
QUERY_DESC_IDN_CONFIGURAION = 0x1,
|
||||
QUERY_DESC_IDN_UNIT = 0x2,
|
||||
QUERY_DESC_IDN_RFU_0 = 0x3,
|
||||
QUERY_DESC_IDN_INTERCONNECT = 0x4,
|
||||
QUERY_DESC_IDN_STRING = 0x5,
|
||||
QUERY_DESC_IDN_RFU_1 = 0x6,
|
||||
QUERY_DESC_IDN_GEOMETRY = 0x7,
|
||||
QUERY_DESC_IDN_POWER = 0x8,
|
||||
QUERY_DESC_IDN_HEALTH = 0x9,
|
||||
QUERY_DESC_IDN_RFU_2 = 0xA,
|
||||
QUERY_DESC_IDN_MAX,
|
||||
};
|
||||
enum query_opcode {
|
||||
UPIU_QUERY_OPCODE_NOP = 0x0,
|
||||
UPIU_QUERY_OPCODE_READ_DESC = 0x1,
|
||||
UPIU_QUERY_OPCODE_WRITE_DESC = 0x2,
|
||||
UPIU_QUERY_OPCODE_READ_ATTR = 0x3,
|
||||
UPIU_QUERY_OPCODE_WRITE_ATTR = 0x4,
|
||||
UPIU_QUERY_OPCODE_READ_FLAG = 0x5,
|
||||
UPIU_QUERY_OPCODE_SET_FLAG = 0x6,
|
||||
UPIU_QUERY_OPCODE_CLEAR_FLAG = 0x7,
|
||||
UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8,
|
||||
UPIU_QUERY_OPCODE_MAX,
|
||||
};
|
||||
#define UPIU_QUERY_OPCODE_HIGH_HPB 0x5500
|
||||
#define UPIU_QUERY_OPCODE_HIGH(opcode) ((opcode) >> 16)
|
||||
#define UPIU_QUERY_OPCODE_LOW(opcode) ((opcode) & 0xffff)
|
||||
#endif
|
||||
|
||||
22
meson.build
Normal file
22
meson.build
Normal file
@@ -0,0 +1,22 @@
|
||||
project('qbootctl', 'cpp')
|
||||
|
||||
deps = [
|
||||
dependency('zlib'),
|
||||
]
|
||||
|
||||
src = [
|
||||
'qbootctl.cpp',
|
||||
'gpt-utils.cpp',
|
||||
'ufs-bsg.cpp',
|
||||
]
|
||||
|
||||
inc = [
|
||||
include_directories('.'),
|
||||
]
|
||||
|
||||
executable('qbootctl', src,
|
||||
include_directories: inc,
|
||||
dependencies: deps,
|
||||
install: true,
|
||||
c_args: [],
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
206
ufs-bsg.cpp
Normal file
206
ufs-bsg.cpp
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#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;
|
||||
|
||||
// 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;
|
||||
// }
|
||||
|
||||
// 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) {
|
||||
fprintf(stderr, "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)
|
||||
fprintf(stderr, "%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) {
|
||||
fprintf(stderr, "%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)
|
||||
fprintf(stderr, "%s: Error from ufs_bsg_ioctl (return value: %d, error no: %d\n)",
|
||||
__func__, ret, errno);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
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();
|
||||
if (ret)
|
||||
return ret;
|
||||
LOGD("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) {
|
||||
fprintf(stderr, "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;
|
||||
}
|
||||
95
ufs-bsg.h
Normal file
95
ufs-bsg.h
Normal file
@@ -0,0 +1,95 @@
|
||||
#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.
|
||||
*/
|
||||
|
||||
#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 node */
|
||||
char ufs_bsg_dev[FNAME_SZ] = "/dev/bsg/ufs-bsg0";
|
||||
|
||||
int fd_ufs_bsg;
|
||||
|
||||
/* 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 /* __RECOVERY_UFS_BSG_H__ */
|
||||
Reference in New Issue
Block a user