diff --git a/core/libs/prx/libc/CMakeLists.txt b/core/libs/prx/libc/CMakeLists.txt index ba4ae9c93..88e49d7ac 100644 --- a/core/libs/prx/libc/CMakeLists.txt +++ b/core/libs/prx/libc/CMakeLists.txt @@ -5,6 +5,8 @@ target_sources(libc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/specifics/windows/CrashReport.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/specifics/linux/DlIteratePhdr.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Strings.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/AllocatingStrings.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/WideConversion.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/StringExtensions.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Math.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Time.cpp diff --git a/core/libs/prx/libc/src/AllocatingStrings.cpp b/core/libs/prx/libc/src/AllocatingStrings.cpp new file mode 100644 index 000000000..d3539587b --- /dev/null +++ b/core/libs/prx/libc/src/AllocatingStrings.cpp @@ -0,0 +1,82 @@ +#include "prx/libc/include/ApplicationHeap.hpp" +#include "prx/libc/include/General.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include "prx/libc/include/WindowsFormatting.hpp" +#endif + +extern "C" { + +char* APS5_VABI strndup_nid_postfix(const char* source, std::size_t limit) { + std::size_t length = 0; + while (length < limit && source[length] != '\0') ++length; + try { + auto* result = static_cast(ApplicationHeapAllocate_nid_no_patch(length + 1)); + if (!result) { errno = 12; return nullptr; } + std::memcpy(result, source, length); + result[length] = '\0'; + return result; + } catch (const std::bad_alloc&) { + errno = 12; + return nullptr; + } +} + +int APS5_VABI asprintf_nid_postfix(char** destination, const char* format, ...) { + if (!destination) { errno = 22; return -1; } + *destination = nullptr; + if (!format) { errno = 22; return -1; } +#ifdef _WIN32 + __builtin_sysv_va_list args; + __builtin_sysv_va_start(args, format); +#else + std::va_list args; + va_start(args, format); +#endif + int result = -1; + try { +#ifdef _WIN32 + std::string text; + const int count = LibcDetail::FormatWindows(nullptr, 0, format, args, &text); + const char* source = text.c_str(); +#else + char* text = nullptr; + const int count = ::vasprintf(&text, format, args); + std::unique_ptr owner(text, std::free); + const char* source = text; +#endif + if (count >= 0) { + auto* output = static_cast(ApplicationHeapAllocate_nid_no_patch(static_cast(count) + 1)); + if (output) { + std::memcpy(output, source, static_cast(count) + 1); + *destination = output; + result = count; + } else errno = 12; + } + } catch (const std::bad_alloc&) { + errno = 12; + } catch (...) { +#ifdef _WIN32 + __builtin_sysv_va_end(args); +#else + va_end(args); +#endif + throw; + } +#ifdef _WIN32 + __builtin_sysv_va_end(args); +#else + va_end(args); +#endif + return result; +} + +} diff --git a/core/libs/prx/libc/src/WideConversion.cpp b/core/libs/prx/libc/src/WideConversion.cpp new file mode 100644 index 000000000..085d945d5 --- /dev/null +++ b/core/libs/prx/libc/src/WideConversion.cpp @@ -0,0 +1,19 @@ +#include "prx/libc/include/general/VabiMacros.hpp" +#include +#include +#include + +extern "C" std::size_t APS5_VABI wcstombs_nid_postfix(char* destination, const std::uint16_t* source, std::size_t capacity) { + std::size_t count = 0; + while (!destination || count < capacity) { + const auto value = source[count]; + if (value > 255) { + errno = 86; + return static_cast(-1); + } + if (destination) destination[count] = static_cast(value); + if (value == 0) break; + ++count; + } + return count; +} diff --git a/core/libs/prx/libkernel/CMakeLists.txt b/core/libs/prx/libkernel/CMakeLists.txt index 801440466..a173504cb 100644 --- a/core/libs/prx/libkernel/CMakeLists.txt +++ b/core/libs/prx/libkernel/CMakeLists.txt @@ -20,6 +20,7 @@ add_library(libkernel SHARED EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/Pthread/src/Rwlock.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Pthread/src/Sem.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Pthread/Posix/Attr.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Pthread/Posix/Barrier.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Pthread/Posix/Cond.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Pthread/Posix/Mutex.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Pthread/Posix/Rwlock.cpp diff --git a/core/libs/prx/libkernel/Pthread/Posix/Barrier.cpp b/core/libs/prx/libkernel/Pthread/Posix/Barrier.cpp new file mode 100644 index 000000000..723fd1267 --- /dev/null +++ b/core/libs/prx/libkernel/Pthread/Posix/Barrier.cpp @@ -0,0 +1,61 @@ +#include "prx/libc/include/General.hpp" +#include +#include +#include +#include + +struct PthreadBarrierPrivate { + std::mutex mutex; + std::condition_variable changed; + unsigned count; + unsigned arrived = 0; + unsigned active = 0; + std::uint64_t generation = 0; +}; + +extern "C" { + +int APS5_VABI pthread_barrier_init_nid_postfix(PthreadBarrierPrivate** barrier, const void* attr, unsigned count) { + if (!barrier || count == 0) return 22; + if (attr) NotImplemented_nid_no_patch("pthread_barrier_init: non-default attributes"); + try { + auto* value = new PthreadBarrierPrivate; + value->count = count; + *barrier = value; + return 0; + } catch (const std::bad_alloc&) { + return 12; + } +} + +int APS5_VABI pthread_barrier_wait_nid_postfix(PthreadBarrierPrivate** barrier) { + if (!barrier || !*barrier) return 22; + auto& value = **barrier; + std::unique_lock lock(value.mutex); + const auto generation = value.generation; + ++value.active; + if (++value.arrived == value.count) { + value.arrived = 0; + ++value.generation; + value.changed.notify_all(); + --value.active; + return -1; + } + value.changed.wait(lock, [&] { return value.generation != generation; }); + --value.active; + return 0; +} + +int APS5_VABI pthread_barrier_destroy_nid_postfix(PthreadBarrierPrivate** barrier) { + if (!barrier || !*barrier) return 22; + auto* value = *barrier; + { + std::lock_guard lock(value->mutex); + if (value->active != 0) return 16; + } + delete value; + *barrier = nullptr; + return 0; +} + +} diff --git a/core/libs/prx/libkernel/Pthread/Posix/Thread.cpp b/core/libs/prx/libkernel/Pthread/Posix/Thread.cpp index f1d43aa31..fc9fd94d8 100644 --- a/core/libs/prx/libkernel/Pthread/Posix/Thread.cpp +++ b/core/libs/prx/libkernel/Pthread/Posix/Thread.cpp @@ -57,6 +57,15 @@ Pthread APS5_VABI pthread_self_nid_postfix(void) { return scePthreadSelf(); } +int APS5_VABI pthread_equal_nid_postfix(Pthread first, Pthread second) { + return first == second; +} + +int APS5_VABI sched_yield_nid_postfix(void) { + std::this_thread::yield(); + return 0; +} + int APS5_VABI pthread_setcancelstate_nid_postfix(int state, int* old_state) { return PosixThread::ToErrno(scePthreadSetcancelstate(state, old_state)); } diff --git a/core/relinker/codegen/include/codegen/x86/X64OpcodeConstants.hpp b/core/relinker/codegen/include/codegen/x86/X64OpcodeConstants.hpp index 2472fe258..022721a23 100644 --- a/core/relinker/codegen/include/codegen/x86/X64OpcodeConstants.hpp +++ b/core/relinker/codegen/include/codegen/x86/X64OpcodeConstants.hpp @@ -130,6 +130,7 @@ inline constexpr std::uint8_t TwoByteModRmRangeFMin = 0x38; inline constexpr std::uint8_t TwoByteModRmRangeFMax = 0x3A; inline constexpr std::uint8_t TwoByteModRmRangeGMin = 0x54; inline constexpr std::uint8_t TwoByteModRmRangeGMax = 0x7F; +inline constexpr std::uint8_t TwoByteEmms = 0x77; inline constexpr std::uint8_t TwoByteModRmRangeHMin = 0xD0; inline constexpr std::uint8_t TwoByteModRmRangeHMax = 0xFE; inline constexpr std::uint8_t TwoByteNopModRm = 0x1F; diff --git a/core/relinker/codegen/src/x86/X64InstructionDecoder.cpp b/core/relinker/codegen/src/x86/X64InstructionDecoder.cpp index fe0ee7ef9..462ff5c2d 100644 --- a/core/relinker/codegen/src/x86/X64InstructionDecoder.cpp +++ b/core/relinker/codegen/src/x86/X64InstructionDecoder.cpp @@ -252,7 +252,7 @@ std::size_t X64InstructionDecoder::Decode(const std::uint8_t* data, std::size_t (opcode >= TwoByteModRmRangeCMin && opcode <= TwoByteModRmRangeCMax) || (opcode >= TwoByteModRmRangeDMin && opcode <= TwoByteModRmRangeDMax) || (opcode >= TwoByteModRmRangeEMin && opcode <= TwoByteModRmRangeEMax) || - (opcode >= TwoByteModRmRangeGMin && opcode <= TwoByteModRmRangeGMax) || + (opcode >= TwoByteModRmRangeGMin && opcode <= TwoByteModRmRangeGMax && opcode != TwoByteEmms) || (opcode >= TwoByteModRmRangeHMin && opcode <= TwoByteModRmRangeHMax) || (opcode >= TwoByteModRmRangeIMin && opcode <= TwoByteModRmRangeIMax) || (opcode >= TwoBytePrefetchGrpMin && opcode <= TwoBytePrefetchGrpMax) ||