VFS Implementation: Difference between revisions

From Vita Development Wiki
Jump to navigation Jump to search
(→‎Types: Add structures for the VFS buffer cache)
 
(109 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 167: Line 167:
! Index !! Normal Operation !! Async Operation !! Vfs Node Function !! Vfs Function
! Index !! Normal Operation !! Async Operation !! Vfs Node Function !! Vfs Function
|-
|-
| 1 || sceIoOpenForDriver || sceIoOpenAsyncForDriver || ||  
| 1 || sceIoOpenForDriver || sceIoOpenAsyncForDriver || 2 || N/A
|-
|-
| 2 || sceIoCloseForDriver || sceIoCloseAsyncForDriver || ||  
| 2 || sceIoCloseForDriver || sceIoCloseAsyncForDriver || 3 || N/A
|-
|-
| 3 || sceIoReadForDriver || sceIoReadAsyncForDriver || 5 || N/A
| 3 || sceIoReadForDriver || sceIoReadAsyncForDriver || 5 || N/A
Line 181: Line 181:
| 7 || sceIoIoctlForDriver || N/A || 8 || N/A
| 7 || sceIoIoctlForDriver || N/A || 8 || N/A
|-
|-
| 8 || sceIoRemoveForDriver || sceIoRemoveAsyncForDriver || ||  
| 8 || sceIoRemoveForDriver || sceIoRemoveAsyncForDriver || 27 || N/A
|-
|-
| 9 || sceIoDopenForDriver || sceIoDopenAsyncForDriver || ||  
| 9 || sceIoDopenForDriver || sceIoDopenAsyncForDriver || 12 || N/A
|-
|-
| 10 || sceIoDcloseForDriver || sceIoDcloseAsyncForDriver || ||  
| 10 || sceIoDcloseForDriver || sceIoDcloseAsyncForDriver || 13 || N/A
|-
|-
| 11 || sceIoDreadForDriver || sceIoDreadAsyncForDriver || 14 || N/A
| 11 || sceIoDreadForDriver || sceIoDreadAsyncForDriver || 14 || N/A
Line 191: Line 191:
| 12 || sceIoMkdirForDriver || sceIoMkdirAsyncForDriver || 10 || N/A
| 12 || sceIoMkdirForDriver || sceIoMkdirAsyncForDriver || 10 || N/A
|-
|-
| 13 || sceIoRmdirForDriver || sceIoRmdirAsyncForDriver || ||  
| 13 || sceIoRmdirForDriver || sceIoRmdirAsyncForDriver || 11 || N/A
|-
|-
| 14 || sceIoRenameForDriver || sceIoRenameAsyncForDriver || ||  
| 14 || sceIoRenameForDriver || sceIoRenameAsyncForDriver || 17 || N/A
|-
|-
| 15 || sceIoChstatForDriver || sceIoChstatAsyncForDriver || 16 || N/A
| 15 || sceIoChstatForDriver || sceIoChstatAsyncForDriver || 16 || N/A
Line 250: Line 250:
struct node_ops2 // size is 0x74 (29 pointers)
struct node_ops2 // size is 0x74 (29 pointers)
{
{
   int (*func1)(void* ctx); // sceIoOpenForDriver (this function creates device handle) (It operates with normal block device name and unix mount)
   int (*sceVfsNodeFunction1ForDriver)(vfs_node_func1_args* args);
   int (*func2)(void* ctx); // sceIoOpenForDriver (another one ?)
   int (*sceVfsNodeOpenForDriver)(vfs_node_func2_args* args);
   int (*func3)(void* ctx); // sceIoOpenForDriver (another one ?) or sceIoCloseForDriver
   int (*sceVfsNodeCloseForDriver)(vfs_node_func3_args* args);
   int (*func4)(void* ctx); // add partition (add vfsNode) (initialize partition entry in table) (for example happens on card insert exclusively) (operates with numeric names)
   int (*sceVfsNodeInitializePartitionForDriver)(vfs_node_func4_args* args);
   int (*func5)(void* ctx); // sceIoReadForDriver
   int (*sceVfsNodeReadForDriver)(vfs_node_func5_args* args);
   int (*func6)(void* ctx); // sceIoWriteForDriver
   int (*sceVfsNodeWriteForDriver)(vfs_node_func6_args* args);
   int (*func7)(void* ctx); // sceIoLseekForDriver or sceIoLseek32?
   int (*sceVfsNodeLseekForDriver)(vfs_node_func7_args* args);
   int (*func8)(void* ctx); // sceIoIoctlForDriver
   int (*sceVfsNodeIoctlForDriver)(vfs_node_func8_args* args);
   int (*func9)(void* ctx); // remove partition (remove vfsNode) (deinitialize partition entry in table) (for example happens on card remove exclusively) (operates with numeric names)
   int (*sceVfsNodeDeinitializePartitionForDriver)(vfs_node_func9_args* args);
   int (*func10)(void* ctx); // sceIoMkdirForDriver
   int (*sceVfsNodeMkdirForDriver)(vfs_node_func10_args* args);
   int (*func11)(void* ctx); // sceIoRmdirForDriver
   int (*sceVfsNodeRmdirForDriver)(vfs_node_func11_args* args);
   int (*func12)(void* ctx); // sceIoDopenForDriver
   int (*sceVfsNodeDopenForDriver)(vfs_node_func12_args* args);
   int (*func13)(void* ctx); // sceIoDcloseForDriver
   int (*sceVfsNodeDcloseForDriver)(vfs_node_func13_args* args);
   int (*func14)(void* ctx); // sceIoDreadForDriver
   int (*sceVfsNodeDreadForDriver)(vfs_node_func14_args* args);
   int (*func15)(void* ctx); // sceIoGetstatForDriver or sceIoGetstatByFdForDriver
   int (*sceVfsNodeGetstatForDriver)(vfs_node_func15_args* args);
   int (*func16)(void* ctx); // sceIoChstatForDriver or sceIoChstatByFdForDriver
   int (*sceVfsNodeChstatForDriver)(vfs_node_func16_args* args);
   int (*func17)(void* ctx); // sceIoRenameForDriver
   int (*sceVfsNodeRenameForDriver)(vfs_node_func17_args* args);
   int (*func18)(void* ctx); // not implemented by all
   int (*sceVfsNodeFunction18ForDriver)(void* args); //not implemented
   int (*func19)(void* ctx); // sceIoPreadForDriver
   int (*sceVfsNodePreadForDriver)(vfs_node_func19_args* args);
   int (*func20)(void* ctx); // sceIoPwriteForDriver
   int (*sceVfsNodePwriteForDriver)(vfs_node_func20_args* args);
   int (*func21)(void* ctx); // ?
   int (*sceVfsNodeFunction21ForDriver)(vfs_node_func21_args* args);
   int (*func22)(void* ctx); // not referenced
   int (*sceVfsNodeFunction22ForDriver)(vfs_node_func22_args* args);
   int (*func23)(void* ctx); // not referenced
   int (*sceVfsNodeFunction23ForDriver)(vfs_node_func23_args* args);
   int (*func24)(void* ctx); // sceIoSyncForDriver or sceIoSyncByFdForDriver
   int (*sceVfsNodeSyncForDriver)(vfs_node_func24_args* args);
   int (*func25)(void* ctx); // sceIoGetstatByFdForDriver
   int (*sceVfsNodeGetstatByFdForDriver)(vfs_node_func25_args* args);
   int (*func26)(void* ctx); // sceIoChstatByFdForDriver
   int (*sceVfsNodeChstatByFdForDriver)(vfs_node_func26_args* args);
   int (*func27)(void* ctx); // ?
   int (*sceVfsNodeRemoveForDriver)(vfs_node_func27_args* args);
   int (*func28)(void* ctx); // ?
   int (*sceVfsNodeFunction28ForDriver)(vfs_node_func28_args* args);
   int (*func29)(void* ctx); // not implemented by all
   int (*sceVfsNodeFunction29ForDriver)(vfs_node_func29_args* args);
};
};


Line 304: Line 304:


   char* filesystem;
   char* filesystem;
   pfs_pmi_buffer_list_ctx* bcl; //holds klicensee
   pfs_pmi_buffer_list_ctx* blc; //holds klicensee
   vfs_block_dev_info* blockDev1;
   vfs_block_dev_info* blockDev1;
   uint32_t unk_1C; //zero
   node_ops2* ops2;
} vfs_mount_point_info_base;
} vfs_mount_point_info_base;


Line 342: Line 342:
   SceUID cond_SceVfsFdCond;
   SceUID cond_SceVfsFdCond;
   uint32_t unk_8;
   uint32_t unk_8;
   uint32_t unk_C;
   uint32_t toggle; //inc before condition wait. dec after condition wait.


} vfs_fd_lock;
} vfs_fd_lock;
Line 357: Line 357:
typedef struct vfs_mount //size is not known exactly, at least 0xD0 + 0x10 + 0x10
typedef struct vfs_mount //size is not known exactly, at least 0xD0 + 0x10 + 0x10
{
{
   uint32_t fast_mutex_SceVfsMnt;
   fast_mutex SceVfsMnt; // size is 0x40
 
  uint32_t unk_4;
  uint32_t unk_8;
  uint32_t unk_C;
 
  uint8_t data1[0x30];


   vfs_node* unk_40; // child ?
   vfs_node* unk_40; // child ?
Line 397: Line 391:
   vfs_add_data* add_data; // 0x5C
   vfs_add_data* add_data; // 0x5C


   uint32_t unk_60;  // counter
   uint32_t some_counter_60;  // counter


   uint32_t unk_64;
   uint32_t unk_64;
Line 414: Line 408:
   uint32_t unk_C0;   
   uint32_t unk_C0;   


   pfs_pmi_buffer_list_ctx* bcl; // C4 - from vfs_mount_point_info_base
   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 454: 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;
   uint32_t unk_4; // most likely SceUID of current thread
   SceUID tid_4; //SceUID of thread in which node was created
   uint32_t unk_8; // counter
   uint32_t some_counter_8; //counter
   SceUID event_flag_SceVfsVnode; // 0xC - event flag SceVfsVnode
   SceUID event_flag_SceVfsVnode; // 0xC - event flag SceVfsVnode


Line 478: Line 507:
                     //which probably points to partition node
                     //which probably points to partition node


   vfs_mount* node; // 0x4C
   vfs_mount* mount; // 0x4C


   vfs_node* prev_node; // 0x50
   vfs_node* prev_node; // 0x50


   vfs_node* unk_54; // copied from node base - singly linked list
   vfs_node* unk_54; // copied from node base - singly linked list
   uint32_t unk_58;  // counter - probably counter of nodes
   uint32_t some_counter_58;  // counter - probably counter of nodes
   void* unk_5C;
   vfs_buff_cache *bc;


   uint32_t unk_60;
   uint32_t unk_60;
Line 493: 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; // some flag
   uint32_t unk_78; // SceIoAccessMode
   uint32_t unk_7C;
   uint32_t unk_7C;


Line 501: Line 530:
   uint32_t unk_8C;
   uint32_t unk_8C;


   uint32_t unk_90; //void* objectBase ?
   SceVfsFileClassObject *obj_internal_90;
   uint32_t unk_94;
   uint32_t maybe_internal_obj_count_94;
   vfs_node* unk_98; //some child node
   vfs_node* child_node; // child node with deeper level of i/o implementation?
   uint32_t unk_9C;
   uint32_t unk_9C;


Line 514: Line 543:
}vfs_node;
}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;
</source>
</source>


Line 603: Line 681:
</source>
</source>


=== vfs_func12 ===
=== vfs_func12 (sceVfsDevctlForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 668: Line 746:
*Turns out ScePfsMgr and SceExfatfs use these exports from their vfs node function callbacks, so this information can be mapped/matched.
*Turns out ScePfsMgr and SceExfatfs use these exports from their vfs node function callbacks, so this information can be mapped/matched.


=== vfs_node_func1 ===
=== vfs_node_func1 (sceVfsNodeFunction1ForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 676: Line 754:
|-
|-
|}
|}
<source lang="c">
int vfs_node_func1(vfs_node *node, vnf1_arg1* dev, int unk2, int unk3);


struct vnf1_arg1
Looks like the functionality of this function is related to <code>sceIoOpenForDriver</code>
{
 
  char* blockDevice;
Particular implementation of this function should assign <code>device handler</code> (specific device info) object to <code>object base</code> (descriptor object)
  uint32_t nameLength;
  char* unixMount;
}vnf1_arg1;


//this type applies only to SceSdif
<source lang="c">
int vfs_node_func1(vfs_node* node, vfs_node_func1_opts* opt, int flags, void* objectBase);


struct vnf1_arg3
typedef struct vfs_node_func1_opts //size is 0xC
{
{
  uint32_t unk_0;
  uint32_t unk_0;
  uint32_t unk_4;
  uint32_t unk_4;
  uint32_t unk_8;
  uint32_t unk_8;
  uint32_t unk_C;


  uint32_t unk_10;
}vfs_node_func1_opts;
  uint32_t unk_14;
  uint32_t unk_18;
  uint32_t unk_1C;
 
  sd_stor_device_handle* handle;
 
  //not sure about size, can be more fields ?
 
}vnf1_arg3;


struct vfs_node_func1_args
struct vfs_node_func1_args
{
{
   vfs_node* node;
   vfs_node* node;
   vnf1_arg1* arg1; //ignored (applies to SceSdif)
   vfs_node_func1_opts* opt;
   uint32_t arg2;
   int flags;
   vnf1_arg3* arg3; //result (applies to SceSdif)
   void* objectBase;
}vfs_node_func1_args;
}vfs_node_func1_args;


Line 718: Line 782:
arguments are packed into <code>vfs_node_func1_args</code> and passed to <code>vfs_node_func1</code> callback
arguments are packed into <code>vfs_node_func1_args</code> and passed to <code>vfs_node_func1</code> callback


=== vfs_node_func2 ===
=== vfs_node_func2 (sceVfsNodeOpenForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 727: Line 791:
|}
|}
<source lang="c">
<source lang="c">
int vfs_node_func2(vfs_node *node, int unk1, int unk2, int unk3, int arg_0);
int vfs_node_func2(vfs_node* new_node, vfs_node** node, void* opt, int flags, SceMode mode);


struct vfs_node_func2_args
struct vfs_node_func2_args
{
{
   vfs_node* node;
   vfs_node* new_node;
   uint32_t arg1;
   vfs_node** node;
   uint32_t arg2;
   void* opt;
   uint32_t arg3;
   int flags;
   uint32_t arg_0;
   SceMode mode;
}vfs_node_func2_args;
}vfs_node_func2_args;


Line 742: Line 806:
arguments are packed into <code>vfs_node_func2_args</code> and passed to <code>vfs_node_func2</code> callback
arguments are packed into <code>vfs_node_func2_args</code> and passed to <code>vfs_node_func2</code> callback


=== vfs_node_func3 ===
=== vfs_node_func3 (sceVfsNodeCloseForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 751: Line 815:
|}
|}
<source lang="c">
<source lang="c">
int vfs_node_func3(vfs_node *node, int unk1);
int vfs_node_func3(vfs_node *node, void *objectBase);


struct vfs_node_func3_args
struct vfs_node_func3_args
{
{
   vfs_node* node;
   vfs_node* node;
   uint32_t arg1;
   void *objectBase;
}vfs_node_func3_args;
}vfs_node_func3_args;


Line 763: Line 827:
arguments are packed into <code>vfs_node_func3_args</code> and passed to <code>vfs_node_func3</code> callback
arguments are packed into <code>vfs_node_func3_args</code> and passed to <code>vfs_node_func3</code> callback


=== vfs_node_func4 ===
=== vfs_node_func4 (sceVfsNodeInitializePartitionForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 771: Line 835:
|-
|-
|}
|}
This function is supposed to create new vfs_node and put it into <code>new_node</code>.
<source lang="c">
<source lang="c">
int vfs_node_func4(vfs_node *node, vfs_node** new_node, vnf4_arg2* dev, int unk3);
int vfs_node_func4(vfs_node *node, vfs_node** new_node, vfs_node_func4_opts* opt, int flags);


struct vnf4_arg2
typedef struct vfs_node_func4_opts //size is 0x10
{
{
   char* blockDeviceName;
   uint32_t unk_0;
   int nameLength;
   uint32_t unk_4;
} vnf4_arg2;
  uint32_t unk_8;
  uint32_t unk_C;
}vfs_node_func4_opts;


struct vfs_node_func4_args
struct vfs_node_func4_args
Line 784: Line 853:
   vfs_node* node;  
   vfs_node* node;  
   vfs_node** new_node; //result
   vfs_node** new_node; //result
   vnf4_arg2* dev;
   vfs_node_func4_opts* opt;
   uint32_t arg3; //ignored (applies to SceSdif)
   uint32_t flags;  
}vfs_node_func4_args;
}vfs_node_func4_args;


Line 792: Line 861:
arguments are packed into <code>vfs_node_func4_args</code> and passed to <code>vfs_node_func4</code> callback
arguments are packed into <code>vfs_node_func4_args</code> and passed to <code>vfs_node_func4</code> callback


=== vfs_node_func5 ===
=== vfs_node_func5 (sceVfsNodeReadForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 815: Line 884:
arguments are packed into <code>vfs_node_func5_args</code> and passed to <code>vfs_node_func5</code> callback
arguments are packed into <code>vfs_node_func5_args</code> and passed to <code>vfs_node_func5</code> callback


=== vfs_node_func6 ===
=== vfs_node_func6 (sceVfsNodeWriteForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 838: Line 907:
arguments are packed into <code>vfs_node_func6_args</code> and passed to <code>vfs_node_func6</code> callback
arguments are packed into <code>vfs_node_func6_args</code> and passed to <code>vfs_node_func6</code> callback


=== vfs_node_func7 ===
=== vfs_node_func7 (sceVfsNodeLseekForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 847: Line 916:
|}
|}
<source lang="c">
<source lang="c">
int vfs_node_func7(vfs_node *node, vnf7_arg1* objectBase, SceOff offset, int whence);
int vfs_node_func7(vfs_node *node, void* objectBase, SceOff offset, int whence);
 
struct vnf7_arg1
{
  uint32_t unk_0;
  uint32_t unk_4;
  uint32_t unk_8;
  uint32_t unk_C;
 
  uint32_t unk_10;
  uint32_t unk_14;
  uint32_t unk_18;
  uint32_t unk_1C;
 
  void* unk_20; // pointer to structure. most likely device specific that has fast_mutex as first field
 
} vnf7_arg1;


struct vfs_node_func7_args
struct vfs_node_func7_args
{
{
   vfs_node* node;
   vfs_node* node;
   vnf7_arg1* objectBase; //some structure
   void* objectBase;
   SceOff offset
   SceOff offset;
   int whence
   int whence;
}vfs_node_func7_args;
}vfs_node_func7_args;


Line 877: Line 930:
arguments are packed into <code>vfs_node_func7_args</code> and passed to <code>vfs_node_func7</code> callback
arguments are packed into <code>vfs_node_func7_args</code> and passed to <code>vfs_node_func7</code> callback


=== vfs_node_func8 ===
=== vfs_node_func8 (sceVfsNodeIoctlForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 903: Line 956:
arguments are packed into <code>vfs_node_func8_args</code> and passed to <code>vfs_node_func8</code> callback
arguments are packed into <code>vfs_node_func8_args</code> and passed to <code>vfs_node_func8</code> callback


=== vfs_node_func9 ===
=== vfs_node_func9 (sceVfsNodeDeinitializePartitionForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 911: Line 964:
|-
|-
|}
|}
<source lang="c">
int vfs_node_func9(vfs_node *node0, vfs_node *node1, void *ctx, int unk);


need to confirm this type with dump
This function is supposed to deinitialize partition, related to specified nodes.


typedef struct vnf9_arg2 //most likely this type is also vfs_node (same partial layout of fields)
<source lang="c">
{
//unk = 0
  char* blockDeviceName;
int vfs_node_func9(vfs_node *new_node, vfs_node *node, void* opt, int unk);
  int nameLength;
  uint32_t unk_8;
  uint32_t unk_C;
 
  uint32_t unk_10;
  uint32_t unk_14;
  uint32_t unk_18;
  uint32_t unk_1C;
 
  uint32_t unk_20;
  uint32_t unk_24;
  uint32_t unk_28;
  uint32_t unk_2C;
 
  uint32_t unk_30;
  uint32_t unk_34;
  uint32_t unk_38;
  uint32_t unk_3C;
 
  uint32_t unk_40;
  uint32_t unk_44;
  partition_entry** unk_48;
}vnf9_arg2;


struct vfs_node_func9_args
struct vfs_node_func9_args
{
{
   vfs_node* node0;
   vfs_node* new_node;
   vfs_node* node1;
   vfs_node* node;
   vnf9_arg2* arg2;
   void* opt;
   uint32_t arg3; //ignored (applies to SceSdif)
   uint32_t unk; // = 0
}vfs_node_func9_args;
}vfs_node_func9_args;


Line 955: Line 983:
arguments are packed into <code>vfs_node_func9_args</code> and passed to <code>vfs_node_func9</code> callback
arguments are packed into <code>vfs_node_func9_args</code> and passed to <code>vfs_node_func9</code> callback


=== vfs_node_func10 ===
=== vfs_node_func10 (sceVfsNodeMkdirForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 964: Line 992:
|}
|}
<source lang="c">
<source lang="c">
int vfs_node_func10(vfs_node* node, void* unk1, void* unk2, SceMode mode);
int vfs_node_func10(vfs_node* node, vfs_node** new_node, void *unk2, SceMode mode);


struct vfs_node_func10_args
struct vfs_node_func10_args
{
{
   vfs_node* node;
   vfs_node* node;
   void* arg1;
   vfs_node** new_node;
   void* arg2;
   void *unk2;
   SceMode mode;
   SceMode mode;
}vfs_node_func10_args;
}vfs_node_func10_args;
Line 978: Line 1,006:
arguments are packed into <code>vfs_node_func10_args</code> and passed to <code>vfs_node_func10</code> callback
arguments are packed into <code>vfs_node_func10_args</code> and passed to <code>vfs_node_func10</code> callback


=== vfs_node_func11 ===
=== vfs_node_func11 (sceVfsNodeRmdirForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 987: Line 1,015:
|}
|}
<source lang="c">
<source lang="c">
int vfs_node_func11(vfs_node *node, int unk1, int unk2, int unused);
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
struct vfs_node_func11_args
{
{
   vfs_node* node;
   vfs_node* node;
   uint32_t arg1;
   vfs_node* new_node;
   uint32_t arg2;
   vfs_node_func11_opts* opts;
}vfs_node_func11_args;
}vfs_node_func11_args;


Line 1,000: Line 1,036:
arguments are packed into <code>vfs_node_func11_args</code> and passed to <code>vfs_node_func11</code> callback
arguments are packed into <code>vfs_node_func11_args</code> and passed to <code>vfs_node_func11</code> callback


=== vfs_node_func12 ===
=== vfs_node_func12 (sceVfsNodeDopenForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 1,009: Line 1,045:
|}
|}
<source lang="c">
<source lang="c">
int vfs_node_func12(vfs_node *node, int unk1, int unk2);
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
struct vfs_node_func12_args
{
{
   vfs_node* node;
   vfs_node* node;
   uint32_t arg1;
   vfs_node_func12_opts* opts;
   uint32_t arg2;
   void* objectBase;
}vfs_node_func12_args;
}vfs_node_func12_args;


Line 1,022: Line 1,066:
arguments are packed into <code>vfs_node_func12_args</code> and passed to <code>vfs_node_func12</code> callback
arguments are packed into <code>vfs_node_func12_args</code> and passed to <code>vfs_node_func12</code> callback


=== vfs_node_func13 ===
=== vfs_node_func13 (sceVfsNodeDcloseForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 1,031: Line 1,075:
|}
|}
<source lang="c">
<source lang="c">
int vfs_node_func13(vfs_node *node, int unk1);
int vfs_node_func13(vfs_node* node, void* objectBase);


struct vfs_node_func13_args
struct vfs_node_func13_args
{
{
   vfs_node* node;
   vfs_node* node;
   uint32_t arg1;
   void* objectBase;
}vfs_node_func13_args;
}vfs_node_func13_args;


Line 1,043: Line 1,087:
arguments are packed into <code>vfs_node_func13_args</code> and passed to <code>vfs_node_func13</code> callback
arguments are packed into <code>vfs_node_func13_args</code> and passed to <code>vfs_node_func13</code> callback


=== vfs_node_func14 ===
=== vfs_node_func14 (sceVfsNodeDreadForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 1,065: Line 1,109:
arguments are packed into <code>vfs_node_func14_args</code> and passed to <code>vfs_node_func14</code> callback
arguments are packed into <code>vfs_node_func14_args</code> and passed to <code>vfs_node_func14</code> callback


=== vfs_node_func15 ===
=== vfs_node_func15 (sceVfsNodeGetstatForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 1,074: Line 1,118:
|}
|}
<source lang="c">
<source lang="c">
int vfs_node_func15(vfs_node *node, vfs_node_func15_arg1* arg1, SceIoStat* stat);


typedef struct vfs_node_func15_arg1 //size is 0x10
typedef struct vfs_node_func15_args {
{
  char* data; //from vfs_node_70 at 0x18
  int len;
  int unk_8;
  int unk_C;
 
}vfs_node_func15_arg1;
 
struct vfs_node_func15_args
{
   vfs_node* node;
   vfs_node* node;
   vfs_node_func15_arg1* arg1;
   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>


arguments are packed into <code>vfs_node_func15_args</code> and passed to <code>vfs_node_func15</code> callback
arguments are packed into <code>vfs_node_func15_args</code> and passed to <code>vfs_node_func15</code> callback


=== vfs_node_func16 ===
=== vfs_node_func16 (sceVfsNodeChstatForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 1,105: Line 1,145:
|}
|}
<source lang="c">
<source lang="c">
int vfs_node_func16(vfs_node *node, void *unk1, SceIoStat *stat, int bits);
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
struct vfs_node_func16_args
{
{
   vfs_node* node;
   vfs_node* node;
   uint32_t arg1;
   vfs_node_func16_opts* opts;
   SceIoStat *stat;
   SceIoStat *stat;
   int bits;
   int bits;
Line 1,119: Line 1,167:
arguments are packed into <code>vfs_node_func16_args</code> and passed to <code>vfs_node_func16</code> callback
arguments are packed into <code>vfs_node_func16_args</code> and passed to <code>vfs_node_func16</code> callback


=== vfs_node_func17 ===
=== vfs_node_func17 (sceVfsNodeRenameForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 1,128: Line 1,176:
|}
|}
<source lang="c">
<source lang="c">
int vfs_node_func17(vfs_node *node, int unk1, int unk2, int unk3, int arg_0, int arg_4);
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
struct vfs_node_func17_args
{
{
   vfs_node* node;
   vfs_node* new_node0;
   uint32_t arg1;
   vfs_node* node0;
   uint32_t arg2;
   vfs_node_func17_opts0* opt0;
   uint32_t arg3;
   vfs_node* new_node1;
   uint32_t arg_0;
   vfs_node** node1;
   uint32_t arg_4;
   vfs_node_func17_opts1* opt1;
}vfs_node_func17_args;
}vfs_node_func17_args;


Line 1,144: Line 1,208:
arguments are packed into <code>vfs_node_func17_args</code> and passed to <code>vfs_node_func17</code> callback
arguments are packed into <code>vfs_node_func17_args</code> and passed to <code>vfs_node_func17</code> callback


=== vfs_node_func19 ===
=== vfs_node_func19 (sceVfsNodePreadForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 1,168: Line 1,232:
arguments are packed into <code>vfs_node_func19_args</code> and passed to <code>vfs_node_func19</code> callback
arguments are packed into <code>vfs_node_func19_args</code> and passed to <code>vfs_node_func19</code> callback


=== vfs_node_func20 ===
=== vfs_node_func20 (sceVfsNodePwriteForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 1,192: Line 1,256:
arguments are packed into <code>vfs_node_func20_args</code> and passed to <code>vfs_node_func20</code> callback
arguments are packed into <code>vfs_node_func20_args</code> and passed to <code>vfs_node_func20</code> callback


=== vfs_node_func21 ===
=== vfs_node_func21 (sceVfsNodeNodeFunction21ForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 1,200: Line 1,264:
|-
|-
|}
|}
This function is used by several i/o functions and it`s purpose is unknown.
<source lang="c">
<source lang="c">
int vfs_node_func21(vfs_node *node);
int vfs_node_func21(vfs_node *node);
Line 1,212: Line 1,279:
arguments are packed into <code>vfs_node_func21_args</code> and passed to <code>vfs_node_func21</code> callback
arguments are packed into <code>vfs_node_func21_args</code> and passed to <code>vfs_node_func21</code> callback


=== vfs_node_func22 ===
=== vfs_node_func22 (sceVfsNodeNodeFunction22ForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 1,220: Line 1,287:
|-
|-
|}
|}
This function is not used by any of the i/o operations.
<source lang="c">
<source lang="c">
int vfs_node_func22(vfs_node *node, int unk1);
int vfs_node_func22(vfs_node *node, void* unk1);


struct vfs_node_func22_args
struct vfs_node_func22_args
{
{
   vfs_node* node;
   vfs_node* node;
   uint32_t arg1;
   void* unk1; //this is probably vfs_node* as well
}vfs_node_func22_args;
}vfs_node_func22_args;


Line 1,233: Line 1,303:
arguments are packed into <code>vfs_node_func22_args</code> and passed to <code>vfs_node_func22</code> callback
arguments are packed into <code>vfs_node_func22_args</code> and passed to <code>vfs_node_func22</code> callback


=== vfs_node_func23 ===
=== vfs_node_func23 (sceVfsNodeNodeFunction23ForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 1,241: Line 1,311:
|-
|-
|}
|}
This function is not used by any of the i/o operations.
<source lang="c">
<source lang="c">
int vfs_node_func23(vfs_node *node, int unk1);
int vfs_node_func23(vfs_node *node, void* unk1);


struct vfs_node_func23_args
struct vfs_node_func23_args
{
{
   vfs_node* node;
   vfs_node* node;
   uint32_t arg1;
   void* unk1; //this is probably vfs_node* as well
}vfs_node_func23_args;
}vfs_node_func23_args;


Line 1,254: Line 1,327:
arguments are packed into <code>vfs_node_func23_args</code> and passed to <code>vfs_node_func23</code> callback
arguments are packed into <code>vfs_node_func23_args</code> and passed to <code>vfs_node_func23</code> callback


=== vfs_node_func24 ===
=== vfs_node_func24 (sceVfsNodeSyncForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 1,276: Line 1,349:
arguments are packed into <code>vfs_node_func24_args</code> and passed to <code>vfs_node_func24</code> callback
arguments are packed into <code>vfs_node_func24_args</code> and passed to <code>vfs_node_func24</code> callback


=== vfs_node_func25 ===
=== vfs_node_func25 (sceVfsNodeGetstatByFdForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 1,299: Line 1,372:
arguments are packed into <code>vfs_node_func25_args</code> and passed to <code>vfs_node_func25</code> callback
arguments are packed into <code>vfs_node_func25_args</code> and passed to <code>vfs_node_func25</code> callback


=== vfs_node_func26 ===
=== vfs_node_func26 (sceVfsNodeChstatByFdForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 1,322: Line 1,395:
arguments are packed into <code>vfs_node_func26_args</code> and passed to <code>vfs_node_func26</code> callback
arguments are packed into <code>vfs_node_func26_args</code> and passed to <code>vfs_node_func26</code> callback


=== vfs_node_func27 ===
=== vfs_node_func27 (sceVfsNodeRemoveForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 1,331: Line 1,404:
|}
|}
<source lang="c">
<source lang="c">
int vfs_node_func27(int unk0, vfs_node *node, int unk2, int unk3);
int vfs_node_func27(vfs_node* new_node, vfs_node* node, void* unk2, void* mem_chunk);


struct vfs_node_func27_args
struct vfs_node_func27_args
{
{
   uint32_t arg0;
   vfs_node* new_node;
   vfs_node* node;
   vfs_node* node;
   uint32_t arg2;
   void* unk2;
   uint32_t arg3;
   void* mem_chunk; // block of size 0x400. has "SCEDEL~" string in the beginning.
   uint32_t unk_10; // zero
   uint32_t unk_10; // = 0
   uint32_t unk_14; // zero
   uint32_t unk_14; // = 0
}vfs_node_func27_args;
}vfs_node_func27_args;


Line 1,347: Line 1,420:
arguments are packed into <code>vfs_node_func27_args</code> and passed to <code>vfs_node_func27</code> callback
arguments are packed into <code>vfs_node_func27_args</code> and passed to <code>vfs_node_func27</code> callback


=== vfs_node_func28 ===
=== vfs_node_func28 (sceVfsNodeFunction28ForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 1,355: Line 1,428:
|-
|-
|}
|}
Looks like the purpose of this function is to <code>close</code> some resource by SceUID like <code>sceIoCloseForDriver</code> or <code>sceIoDcloseForDriver</code>.
<source lang="c">
<source lang="c">
int vfs_node_func28(vfs_node *node, int unk1, int unused1, int unused2);
int vfs_node_func28(vfs_node *node, void *objectBase, int unused0, int unused1);


struct vfs_node_func28_args
struct vfs_node_func28_args
{
{
   vfs_node* node;
   vfs_node* node;
   uint32_t arg1;
   uint32_t objectBase;
   uint32_t unk_8; // zero
   uint32_t unk_8; // = 0
   uint32_t unk_C; // zero
   uint32_t unk_C; // = 0
}vfs_node_func28_args;
}vfs_node_func28_args;


Line 1,370: Line 1,446:
arguments are packed into <code>vfs_node_func28_args</code> and passed to <code>vfs_node_func28</code> callback
arguments are packed into <code>vfs_node_func28_args</code> and passed to <code>vfs_node_func28</code> callback


=== vfs_node_func29 ===
=== vfs_node_func29 (sceVfsNodeFunction29ForDriver) ===
{| class="wikitable"
{| class="wikitable"
|-
|-
Line 1,378: Line 1,454:
|-
|-
|}
|}
This function is not implemented by any of the VFS nodes.
<source lang="c">
<source lang="c">
int vfs_node_func29(vfs_node *node, int unused, int unk2, int unk3, int arg_0, int arg_4, int arg_8, int arg_C);
int vfs_node_func29(vfs_node* node, SceInt64 unk1, SceInt64 unk2, int arg_8, int arg_C);


struct vfs_node_func29_args
struct vfs_node_func29_args
{
{
   uint32_t unk_0;
   vfs_node* node;
  uint32_t unk_4;
   uint32_t dummy; //alignment
   uint32_t arg2;
   SceInt64 unk1;
   uint32_t arg3;
   SceInt64 unk2;
   uint32_t arg_0;
  uint32_t arg_4;
   uint32_t arg_8;
   uint32_t arg_8;
   uint32_t arg_C;
   uint32_t arg_C;

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 like vfs_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