VFS Implementation

VFS Operations

 * implemented operation is marked as
 * not implemented is marked as
 * return 0 placeholder is marked as
 * return error is marked with corresponding error name

VFS Node Operations

 * implemented operation is marked as
 * not implemented is marked as
 * return 0 placeholder is marked as
 * return error is marked with corresponding error name

Typical i/o operation execution
This is a very brief desctiption for overall understanding of io  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  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
 * 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  and calls exported function like
 * exported function packs all arguments into single stucture and calls real callback since it has  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  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  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.

However there are exceptions: sceIoLseek32, sceIoIoctlForDriver, sceIoDevctlForDriver, sceIoGetstatForDriver_2, sceIoChstatForDriver_2, sceIoDreadForDriver_2 do not have async version.

Types
//then add offset 8 to that object base since first 8 bytes are reserved

struct SceUIDVfsFileClassInternal { int unk0; int unk4; SceOff offset; //for example used in Read/Pread int flags; // 0x10 some flags int unk14; vfs_node *node; //0x18 SceUIDVfsFileClassInternal *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]; };

struct SceUIDVfsFileClassObj { SceObjectBase base; SceUIDVfsFileClassInternal internal; };

//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 SceUIDVfsFileClassInternal vfs_object_base;

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)

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)
Looks like the functionality of this function is related to

Particular implementation of this function should assign  (specific device info) object to   (descriptor object)

arguments are packed into  and passed to   callback

vfs_node_func2 (sceVfsNodeOpenForDriver)
arguments are packed into  and passed to   callback

vfs_node_func3 (sceVfsNodeCloseForDriver)
arguments are packed into  and passed to   callback

vfs_node_func4 (sceVfsNodeInitializePartitionForDriver)
This function is supposed to create new vfs_node and put it into.

arguments are packed into  and passed to   callback

vfs_node_func5 (sceVfsNodeReadForDriver)
arguments are packed into  and passed to   callback

vfs_node_func6 (sceVfsNodeWriteForDriver)
arguments are packed into  and passed to   callback

vfs_node_func7 (sceVfsNodeLseekForDriver)
arguments are packed into  and passed to   callback

vfs_node_func8 (sceVfsNodeIoctlForDriver)
arguments are packed into  and passed to   callback

vfs_node_func9 (sceVfsNodeDeinitializePartitionForDriver)
This function is supposed to deinitialize partition, related to specified nodes.

arguments are packed into  and passed to   callback

vfs_node_func10 (sceVfsNodeMkdirForDriver)
arguments are packed into  and passed to   callback

vfs_node_func11 (sceVfsNodeRmdirForDriver)
arguments are packed into  and passed to   callback

vfs_node_func12 (sceVfsNodeDopenForDriver)
arguments are packed into  and passed to   callback

vfs_node_func13 (sceVfsNodeDcloseForDriver)
arguments are packed into  and passed to   callback

vfs_node_func14 (sceVfsNodeDreadForDriver)
arguments are packed into  and passed to   callback

vfs_node_func15 (sceVfsNodeGetstatForDriver)
arguments are packed into  and passed to   callback

vfs_node_func16 (sceVfsNodeChstatForDriver)
arguments are packed into  and passed to   callback

vfs_node_func17 (sceVfsNodeRenameForDriver)
arguments are packed into  and passed to   callback

vfs_node_func19 (sceVfsNodePreadForDriver)
arguments are packed into  and passed to   callback

vfs_node_func20 (sceVfsNodePwriteForDriver)
arguments are packed into  and passed to   callback

vfs_node_func21 (sceVfsNodeNodeFunction21ForDriver)
This function is used by several i/o functions and it`s purpose is unknown.

arguments are packed into  and passed to   callback

vfs_node_func22 (sceVfsNodeNodeFunction22ForDriver)
This function is not used by any of the i/o operations.

arguments are packed into  and passed to   callback

vfs_node_func23 (sceVfsNodeNodeFunction23ForDriver)
This function is not used by any of the i/o operations.

arguments are packed into  and passed to   callback

vfs_node_func24 (sceVfsNodeSyncForDriver)
arguments are packed into  and passed to   callback

vfs_node_func25 (sceVfsNodeGetstatByFdForDriver)
arguments are packed into  and passed to   callback

vfs_node_func26 (sceVfsNodeChstatByFdForDriver)
arguments are packed into  and passed to   callback

vfs_node_func27 (sceVfsNodeRemoveForDriver)
arguments are packed into  and passed to   callback

vfs_node_func28 (sceVfsNodeFunction28ForDriver)
Looks like the purpose of this function is to  some resource by SceUID like   or.

arguments are packed into  and passed to   callback

vfs_node_func29 (sceVfsNodeFunction29ForDriver)
This function is not implemented by any of the VFS nodes.

arguments are packed into  and passed to   callback