From 4695aaa8306158e94df8292106bdc3889976dd1e Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Thu, 16 Jan 2025 18:27:52 +0200 Subject: [PATCH] sceKernelAio* implementation (#2160) * draft Aio from https://github.com/GoldHEN/GoldHEN_Plugins_Repository * cleanup and fixes to Aio --- CMakeLists.txt | 2 + src/core/libraries/kernel/aio.cpp | 339 ++++++++++++++++++++++++ src/core/libraries/kernel/aio.h | 43 +++ src/core/libraries/kernel/file_system.h | 3 +- src/core/libraries/kernel/kernel.cpp | 2 + src/core/libraries/kernel/time.h | 1 + 6 files changed, 389 insertions(+), 1 deletion(-) create mode 100644 src/core/libraries/kernel/aio.cpp create mode 100644 src/core/libraries/kernel/aio.h diff --git a/CMakeLists.txt b/CMakeLists.txt index be87de119..30cb033ed 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -250,6 +250,8 @@ set(KERNEL_LIB src/core/libraries/kernel/sync/mutex.cpp src/core/libraries/kernel/time.h src/core/libraries/kernel/orbis_error.h src/core/libraries/kernel/posix_error.h + src/core/libraries/kernel/aio.cpp + src/core/libraries/kernel/aio.h ) set(NETWORK_LIBS src/core/libraries/network/http.cpp diff --git a/src/core/libraries/kernel/aio.cpp b/src/core/libraries/kernel/aio.cpp new file mode 100644 index 000000000..e017010cb --- /dev/null +++ b/src/core/libraries/kernel/aio.cpp @@ -0,0 +1,339 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include + +#include "aio.h" +#include "common/assert.h" +#include "common/debug.h" +#include "common/logging/log.h" +#include "core/libraries/kernel/equeue.h" +#include "core/libraries/kernel/orbis_error.h" +#include "core/libraries/libs.h" +#include "file_system.h" + +namespace Libraries::Kernel { + +#define MAX_QUEUE 512 + +static s32* id_state; +static s32 id_index; + +s32 sceKernelAioInitializeImpl(void* p, s32 size) { + + return 0; +} + +s32 PS4_SYSV_ABI sceKernelAioDeleteRequest(OrbisKernelAioSubmitId id, s32* ret) { + if (ret == nullptr) { + return ORBIS_KERNEL_ERROR_EFAULT; + } + id_state[id] = ORBIS_KERNEL_AIO_STATE_ABORTED; + *ret = 0; + return 0; +} + +s32 PS4_SYSV_ABI sceKernelAioDeleteRequests(OrbisKernelAioSubmitId id[], s32 num, s32 ret[]) { + if (ret == nullptr) { + return ORBIS_KERNEL_ERROR_EFAULT; + } + for (s32 i = 0; i < num; i++) { + id_state[id[i]] = ORBIS_KERNEL_AIO_STATE_ABORTED; + ret[i] = 0; + } + + return 0; +} +s32 PS4_SYSV_ABI sceKernelAioPollRequest(OrbisKernelAioSubmitId id, s32* state) { + if (state == nullptr) { + return ORBIS_KERNEL_ERROR_EFAULT; + } + *state = id_state[id]; + return 0; +} + +s32 PS4_SYSV_ABI sceKernelAioPollRequests(OrbisKernelAioSubmitId id[], s32 num, s32 state[]) { + if (state == nullptr) { + return ORBIS_KERNEL_ERROR_EFAULT; + } + for (s32 i = 0; i < num; i++) { + state[i] = id_state[id[i]]; + } + + return 0; +} + +s32 PS4_SYSV_ABI sceKernelAioCancelRequest(OrbisKernelAioSubmitId id, s32* state) { + if (state == nullptr) { + return ORBIS_KERNEL_ERROR_EFAULT; + } + if (id) { + id_state[id] = ORBIS_KERNEL_AIO_STATE_ABORTED; + *state = ORBIS_KERNEL_AIO_STATE_ABORTED; + } else { + *state = ORBIS_KERNEL_AIO_STATE_PROCESSING; + } + return 0; +} + +s32 PS4_SYSV_ABI sceKernelAioCancelRequests(OrbisKernelAioSubmitId id[], s32 num, s32 state[]) { + if (state == nullptr) { + return ORBIS_KERNEL_ERROR_EFAULT; + } + for (s32 i = 0; i < num; i++) { + if (id[i]) { + id_state[id[i]] = ORBIS_KERNEL_AIO_STATE_ABORTED; + state[i] = ORBIS_KERNEL_AIO_STATE_ABORTED; + } else { + state[i] = ORBIS_KERNEL_AIO_STATE_PROCESSING; + } + } + + return 0; +} + +s32 PS4_SYSV_ABI sceKernelAioWaitRequest(OrbisKernelAioSubmitId id, s32* state, u32* usec) { + if (state == nullptr) { + return ORBIS_KERNEL_ERROR_EFAULT; + } + u32 timer = 0; + + s32 timeout = 0; + + while (id_state[id] == ORBIS_KERNEL_AIO_STATE_PROCESSING) { + sceKernelUsleep(10); + + timer += 10; + if (*usec) { + if (timer > *usec) { + timeout = 1; + break; + } + } + } + + *state = id_state[id]; + + if (timeout) + return ORBIS_KERNEL_ERROR_ETIMEDOUT; + return 0; +} + +s32 PS4_SYSV_ABI sceKernelAioWaitRequests(OrbisKernelAioSubmitId id[], s32 num, s32 state[], + u32 mode, u32* usec) { + if (state == nullptr) { + return ORBIS_KERNEL_ERROR_EFAULT; + } + u32 timer = 0; + s32 timeout = 0; + s32 completion = 0; + + for (s32 i = 0; i < num; i++) { + if (!completion && !timeout) { + while (id_state[id[i]] == ORBIS_KERNEL_AIO_STATE_PROCESSING) { + sceKernelUsleep(10); + timer += 10; + + if (*usec) { + if (timer > *usec) { + timeout = 1; + break; + } + } + } + } + + if (mode == 0x02) { + if (id_state[id[i]] == ORBIS_KERNEL_AIO_STATE_COMPLETED) + completion = 1; + } + + state[i] = id_state[id[i]]; + } + + if (timeout) + return ORBIS_KERNEL_ERROR_ETIMEDOUT; + + return 0; +} + +s32 PS4_SYSV_ABI sceKernelAioSubmitReadCommands(OrbisKernelAioRWRequest req[], s32 size, s32 prio, + OrbisKernelAioSubmitId* id) { + if (req == nullptr) { + return ORBIS_KERNEL_ERROR_EFAULT; + } + if (id == nullptr) { + return ORBIS_KERNEL_ERROR_EFAULT; + } + id_state[id_index] = ORBIS_KERNEL_AIO_STATE_PROCESSING; + + for (s32 i = 0; i < size; i++) { + + s64 ret = sceKernelPread(req[i].fd, req[i].buf, req[i].nbyte, req[i].offset); + + if (ret < 0) { + req[i].result->state = ORBIS_KERNEL_AIO_STATE_ABORTED; + req[i].result->returnValue = ret; + + } else { + req[i].result->state = ORBIS_KERNEL_AIO_STATE_COMPLETED; + req[i].result->returnValue = ret; + } + } + + id_state[id_index] = ORBIS_KERNEL_AIO_STATE_COMPLETED; + + *id = id_index; + + id_index = (id_index + 1) % MAX_QUEUE; + + if (!id_index) + id_index++; + + return 0; +} + +s32 PS4_SYSV_ABI sceKernelAioSubmitReadCommandsMultiple(OrbisKernelAioRWRequest req[], s32 size, + s32 prio, OrbisKernelAioSubmitId id[]) { + if (req == nullptr) { + return ORBIS_KERNEL_ERROR_EFAULT; + } + if (id == nullptr) { + return ORBIS_KERNEL_ERROR_EFAULT; + } + for (s32 i = 0; i < size; i++) { + id_state[id_index] = ORBIS_KERNEL_AIO_STATE_PROCESSING; + + s64 ret = sceKernelPread(req[i].fd, req[i].buf, req[i].nbyte, req[i].offset); + + if (ret < 0) { + req[i].result->state = ORBIS_KERNEL_AIO_STATE_ABORTED; + req[i].result->returnValue = ret; + + id_state[id_index] = ORBIS_KERNEL_AIO_STATE_ABORTED; + + } else { + req[i].result->state = ORBIS_KERNEL_AIO_STATE_COMPLETED; + req[i].result->returnValue = ret; + + id_state[id_index] = ORBIS_KERNEL_AIO_STATE_COMPLETED; + } + + id[i] = id_index; + + id_index = (id_index + 1) % MAX_QUEUE; + + if (!id_index) + id_index++; + } + + return 0; +} + +s32 PS4_SYSV_ABI sceKernelAioSubmitWriteCommands(OrbisKernelAioRWRequest req[], s32 size, s32 prio, + OrbisKernelAioSubmitId* id) { + if (req == nullptr) { + return ORBIS_KERNEL_ERROR_EFAULT; + } + if (id == nullptr) { + return ORBIS_KERNEL_ERROR_EFAULT; + } + for (s32 i = 0; i < size; i++) { + id_state[id_index] = ORBIS_KERNEL_AIO_STATE_PROCESSING; + + s64 ret = sceKernelPwrite(req[i].fd, req[i].buf, req[i].nbyte, req[i].offset); + + if (ret < 0) { + req[i].result->state = ORBIS_KERNEL_AIO_STATE_ABORTED; + req[i].result->returnValue = ret; + + id_state[id_index] = ORBIS_KERNEL_AIO_STATE_ABORTED; + + } else { + req[i].result->state = ORBIS_KERNEL_AIO_STATE_COMPLETED; + req[i].result->returnValue = ret; + + id_state[id_index] = ORBIS_KERNEL_AIO_STATE_COMPLETED; + } + } + + *id = id_index; + + id_index = (id_index + 1) % MAX_QUEUE; + + // skip id_index equals 0 , because sceKernelAioCancelRequest will submit id + // equal to 0 + if (!id_index) + id_index++; + + return 0; +} + +s32 PS4_SYSV_ABI sceKernelAioSubmitWriteCommandsMultiple(OrbisKernelAioRWRequest req[], s32 size, + s32 prio, OrbisKernelAioSubmitId id[]) { + if (req == nullptr) { + return ORBIS_KERNEL_ERROR_EFAULT; + } + if (id == nullptr) { + return ORBIS_KERNEL_ERROR_EFAULT; + } + for (s32 i = 0; i < size; i++) { + id_state[id_index] = ORBIS_KERNEL_AIO_STATE_PROCESSING; + s64 ret = sceKernelPwrite(req[i].fd, req[i].buf, req[i].nbyte, req[i].offset); + + if (ret < 0) { + req[i].result->state = ORBIS_KERNEL_AIO_STATE_ABORTED; + req[i].result->returnValue = ret; + + id_state[id_index] = ORBIS_KERNEL_AIO_STATE_ABORTED; + + } else { + req[i].result->state = ORBIS_KERNEL_AIO_STATE_COMPLETED; + req[i].result->returnValue = ret; + id_state[id_index] = ORBIS_KERNEL_AIO_STATE_COMPLETED; + } + + id[i] = id_index; + id_index = (id_index + 1) % MAX_QUEUE; + + if (!id_index) + id_index++; + } + return 0; +} + +s32 PS4_SYSV_ABI sceKernelAioSetParam() { + LOG_ERROR(Kernel, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceKernelAioInitializeParam() { + LOG_ERROR(Kernel, "(STUBBED) called"); + return ORBIS_OK; +} + +void RegisterAio(Core::Loader::SymbolsResolver* sym) { + id_index = 1; + id_state = (int*)malloc(sizeof(int) * MAX_QUEUE); + memset(id_state, 0, sizeof(sizeof(int) * MAX_QUEUE)); + + LIB_FUNCTION("fR521KIGgb8", "libkernel", 1, "libkernel", 1, 1, sceKernelAioCancelRequest); + LIB_FUNCTION("3Lca1XBrQdY", "libkernel", 1, "libkernel", 1, 1, sceKernelAioCancelRequests); + LIB_FUNCTION("5TgME6AYty4", "libkernel", 1, "libkernel", 1, 1, sceKernelAioDeleteRequest); + LIB_FUNCTION("Ft3EtsZzAoY", "libkernel", 1, "libkernel", 1, 1, sceKernelAioDeleteRequests); + LIB_FUNCTION("vYU8P9Td2Zo", "libkernel", 1, "libkernel", 1, 1, sceKernelAioInitializeImpl); + LIB_FUNCTION("nu4a0-arQis", "libkernel", 1, "libkernel", 1, 1, sceKernelAioInitializeParam); + LIB_FUNCTION("2pOuoWoCxdk", "libkernel", 1, "libkernel", 1, 1, sceKernelAioPollRequest); + LIB_FUNCTION("o7O4z3jwKzo", "libkernel", 1, "libkernel", 1, 1, sceKernelAioPollRequests); + LIB_FUNCTION("9WK-vhNXimw", "libkernel", 1, "libkernel", 1, 1, sceKernelAioSetParam); + LIB_FUNCTION("HgX7+AORI58", "libkernel", 1, "libkernel", 1, 1, sceKernelAioSubmitReadCommands); + LIB_FUNCTION("lXT0m3P-vs4", "libkernel", 1, "libkernel", 1, 1, + sceKernelAioSubmitReadCommandsMultiple); + LIB_FUNCTION("XQ8C8y+de+E", "libkernel", 1, "libkernel", 1, 1, sceKernelAioSubmitWriteCommands); + LIB_FUNCTION("xT3Cpz0yh6Y", "libkernel", 1, "libkernel", 1, 1, + sceKernelAioSubmitWriteCommandsMultiple); + LIB_FUNCTION("KOF-oJbQVvc", "libkernel", 1, "libkernel", 1, 1, sceKernelAioWaitRequest); + LIB_FUNCTION("lgK+oIWkJyA", "libkernel", 1, "libkernel", 1, 1, sceKernelAioWaitRequests); +} + +} // namespace Libraries::Kernel \ No newline at end of file diff --git a/src/core/libraries/kernel/aio.h b/src/core/libraries/kernel/aio.h new file mode 100644 index 000000000..0ad21e938 --- /dev/null +++ b/src/core/libraries/kernel/aio.h @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include +#include + +#include "common/types.h" + +namespace Core::Loader { +class SymbolsResolver; +} + +namespace Libraries::Kernel { + +enum AioState { + ORBIS_KERNEL_AIO_STATE_SUBMITTED = 1, + ORBIS_KERNEL_AIO_STATE_PROCESSING = 2, + ORBIS_KERNEL_AIO_STATE_COMPLETED = 3, + ORBIS_KERNEL_AIO_STATE_ABORTED = 4 +}; + +struct OrbisKernelAioResult { + s64 returnValue; + u32 state; +}; + +typedef s32 OrbisKernelAioSubmitId; + +struct OrbisKernelAioRWRequest { + s64 offset; + s64 nbyte; + void* buf; + OrbisKernelAioResult* result; + s32 fd; +}; + +void RegisterAio(Core::Loader::SymbolsResolver* sym); +} // namespace Libraries::Kernel \ No newline at end of file diff --git a/src/core/libraries/kernel/file_system.h b/src/core/libraries/kernel/file_system.h index 6443962ff..1838df2fe 100644 --- a/src/core/libraries/kernel/file_system.h +++ b/src/core/libraries/kernel/file_system.h @@ -67,7 +67,8 @@ constexpr int ORBIS_KERNEL_O_DIRECTORY = 0x00020000; s64 PS4_SYSV_ABI sceKernelWrite(int d, const void* buf, size_t nbytes); s64 PS4_SYSV_ABI sceKernelRead(int d, void* buf, size_t nbytes); - +s64 PS4_SYSV_ABI sceKernelPread(int d, void* buf, size_t nbytes, s64 offset); +s64 PS4_SYSV_ABI sceKernelPwrite(int d, void* buf, size_t nbytes, s64 offset); void RegisterFileSystem(Core::Loader::SymbolsResolver* sym); } // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/kernel.cpp b/src/core/libraries/kernel/kernel.cpp index b05c96fad..a9d04ca38 100644 --- a/src/core/libraries/kernel/kernel.cpp +++ b/src/core/libraries/kernel/kernel.cpp @@ -28,6 +28,7 @@ #include #endif #include +#include "aio.h" namespace Libraries::Kernel { @@ -218,6 +219,7 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) { Libraries::Kernel::RegisterEventQueue(sym); Libraries::Kernel::RegisterProcess(sym); Libraries::Kernel::RegisterException(sym); + Libraries::Kernel::RegisterAio(sym); LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard); LIB_FUNCTION("PfccT7qURYE", "libkernel", 1, "libkernel", 1, 1, kernel_ioctl); diff --git a/src/core/libraries/kernel/time.h b/src/core/libraries/kernel/time.h index 6aa281aaf..407b6f9ed 100644 --- a/src/core/libraries/kernel/time.h +++ b/src/core/libraries/kernel/time.h @@ -82,6 +82,7 @@ int PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2, int PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time, OrbisTimesec* st, u64* dst_sec); +int PS4_SYSV_ABI sceKernelUsleep(u32 microseconds); void RegisterTime(Core::Loader::SymbolsResolver* sym);