mirror of
https://github.com/drakmor/ShadowMountPlus.git
synced 2026-10-21 22:22:28 -05:00
Fix /dev/lvd attach
This commit is contained in:
1 parent
aff2fc0e6c
commit
2db6b49439
3 files changed
+124
-74
No files matched your search
+26
-16
@@ -9,36 +9,46 @@
|
||||
#define UFS_ATTACH_USE_MDCTL 0
|
||||
|
||||
// --- LVD Definitions ---
|
||||
// - ioctl: ATTACH=0xC0286D00, DETACH=0xC0286D01, ATTACH2 path=0xC0286D09.
|
||||
// - single-image path uses raw option flags 0x8/0x9 -> normalized 0x14/0x1C.
|
||||
// - DownloadData/LWFS path (imgtype=7) uses normalized options 0x16/0x1E.
|
||||
// - image_type values accepted by validator: 0..0xC (13 values total).
|
||||
// this code uses image_type=7 for UFS (DownloadData-like), 0 for generic path.
|
||||
// - layer source_type observed: 1=file, 2=char/block-like source (/dev/sbram0).
|
||||
// - layer entry flag bit0 is "no bitmap file specified".
|
||||
// Kernel exposes base attach (V0), extended attach (V1/Attach2) and detach.
|
||||
// This code only builds V0 layer descriptors, so it uses the base attach path.
|
||||
// Wrapper-side raw attach presets:
|
||||
// - 0x8/0x9 -> single-image/save-data family (normalized 0x14/0x1C)
|
||||
// - 0xC/0xD -> download-data/LWFS family (normalized 0x16/0x1E)
|
||||
// raw bit3 (0x8) sets the DONT_MAP_BM-style mode, raw bit2 (0x4) switches to
|
||||
// the DD/LWFS family, and raw bit0 (0x1) selects the alternate preset inside a
|
||||
// family. Firmware pairs bit0 with read-only mount variants, but this is not a
|
||||
// standalone LVD readonly bit by itself.
|
||||
// image_type values accepted by validator: 0..0xC (13 values total).
|
||||
// layer source_type observed: 1=file, 2=device/special source (/dev/sbram0, char/block).
|
||||
// layer descriptor flag bit0 is "no bitmap file specified".
|
||||
#define LVD_CTRL_PATH "/dev/lvdctl"
|
||||
#define MD_CTRL_PATH "/dev/mdctl"
|
||||
#define SCE_LVD_IOC_ATTACH 0xC0286D00
|
||||
#define SCE_LVD_IOC_ATTACH_V0 0xC0286D00
|
||||
#define SCE_LVD_IOC_ATTACH_V1 0xC0286D09
|
||||
#define SCE_LVD_IOC_DETACH 0xC0286D01
|
||||
#define LVD_ATTACH_IO_VERSION 1
|
||||
#define LVD_ATTACH_OPTION_FLAGS_DEFAULT 0x9
|
||||
#define LVD_ATTACH_OPTION_FLAGS_RW 0x8
|
||||
#define LVD_ATTACH_OPTION_NORM_DD_RO 0x1E
|
||||
#define LVD_ATTACH_OPTION_NORM_DD_RW 0x16
|
||||
#define LVD_ATTACH_IO_VERSION_V0 0u
|
||||
#define LVD_ATTACH_IO_VERSION_V1 1u
|
||||
#define LVD_ATTACH_RAW_FLAGS_SINGLE_RO 0x9
|
||||
#define LVD_ATTACH_RAW_FLAGS_SINGLE_RW 0x8
|
||||
#define LVD_ATTACH_RAW_FLAGS_DD_RO 0xD
|
||||
#define LVD_ATTACH_RAW_FLAGS_DD_RW 0xC
|
||||
#
|
||||
#define LVD_SECTOR_SIZE_EXFAT 512u
|
||||
#define LVD_SECTOR_SIZE_UFS 4096u
|
||||
#define LVD_SECTOR_SIZE_PFS 32768u
|
||||
#define LVD_SECTOR_SIZE_PFS 4096u
|
||||
#define LVD_SECONDARY_UNIT_SINGLE_IMAGE 0x10000u
|
||||
#define MD_SECTOR_SIZE_EXFAT 512u
|
||||
#define MD_SECTOR_SIZE_UFS 512u
|
||||
// Raw option bits are normalized by sceFsLvdAttachCommon before validation:
|
||||
// raw:0x1->norm:0x08, raw:0x2->norm:0x80, raw:0x4->norm:0x02, raw:0x8->norm:0x10.
|
||||
// The normalized masks are then checked against validator constraints (0x82/0x92).
|
||||
#define LVD_ATTACH_IMAGE_TYPE 0
|
||||
#define LVD_ATTACH_IMAGE_TYPE_SINGLE 0
|
||||
#define LVD_ATTACH_IMAGE_TYPE_UFS_DOWNLOAD_DATA 7
|
||||
#define LVD_ATTACH_IMAGE_TYPE_PFS_SAVE_DATA 0 // also works 5
|
||||
#define LVD_ATTACH_IMAGE_TYPE_PFS_SAVE_DATA 5
|
||||
#define LVD_ATTACH_LAYER_COUNT 1
|
||||
#define LVD_ATTACH_LAYER_ARRAY_SIZE 3
|
||||
#define LVD_ENTRY_TYPE_FILE 1
|
||||
#define LVD_ENTRY_TYPE_SPECIAL 2
|
||||
#define LVD_ENTRY_FLAG_NO_BITMAP 0x1
|
||||
#define LVD_NODE_WAIT_US 100000
|
||||
#define LVD_NODE_WAIT_RETRIES 100
|
||||
|
||||
+16
-18
@@ -29,14 +29,12 @@ typedef struct {
|
||||
} devpfs_mount_profile_t;
|
||||
|
||||
typedef struct {
|
||||
// Source object class (observed: 1=file, 2=device-like source).
|
||||
// Source object class (observed: 1=file, 2=device-like/special source).
|
||||
uint16_t source_type;
|
||||
// Layer behavior flags (observed bit0 = no bitmap file path).
|
||||
uint8_t entry_flags;
|
||||
// Layer descriptor flags (observed bit0 = no bitmap file path).
|
||||
uint16_t flags;
|
||||
// Must be zero.
|
||||
uint8_t reserved0;
|
||||
// Must be zero.
|
||||
uint32_t reserved1;
|
||||
uint32_t reserved0;
|
||||
// Backing file or device path.
|
||||
const char *path;
|
||||
// Data start offset in backing object (bytes).
|
||||
@@ -49,28 +47,28 @@ typedef struct {
|
||||
uint64_t bitmap_offset;
|
||||
// Bitmap size (bytes), 0 when bitmap is unused.
|
||||
uint64_t bitmap_size;
|
||||
} lvd_kernel_layer_t;
|
||||
} lvd_ioctl_layer_v0_t;
|
||||
|
||||
typedef struct {
|
||||
// Protocol version for /dev/lvdctl ioctl payload (valid <=1).
|
||||
// Protocol version for /dev/lvdctl ioctl payload (0 = V0/base attach).
|
||||
uint32_t io_version;
|
||||
// Input: usually -1 for auto-assign. Output: created lvd unit id.
|
||||
int32_t device_id;
|
||||
// Sector-like size fields used by LVD attach request validation.
|
||||
// In refs these are populated from statfs and clamped to <= 4096.
|
||||
uint32_t sector_size_0;
|
||||
uint32_t sector_size_1;
|
||||
// Encoded option length derived from option flags (0x14 for 0x8, 0x1C for 0x9).
|
||||
uint16_t option_len;
|
||||
// LVD image type id (validator accepts 0..0xC; this code uses 0).
|
||||
// User-visible sector size exported by /dev/lvdN.
|
||||
uint32_t sector_size;
|
||||
// Secondary unit/granularity validated against sector_size.
|
||||
uint32_t secondary_unit;
|
||||
// Normalized attach flags produced from wrapper raw options.
|
||||
uint16_t flags;
|
||||
// LVD image type id (validator accepts 0..0xC).
|
||||
uint16_t image_type;
|
||||
// Number of valid entries in layers_ptr.
|
||||
uint32_t layer_count;
|
||||
// Total exported virtual size (bytes).
|
||||
uint64_t device_size;
|
||||
// Pointer to layer array in user payload.
|
||||
lvd_kernel_layer_t *layers_ptr;
|
||||
} lvd_ioctl_attach_t;
|
||||
// Pointer to V0 layer array in user payload.
|
||||
lvd_ioctl_layer_v0_t *layers_ptr;
|
||||
} lvd_ioctl_attach_v0_t;
|
||||
|
||||
typedef struct {
|
||||
// Must be zero.
|
||||
|
||||
+82
-40
@@ -23,7 +23,7 @@ static bool wait_for_dev_node_state(const char *devname, bool should_exist) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint32_t get_lvd_sector_size(image_fs_type_t fs_type) {
|
||||
static uint32_t get_lvd_sector_size_fallback(image_fs_type_t fs_type) {
|
||||
const runtime_config_t *cfg = runtime_config();
|
||||
switch (fs_type) {
|
||||
case IMAGE_FS_UFS:
|
||||
@@ -36,6 +36,31 @@ static uint32_t get_lvd_sector_size(image_fs_type_t fs_type) {
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t get_lvd_sector_size(const char *path, image_fs_type_t fs_type) {
|
||||
uint32_t fallback = get_lvd_sector_size_fallback(fs_type);
|
||||
if (!path)
|
||||
return fallback;
|
||||
|
||||
struct statfs sfs;
|
||||
if (statfs(path, &sfs) != 0)
|
||||
return fallback;
|
||||
|
||||
uint64_t fs_cluster_size = (uint64_t)sfs.f_bsize;
|
||||
if (fs_cluster_size == 0)
|
||||
fs_cluster_size = (uint64_t)sfs.f_iosize;
|
||||
if (fs_cluster_size == 0 || fs_cluster_size >= (uint64_t)fallback)
|
||||
return fallback;
|
||||
|
||||
return (uint32_t)fs_cluster_size;
|
||||
}
|
||||
|
||||
static uint32_t get_lvd_secondary_unit(const char *path,
|
||||
image_fs_type_t fs_type) {
|
||||
if (fs_type == IMAGE_FS_EXFAT)
|
||||
return LVD_SECONDARY_UNIT_SINGLE_IMAGE;
|
||||
return get_lvd_sector_size(path, fs_type);
|
||||
}
|
||||
|
||||
static uint32_t get_md_sector_size(image_fs_type_t fs_type) {
|
||||
const runtime_config_t *cfg = runtime_config();
|
||||
switch (fs_type) {
|
||||
@@ -54,14 +79,14 @@ static unsigned int get_md_attach_options(bool mount_read_only) {
|
||||
return options;
|
||||
}
|
||||
|
||||
static uint16_t get_lvd_attach_option(image_fs_type_t fs_type,
|
||||
bool mount_read_only) {
|
||||
if (fs_type == IMAGE_FS_UFS) {
|
||||
return mount_read_only ? LVD_ATTACH_OPTION_NORM_DD_RO
|
||||
: LVD_ATTACH_OPTION_NORM_DD_RW;
|
||||
static uint16_t get_lvd_attach_raw_flags(image_fs_type_t fs_type,
|
||||
bool mount_read_only) {
|
||||
if (fs_type == IMAGE_FS_UFS) {
|
||||
return mount_read_only ? LVD_ATTACH_RAW_FLAGS_DD_RO
|
||||
: LVD_ATTACH_RAW_FLAGS_DD_RW;
|
||||
}
|
||||
return mount_read_only ? LVD_ATTACH_OPTION_FLAGS_DEFAULT
|
||||
: LVD_ATTACH_OPTION_FLAGS_RW;
|
||||
return mount_read_only ? LVD_ATTACH_RAW_FLAGS_SINGLE_RO
|
||||
: LVD_ATTACH_RAW_FLAGS_SINGLE_RW;
|
||||
}
|
||||
|
||||
static unsigned int get_nmount_flags(image_fs_type_t fs_type,
|
||||
@@ -77,15 +102,38 @@ static unsigned int get_nmount_flags(image_fs_type_t fs_type,
|
||||
return mount_read_only ? MNT_RDONLY : 0;
|
||||
}
|
||||
|
||||
static uint16_t lvd_option_len_from_flags(uint16_t options) {
|
||||
if ((options & 0x800Eu) != 0u) {
|
||||
uint32_t raw = (uint32_t)options;
|
||||
static uint16_t normalize_lvd_raw_flags(uint16_t raw_flags) {
|
||||
if ((raw_flags & 0x800Eu) != 0u) {
|
||||
uint32_t raw = (uint32_t)raw_flags;
|
||||
uint32_t len = (raw & 0xFFFF8000u) + ((raw & 2u) << 6) +
|
||||
(8u * (raw & 1u)) + (2u * ((raw >> 2) & 1u)) +
|
||||
(2u * (raw & 8u)) + 4u;
|
||||
return (uint16_t)len;
|
||||
}
|
||||
return (uint16_t)(8u * ((uint32_t)options & 1u) + 4u);
|
||||
return (uint16_t)(8u * ((uint32_t)raw_flags & 1u) + 4u);
|
||||
}
|
||||
|
||||
static uint16_t get_lvd_image_type(image_fs_type_t fs_type) {
|
||||
if (fs_type == IMAGE_FS_UFS)
|
||||
return LVD_ATTACH_IMAGE_TYPE_UFS_DOWNLOAD_DATA;
|
||||
if (fs_type == IMAGE_FS_PFS)
|
||||
return LVD_ATTACH_IMAGE_TYPE_PFS_SAVE_DATA;
|
||||
return LVD_ATTACH_IMAGE_TYPE_SINGLE;
|
||||
}
|
||||
|
||||
static uint16_t get_lvd_source_type(const char *path) {
|
||||
if (!path)
|
||||
return LVD_ENTRY_TYPE_FILE;
|
||||
|
||||
if (strncmp(path, "/dev/sbram0", strlen("/dev/sbram0")) == 0)
|
||||
return LVD_ENTRY_TYPE_SPECIAL;
|
||||
|
||||
struct stat st;
|
||||
if (stat(path, &st) == 0) {
|
||||
if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))
|
||||
return LVD_ENTRY_TYPE_SPECIAL;
|
||||
}
|
||||
return LVD_ENTRY_TYPE_FILE;
|
||||
}
|
||||
|
||||
// --- Image Path and Naming Helpers ---
|
||||
@@ -271,49 +319,42 @@ static bool attach_lvd_backend(const char *file_path, image_fs_type_t fs_type,
|
||||
return false;
|
||||
}
|
||||
|
||||
lvd_kernel_layer_t *layers =
|
||||
calloc(LVD_ATTACH_LAYER_ARRAY_SIZE, sizeof(*layers));
|
||||
if (!layers) {
|
||||
log_debug(" [IMG] calloc layers failed");
|
||||
close(lvd_fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
layers[0].source_type = LVD_ENTRY_TYPE_FILE;
|
||||
layers[0].entry_flags = LVD_ENTRY_FLAG_NO_BITMAP;
|
||||
lvd_ioctl_layer_v0_t layers[LVD_ATTACH_LAYER_COUNT];
|
||||
memset(layers, 0, sizeof(layers));
|
||||
layers[0].source_type = get_lvd_source_type(file_path);
|
||||
layers[0].flags = LVD_ENTRY_FLAG_NO_BITMAP;
|
||||
layers[0].path = file_path;
|
||||
layers[0].offset = 0;
|
||||
layers[0].size = (uint64_t)file_size;
|
||||
|
||||
lvd_ioctl_attach_t req;
|
||||
uint32_t sector_size = get_lvd_sector_size(file_path, fs_type);
|
||||
uint32_t secondary_unit = get_lvd_secondary_unit(file_path, fs_type);
|
||||
uint16_t raw_flags = get_lvd_attach_raw_flags(fs_type, mount_read_only);
|
||||
uint16_t normalized_flags = normalize_lvd_raw_flags(raw_flags);
|
||||
|
||||
lvd_ioctl_attach_v0_t req;
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.io_version = LVD_ATTACH_IO_VERSION;
|
||||
req.image_type = (fs_type == IMAGE_FS_UFS)
|
||||
? LVD_ATTACH_IMAGE_TYPE_UFS_DOWNLOAD_DATA
|
||||
: (fs_type == IMAGE_FS_PFS)
|
||||
? LVD_ATTACH_IMAGE_TYPE_PFS_SAVE_DATA
|
||||
: LVD_ATTACH_IMAGE_TYPE;
|
||||
req.io_version = LVD_ATTACH_IO_VERSION_V0;
|
||||
req.image_type = get_lvd_image_type(fs_type);
|
||||
req.layer_count = LVD_ATTACH_LAYER_COUNT;
|
||||
req.device_size = (uint64_t)file_size;
|
||||
req.layers_ptr = layers;
|
||||
req.sector_size_0 = get_lvd_sector_size(fs_type);
|
||||
req.sector_size_1 = req.sector_size_0;
|
||||
|
||||
uint16_t attach_option = get_lvd_attach_option(fs_type, mount_read_only);
|
||||
req.option_len = (fs_type == IMAGE_FS_UFS) ? attach_option
|
||||
: lvd_option_len_from_flags(attach_option);
|
||||
req.sector_size = sector_size;
|
||||
req.secondary_unit = secondary_unit;
|
||||
req.flags = normalized_flags;
|
||||
req.device_id = -1;
|
||||
|
||||
int last_errno = 0;
|
||||
log_debug(" [IMG][%s] attach try: ver=%u sec=%u options=0x%x len=0x%x",
|
||||
log_debug(" [IMG][%s] attach try: ver=%u sec=%u sec2=%u raw=0x%x "
|
||||
"flags=0x%x img=%u",
|
||||
attach_backend_name(ATTACH_BACKEND_LVD), req.io_version,
|
||||
req.sector_size_0, attach_option, req.option_len);
|
||||
int ret = ioctl(lvd_fd, SCE_LVD_IOC_ATTACH, &req);
|
||||
req.sector_size, req.secondary_unit, raw_flags, req.flags,
|
||||
req.image_type);
|
||||
int ret = ioctl(lvd_fd, SCE_LVD_IOC_ATTACH_V0, &req);
|
||||
if (ret != 0)
|
||||
last_errno = errno;
|
||||
close(lvd_fd);
|
||||
int unit_id = req.device_id;
|
||||
free(layers);
|
||||
|
||||
if (ret != 0) {
|
||||
errno = last_errno;
|
||||
@@ -580,7 +621,8 @@ static bool validate_mounted_image(const char *file_path, image_fs_type_t fs_typ
|
||||
|
||||
uint32_t min_device_sector =
|
||||
(attach_backend == ATTACH_BACKEND_MD) ? get_md_sector_size(fs_type)
|
||||
: get_lvd_sector_size(fs_type);
|
||||
: get_lvd_sector_size(file_path,
|
||||
fs_type);
|
||||
uint64_t fs_block_size = (uint64_t)mounted_sfs.f_bsize;
|
||||
if (fs_block_size >= (uint64_t)min_device_sector)
|
||||
return true;
|
||||
|
||||
Reference in new issue
Block a user