VFS Implementation: Difference between revisions
(→Types) |
(→Types: Add structures for the VFS buffer cache) |
||
(22 intermediate revisions by 2 users not shown) | |||
Line 4: | Line 4: | ||
! Module !! Name !! Comment | ! Module !! Name !! Comment | ||
|- | |- | ||
| [[SceSdstor|SceSdstor]] || sdstor_dev_fs || | | [[SceSdstor|SceSdstor]] || sdstor_dev_fs || read/write sector data | ||
|- | |- | ||
| [[SceExfatfs|SceExfatfs]] || exfat || | | [[SceExfatfs|SceExfatfs]] || exfat || analyze fs, save cache | ||
|- | |- | ||
| [[SceIofilemgr|SceIofilemgr]] || dummy_ttyp_dev_fs || | | [[SceIofilemgr|SceIofilemgr]] || dummy_ttyp_dev_fs || file io api | ||
|- | |- | ||
| [[ScePfsMgr|ScePfsMgr]] || PFS_REDIRECT_INF || Redirect Pseudo Drive. | | [[ScePfsMgr|ScePfsMgr]] || PFS_REDIRECT_INF || Redirect Pseudo Drive. | ||
Line 304: | Line 304: | ||
char* filesystem; | char* filesystem; | ||
pfs_pmi_buffer_list_ctx* | pfs_pmi_buffer_list_ctx* blc; //holds klicensee | ||
vfs_block_dev_info* blockDev1; | vfs_block_dev_info* blockDev1; | ||
node_ops2* ops2; | |||
} vfs_mount_point_info_base; | } vfs_mount_point_info_base; | ||
Line 391: | Line 391: | ||
vfs_add_data* add_data; // 0x5C | vfs_add_data* add_data; // 0x5C | ||
uint32_t | uint32_t some_counter_60; // counter | ||
uint32_t unk_64; | uint32_t unk_64; | ||
Line 408: | Line 408: | ||
uint32_t unk_C0; | uint32_t unk_C0; | ||
pfs_pmi_buffer_list_ctx* | pfs_pmi_buffer_list_ctx* blc; // C4 - from vfs_mount_point_info_base | ||
vfs_fd_lock* fd_lock_ptr; // C8 - points to area in this structure | vfs_fd_lock* fd_lock_ptr; // C8 - points to area in this structure | ||
Line 448: | Line 448: | ||
char* data; // 1C | char* data; // 1C | ||
} vfs_node_70; | } vfs_node_70; | ||
struct vfs_buff_data | |||
{ | |||
void * data; | |||
uint32_t status; | |||
SceOff offset; | |||
struct vfs_buff_data *next; | |||
uint32_t unk; | |||
}; | |||
struct vfs_buff_cache | |||
{ | |||
void * io; // ioBuff aligned to 0x200 | |||
uint32_t ioBuffSize; | |||
uint32_t ioBuffCachedSize; | |||
uint32_t status; | |||
SceOff ioBuffOffset; | |||
uint8_t nWay; | |||
uint8_t nArray; // Number of sets | |||
uint16_t flags; | |||
SceUID pid; | |||
uint32_t dataSize; // Size of each line of data | |||
void * dataBuff; | |||
void * ioBuff; | |||
int (*writeCb)(vfs_node_func6_args* args); | |||
SceUID hostBlock; // Only allocated when the node is on the host0: mount point | |||
void * unkBuff; // Ditto. Fixed 0x8200 size | |||
struct vfs_buff_data *dataSets[]; | |||
}; | |||
struct vfs_node //size is 0x100 | struct vfs_node //size is 0x100 | ||
{ | { | ||
uint32_t unk_0; | uint32_t unk_0; | ||
SceUID tid_4; //SceUID of thread in which node was created | |||
uint32_t | uint32_t some_counter_8; //counter | ||
SceUID event_flag_SceVfsVnode; // 0xC - event flag SceVfsVnode | SceUID event_flag_SceVfsVnode; // 0xC - event flag SceVfsVnode | ||
Line 477: | Line 512: | ||
vfs_node* unk_54; // copied from node base - singly linked list | vfs_node* unk_54; // copied from node base - singly linked list | ||
uint32_t | uint32_t some_counter_58; // counter - probably counter of nodes | ||
vfs_buff_cache *bc; | |||
uint32_t unk_60; | uint32_t unk_60; | ||
Line 487: | Line 522: | ||
vfs_node_70* unk_70; | vfs_node_70* unk_70; | ||
uint32_t unk_74; // = 0x8000 | uint32_t unk_74; // = 0x8000 | ||
uint32_t unk_78; // | uint32_t unk_78; // SceIoAccessMode | ||
uint32_t unk_7C; | uint32_t unk_7C; | ||
Line 495: | Line 530: | ||
uint32_t unk_8C; | uint32_t unk_8C; | ||
SceVfsFileClassObject *obj_internal_90; | |||
uint32_t maybe_internal_obj_count_94; | uint32_t maybe_internal_obj_count_94; | ||
vfs_node* child_node; // child node with deeper level of i/o implementation? | vfs_node* child_node; // child node with deeper level of i/o implementation? | ||
Line 508: | Line 543: | ||
}vfs_node; | }vfs_node; | ||
//size is 0x20 | |||
struct vfs_obj_file_info | struct vfs_obj_file_info | ||
{ | { | ||
Line 516: | Line 552: | ||
int unk10; | int unk10; | ||
int unk14; | int unk14; | ||
int | int flags; | ||
SceMode mode; | |||
}; | }; | ||
Line 523: | Line 559: | ||
//then add offset 8 to that object base since first 8 bytes are reserved | //then add offset 8 to that object base since first 8 bytes are reserved | ||
struct | typedef struct SceVfsFileClassObject { | ||
{ | SceBool is_dir_handler; | ||
int flags; // open flags | |||
int | |||
SceOff offset; //for example used in Read/Pread | SceOff offset; //for example used in Read/Pread | ||
int | int flags2; // 0x10 some flags | ||
SceUID pid; | |||
vfs_node *node; //0x18 | vfs_node *node; //0x18 | ||
SceVfsFileClassObject *prev_obj; | |||
void* device_handle; //0x20 - for Sdstor this will be sd_stor_device_handle* | void* device_handle; //0x20 - for Sdstor this will be sd_stor_device_handle* | ||
uint16_t unk24; | uint16_t unk24; | ||
Line 540: | Line 575: | ||
vfs_obj_file_info *file_info; | vfs_obj_file_info *file_info; | ||
char unk34[12]; | char unk34[12]; | ||
}; | } SceVfsFileClassObject; | ||
struct | typedef struct SceUIDVfsFileClassObject { | ||
{ | |||
SceObjectBase base; | SceObjectBase base; | ||
SceVfsFileClassObject vfs_object; | |||
}; | } SceUIDVfsFileClassObject; | ||
//this one is acquired by sceKernelGetObjForUid using SceUID file descriptor | //this one is acquired by sceKernelGetObjForUid using SceUID file descriptor | ||
//then add offset 8 to that object base since first 8 bytes are reserved | //then add offset 8 to that object base since first 8 bytes are reserved | ||
typedef | typedef SceVfsFileClassObject vfs_object_base; | ||
typedef struct SceVfsPath { //size is 0xC | |||
char *path; | |||
SceSize path_len; | |||
char *path2; | |||
} SceVfsPath; | |||
</source> | </source> | ||
Line 756: | Line 795: | ||
struct vfs_node_func2_args | struct vfs_node_func2_args | ||
{ | { | ||
vfs_node* | vfs_node* new_node; | ||
vfs_node** node; | vfs_node** node; | ||
void* opt; | void* opt; | ||
Line 1,079: | Line 1,118: | ||
|} | |} | ||
<source lang="c"> | <source lang="c"> | ||
typedef struct vfs_node_func15_args { | |||
struct vfs_node_func15_args | |||
{ | |||
vfs_node* node; | vfs_node* node; | ||
SceVfsPath *path_into; | |||
SceIoStat* stat; | SceIoStat* stat; | ||
}vfs_node_func15_args; | } vfs_node_func15_args; | ||
typedef struct SceVfsStat { // size is 0xC | |||
SceVfsNode *node; | |||
SceVfsPath *path_info; | |||
SceIoStat *stat; | |||
} SceVfsStat; | |||
int vfs_node_func15(vfs_node* node, vfs_node_func15_opts* opts, SceIoStat* stat); | |||
</source> | </source> | ||
Line 1,140: | Line 1,176: | ||
|} | |} | ||
<source lang="c"> | <source lang="c"> | ||
int vfs_node_func17(vfs_node* new_node0, vfs_node* node0, | int vfs_node_func17(vfs_node* new_node0, vfs_node* node0, vfs_node_func17_opts0* opt0, vfs_node* new_node1, vfs_node** node1, vfs_node_func17_opts* opt1); | ||
typedef struct | typedef struct vfs_node_func17_opts0 //size is 0x10 | ||
{ | { | ||
uint32_t unk_0; | uint32_t unk_0; | ||
Line 1,148: | Line 1,184: | ||
uint32_t unk_8; | uint32_t unk_8; | ||
uint32_t unk_C; | uint32_t unk_C; | ||
} | }vfs_node_func17_opts0; | ||
typedef struct | typedef struct vfs_node_func17_opts1 //size is 0x10 | ||
{ | { | ||
uint32_t unk_0; | uint32_t unk_0; | ||
Line 1,156: | Line 1,192: | ||
uint32_t unk_8; | uint32_t unk_8; | ||
uint32_t unk_C; | uint32_t unk_C; | ||
} | }vfs_node_func17_opts1; | ||
struct vfs_node_func17_args | struct vfs_node_func17_args | ||
Line 1,162: | Line 1,198: | ||
vfs_node* new_node0; | vfs_node* new_node0; | ||
vfs_node* node0; | vfs_node* node0; | ||
vfs_node_func17_opts0* opt0; | |||
vfs_node* new_node1; | vfs_node* new_node1; | ||
vfs_node** node1; | vfs_node** node1; | ||
vfs_node_func17_opts1* opt1; | |||
}vfs_node_func17_args; | }vfs_node_func17_args; | ||
Latest revision as of 00:09, 20 June 2024
VFS Nodes
Module | Name | Comment |
---|---|---|
SceSdstor | sdstor_dev_fs | read/write sector data |
SceExfatfs | exfat | analyze fs, save cache |
SceIofilemgr | dummy_ttyp_dev_fs | file io api |
ScePfsMgr | PFS_REDIRECT_INF | Redirect Pseudo Drive. |
ScePfsMgr | PFS_GDSD_INF | Gamedata/Savedata Pseudo Drive. |
ScePfsMgr | PFS_AC_INF | AC Pseudo Drive. |
VFS Operations
- implemented operation is marked as
implemented
- not implemented is marked as
- return 0 placeholder is marked as
0
- return error is marked with corresponding error name
Function | sdstor_dev_fs | exfat | dummy_ttyp_dev_fs | PFS_REDIRECT_INF | PFS_GDSD_INF | PFS_AC_INF |
---|---|---|---|---|---|---|
1 | implemented | implemented | implemented | implemented | implemented | implemented |
2 | SCE_ERROR_ERRNO_EBUSY | implemented | 0 | implemented | implemented | implemented |
3 | implemented | implemented | implemented | implemented | implemented | implemented |
4 | implemented | |||||
5 | ||||||
6 | ||||||
7 | implemented | 0 | implemented | implemented | ||
8 | ||||||
9 | 0 | 0 | 0 | 0 | 0 | 0 |
10 | 0 | 0 | 0 | 0 | 0 | |
11 | ||||||
12 | implemented | implemented | implemented | implemented | implemented | |
13 | implemented | implemented | implemented | implemented | implemented |
VFS Node Operations
- implemented operation is marked as
implemented
- not implemented is marked as
- return 0 placeholder is marked as
0
- return error is marked with corresponding error name
Function | sdstor_dev_fs | exfat | dummy_ttyp_dev_fs | PFS_REDIRECT_INF | PFS_GDSD_INF | PFS_AC_INF |
---|---|---|---|---|---|---|
1 | implemented | implemented | 0 | implemented | implemented | implemented |
2 | implemented | implemented | implemented | implemented | ||
3 | implemented | implemented | 0 | implemented | implemented | implemented |
4 | implemented | implemented | implemented | implemented | implemented | implemented |
5 | implemented | implemented | 0 | implemented | implemented | implemented |
6 | implemented | implemented | implemented | implemented | implemented | implemented |
7 | implemented | implemented | 0 | implemented | implemented | implemented |
8 | SCE_ERROR_ERRNO_EUNSUP | 0 | implemented | implemented | implemented | |
9 | implemented | implemented | implemented | implemented | implemented | |
10 | implemented | implemented | implemented | implemented | ||
11 | implemented | implemented | implemented | implemented | ||
12 | implemented | implemented | implemented | implemented | ||
13 | implemented | implemented | implemented | implemented | ||
14 | implemented | implemented | implemented | implemented | ||
15 | implemented | implemented | implemented | implemented | ||
16 | implemented | implemented | implemented | implemented | ||
17 | implemented | implemented | implemented | implemented | ||
18 | ||||||
19 | implemented | implemented | implemented | implemented | implemented | |
20 | implemented | implemented | implemented | implemented | implemented | |
21 | 0 | implemented | 0 | implemented | implemented | implemented |
22 | implemented | |||||
23 | implemented | |||||
24 | 0 | implemented | implemented | implemented | implemented | |
25 | implemented | implemented | implemented | implemented | ||
26 | implemented | implemented | implemented | implemented | ||
27 | implemented | implemented | implemented | implemented | ||
28 | implemented | implemented | implemented | implemented | ||
29 |
Typical i/o operation execution
This is a very brief desctiption for overall understanding of io vfs_node
operations.
Implementation of SceIofilemgr is quite solid and most of the functions are implemented in the same manner however there could be exceptions.
When io operation like sceIoLseek
is called here is what happens:
- all user space arguments are copied to kernel space, usually onto the kernel stack. all user space uids are converted to kernel space uids
- optionally control may be passed to wrapper function that also does conversion
- then control is passed to kernel level function like
sceIoLseekForDriver
- kernel level function checks 0x2198 (IoSchedulerDispatcher initialized) flag
if dispatcher is not initialized:
- kernel level function updates 0x1964 (i/o dirty) and 0x1980 (i/o counter) flags
- kernel level function spawns separate thread and passes all arguments in single structure
- separate thread then unpacks all arguments, finds
vfs_node
and calls exported function likevfs_node_func7
- exported function packs all arguments into single stucture and calls real callback since it has
vfs_node
with node operation table - callback routine should be located in generic device driver, like SceSdstor, SceExfatfs or ScePfsMgr. It unpacks the arguments and then does something. For example SceSdstor dispatches the call further to SceSdif, SceWlanBt, SceMsif and SceUsbMass.
- kernel level function updates 0x1980 (i/o counter) flag
if dispatcher is initialized:
- kernel level function passes arguments to wrapper
- wrapper initializes
io_contex
and assigns i/o operation index - wrapper updates 0x1964 (i/o dirty) and 0x1980 (i/o counter) flags
- wrapper runs dispatcher function (offset 0x17C00) in separate thread. this function selects proper
vfs_node
function based on i/o operation index. - wrapper updates 0x1980 (i/o counter) flag
i/o operation index
Typically operations are dispatched from kernel functions.
However there are exceptions: sceIoLseek32, sceIoDopenAsync, sceIoDreadAsync, sceIoDcloseAsync user functions can be dispatched.
Typically operations have normal and async version - regulated by async flag in io_context
.
However there are exceptions: sceIoLseek32, sceIoIoctlForDriver, sceIoDevctlForDriver, sceIoGetstatForDriver_2, sceIoChstatForDriver_2, sceIoDreadForDriver_2 do not have async version.
Index | Normal Operation | Async Operation | Vfs Node Function | Vfs Function |
---|---|---|---|---|
1 | sceIoOpenForDriver | sceIoOpenAsyncForDriver | 2 | N/A |
2 | sceIoCloseForDriver | sceIoCloseAsyncForDriver | 3 | N/A |
3 | sceIoReadForDriver | sceIoReadAsyncForDriver | 5 | N/A |
4 | sceIoWriteForDriver | sceIoWriteAsyncForDriver | 6 | N/A |
5 | sceIoLseekForDriver | sceIoLseekAsyncForDriver | 7 | N/A |
6 | sceIoLseek32 | N/A | 7 | N/A |
7 | sceIoIoctlForDriver | N/A | 8 | N/A |
8 | sceIoRemoveForDriver | sceIoRemoveAsyncForDriver | 27 | N/A |
9 | sceIoDopenForDriver | sceIoDopenAsyncForDriver | 12 | N/A |
10 | sceIoDcloseForDriver | sceIoDcloseAsyncForDriver | 13 | N/A |
11 | sceIoDreadForDriver | sceIoDreadAsyncForDriver | 14 | N/A |
12 | sceIoMkdirForDriver | sceIoMkdirAsyncForDriver | 10 | N/A |
13 | sceIoRmdirForDriver | sceIoRmdirAsyncForDriver | 11 | N/A |
14 | sceIoRenameForDriver | sceIoRenameAsyncForDriver | 17 | N/A |
15 | sceIoChstatForDriver | sceIoChstatAsyncForDriver | 16 | N/A |
16 | sceIoChstatByFdForDriver | sceIoChstatByFdAsyncForDriver | 26 | N/A |
17 | sceIoGetstatForDriver | sceIoGetstatAsyncForDriver | 15 | N/A |
18 | sceIoGetstatByFdForDriver | sceIoGetstatByFdAsyncForDriver | 25 | N/A |
19 | sceIoDevctlForDriver | N/A | N/A | 12 |
20 | sceIoSyncForDriver | sceIoSyncAsyncForDriver | 24 | N/A |
21 | sceIoSyncByFdForDriver | sceIoSyncByFdAsyncForDriver | 24 | N/A |
22 | sceIoPreadForDriver | sceIoPreadAsyncForDriver | 19 | N/A |
23 | sceIoPwriteForDriver | sceIoPwriteAsyncForDriver | 20 | N/A |
24 | sceIoGetstatForDriver_2 | N/A | 15 | N/A |
25 | sceIoChstatForDriver_2 | N/A | 16 | N/A |
26 | sceIoDreadForDriver_2 | N/A | 14 | N/A |
27 | N/A | sceIoDopenAsync | ||
28 | N/A | sceIoDreadAsync | ||
29 | N/A | sceIoDcloseAsync |
Types
//probably vfsops struct node_ops1 // size is 0x34 (13 pointers) { int (*func1)(void* ctx); int (*func2)(void* ctx); // ? int (*func3)(void* ctx); int (*func4)(void* ctx); int (*func5)(void* ctx); // not implemented by all int (*func6)(void* ctx); // not implemented by all int (*func7)(void* ctx); int (*func8)(void* ctx); // not implemented by all int (*func9)(void* ctx); // called by sceVfsAddVfs int (*func10)(void* ctx); // called by sceVfsDeleteVfs int (*func11)(void* ctx); // not implemented by all int (*func12)(void* ctx); // sceIoDevctlForDriver int (*func13)(void* ctx); // (initialize partition entry in table)(map block device name on numeric name) }; //probably vnodeops struct node_ops2 // size is 0x74 (29 pointers) { int (*sceVfsNodeFunction1ForDriver)(vfs_node_func1_args* args); int (*sceVfsNodeOpenForDriver)(vfs_node_func2_args* args); int (*sceVfsNodeCloseForDriver)(vfs_node_func3_args* args); int (*sceVfsNodeInitializePartitionForDriver)(vfs_node_func4_args* args); int (*sceVfsNodeReadForDriver)(vfs_node_func5_args* args); int (*sceVfsNodeWriteForDriver)(vfs_node_func6_args* args); int (*sceVfsNodeLseekForDriver)(vfs_node_func7_args* args); int (*sceVfsNodeIoctlForDriver)(vfs_node_func8_args* args); int (*sceVfsNodeDeinitializePartitionForDriver)(vfs_node_func9_args* args); int (*sceVfsNodeMkdirForDriver)(vfs_node_func10_args* args); int (*sceVfsNodeRmdirForDriver)(vfs_node_func11_args* args); int (*sceVfsNodeDopenForDriver)(vfs_node_func12_args* args); int (*sceVfsNodeDcloseForDriver)(vfs_node_func13_args* args); int (*sceVfsNodeDreadForDriver)(vfs_node_func14_args* args); int (*sceVfsNodeGetstatForDriver)(vfs_node_func15_args* args); int (*sceVfsNodeChstatForDriver)(vfs_node_func16_args* args); int (*sceVfsNodeRenameForDriver)(vfs_node_func17_args* args); int (*sceVfsNodeFunction18ForDriver)(void* args); //not implemented int (*sceVfsNodePreadForDriver)(vfs_node_func19_args* args); int (*sceVfsNodePwriteForDriver)(vfs_node_func20_args* args); int (*sceVfsNodeFunction21ForDriver)(vfs_node_func21_args* args); int (*sceVfsNodeFunction22ForDriver)(vfs_node_func22_args* args); int (*sceVfsNodeFunction23ForDriver)(vfs_node_func23_args* args); int (*sceVfsNodeSyncForDriver)(vfs_node_func24_args* args); int (*sceVfsNodeGetstatByFdForDriver)(vfs_node_func25_args* args); int (*sceVfsNodeChstatByFdForDriver)(vfs_node_func26_args* args); int (*sceVfsNodeRemoveForDriver)(vfs_node_func27_args* args); int (*sceVfsNodeFunction28ForDriver)(vfs_node_func28_args* args); int (*sceVfsNodeFunction29ForDriver)(vfs_node_func29_args* args); }; struct vfs_unmount_data { const char *mountpoint; int flags; }; typedef struct vfs_block_dev_info //size is 0x14 { char* vitaMount; char* filesystem; // Some name, I guess it is filesystem char* blockDevicePrimary; char* blockDeviceSecondary; // can be 0 uint32_t vshMountId; //must be same as in mount_point_info }vfs_block_dev_info; typedef struct vfs_mount_point_info_base { char* unixMount; char* originalPath; uint32_t devMajor; uint32_t devMinor; char* filesystem; pfs_pmi_buffer_list_ctx* blc; //holds klicensee vfs_block_dev_info* blockDev1; node_ops2* ops2; } vfs_mount_point_info_base; typedef struct vfs_mount_point_info //size is 0x38 { uint32_t vshMountId; vfs_mount_point_info_base base; vfs_block_dev_info* blockDev2; //same as blockDev1 uint32_t unk_28; //zero - except for (ux0:, gro0:, grw0:) - maybe related to device specific data? uint32_t unk_2C; //zero uint32_t unk_30; //zero uint32_t unk_34; //zero }vfs_mount_point_info; struct vfs_add_data { node_ops1* funcs1; const char *name; //exfat etc. max size is 0x20 int flags; //0x0E int unk_C; //0x01 / 0x00 (root, leaf ?) int unk_10; //0x10 node_ops2* funcs2; int unk_18; //0x00 vfs_add_data* next_element; //ptr to next element, confirmed }; typedef struct vfs_fd_lock { SceUID mutex_SceVfsFdLock; SceUID cond_SceVfsFdCond; uint32_t unk_8; uint32_t toggle; //inc before condition wait. dec after condition wait. } vfs_fd_lock; typedef struct vfs_mount_cc { node_ops2* ops; // only functions 3, 13, 21 are available. everything else should give 0x80010013 uint32_t dirty; // (1/0) checked on suspend uint32_t* flag; // (1/0) shows if wait for eventFlag should be called or not // pointer to data section, offset 3C, 38 or 2C SceUID* eventFlag; // pointer to data section, offset 30, 20 or 28 } vfs_mount_cc; typedef struct vfs_mount //size is not known exactly, at least 0xD0 + 0x10 + 0x10 { fast_mutex SceVfsMnt; // size is 0x40 vfs_node* unk_40; // child ? SceUID pool; // 0x44 - SceIoVfsHeap uint32_t unk_48; // = 0x101 union _devMajor { struct _dmDword { uint32_t unk_4C; } dw; struct _dmWord { uint16_t unk_4C; uint16_t unk_4E; } w; struct _dmByte { uint8_t unk_4C; uint8_t unk_4D; uint8_t unk_4E; uint8_t unk_4F; } b; } devMajor; uint32_t devMinor; // 0x50 vfs_node* unk_54; uint32_t unk_58; // counter vfs_add_data* add_data; // 0x5C uint32_t some_counter_60; // counter uint32_t unk_64; uint32_t unk_68; uint32_t unk_6C; vfs_mount* unk_70; // next ? vfs_mount* unk_74; // prev ? vfs_mount* unk_78; //singly linked list related to pointer 19D0 in data section vfs_block_dev_info* blockDev; // 0x7C char unixMount[0x40]; // 0x80 /gro/exfat, /ux/exfat etc uint32_t unk_C0; pfs_pmi_buffer_list_ctx* blc; // C4 - from vfs_mount_point_info_base vfs_fd_lock* fd_lock_ptr; // C8 - points to area in this structure vfs_mount_cc* unk_CC; // CC - points to area in this structure vfs_fd_lock fd_lock; // D0 vfs_mount_cc unk_E0; //E0; } vfs_mount; //this structure contains device specific data //this definition applies only to SceSdif driver //it is yet unknown what data is stored by SceExfatfs, ScePfsMgr and SceIofilemgr implementations struct vfs_device_info //size is 0xC { partition_entry* partition; sd_stor_device* device; uint32_t unk_8; } vfs_device_info; struct child_node_info { vfs_node* node; } child_node_info; typedef struct vfs_node_70 { uint32_t unk_0; uint32_t unk_4; uint32_t unk_8; vfs_node_70* unk_C; //zero or pointer to next element void* unk_10; //pointer to struct of at least size 0x94 uint32_t unk_14; //number uint32_t len; // 18 char* data; // 1C } vfs_node_70; struct vfs_buff_data { void * data; uint32_t status; SceOff offset; struct vfs_buff_data *next; uint32_t unk; }; struct vfs_buff_cache { void * io; // ioBuff aligned to 0x200 uint32_t ioBuffSize; uint32_t ioBuffCachedSize; uint32_t status; SceOff ioBuffOffset; uint8_t nWay; uint8_t nArray; // Number of sets uint16_t flags; SceUID pid; uint32_t dataSize; // Size of each line of data void * dataBuff; void * ioBuff; int (*writeCb)(vfs_node_func6_args* args); SceUID hostBlock; // Only allocated when the node is on the host0: mount point void * unkBuff; // Ditto. Fixed 0x8200 size struct vfs_buff_data *dataSets[]; }; struct vfs_node //size is 0x100 { uint32_t unk_0; SceUID tid_4; //SceUID of thread in which node was created uint32_t some_counter_8; //counter SceUID event_flag_SceVfsVnode; // 0xC - event flag SceVfsVnode uint32_t evid_bits; // 0x10 uint32_t unk_14; uint32_t unk_18; uint32_t unk_1C; uint8_t data1[0x20]; node_ops2 *ops; // 0x40 uint32_t unk_44; void* dev_info; //allocated on heap with uid from uid field //this is device specific / node specific data //for partition node this will be vfs_device_info* //for pfs node it looks like to be child_node_info* //which probably points to partition node vfs_mount* mount; // 0x4C vfs_node* prev_node; // 0x50 vfs_node* unk_54; // copied from node base - singly linked list uint32_t some_counter_58; // counter - probably counter of nodes vfs_buff_cache *bc; uint32_t unk_60; uint32_t unk_64; uint32_t unk_68; SceUID pool_uid; // 0x6C - SceIoVfsHeap or other pool vfs_node_70* unk_70; uint32_t unk_74; // = 0x8000 uint32_t unk_78; // SceIoAccessMode uint32_t unk_7C; uint32_t unk_80; uint32_t unk_84; uint32_t unk_88; uint32_t unk_8C; SceVfsFileClassObject *obj_internal_90; uint32_t maybe_internal_obj_count_94; vfs_node* child_node; // child node with deeper level of i/o implementation? uint32_t unk_9C; uint8_t data2[0x30]; uint32_t unk_D0; // devMajor.w.unk_4E uint8_t data3[0x2C]; }vfs_node; //size is 0x20 struct vfs_obj_file_info { char *file; int file_len; int some_index; int unkC; int unk10; int unk14; int flags; SceMode mode; }; //this one is aquired by <code>sceKernelCreateUidObj</code> //then add offset 8 to that object base since first 8 bytes are reserved typedef struct SceVfsFileClassObject { SceBool is_dir_handler; int flags; // open flags SceOff offset; //for example used in Read/Pread int flags2; // 0x10 some flags SceUID pid; vfs_node *node; //0x18 SceVfsFileClassObject *prev_obj; void* device_handle; //0x20 - for Sdstor this will be sd_stor_device_handle* uint16_t unk24; uint8_t unk26; uint8_t unk27; vfs_fd_lock *fd_lock_ptr; //0x28 int devMinor; //0x2C vfs_obj_file_info *file_info; char unk34[12]; } SceVfsFileClassObject; typedef struct SceUIDVfsFileClassObject { SceObjectBase base; SceVfsFileClassObject vfs_object; } SceUIDVfsFileClassObject; //this one is acquired by sceKernelGetObjForUid using SceUID file descriptor //then add offset 8 to that object base since first 8 bytes are reserved typedef SceVfsFileClassObject vfs_object_base; typedef struct SceVfsPath { //size is 0xC char *path; SceSize path_len; char *path2; } SceVfsPath;
SceIofilemgrForDriver vfs callbacks
Vfs callbacks are harder to reverse since it looks like not all of them are exported. Looks like some of them are not even exposed as subroutines.
Here will go an attempt to desctibe interface of actual callbacks with single ctx argument (as opposed to exported functions that pack arguments into ctx)
vfs_func1
typedef struct vfs_func1_args { vfs_mount* arg0; void* arg1; }vfs_func1_args; int vfs_func1(vfs_func1_args* ctx)
vfs_func2
typedef struct vfs_func2_args { //fields are yet unknown }vfs_func2_args; int vfs_func2(vfs_func2_args* ctx)
vfs_func3
typedef struct vfs_func3_args { vfs_mount* arg0; uint32_t arg1; vfs_node* arg2; }vfs_func3_args; int vfs_func3(vfs_func3_args* ctx)
vfs_func4
typedef struct vfs_func4_args { vfs_node *node; uint32_t unk_4; uint32_t unk_8; //more fields? }vfs_func4_args; int vfs_func4(vfs_func4_args* ctx)
vfs_func7
typedef struct vfs_func7_args { //fields are yet unknown }vfs_func7_args; int vfs_func7(vfs_func7_args* ctx)
vfs_func9
typedef struct vfs_func9_args { //fields are yet unknown }vfs_func9_args; int vfs_func9(vfs_func9_args* ctx)
vfs_func10
typedef struct vfs_func10_args { //fields are yet unknown }vfs_func10_args; int vfs_func10(vfs_func10_args* ctx)
vfs_func12 (sceVfsDevctlForDriver)
Version | NID |
---|---|
3.60 | 0xB07B307D |
int vfs_func12(vfs_mount* mount, const char *dev, unsigned int cmd, void *indata, int inlen, void *outdata, int outlen); typedef struct vfs_func12_args { uint32_t unk_0; uint32_t unk_4; uint32_t unk_8; // some switch number char* name; uint32_t nameLength; uint32_t unk_14; uint32_t unk_18; //more fields ? }vfs_func12_args;
vfs_func13
Version | NID |
---|---|
3.60 | 0xF7DAC0F5 |
typedef struct vfs_func13_args { uint32_t unk_0; char* blockDeviceName; uint32_t unk_8; uint32_t unk_C; char* numericName; uint32_t blockDeviceNameLength; uint32_t* numericNameLength; }vfs_func13_args; int vfs_func13(vfs_func13_args* ctx)
SceIofilemgrForDriver vfs node callbacks
It looks like vfs callbacks are exported. Callbacks can be identified using these steps:
- Find all functions that contain indirect calls
- Locate only calls that use address, taken from table, that is pointed by vfs_node (offset 0x40, then valid offset inside pointer table)
- Trace back to first exported function (usually this is single export, not far away in call stack)
- Turns out ScePfsMgr and SceExfatfs use these exports from their vfs node function callbacks, so this information can be mapped/matched.
vfs_node_func1 (sceVfsNodeFunction1ForDriver)
Version | NID |
---|---|
3.60 | 0x76B79BEC |
Looks like the functionality of this function is related to sceIoOpenForDriver
Particular implementation of this function should assign device handler
(specific device info) object to object base
(descriptor object)
int vfs_node_func1(vfs_node* node, vfs_node_func1_opts* opt, int flags, void* objectBase); typedef struct vfs_node_func1_opts //size is 0xC { uint32_t unk_0; uint32_t unk_4; uint32_t unk_8; }vfs_node_func1_opts; struct vfs_node_func1_args { vfs_node* node; vfs_node_func1_opts* opt; int flags; void* objectBase; }vfs_node_func1_args;
arguments are packed into vfs_node_func1_args
and passed to vfs_node_func1
callback
vfs_node_func2 (sceVfsNodeOpenForDriver)
Version | NID |
---|---|
3.60 | 0x9E347C7D |
int vfs_node_func2(vfs_node* new_node, vfs_node** node, void* opt, int flags, SceMode mode); struct vfs_node_func2_args { vfs_node* new_node; vfs_node** node; void* opt; int flags; SceMode mode; }vfs_node_func2_args;
arguments are packed into vfs_node_func2_args
and passed to vfs_node_func2
callback
vfs_node_func3 (sceVfsNodeCloseForDriver)
Version | NID |
---|---|
3.60 | 0x40944C2E |
int vfs_node_func3(vfs_node *node, void *objectBase); struct vfs_node_func3_args { vfs_node* node; void *objectBase; }vfs_node_func3_args;
arguments are packed into vfs_node_func3_args
and passed to vfs_node_func3
callback
vfs_node_func4 (sceVfsNodeInitializePartitionForDriver)
Version | NID |
---|---|
3.60 | 0xA5A6A55C |
This function is supposed to create new vfs_node and put it into new_node
.
int vfs_node_func4(vfs_node *node, vfs_node** new_node, vfs_node_func4_opts* opt, int flags); typedef struct vfs_node_func4_opts //size is 0x10 { uint32_t unk_0; uint32_t unk_4; uint32_t unk_8; uint32_t unk_C; }vfs_node_func4_opts; struct vfs_node_func4_args { vfs_node* node; vfs_node** new_node; //result vfs_node_func4_opts* opt; uint32_t flags; }vfs_node_func4_args;
arguments are packed into vfs_node_func4_args
and passed to vfs_node_func4
callback
vfs_node_func5 (sceVfsNodeReadForDriver)
Version | NID |
---|---|
3.60 | 0x570388A5 |
int vfs_node_func5(vfs_node *n0, void *objectBase, void *data, SceSize size, int *nBytesRead); struct vfs_node_func5_args { vfs_node* node; void* objectBase; void* data; SceSize size; }vfs_node_func5_args;
arguments are packed into vfs_node_func5_args
and passed to vfs_node_func5
callback
vfs_node_func6 (sceVfsNodeWriteForDriver)
Version | NID |
---|---|
3.60 | 0x9A68378D |
int vfs_node_func6(vfs_node *n0, void *objectBase, const void *data, SceSize size, int *nBytesWritten); struct vfs_node_func6_args { vfs_node* node; void* objectBase; const void* data; SceSize size; }vfs_node_func6_args;
arguments are packed into vfs_node_func6_args
and passed to vfs_node_func6
callback
vfs_node_func7 (sceVfsNodeLseekForDriver)
Version | NID |
---|---|
3.60 | 0xB2B13818 |
int vfs_node_func7(vfs_node *node, void* objectBase, SceOff offset, int whence); struct vfs_node_func7_args { vfs_node* node; void* objectBase; SceOff offset; int whence; }vfs_node_func7_args;
arguments are packed into vfs_node_func7_args
and passed to vfs_node_func7
callback
vfs_node_func8 (sceVfsNodeIoctlForDriver)
Version | NID |
---|---|
3.60 | 0x333C904D |
int vfs_node_func8(vfs_node* node, void* objectBase, unsigned int cmd, void *indata, int inlen, void *outdata, int outlen); struct vfs_node_func8_args { vfs_node* node; void* objectBase; unsigned int cmd; void *indata; int inlen; void *outdata; int outlen; }vfs_node_func8_args;
arguments are packed into vfs_node_func8_args
and passed to vfs_node_func8
callback
vfs_node_func9 (sceVfsNodeDeinitializePartitionForDriver)
Version | NID |
---|---|
3.60 | 0xDC1E7EE4 |
This function is supposed to deinitialize partition, related to specified nodes.
//unk = 0 int vfs_node_func9(vfs_node *new_node, vfs_node *node, void* opt, int unk); struct vfs_node_func9_args { vfs_node* new_node; vfs_node* node; void* opt; uint32_t unk; // = 0 }vfs_node_func9_args;
arguments are packed into vfs_node_func9_args
and passed to vfs_node_func9
callback
vfs_node_func10 (sceVfsNodeMkdirForDriver)
Version | NID |
---|---|
3.60 | 0x2F3F8C70 |
int vfs_node_func10(vfs_node* node, vfs_node** new_node, void *unk2, SceMode mode); struct vfs_node_func10_args { vfs_node* node; vfs_node** new_node; void *unk2; SceMode mode; }vfs_node_func10_args;
arguments are packed into vfs_node_func10_args
and passed to vfs_node_func10
callback
vfs_node_func11 (sceVfsNodeRmdirForDriver)
Version | NID |
---|---|
3.60 | 0x1D551105 |
int vfs_node_func11(vfs_node* node, vfs_node* new_node, vfs_node_func11_opts* opts, int unused); typedef struct vfs_node_func11_opts //size is 0xC { uint32_t unk_0; uint32_t unk_4; uint32_t unk_8; }vfs_node_func11_opts; struct vfs_node_func11_args { vfs_node* node; vfs_node* new_node; vfs_node_func11_opts* opts; }vfs_node_func11_args;
arguments are packed into vfs_node_func11_args
and passed to vfs_node_func11
callback
vfs_node_func12 (sceVfsNodeDopenForDriver)
Version | NID |
---|---|
3.60 | 0x00C9C2DD |
int vfs_node_func12(vfs_node* node, vfs_node_func12_opts* opts, void* objectBase); typedef struct vfs_node_func12_opts //size is 0xC { uint32_t unk_0; uint32_t unk_4; uint32_t unk_8; }vfs_node_func12_opts; struct vfs_node_func12_args { vfs_node* node; vfs_node_func12_opts* opts; void* objectBase; }vfs_node_func12_args;
arguments are packed into vfs_node_func12_args
and passed to vfs_node_func12
callback
vfs_node_func13 (sceVfsNodeDcloseForDriver)
Version | NID |
---|---|
3.60 | 0x1350F5C7 |
int vfs_node_func13(vfs_node* node, void* objectBase); struct vfs_node_func13_args { vfs_node* node; void* objectBase; }vfs_node_func13_args;
arguments are packed into vfs_node_func13_args
and passed to vfs_node_func13
callback
vfs_node_func14 (sceVfsNodeDreadForDriver)
Version | NID |
---|---|
3.60 | 0x77584C8F |
int vfs_node_func14(vfs_node* node, void* objectBase, SceIoDirent* dir); struct vfs_node_func14_args { vfs_node* node; void* objectBase; SceIoDirent* dir; }vfs_node_func14_args;
arguments are packed into vfs_node_func14_args
and passed to vfs_node_func14
callback
vfs_node_func15 (sceVfsNodeGetstatForDriver)
Version | NID |
---|---|
3.60 | 0x50A63ACF |
typedef struct vfs_node_func15_args { vfs_node* node; SceVfsPath *path_into; SceIoStat* stat; } vfs_node_func15_args; typedef struct SceVfsStat { // size is 0xC SceVfsNode *node; SceVfsPath *path_info; SceIoStat *stat; } SceVfsStat; int vfs_node_func15(vfs_node* node, vfs_node_func15_opts* opts, SceIoStat* stat);
arguments are packed into vfs_node_func15_args
and passed to vfs_node_func15
callback
vfs_node_func16 (sceVfsNodeChstatForDriver)
Version | NID |
---|---|
3.60 | 0x1974FA92 |
int vfs_node_func16(vfs_node* node, vfs_node_func16_opts* opts, SceIoStat *stat, int bits); typedef struct vfs_node_func16_opts //size is 0xC { uint32_t unk_0; uint32_t unk_4; uint32_t unk_8; }vfs_node_func16_opts; struct vfs_node_func16_args { vfs_node* node; vfs_node_func16_opts* opts; SceIoStat *stat; int bits; }vfs_node_func16_args;
arguments are packed into vfs_node_func16_args
and passed to vfs_node_func16
callback
vfs_node_func17 (sceVfsNodeRenameForDriver)
Version | NID |
---|---|
3.60 | 0x36A794C7 |
int vfs_node_func17(vfs_node* new_node0, vfs_node* node0, vfs_node_func17_opts0* opt0, vfs_node* new_node1, vfs_node** node1, vfs_node_func17_opts* opt1); typedef struct vfs_node_func17_opts0 //size is 0x10 { uint32_t unk_0; uint32_t unk_4; uint32_t unk_8; uint32_t unk_C; }vfs_node_func17_opts0; typedef struct vfs_node_func17_opts1 //size is 0x10 { uint32_t unk_0; uint32_t unk_4; uint32_t unk_8; uint32_t unk_C; }vfs_node_func17_opts1; struct vfs_node_func17_args { vfs_node* new_node0; vfs_node* node0; vfs_node_func17_opts0* opt0; vfs_node* new_node1; vfs_node** node1; vfs_node_func17_opts1* opt1; }vfs_node_func17_args;
arguments are packed into vfs_node_func17_args
and passed to vfs_node_func17
callback
vfs_node_func19 (sceVfsNodePreadForDriver)
Version | NID |
---|---|
3.60 | 0xABBC80E3 |
int vfs_node_func19(vfs_node *n0, void *objectBase, char *data, int size, SceOff offset, int *nBytesRead); struct vfs_node_func19_args { vfs_node* node; void* objectBase; void* data; SceSize size; SceOff offset; }vfs_node_func19_args;
arguments are packed into vfs_node_func19_args
and passed to vfs_node_func19
callback
vfs_node_func20 (sceVfsNodePwriteForDriver)
Version | NID |
---|---|
3.60 | 0xA53C040D |
int vfs_node_func20(vfs_node *n0, void *objectBase, void *data, int size, SceOff offset, int *nBytesWritten); struct vfs_node_func20_args { vfs_node* node; void* objectBase; const void* data; SceSize size; SceOff offset; }vfs_node_func20_args;
arguments are packed into vfs_node_func20_args
and passed to vfs_node_func20
callback
vfs_node_func21 (sceVfsNodeNodeFunction21ForDriver)
Version | NID |
---|---|
3.60 | 0x8FB94521 |
This function is used by several i/o functions and it`s purpose is unknown.
int vfs_node_func21(vfs_node *node); struct vfs_node_func21_args { vfs_node* node; }vfs_node_func21_args;
arguments are packed into vfs_node_func21_args
and passed to vfs_node_func21
callback
vfs_node_func22 (sceVfsNodeNodeFunction22ForDriver)
Version | NID |
---|---|
3.60 | 0x942AA61F |
This function is not used by any of the i/o operations.
int vfs_node_func22(vfs_node *node, void* unk1); struct vfs_node_func22_args { vfs_node* node; void* unk1; //this is probably vfs_node* as well }vfs_node_func22_args;
arguments are packed into vfs_node_func22_args
and passed to vfs_node_func22
callback
vfs_node_func23 (sceVfsNodeNodeFunction23ForDriver)
Version | NID |
---|---|
3.60 | 0x0D8A806E |
This function is not used by any of the i/o operations.
int vfs_node_func23(vfs_node *node, void* unk1); struct vfs_node_func23_args { vfs_node* node; void* unk1; //this is probably vfs_node* as well }vfs_node_func23_args;
arguments are packed into vfs_node_func23_args
and passed to vfs_node_func23
callback
vfs_node_func24 (sceVfsNodeSyncForDriver)
Version | NID |
---|---|
3.60 | 0x9CD96406 |
int vfs_node_func24(vfs_node *node, void *objectBase, int flag); struct vfs_node_func24_args { vfs_node* node; void *objectBase; int flag; }vfs_node_func24_args;
arguments are packed into vfs_node_func24_args
and passed to vfs_node_func24
callback
vfs_node_func25 (sceVfsNodeGetstatByFdForDriver)
Version | NID |
---|---|
3.60 | 0x1DBCBB01 |
int vfs_node_func25(vfs_node *node, void* objectBase, SceIoStat *stat); struct vfs_node_func25_args { vfs_node* node; void* objectBase; SceIoStat *stat; }vfs_node_func25_args;
arguments are packed into vfs_node_func25_args
and passed to vfs_node_func25
callback
vfs_node_func26 (sceVfsNodeChstatByFdForDriver)
Version | NID |
---|---|
3.60 | 0x082AFD7F |
int vfs_node_func26(vfs_node *node, void *objectBase, SceIoStat *stat, int bits); struct vfs_node_func26_args { vfs_node* node; void *objectBase; SceIoStat *stat; int bits; }vfs_node_func26_args;
arguments are packed into vfs_node_func26_args
and passed to vfs_node_func26
callback
vfs_node_func27 (sceVfsNodeRemoveForDriver)
Version | NID |
---|---|
3.60 | 0xF53399BC |
int vfs_node_func27(vfs_node* new_node, vfs_node* node, void* unk2, void* mem_chunk); struct vfs_node_func27_args { vfs_node* new_node; vfs_node* node; void* unk2; void* mem_chunk; // block of size 0x400. has "SCEDEL~" string in the beginning. uint32_t unk_10; // = 0 uint32_t unk_14; // = 0 }vfs_node_func27_args;
arguments are packed into vfs_node_func27_args
and passed to vfs_node_func27
callback
vfs_node_func28 (sceVfsNodeFunction28ForDriver)
Version | NID |
---|---|
3.60 | 0x0F7E1718 |
Looks like the purpose of this function is to close
some resource by SceUID like sceIoCloseForDriver
or sceIoDcloseForDriver
.
int vfs_node_func28(vfs_node *node, void *objectBase, int unused0, int unused1); struct vfs_node_func28_args { vfs_node* node; uint32_t objectBase; uint32_t unk_8; // = 0 uint32_t unk_C; // = 0 }vfs_node_func28_args;
arguments are packed into vfs_node_func28_args
and passed to vfs_node_func28
callback
vfs_node_func29 (sceVfsNodeFunction29ForDriver)
Version | NID |
---|---|
3.60 | 0xEEAE8B51 |
This function is not implemented by any of the VFS nodes.
int vfs_node_func29(vfs_node* node, SceInt64 unk1, SceInt64 unk2, int arg_8, int arg_C); struct vfs_node_func29_args { vfs_node* node; uint32_t dummy; //alignment SceInt64 unk1; SceInt64 unk2; uint32_t arg_8; uint32_t arg_C; }vfs_node_func29_args;
arguments are packed into vfs_node_func29_args
and passed to vfs_node_func29
callback