From 3c273d6dafba3762d98bfef4a562e9c3605e2f14 Mon Sep 17 00:00:00 2001 From: IllusionMan1212 Date: Sun, 22 Jun 2025 21:02:09 +0200 Subject: [PATCH] update to latest vita-headers --- Kernel/FastMutex.odin | 21 ++ Kernel/Vfp.odin | 24 ++ Kernel/sdif.odin | 13 + Kernel/types.odin | 41 +++ Net/Adhoc.odin | 23 ++ Net/types.odin | 46 +++ NpDrm/NpDrm.odin | 14 +- NpDrm/types.odin | 32 +- PhotoImport/PhotoImport.odin | 22 ++ PhotoImport/types.odin | 33 ++ PhotoReview/PhotoReview.odin | 22 ++ PhotoReview/types.odin | 22 ++ PspnetAdhoc/types.odin | 1 + Vfs/Vfs.odin | 203 ++++++++++++ Vfs/types.odin | 623 +++++++++++++++++++++++++++++++++++ VshBridge/VshBridge.odin | 32 +- VshBridge/types.odin | 25 ++ vita-headers | 2 +- 18 files changed, 1171 insertions(+), 28 deletions(-) create mode 100644 Kernel/FastMutex.odin create mode 100644 Kernel/Vfp.odin create mode 100644 Kernel/sdif.odin create mode 100644 Net/Adhoc.odin create mode 100644 PhotoImport/PhotoImport.odin create mode 100644 PhotoImport/types.odin create mode 100644 PhotoReview/PhotoReview.odin create mode 100644 PhotoReview/types.odin create mode 100644 Vfs/Vfs.odin create mode 100644 Vfs/types.odin create mode 100644 VshBridge/types.odin diff --git a/Kernel/FastMutex.odin b/Kernel/FastMutex.odin new file mode 100644 index 0000000..a6c0368 --- /dev/null +++ b/Kernel/FastMutex.odin @@ -0,0 +1,21 @@ +package kernel + +import "core:c" +import sce "../common" + +foreign import threadmgr "system:SceThreadmgrForDriver_stub" + +foreign threadmgr { + ksceKernelInitializeFastMutex :: proc(fast_mutex: ^SceKernelFastMutex, name: cstring, attr: c.int, opt: rawptr) -> c.int --- + ksceKernelFinalizeFastMutex :: proc(fast_mutex: ^SceKernelFastMutex) -> c.int --- + + ksceKernelLockFastMutex :: proc(fast_mutex: ^SceKernelFastMutex) -> c.int --- + ksceKernelTryLockFastMutex :: proc(fast_mutex: ^SceKernelFastMutex) -> c.int --- + ksceKernelUnlockFastMutex :: proc(fast_mutex: ^SceKernelFastMutex) -> c.int --- + + ksceKernelGetFastMutexInfo :: proc(fast_mutex: ^SceKernelFastMutex, info: rawptr) -> c.int --- +} + +/* backward compatibility */ + +ksceKernelDeleteFastMutex :: ksceKernelFinalizeFastMutex diff --git a/Kernel/Vfp.odin b/Kernel/Vfp.odin new file mode 100644 index 0000000..71c17e8 --- /dev/null +++ b/Kernel/Vfp.odin @@ -0,0 +1,24 @@ +package kernel + +import "core:c" +import sce "../common" + +foreign import vfp "SceKernelThreadMgr_stub" + +foreign vfp { + sceKernelChangeThreadVfpException :: proc(clear: sce.UInt32, set: sce.UInt32) -> c.int --- +} + +foreign import vfpKern "SceThreadmgrForDriver_stub" + +foreign vfpKern { + /**Add commentMore actions + * @brief Change the current thread vfp exception mask + * + * @param[in] clear - The value to clear flag. ORed `SCE_KERNEL_VFP_EXCP_*` + * @param[in] set - The value to set flag. ORed `SCE_KERNEL_VFP_EXCP_*` + * + * @return SCE_OK on success, < 0 on error + */ + ksceKernelChangeThreadVfpException :: proc(clear: sce.UInt32, set: sce.UInt32) -> c.int --- +} diff --git a/Kernel/sdif.odin b/Kernel/sdif.odin new file mode 100644 index 0000000..094512d --- /dev/null +++ b/Kernel/sdif.odin @@ -0,0 +1,13 @@ +package kernel + +import "core:c" +import sce "../common" + +foreign import sdif "SceSdifForDriver" + +foreign sdif { + ksceSdifGetSdContextPartValidateMmc :: proc(dev_index: SceSdifDeviceIndex) -> ^SceSdifDeviceContext --- + ksceSdifInitializeMmcDevice :: proc(dev_index: SceSdifDeviceIndex, dev_ctx: ^SceSdifDeviceContext) -> c.int --- + ksceSdifWriteCmd56 :: proc(dev_ctx: ^SceSdifDeviceContext, buf: rawptr, size: sce.Size) -> c.int --- + ksceSdifReadCmd56 :: proc(dev_ctx: ^SceSdifDeviceContext, buf: rawptr, size: sce.Size) -> c.int --- +} diff --git a/Kernel/types.odin b/Kernel/types.odin index 1c1eb99..b328496 100644 --- a/Kernel/types.odin +++ b/Kernel/types.odin @@ -950,3 +950,44 @@ SceKernelMemoryType :: enum c.int { // sysmem.h end // + +// +// fastmutex.h start +// + +SceKernelFastMutex :: struct { + data: [0x40]sce.UInt8, +} +#assert(size_of(SceKernelFastMutex) == 0x40) + +// +// fastmutex.h end +// + +SceSdifDeviceIndex :: enum { + EMMC = 0x0, + GC = 0x1, + SDIO = 0x2, + SD = 0x3, +} + +SceSdifDeviceType :: enum { + INVALID = 0x0, + MMC = 0x1, + SD = 0x2, + SDIO = 0x3, +} + +SceSdifDeviceContext :: rawptr + +/* + * Value linked to fpcsr + */ +SCE_KERNEL_VFP_EXCP_IOC :: (0x00000001) +SCE_KERNEL_VFP_EXCP_DZC :: (0x00000002) +SCE_KERNEL_VFP_EXCP_OFC :: (0x00000004) +SCE_KERNEL_VFP_EXCP_UFC :: (0x00000008) +SCE_KERNEL_VFP_EXCP_IXC :: (0x00000010) +SCE_KERNEL_VFP_EXCP_IDC :: (0x00000080) +SCE_KERNEL_VFP_EXCP_QC :: (0x08000000) +SCE_KERNEL_VFP_EXCP_ALL :: (SCE_KERNEL_VFP_EXCP_IOC | SCE_KERNEL_VFP_EXCP_DZC | SCE_KERNEL_VFP_EXCP_OFC | SCE_KERNEL_VFP_EXCP_UFC | SCE_KERNEL_VFP_EXCP_IXC | SCE_KERNEL_VFP_EXCP_IDC | SCE_KERNEL_VFP_EXCP_QC) diff --git a/Net/Adhoc.odin b/Net/Adhoc.odin new file mode 100644 index 0000000..0b146d2 --- /dev/null +++ b/Net/Adhoc.odin @@ -0,0 +1,23 @@ +package net + +import "core:c" +import sce "../common" + +foreign import adhoc "system:SceNetAdhocMatching_stub" + +foreign adhoc { + sceNetAdhocMatchingInit :: proc(pool_size: c.uint, pool_ptr: rawptr) -> c.int --- + sceNetAdhocMatchingTerm :: proc() -> c.int --- + sceNetAdhocMatchingStart :: proc(id: c.int, thread_priority: c.int, thread_stack_size: c.int, thread_cpu_affinity_mask: c.int, hello_opt_len: c.int, hello_opt: rawptr) -> c.int --- + sceNetAdhocMatchingCreate :: proc(mode: SceNetAdhocMatchingMode, max_members: c.int, port: sce.UShort16, rx_buffer_len: c.int, hello_interval: c.uint, keep_alive_interval: c.uint, retry_count: c.int, rexmt_interval: c.uint, handler_callback: SceNetAdhocMatchingCallback) -> c.int --- + sceNetAdhocMatchingStop :: proc(id: c.int) -> c.int --- + sceNetAdhocMatchingDelete :: proc(id: c.int) -> c.int --- + sceNetAdhocMatchingAbortSendData :: proc(id: c.int, addr: ^SceNetInAddr) -> c.int --- + sceNetAdhocMatchingCancelTargetWithOpt :: proc(id: c.int, target: ^SceNetInAddr, opt_len: c.int, opt: ^c.char) -> c.int --- + sceNetAdhocMatchingCancelTarget :: proc(id: c.int, target: ^SceNetInAddr) -> c.int --- + sceNetAdhocMatchingSetHelloOpt :: proc(id: c.int, opt_len: c.int, opt: rawptr) -> c.int --- + sceNetAdhocMatchingGetHelloOpt :: proc(id: c.int, opt_len: ^c.uint, opt: rawptr) -> c.int --- + sceNetAdhocMatchingGetMembers :: proc(id: c.int, members_count: ^c.uint, members: ^SceNetAdhocMatchingMember) -> c.int --- + sceNetAdhocMatchingSelectTarget :: proc(id: c.int, target: ^SceNetInAddr, opt_len: c.int, opt: rawptr) -> c.int --- + sceNetAdhocMatchingSendData :: proc(id: c.int, addr: ^SceNetInAddr, data_len: c.int, data: rawptr) -> c.int --- +} diff --git a/Net/types.odin b/Net/types.odin index 57dad7f..6f00a7d 100644 --- a/Net/types.odin +++ b/Net/types.odin @@ -1,6 +1,7 @@ package net import "core:c" +import sce "../common" /** Resolver specific error codes */ SceNetResolverErrorCode :: enum c.int { @@ -549,6 +550,40 @@ SceNetIcmpCode :: enum c.int { TIME_EXCEEDED_FRT_EXCEEDED = 1 } +SceNetAdhocMatchingErrorCode :: enum { + INVALID_MODE = 0x80413101, + INVALID_PORT = 0x80413102, + INVALID_MAXNUM = 0x80413103, + RXBUF_TOO_SHORT = 0x80413104, + INVALID_OPTLEN = 0x80413105, + INVALID_ARG = 0x80413106, + INVALID_ID = 0x80413107, + ID_NOT_AVAIL = 0x80413108, + NO_SPACE = 0x80413109, + IS_RUNNING = 0x8041310a, + NOT_RUNNING = 0x8041310b, + UNKNOWN_TARGET = 0x8041310c, + TARGET_NOT_READY = 0x8041310d, + EXCEED_MAXNUM = 0x8041310e, + REQUEST_IN_PROGRESS = 0x8041310f, + ALREADY_ESTABLISHED = 0x80413110, + BUSY = 0x80413111, + ALREADY_INITIALIZED = 0x80413112, + NOT_INITIALIZED = 0x80413113, + PORT_IN_USE = 0x80413114, + STACKSIZE_TOO_SHORT = 0x80413115, + INVALID_DATALEN = 0x80413116, + NOT_ESTABLISHED = 0x80413117, + DATA_BUSY = 0x80413118, + INVALID_ALIGNMENT = 0x80413119 +} + +SceNetAdhocMatchingMode :: enum { + PARENT = 1, + CHILD, + P2P, +} + SCE_NET_IP_DEFAULT_MULTICAST_TTL :: 1 SCE_NET_IP_DEFAULT_MULTICAST_LOOP :: 1 @@ -577,6 +612,17 @@ SCE_NET_DEBUG_NAME_LEN_MAX :: 31 SCE_NET_ID_SOCKET_MIN :: 0 SCE_NET_ID_SOCKET_MAX :: 1023 +SceNetAdhocMatchingCallback :: #type proc "c" ( + id: c.int, + type: c.int, + addr: ^SceNetInAddr, + opt_len: sce.Size, + opt: rawptr) + +SceNetAdhocMatchingMember :: struct { + addr: SceNetInAddr, +} + SceNetFdSet :: struct { bits: [32]c.uint, } diff --git a/NpDrm/NpDrm.odin b/NpDrm/NpDrm.odin index 10886f0..1c03ecb 100644 --- a/NpDrm/NpDrm.odin +++ b/NpDrm/NpDrm.odin @@ -56,20 +56,22 @@ foreign npdrm { * * @return 0 on success, < 0 on error. */ - _sceNpDrmGetRifNameForInstall :: proc(rif_name: [^]c.char, rif_data: rawptr, unk: c.int) -> c.int --- + _sceNpDrmGetRifNameForInstall :: proc(rif_name: [^]c.char, rif_data: *SceNpDrmLicense, unk: c.int) -> c.int --- /** * Get PSM rif key * * @param[in] license_buf - RIF buffer (1024 bytes) * - * @param[out] keydata - Decrypted key data + * @param[out] keydata - Decrypted keyset + * + * @param[out] exp_time - Expire times output * * @param[in] flags - Unknown * * @return 0 on success, < 0 on error */ - scePsmDrmGetRifKey :: proc(#by_ptr license_buf: ScePsmDrmLicense, keydata: [^]c.char, flags: c.int) -> c.int --- + scePsmDrmGetRifKey :: proc(#by_ptr license_buf: ScePsmDrmLicense, keydata: *ScePsmDrmKeySet, flags: c.int, exp_time: *ScePsmDrmExpireTime) -> c.int --- } foreign npdrmpackage { @@ -154,7 +156,7 @@ foreign npdrmkern { * * @return 0 on success, < 0 on error. */ - ksceNpDrmGetRifVitaKey :: proc(license: rawptr, klicense: rawptr, flags: ^c.int, sku_flags: ^c.int, lic_start_time: ^sce.UInt64, lic_exp_time: ^sce.UInt64) -> c.int --- + ksceNpDrmGetRifVitaKey :: proc(license: ^SceNpDrmLicense, klicense: rawptr, flags: ^c.int, sku_flags: ^c.int, lic_start_time: ^sce.UInt64, lic_exp_time: ^sce.UInt64) -> c.int --- /** * Get license key info for a PSP game @@ -167,7 +169,7 @@ foreign npdrmkern { * * @return 0 on success, < 0 on error. */ - ksceNpDrmGetRifPspKey :: proc(license: rawptr, klicense: rawptr, flags: c.int, lic_start_time: ^sce.UInt64, lic_exp_time: ^sce.UInt64) -> c.int --- + ksceNpDrmGetRifPspKey :: proc(license: ^SceNpDrmLicense, klicense: rawptr, flags: c.int, lic_start_time: ^sce.UInt64, lic_exp_time: ^sce.UInt64) -> c.int --- /** * Get license info @@ -187,7 +189,7 @@ foreign npdrmkern { * * @return 0 on success, < 0 on error. */ - ksceNpDrmGetRifInfo :: proc(license: rawptr, license_size: sce.Size, check_sign: c.int, content_id: [^]c.char, account_id: ^sce.UInt64, license_version: ^c.int, license_flags: ^c.int, flags: ^c.int, sku_flags: ^c.int, lic_start_time: ^sce.Int64, lic_exp_time: ^sce.Int64, flags2: ^sce.UInt64) -> c.int --- + ksceNpDrmGetRifInfo :: proc(license: ^SceNpDrmLicense, license_size: sce.Size, check_sign: c.int, content_id: [^]c.char, account_id: ^sce.UInt64, license_version: ^c.int, license_flags: ^c.int, flags: ^c.int, sku_flags: ^c.int, lic_start_time: ^sce.Int64, lic_exp_time: ^sce.Int64, flags2: ^sce.UInt64) -> c.int --- /** * Verify a eboot.pbp signature "__sce_ebootpbp" diff --git a/NpDrm/types.odin b/NpDrm/types.odin index 6a573c1..e177259 100644 --- a/NpDrm/types.odin +++ b/NpDrm/types.odin @@ -3,6 +3,22 @@ package npdrm import "core:c" import sce "../common" +ScePsmDrmKeySet :: struct { + hmac_key: [0x20]sce.UInt8, + key: [0x10]sce.UInt8, + signature: [0x1D0]sce.UInt8, +} +#assert(size_of(ScePsmDrmKeySet) == 0x200) + +ScePsmDrmExpireTime :: struct { // size is 0x10 + start_date: ^sce.RtcTick, + end_date: ^sce.RtcTick, + pad: [2]c.int, +} +#assert(size_of(ScePsmDrmExpireTime) == 0x10) + +VITASDK_BUILD_ASSERT_EQ(0x10, ScePsmDrmExpireTime); + SceNpDrmActivationData :: struct { // size is 0x1038 act_type: sce.Int16, version_flag: sce.Int16, @@ -21,16 +37,16 @@ SceNpDrmActivationData :: struct { // size is 0x1038 #assert(size_of(SceNpDrmActivationData) == 0x1038) SceNpDrmLicense :: struct { // size is 0x200 - version: sce.Int16, // -1 VITA, 0 PSP, 1 PSP-VITA + version: sce.Int16, // -1 VITA (NPDRM_FREE), 0 PSP, 1 PSP-VITA version_flags: sce.Int16, // 0, 1 license_type: sce.Int16, // 1 license_flags: sce.Int16, // 0x400:non-check ecdsa - account_id: sce.UInt64, + account_id: sce.UInt64, // 0x0:NPDRM_FREE content_id: [0x30]c.char, key_table: [0x10]c.char, key1: [0x10]c.char, - start_time: sce.Int64, - expiration_time: sce.Int64, + start_time: sce.RtcTick, + expiration_time: sce.RtcTick, ecdsa_signature: [0x28]c.char, flags: sce.Int64, key2: [0x10]c.char, @@ -52,14 +68,12 @@ ScePsmDrmLicense :: struct { account_id: sce.UInt64, unk3: sce.UInt32, unk4: sce.UInt32, - start_time: sce.UInt64, - expiration_time: sce.UInt64, + start_time: sce.RtcTick, + expiration_time: sce.RtcTick, activation_checksum: [0x20]sce.UInt8, content_id: [0x30]c.char, unk5: [0x80]sce.UInt8, - unk6: [0x20]sce.UInt8, - key: [0x10]sce.UInt8, - signature: [0x1D0]sce.UInt8, + keyset: ScePsmDrmKeySet, rsa_signature: [0x100]sce.UInt8, } #assert(size_of(ScePsmDrmLicense) == 0x400) diff --git a/PhotoImport/PhotoImport.odin b/PhotoImport/PhotoImport.odin new file mode 100644 index 0000000..ca949f2 --- /dev/null +++ b/PhotoImport/PhotoImport.odin @@ -0,0 +1,22 @@ +package photoimport + +import "core:c" +import sce "../common" +import sceClib "../Clib" +import sceCommonDialog "../CommonDialog" + +foreign import photoimport "system:SceCommonDialog_stub" + +scePhotoImportDialogParamInit :: #force_inline proc(param: ^ScePhotoImportDialogParam) { + sceClib.sceClibMemset(param, 0x0, size_of(ScePhotoImportDialogParam)) + sceCommonDialog._sceCommonDialogSetMagicNumber(¶m.commonParam) + param.sdkVersion = sce.PSP2_SDK_VERSION +} + +foreign photoimport { + scePhotoImportDialogInit :: proc(param: ^ScePhotoImportDialogParam) -> c.int --- + scePhotoImportDialogTerm :: proc() -> c.int --- + scePhotoImportDialogGetResult :: proc(result: ^ScePhotoImportDialogResult) -> c.int --- + scePhotoImportDialogGetStatus :: proc() -> c.int --- + scePhotoImportDialogAbort :: proc() -> c.int --- +} diff --git a/PhotoImport/types.odin b/PhotoImport/types.odin new file mode 100644 index 0000000..eb2ace1 --- /dev/null +++ b/PhotoImport/types.odin @@ -0,0 +1,33 @@ +package photoimport + +import "core:c" +import sce "../common" + +ScePhotoImportDialogImportInfo :: struct { + path: [0x400]c.char, + unk_0x400: [0x100]c.char, + unk_0x500: [0x20]sce.UInt8, + unk_0x520: c.int, + unk_0x524: c.int, + unk_0x528: c.int, + unk_0x52C: c.int, +} +#assert(size_of(ScePhotoImportDialogImportInfo) == 0x530) // not sure for size. + +ScePhotoImportDialogParam :: struct { + sdkVersion: sce.UInt32, + commonParam: sce.CommonDialogParam, + unk_0x50: sce.UInt32, // should be 0 + unk_0x54: sce.UInt32, // should be `(unk_0x54 & 7) != 0 && (unk_0x54 & ~7) == 0` + unk_0x58: sce.UInt32, + unk_0x5C: rawptr, + unk_0x60: [0x20]sce.UInt8, +} +#assert(size_of(ScePhotoImportDialogParam) == 0x80) + +ScePhotoImportDialogResult :: struct { + result: sce.Int32, + unk_0x04: sce.Int32, + reserved: [0x20]sce.Char8, +} +#assert(size_of(ScePhotoImportDialogResult) == 0x28) diff --git a/PhotoReview/PhotoReview.odin b/PhotoReview/PhotoReview.odin new file mode 100644 index 0000000..82d758e --- /dev/null +++ b/PhotoReview/PhotoReview.odin @@ -0,0 +1,22 @@ +package photoreview + +import "core:c" +import sce "../common" +import sceClib "../Clib" +import sceCommonDialog "../CommonDialog" + +foreign import photoreview "system:SceCommonDialog_stub" + +scePhotoReviewDialogParamInit :: #force_inline proc(param: ^ScePhotoReviewDialogParam) { + sceClib.sceClibMemset(param, 0, size_of(ScePhotoReviewDialogParam)) + sceCommonDialog._sceCommonDialogSetMagicNumber(¶m.commonParam) + param.sdkVersion = sce.PSP2_SDK_VERSION +} + +foreign photoreview { + scePhotoReviewDialogInit :: proc(param: ^ScePhotoReviewDialogParam) -> c.int --- + scePhotoReviewDialogTerm :: proc() -> c.int --- + scePhotoReviewDialogGetResult :: proc(result: ^ScePhotoReviewDialogResult) -> c.int --- + scePhotoReviewDialogGetStatus :: proc() -> c.int --- + scePhotoReviewDialogAbort :: proc() -> c.int --- +} diff --git a/PhotoReview/types.odin b/PhotoReview/types.odin new file mode 100644 index 0000000..8bb5ebb --- /dev/null +++ b/PhotoReview/types.odin @@ -0,0 +1,22 @@ +package photoreview + +import sce "../common" +import sceCommonDialog "../CommonDialog" + +ScePhotoReviewDialogParam :: struct { + sdkVersion: sce.UInt32, + commonParam: sceCommonDialog.SceCommonDialogParam, + unk_0x50: sce.UInt32, // seems 1 only? + path: [0x400]sce.UInt8, + internal_memory: rawptr, + internal_memory_size: sce.Size, + unk_0x454: [0x20]sce.UInt8, +} +#assert(size_of(ScePhotoReviewDialogParam) == 0x47C) + +ScePhotoReviewDialogResult :: struct { + result: sce.Int32, + unk_0x04: sce.Int32, + reserved: [0x1C]sce.Char8, +} +#assert(size_of(ScePhotoReviewDialogResult) == 0x24) diff --git a/PspnetAdhoc/types.odin b/PspnetAdhoc/types.odin index 59bf8b7..7732208 100644 --- a/PspnetAdhoc/types.odin +++ b/PspnetAdhoc/types.odin @@ -93,6 +93,7 @@ SceNetAdhocPtpStat :: struct { rcv_sb_cc: c.uint, state: c.int, } +#assert(size_of(SceNetAdhocPtpStat) == 0x24) ScePspnetAdhocFlags :: enum c.int { NONBLOCK = 0x0001, diff --git a/Vfs/Vfs.odin b/Vfs/Vfs.odin new file mode 100644 index 0000000..3401577 --- /dev/null +++ b/Vfs/Vfs.odin @@ -0,0 +1,203 @@ +package vfs + +import "core:c" +import sce "../common" +import sceIo "../Io" + +foreign import vfs "system:SceIofilemgrForDriver_stub" + +foreign vfs { + /** + * Register a VFS implementation + * + * @param vfs_info - The VFS Info structure for the VFS. (This pointer should remain persistent until the VFS is deleted) + * + * @return 0 on success, < 0 on error + */ + ksceVfsAddVfs :: proc(vfs_info: ^SceVfsInfo) -> c.int --- + /** + * Unegister a VFS implementation + * + * @param name - The name of the VFS implementation to unregister + * @param vfs_info - The VFS Info structure for the VFS. (This pointer should remain persistent until the VFS is deleted) + * + * @return 0 on success, < 0 on error + */ + ksceVfsDeleteVfs :: proc(name: cstring, vfs_info: ^^SceVfsInfo) -> c.int --- + + /** + * Mount a drive + * + * @param param - The mount parameters + * + * @return 0 on success, < 0 on error + */ + vfsMount :: proc(param: ^SceVfsMountParam) -> c.int --- + /** + * Unmount a drive + * + * @param param - The unmount parameters + * + * @return 0 on success, < 0 on error + */ + vfsUmount :: proc(param: ^SceVfsUmountParam) -> c.int --- + + /** + * Mount a drive via the mount daemon + * + * @param param - The mount parameters + * + * @return 0 on success, < 0 on error + */ + vfsMountForPFS :: proc(param: ^SceVfsMountParam) -> c.int --- + /** + * Unmount a drive via the mount daemon + * + * @param param - The unmount parameters + * + * @return 0 on success, < 0 on error + */ + vfsUmountForPFS :: proc(param: ^SceVfsUmountParam, unk: c.int, unk2: c.int) -> c.int --- + + /** + * Lock the mnt + * + * @param mnt - The mountpoint to lock + * + * @return 0 on success, < 0 on error + */ + vfsLockMnt :: proc(mnt: ^SceVfsMount) -> c.int --- + /** + * Unlock the mnt + * + * @param mnt - The mountpoint to unlock + * + * @return 0 on success, < 0 on error + */ + vfsUnlockMnt :: proc(mnt: ^SceVfsMount) -> c.int --- + /** + * Is the mnt lock held by the current thread ? + * + * @param mnt - The mount point to query + * + * @return SCE_TRUE if the lock is held, SCE_FALSE if it is not, and < 0 on error + */ + vfsIsLockedMnt :: proc(mnt: ^SceVfsMount) -> sce.Bool --- + + /** + * Allocate a new VFS file object + * + * @param vp - The vnode the file should be referencing + * @param file - The pointer reference the file will be returned to + * @param name - The name of the file + * + * @return The UID of the file object on success, < 0 on error + */ + vfsAllocateFile :: proc(vp: ^SceVfsVnode, file: ^^SceVfsFile, name: cstring) -> sce.UID --- + /** + * Free a File object + * + * @param vp - Vnode for the file handle being freed + * @param fd - UID of the file being freed + * + * @return 0 on success, < 0 on error + */ + vfsFreeFile :: proc(vp: ^SceVfsVnode, fd: sce.UID) -> c.int --- + + /** + * Get a new vnode from the pool + * + * @param mnt - The mountpoint the vnode will be attached to + * @param vops - The vnode vop table for executing VFS Vops + * @param unk - Must be 0 + * @param vpp - The pointer reference to return the vnode to + * + * @return 0 on success, < 0 on error + */ + vfsGetNewVnode :: proc(mnt: ^SceVfsMount, vops: ^SceVopTable, unk: c.int, vpp: ^^SceVfsVnode) -> c.int --- + /** + * Return a vnode to the pool + * + * @param vp - The vnode to return + * + * @return 0 on success, < 0 on error + */ + vfsFreeVnode :: proc(vp: ^SceVfsVnode) -> c.int --- + + /** + * Lock a vnode + * + * @param vp - Target vnode + * + * @return 0 on success, < 0 on error + */ + vfsLockVnode :: proc(vp: ^SceVfsVnode) -> c.int --- + /** + * Unlock a vnode + * + * @param vp - Target vnode + * + * @return 0 on success, < 0 on error + */ + vfsUnlockVnode :: proc(vp: ^SceVfsVnode) -> c.int --- + /** + * Does the current thread own the vnode lock + * + * @param vp - Target vnode + * + * @return SCE_TRUE if the lock is owned, SCE_FALSE if it is not, and < 0 on error + */ + vfsIsOwnerVnode :: proc(vp: ^SceVfsVnode) -> sce.Bool --- + + /** + * Get the name of a vnode + * + * @param vp - Target vnode + * @param name - Buffer for the name + * @param n - Buffer size + * @param result - Length of the returned name + * + * @return 0 on success, < 0 on error + */ + vfsGetVnodeName :: proc(vp: ^SceVfsVnode, name: cstring, n: sce.Size, result: ^sce.Size) -> c.int --- + + /** + * @name VFS Vop APIs + * + * These are relevant when doing operations on vnodes owned by other VFS implementations (block devices, etc.) + */ + ksceVopOpen :: proc(vp: ^SceVfsVnode, path: ^SceVfsPath, flags: c.int, file: ^SceVfsFile) -> c.int --- + ksceVopCreate :: proc(dvp: ^SceVfsVnode, vpp: ^^SceVfsVnode, path: ^SceVfsPath, flags: c.int, mode: c.int) -> c.int --- + ksceVopClose :: proc(vp: ^SceVfsVnode, file: ^SceVfsFile) -> c.int --- + ksceVopLookup :: proc(dvp: ^SceVfsVnode, vpp: ^^SceVfsVnode, path: ^SceVfsPath, flags: sce.UInt32) -> c.int --- + ksceVopRead :: proc(vp: ^SceVfsVnode, file: ^SceVfsFile, data: rawptr, nbyte: sce.Size, result: ^sce.Size) -> c.int --- + ksceVopWrite :: proc(vp: ^SceVfsVnode, file: ^SceVfsFile, data: rawptr, nbyte: sce.Size, result: ^sce.Size) -> c.int --- + ksceVopLseek :: proc(vp: ^SceVfsVnode, file: ^SceVfsFile, offset: sce.Off, whence: c.int) -> sce.Off --- + + ksceVopIoctl :: proc(vp: ^SceVfsVnode, file: ^SceVfsFile, cmd: c.int, in_data: rawptr, in_len: sce.Size, out_data: rawptr, out_len: sce.Size) -> c.int --- + ksceVopRemove :: proc(dvp: ^SceVfsVnode, vp: ^SceVfsVnode, path: ^SceVfsPath, flags: sce.UInt32) -> c.int --- + ksceVopMkdir :: proc(dvp: ^SceVfsVnode, vpp: ^^SceVfsVnode, path: ^SceVfsPath, mode: c.int) -> c.int --- + ksceVopRmdir :: proc(dvp: ^SceVfsVnode, vp: ^SceVfsVnode, path: ^SceVfsPath) -> c.int --- + + ksceVopDopen :: proc(vp: ^SceVfsVnode, path: ^SceVfsPath, file: ^SceVfsFile) -> c.int --- + ksceVopDclose :: proc(vp: ^SceVfsVnode, file: ^SceVfsFile) -> c.int --- + ksceVopDread :: proc(vp: ^SceVfsVnode, file: ^SceVfsFile, dir: ^sceIo.SceIoDirent) -> c.int --- + + ksceVopGetstat :: proc(vp: ^SceVfsVnode, path: ^SceVfsPath, stat: ^sceIo.SceIoStat) -> c.int --- + ksceVopChstat :: proc(vp: ^SceVfsVnode, path: ^SceVfsPath, stat: ^sceIo.SceIoStat, bit: c.int) -> c.int --- + + ksceVopRename :: proc(odvp: ^SceVfsVnode, ovp: ^SceVfsVnode, old_path: ^SceVfsPath, ndvp: ^SceVfsVnode, nvpp: ^^SceVfsVnode, new_path: ^SceVfsPath) -> c.int --- + ksceVopPread :: proc(vp: ^SceVfsVnode, file: ^SceVfsFile, data: rawptr, nbyte: sce.Size, offset: sce.Off, pResult: ^sce.Size) -> c.int --- + ksceVopPwrite :: proc(vp: ^SceVfsVnode, file: ^SceVfsFile, data: rawptr, nbyte: sce.Size, offset: sce.Off, result: ^sce.Size) -> c.int --- + ksceVopInactive :: proc(vp: ^SceVfsVnode) -> c.int --- + ksceVopSync :: proc(vp: ^SceVfsVnode, file: ^SceVfsFile, flags: c.int) -> c.int --- + ksceVopFgetstat :: proc(vp: ^SceVfsVnode, file: ^SceVfsFile, stat: ^sceIo.SceIoStat) -> c.int --- + ksceVopFchstat :: proc(vp: ^SceVfsVnode, file: ^SceVfsFile, stat: ^sceIo.SceIoStat , bit: c.int) -> c.int --- + + ksceVopLink :: proc(fvp: ^SceVfsVnode, tvp: ^SceVfsVnode) -> c.int --- + ksceVopUnlink :: proc(fvp: ^SceVfsVnode, tvp: ^SceVfsVnode) -> c.int --- + + ksceVopWhiteout :: proc(dvp: ^SceVfsVnode, vp: ^SceVfsVnode, old_path: ^SceVfsPath, new_path: ^SceVfsPath) -> c.int --- + ksceVopCleanup :: proc(vp: ^SceVfsVnode, file: ^SceVfsFile) -> c.int --- + ksceVopZerofill :: proc(vp: ^SceVfsVnode, unk: sce.UInt64, unk1: sce.UInt64, unk2: sce.UInt64) -> c.int --- +} diff --git a/Vfs/types.odin b/Vfs/types.odin new file mode 100644 index 0000000..f66025a --- /dev/null +++ b/Vfs/types.odin @@ -0,0 +1,623 @@ +package vfs + +import "core:c" +import sce "../common" +import sceKernel "../Kernel" +import sceIo "../Io" + +SceVfsType :: enum sce.UInt32 { + FS = 0x00000000, + DEVFS = 0x00000010, +} + +SceVfsInfo :: struct { + vfs_ops: ^SceVfsOpTable, + vfs_name: cstring, + vfs_name_len: sce.Size, + ref_count : sce.UInt32, + type: SceVfsType, + default_vops: ^SceVopTable, + vfs_data: rawptr, + next: ^SceVfsInfo, +} +#assert(size_of(SceVfsInfo) == 0x20) + +SceVfsPath :: struct { + name: cstring, + name_length: sce.Size, + path: cstring, +} +#assert(size_of(SceVfsPath) == 0xC) + +SceVfsMountData :: struct { + assign_name: cstring, + fs_name: cstring, + blockdev_name: cstring, + blockdev_name_no_part: cstring, + mnt_id: sce.UInt32, +} +#assert(size_of(SceVfsMountData) == 0x14) + +SceVfsFsType :: enum sce.UInt8 { + FS = 0x01, + PFS = 0x03, + HOSTFS = 0x04, + BLKDEV = 0x10, + CHRDEV = 0x20, +} + +SceVfsMountType :: enum { + PFS = 0x00000001, + FSROOT = 0x00000002, + DEVFS = 0x00000003, + STACKFS = 0x00000005, + HOSTFS = 0x00000006, +} + +SCE_VFS_MOUNT_FLAG_TYPE_MASK :: 0x00000006 +SCE_VFS_MOUNT_FLAG_RDONLY :: 0x00001000 +SCE_VFS_MOUNT_FLAG_NOBUF :: 0x00002000 +SCE_VFS_MOUNT_FLAG_NUMBERED :: 0x00004000 +SCE_VFS_MOUNT_FLAG_REMOTE :: 0x00008000 +SCE_VFS_MOUNT_FLAG_INTERNAL :: 0x00010000 +SCE_VFS_MOUNT_FLAG_EXTERNAL :: 0x00020000 +SCE_VFS_MOUNT_FLAG_WRITE_CACHE :: 0x00040000 +SCE_VFS_MOUNT_FLAG_NO_RECLAIM :: 0x00100000 + +// Opaque +FdLock :: struct{} +Fumount :: struct{} +BuffCache :: struct{} +Flock :: struct{} +DebugPath :: struct{} +Ncache :: struct{} + +SceVfsMount :: struct { + fast_mutex: sceKernel.SceKernelFastMutex, + + mnt_vnode: ^SceVfsVnode, + + allocator: sce.UID, + + state: sce.UInt32, + fs_type: SceVfsFsType, //!< One of SCE_VFS_FS_TYPE_* + opt: sce.UInt16, + mnt_flags: sce.UInt32, //!< ORed together SCE_VFS_MOUNT_FLAG_* flags + + vnode_list: ^SceVfsVnode, + vnode_num: sce.UInt32, + + mnt_vfs_inf: ^SceVfsInfo, + mnt_ref_count: sce.UInt32, + + opened_entry_num: sce.UInt32, + available_entry_num: sce.UInt32, + + pid: sce.UID, + + mnted_on_list: ^SceVfsMount, + mnted_on_list_prev: ^SceVfsMount, + mnt_list_next: ^SceVfsMount, + + mnt_data: ^SceVfsMountData, + path: [64]byte, + + default_io_cache_size: sce.UInt32, + + data: rawptr, //!< VFS Implementation defined mount point data. + + fd_lock: ^FdLock, + fumount: ^Fumount, + + opaque: [4]sce.UInt32, // Backing storage for pFdLock + opaque2: [4]sce.UInt32, // Backing storage for pFumount + + padding: [16]sce.UInt8, +} +#assert(size_of(SceVfsMount) == 0x100) + + +SCE_VNODE_TYPE_REG :: (0x00000001) //!< Regular file +SCE_VNODE_TYPE_DIR :: (0x00000002) //!< Regular directory +SCE_VNODE_TYPE_CHR :: (0x00000010) //!< Character file +SCE_VNODE_TYPE_ROOT :: (0x00001000) //!< Root vnode +SCE_VNODE_TYPE_DEV :: (0x00002000) //!< Device vnode +SCE_VNODE_TYPE_MOUNTED :: (0x00004000) //!< Vnode used as a backing for a mountpoint + +SCE_VNODE_TYPE_CHRDEV :: (SCE_VNODE_TYPE_DEV | SCE_VNODE_TYPE_CHR) +SCE_VNODE_TYPE_ROOTDIR :: (SCE_VNODE_TYPE_ROOT | SCE_VNODE_TYPE_DIR) //!< Root directory +SCE_VNODE_TYPE_ROOTDIR_DEVFS :: (0x10000 | 0x20) //!< Root directory on devfs mountpoints + +SCE_VNODE_STATE_ACTIVE :: (0x00000001) //!< Vnode is active and valid for all operations +SCE_VNODE_STATE_INACTIVE :: (0x00000100) //!< Vnode is inactive and may be pending deletion or otherwise. +SCE_VNODE_STATE_UNMOUNTED :: (0x00000200) +SCE_VNODE_STATE_DELETED :: (0x00000400) +SCE_VNODE_STATE_RECLAIMED :: (0x00002000) +SCE_VNODE_STATE_NEW :: (0x00008000) + +SceVfsVnode :: struct { + vdlock: struct { + waiter: sce.UInt32, + owner_id: sce.UID, + recursive_count: sce.UInt32, + wait_id: sce.UID, + wait_pattern: sce.UInt32, + }, + + padding: [44]sce.UInt8, + + core: struct { + ops: ^SceVopTable, + + node_inf: sce.UInt32, //!< Field for private VFS vnode info + node_data: rawptr, //!< Pointer for private VFS data + + mnt: ^SceVfsMount, + + dd: ^SceVfsVnode, //!< Parent vnode + next: ^SceVfsVnode, + + ref_count: sce.UInt32, + + bc: ^BuffCache, + + fid: [2]sce.UInt32, + flock: ^Flock, + + allocator: sce.UID, + + ncache: ^Ncache, + + state: sce.UInt32, //!< One of SCE_VNODE_STATE_* + type: sce.UInt32, //!< ORed together SCE_VNODE_TYPE_* flags + + vop_tbl: ^SceVopTable, //!< Internal use only + + size: sce.UInt64, + acl_data: [2]sce.UInt32, //!< Typically holds st_attr in acl_data[0] + + fd_list: ^SceVfsFile, + fd_num: sce.UInt32, + + link_to: ^SceVfsVnode, + linked_num: sce.UInt32, + + unused: [48]sce.UInt8, + + mnt_opt: sce.UInt32, + unk_0xd4: sce.UInt32, + }, + + padding2: [40]sce.UInt8, +} +#assert(size_of(SceVfsVnode) == 0x100) + + +SCE_VFS_FILE_STATE_OPEN :: (0x00000001) //!< File is open +SCE_VFS_FILE_STATE_CLOSED :: (0x00000200) //!< File is closed +SCE_VFS_FILE_STATE_UNK :: (0x00000800) //!< Unknown status +SCE_VFS_FILE_STATE_DUMMY :: (0x00010000) //!< Dummy file + +/** + * VFS File + * + * The file structure is contained within the SceUIDVfsFileObject structure, and represents file handles in the VFS. + */ +SceVfsFile :: struct { + is_dir: sce.UInt32, + flags: sce.UInt32, + + position: sce.Off, + + state: sce.UInt32, + pid: sce.UID, + + vp: ^SceVfsVnode, + next: ^SceVfsFile, + + fd: sce.UInt32, //!< File descriptor provided and used by VFS implementation + flock_busy_count: sce.UInt16, + + is_locked: sce.UInt8, + has_flock_ent: sce.UInt8, + + fd_lock: ^FdLock, + + idata: sce.UInt32, + + debug_path: ^DebugPath, + + ioSchedData: [3]sce.UInt32, +} +#assert(size_of(SceVfsFile) == 0x40) + +/** + * @name VFS Operation Arguments and Callback Table + */ +/** @{ */ +SceVfsOpMountArgs :: struct { + mnt: ^SceVfsMount, + dev_file_path: ^SceVfsPath, //!< Path to the device file. +} +#assert(size_of(SceVfsOpMountArgs) == 0x8) + +SceVfsOpUmountArgs :: struct { + mnt: ^SceVfsMount, + flags: c.int, +} +#assert(size_of(SceVfsOpUmountArgs) == 0x8) + +SceVfsOpSetRootArgs :: struct { + mnt: ^SceVfsMount, + unk: c.int, + vp: ^SceVfsVnode, +} +#assert(size_of(SceVfsOpSetRootArgs) == 0xC) + +SceVfsOpGetRootArgs :: struct { + mnt: ^SceVfsMount, + unk: c.int, + vpp: ^^SceVfsVnode, +} +#assert(size_of(SceVfsOpGetRootArgs) == 0xC) + +SceVfsOpSyncArgs :: struct { + mnt: ^SceVfsMount, + flags: c.int, +} +#assert(size_of(SceVfsOpSyncArgs) == 0x8) + +SceVfsOpInitArgs :: struct { + vfs_inf: ^SceVfsInfo, +} +#assert(size_of(SceVfsOpInitArgs) == 0x4) + +SceVfsOpFiniArgs :: struct { + vfs_inf: ^SceVfsInfo, +} +#assert(size_of(SceVfsOpFiniArgs) == 0x4) + +SceVfsOpDevctlArg :: struct { + mnt: ^SceVfsMount, + dev: cstring, + cmd: c.uint, + arg: rawptr, + arg_len: sce.Size, + buf: rawptr, + buf_len: sce.Size, +} +#assert(size_of(SceVfsOpDevctlArg) == 0x1C) + +SceVfsOpDecodePathElemArgs :: struct { + mnt: ^SceVfsMount, + path: cstring, + path2: ^cstring, // path + something + path3: ^cstring, // path3 + *decodeLen + buf: [^]byte, + buf_len: sce.Size, + decode_len: ^sce.Size, // out +} +#assert(size_of(SceVfsOpDecodePathElemArgs) == 0x1C) + +SceVfsOpTable :: struct { + vfs_mount: #type proc "c" (argp: ^SceVfsOpMountArgs) -> c.int, + vfs_umount: #type proc "c" (argp: ^SceVfsOpUmountArgs) -> c.int, + vfs_set_root: #type proc "c" (argp: ^SceVfsOpSetRootArgs) -> c.int, + vfs_get_root: #type proc "c" (argp: ^SceVfsOpGetRootArgs) -> c.int, + + reserved: [2]rawptr, // Unused + + vfs_sync: #type proc "c" (argp: ^SceVfsOpSyncArgs) -> c.int, + + reserved2: rawptr, // Unused + + vfs_init: #type proc "c" (argp: ^SceVfsOpInitArgs) -> c.int, + vfs_fini: #type proc "c" (argp: ^SceVfsOpFiniArgs) -> c.int, + + reserved3: rawptr, // Unused + + vfs_devctl: #type proc "c" (arg: ^SceVfsOpDevctlArg) -> c.int, + vfs_decode_path_elem: #type proc "c" (argp: ^SceVfsOpDecodePathElemArgs) -> c.int, +} +#assert(size_of(SceVfsOpTable) == 0x34) +/** @} */ + +/** + * @name VFS Vnode Operation Arguments and Callback Table + */ +/** @{ */ +SceVopOpenArgs :: struct { + vp: ^SceVfsVnode, + path: ^SceVfsPath, + flags: c.int, + file: ^SceVfsFile, +} +#assert(size_of(SceVopOpenArgs) == 0x10) + +SceVopCreateArgs :: struct { + dvp: ^SceVfsVnode, + vpp: ^^SceVfsVnode, + path: ^SceVfsPath, + flags: c.int, + mode: c.int, +} +#assert(size_of(SceVopCreateArgs) == 0x14) + +SceVopCloseArgs :: struct { + vp: ^SceVfsVnode, + file: ^SceVfsFile, +} +#assert(size_of(SceVopCloseArgs) == 0x8) + +SceVopLookupArgs :: struct { + dvp: ^SceVfsVnode, + vpp: ^^SceVfsVnode, + path: ^SceVfsPath, + flags: sce.UInt32, +} +#assert(size_of(SceVopLookupArgs) == 0x10) + +SceVopReadArgs :: struct { + vp: ^SceVfsVnode, + file: ^SceVfsFile, + buf: rawptr, + nbyte: sce.Size, +} +#assert(size_of(SceVopReadArgs) == 0x10) + +SceVopWriteArgs :: struct { + vp: ^SceVfsVnode, + file: ^SceVfsFile, + buf: rawptr, + nbyte: sce.Size, +} +#assert(size_of(SceVopWriteArgs) == 0x10) + +SceVopLseekArgs :: struct { + vp: ^SceVfsVnode, + file: ^SceVfsFile, + offset: sce.Off, + whence: c.int, +} +#assert(size_of(SceVopLseekArgs) == 0x18) + +SceVopIoctlArgs :: struct { + vp: ^SceVfsVnode, + file: ^SceVfsFile, + cmd: c.int, + in_data: rawptr, + in_len: sce.Size, + out_data: rawptr, + out_len: sce.Size, +} +#assert(size_of(SceVopIoctlArgs) == 0x1C) + +SceVopRemoveArgs :: struct { + dvp: ^SceVfsVnode, + vp: ^SceVfsVnode, + path: ^SceVfsPath, + flags: sce.UInt32, +} +#assert(size_of(SceVopRemoveArgs) == 0x10) + +SceVopMkdirArgs :: struct { + dvp: ^SceVfsVnode, + vpp: ^^SceVfsVnode, + path: ^SceVfsPath, + mode: c.int, +} +#assert(size_of(SceVopMkdirArgs) == 0x10) + +SceVopRmdirArgs :: struct { + dvp: ^SceVfsVnode, + vp: ^SceVfsVnode, + path: ^SceVfsPath, +} +#assert(size_of(SceVopRmdirArgs) == 0xC) + +SceVopDopenArgs :: struct { + vp: ^SceVfsVnode, + path: ^SceVfsPath, + file: ^SceVfsFile, +} +#assert(size_of(SceVopDopenArgs) == 0xC) + +SceVopDcloseArgs :: struct { + vp: ^SceVfsVnode, + file: ^SceVfsFile, +} +#assert(size_of(SceVopDcloseArgs) == 0x8) + +SceVopDreadArgs :: struct { + vp: ^SceVfsVnode, + file: ^SceVfsFile, + dir: ^sceIo.SceIoDirent, +} +#assert(size_of(SceVopDreadArgs) == 0xC) + +SceVopGetstatArgs :: struct { + vp: ^SceVfsVnode, + path: ^SceVfsPath, + stat: ^sceIo.SceIoStat, +} +#assert(size_of(SceVopGetstatArgs) == 0xC) + +SceVopChstatArgs :: struct { + vp: ^SceVfsVnode, + path: ^SceVfsPath, + stat: ^sceIo.SceIoStat, + bit: c.int, +} +#assert(size_of(SceVopChstatArgs) == 0x10) + +SceVopFchstatArgs :: struct { + vp: ^SceVfsVnode, + file: ^SceVfsFile, + stat: ^sceIo.SceIoStat, + bit: sce.UInt32, +} +#assert(size_of(SceVopFchstatArgs) == 0x10) + +SceVopFgetstatArgs :: struct { + vp: ^SceVfsVnode, + file: ^SceVfsFile, + stat: ^sceIo.SceIoStat, +} +#assert(size_of(SceVopFgetstatArgs) == 0xC) + +SceVopInactiveArgs :: struct { + vp: ^SceVfsVnode, +} +#assert(size_of(SceVopInactiveArgs) == 0x4) + +SceVopLinkArgs :: struct { + fvp: ^SceVfsVnode, + tvp: ^SceVfsVnode, +} +#assert(size_of(SceVopLinkArgs) == 0x8) + +SceVopUnlinkArgs :: struct { + fvp: ^SceVfsVnode, + tvp: ^SceVfsVnode, +} +#assert(size_of(SceVopUnlinkArgs) == 0x8) + +SceVopSyncArgs :: struct { + vp: ^SceVfsVnode, + file: ^SceVfsFile, + flags: c.int, +} +#assert(size_of(SceVopSyncArgs) == 0xC) + +SceVopRenameArgs :: struct { + odvp: ^SceVfsVnode, + ovp: ^SceVfsVnode, + old_path: ^SceVfsPath, + ndvp: ^SceVfsVnode, + nvpp: ^^SceVfsVnode, + new_path: ^SceVfsPath, +} +#assert(size_of(SceVopRenameArgs) == 0x18) + +SceVopPreadArgs :: struct { + vp: ^SceVfsVnode, + file: ^SceVfsFile, + buf: rawptr, + nbyte: sce.Size, + offset: sce.Off, +} +#assert(size_of(SceVopPreadArgs) == 0x18) + +SceVopPwriteArgs :: struct { + vp: ^SceVfsVnode, + file: ^SceVfsFile, + buf: rawptr, + nbyte: sce.Size, + offset: sce.Off, +} +#assert(size_of(SceVopPwriteArgs) == 0x18) + +SceVopWhiteoutArgs :: struct { + dvp: ^SceVfsVnode, + vp: ^SceVfsVnode, + old_path: ^SceVfsPath, + new_path: ^SceVfsPath, +} +#assert(size_of(SceVopWhiteoutArgs) == 0x10) + +SceVopCleanupArgs :: struct { + vp: ^SceVfsVnode, + file: ^SceVfsFile, +} +#assert(size_of(SceVopCleanupArgs) == 0x8) + +SceVopZerofillArgs :: struct { + vp: ^SceVfsVnode, + unk: sce.UInt64, + unk1: sce.UInt64, + unk2: sce.UInt64, +} +#assert(size_of(SceVopZerofillArgs) == 0x20) + +SceVopTable :: struct { + vop_open: #type proc "c" (argp: ^SceVopOpenArgs) -> c.int, + vop_create: #type proc "c" (argp: ^SceVopCreateArgs) -> c.int, + vop_close: #type proc "c" (argp: ^SceVopCloseArgs) -> c.int, + vop_lookup: #type proc "c" (argp: ^SceVopLookupArgs) -> c.int, + + vop_read: #type proc "c" (argp: ^SceVopReadArgs) -> sce.SSize, + vop_write: #type proc "c" (argp: ^SceVopWriteArgs) -> sce.SSize, + vop_lseek: #type proc "c" (argp: ^SceVopLseekArgs) -> sce.Off, + + vop_ioctl: #type proc "c" (argp: ^SceVopIoctlArgs) -> c.int, + + vop_remove: #type proc "c" (argp: ^SceVopRemoveArgs) -> c.int, + + vop_mkdir: #type proc "c" (argp: ^SceVopMkdirArgs) -> c.int, + vop_rmdir: #type proc "c" (argp: ^SceVopRmdirArgs) -> c.int, + + vop_dopen: #type proc "c" (argp: ^SceVopDopenArgs) -> c.int, + vop_dclose: #type proc "c" (argp: ^SceVopDcloseArgs) -> c.int, + vop_dread: #type proc "c" (argp: ^SceVopDreadArgs) -> c.int, + + vop_getstat: #type proc "c" (argp: ^SceVopGetstatArgs) -> c.int, + vop_chstat: #type proc "c" (argp: ^SceVopChstatArgs) -> c.int, + + vop_rename: #type proc "c" (argp: ^SceVopRenameArgs) -> c.int, + + reserved: rawptr, // Unused + + vop_pread: #type proc "c" (argp: ^SceVopPreadArgs) -> sce.SSize, + vop_pwrite: #type proc "c" (argp: ^SceVopPwriteArgs) -> sce.SSize, + + vop_inactive: #type proc "c" (argp: ^SceVopInactiveArgs) -> c.int, + vop_link: #type proc "c" (argp: ^SceVopLinkArgs) -> c.int, + vop_unlink: #type proc "c" (argp: ^SceVopUnlinkArgs) -> c.int, + + vop_sync: #type proc "c" (argp: ^SceVopSyncArgs) -> c.int, + + vop_fgetstat: #type proc "c" (argp: ^SceVopFgetstatArgs) -> c.int, + vop_fchstat: #type proc "c" (argp: ^SceVopFchstatArgs) -> c.int, + + vop_whiteout: #type proc "c" (argp: ^SceVopWhiteoutArgs) -> c.int, + vop_cleanup: #type proc "c" (argp: ^SceVopCleanupArgs) -> c.int, + vop_verofill: #type proc "c" (argp: ^SceVopZerofillArgs) -> c.int, +} +#assert(size_of(SceVopTable) == 0x74) +/** @} */ + +/** + * @name VFS Core API + */ +/** @{ */ +/** + * Parameters for vfsMount and vfsMountForPFS + */ +SceVfsMountParam :: struct { + root_path: cstring, //!< This is the internal root path of the mountpoint. (example: /ux/exfat for ux0:) + blockdev_name: cstring, //!< Overrides blockdevName in misc->blockdevName + + fs_type: sce.UInt8, //!< One of SCE_VFS_FS_TYPE_* + opt: sce.UInt16, //!< Used to identify the IO Scheduler queue to use for the mountpoint + mnt_flags: sce.UInt32, //!< ORed together SCE_VFS_MOUNT_FLAG_* flags + + vfs_name: cstring, //!< Name of the VFS to use for the mountpoint + + data: rawptr, //!< To be passed to the created mountpoint + + misc: ^SceVfsMountData, + + vops: ^SceVopTable, //!< Overrides defaultVops in the VFS Info for the root vnode of the VFS +} +#assert(size_of(SceVfsMountParam) == 0x20) + +SCE_VFS_UMOUNT_FLAG_FORCE :: (0x1) //!< Force unmount + +/** + * Parameters for vfsUmount and vfsUmountForPFS + */ +SceVfsUmountParam :: struct { + assign_name: cstring, //!< Assigned name of the mountpoint to unmount + flag: c.int, //!< One of SCE_VFS_UMOUNT_FLAG_* +} +#assert(size_of(SceVfsUmountParam) == 8) diff --git a/VshBridge/VshBridge.odin b/VshBridge/VshBridge.odin index 059021f..35d4df6 100644 --- a/VshBridge/VshBridge.odin +++ b/VshBridge/VshBridge.odin @@ -36,25 +36,33 @@ foreign vshbridge { _vshKernelSearchModuleByName :: proc(module_name: cstring, buffer: rawptr) -> sce.UID --- /** - * @param[in] id - mount id - * @param[in] path - mount path - * @param[in] permission - 1/RO 2/RW - * @param[in] buf - work buffer + * @brief Mount a partition. * - * @return 0 >= on success, < 0 on error. + * @param[in] id - Mount ID (one of ::SceVshMountId) + * @param[in] path - Mount path (optional, can be NULL) + * @param[in] permission - `1` for read-only, `2` for read-write. + * @param[in] buf - Work buffer. Allocate `0x100` and (important!) fill with `0`. + * + * @return `>= 0` on success, `< 0` on error. */ - _vshIoMount :: proc(id: c.int, path: cstring, permission: c.int, buf: rawptr) -> c.int --- + _vshIoMount :: proc(id: SceVshMountId, path: cstring, permission: c.int, buf: rawptr) -> c.int --- /** - * @param[in] id - mount id - * @param[in] force - Set to 1 to force umount - * @param[in] unk2 - Unknown, set 0 - * @param[in] unk3 - Unknown, set 0 + * @brief Unmount a partition. * - * @return 0 >= on success, < 0 on error. + * @warning Unmounting system partitions can cause system instability, even if + * you remount them back. For example, FIOS overlays used by the Shell + * won't get recreated and would effectively render the Shell unusable + * + * @param[in] id - Mount ID (one of ::SceVshMountId) + * @param[in] force - `1` to force unmount, `0` otherwise. + * @param[in] unk2 - Unknown, set to `0`. + * @param[in] unk3 - Unknown, set to `0`. + * + * @return `>= 0` on success, `< 0` on error. */ - vshIoUmount :: proc(id: c.int, force: c.int, unk2: c.int, unk3: c.int) -> c.int --- + vshIoUmount :: proc(id: SceVshMountId, force: c.int, unk2: c.int, unk3: c.int) -> c.int --- vshIdStorageIsDirty :: proc() -> c.int --- vshIdStorageIsFormatted :: proc() -> c.int --- diff --git a/VshBridge/types.odin b/VshBridge/types.odin new file mode 100644 index 0000000..c806dc1 --- /dev/null +++ b/VshBridge/types.odin @@ -0,0 +1,25 @@ +package vshbridge + +import "core:c" + +SceVshMountId :: enum c.int { + SCE_VSH_MOUNT_SD0 = 0x00100, + SCE_VSH_MOUNT_OS0 = 0x00200, + SCE_VSH_MOUNT_VS0 = 0x00300, + SCE_VSH_MOUNT_VD0 = 0x00400, + SCE_VSH_MOUNT_TM0 = 0x00500, + SCE_VSH_MOUNT_UR0 = 0x00600, + SCE_VSH_MOUNT_UD0 = 0x00700, + SCE_VSH_MOUNT_UX0 = 0x00800, + SCE_VSH_MOUNT_GRO0 = 0x00900, + SCE_VSH_MOUNT_GRW0 = 0x00A00, + SCE_VSH_MOUNT_SA0 = 0x00B00, + SCE_VSH_MOUNT_PD0 = 0x00C00, + SCE_VSH_MOUNT_IMC0 = 0x00D00, + SCE_VSH_MOUNT_XMC0 = 0x00E00, + SCE_VSH_MOUNT_UMA0 = 0x00F00, + SCE_VSH_MOUNT_LMA0 = 0x10000, + SCE_VSH_MOUNT_LMB0 = 0x20000, + SCE_VSH_MOUNT_MFA0 = 0x50000, + SCE_VSH_MOUNT_MFB0 = 0x60000, +} diff --git a/vita-headers b/vita-headers index 96b8721..68c368a 160000 --- a/vita-headers +++ b/vita-headers @@ -1 +1 @@ -Subproject commit 96b8721d90b2d3e0422b13129d33b46c9bfd812d +Subproject commit 68c368a1533cf2ebcbbef2131cc981716d0576bc