diff --git a/CMakeLists.txt b/CMakeLists.txt index 035a996a8..d7e9b267a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1097,9 +1097,13 @@ if (ENABLE_DISCORD_RPC) target_compile_definitions(shadps4 PRIVATE ENABLE_DISCORD_RPC) endif() -# Optional due to https://github.com/shadps4-emu/shadPS4/issues/1704 -if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND ENABLE_USERFAULTFD) - target_compile_definitions(shadps4 PRIVATE ENABLE_USERFAULTFD) +if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") + # Optional due to https://github.com/shadps4-emu/shadPS4/issues/1704 + if (ENABLE_USERFAULTFD) + target_compile_definitions(shadps4 PRIVATE ENABLE_USERFAULTFD) + endif() + + target_link_libraries(shadps4 PRIVATE uuid) endif() if (APPLE) diff --git a/src/core/libraries/kernel/kernel.cpp b/src/core/libraries/kernel/kernel.cpp index 959a8605a..c7eafe799 100644 --- a/src/core/libraries/kernel/kernel.cpp +++ b/src/core/libraries/kernel/kernel.cpp @@ -28,8 +28,12 @@ #ifdef _WIN64 #include +#else +#include #endif #include +#include +#include #include "aio.h" namespace Libraries::Kernel { @@ -150,23 +154,23 @@ struct OrbisKernelUuid { u8 clockSeqLow; u8 node[6]; }; +static_assert(sizeof(OrbisKernelUuid) == 0x10); int PS4_SYSV_ABI sceKernelUuidCreate(OrbisKernelUuid* orbisUuid) { + if (!orbisUuid) { + return ORBIS_KERNEL_ERROR_EINVAL; + } #ifdef _WIN64 UUID uuid; - UuidCreate(&uuid); - orbisUuid->timeLow = uuid.Data1; - orbisUuid->timeMid = uuid.Data2; - orbisUuid->timeHiAndVersion = uuid.Data3; - orbisUuid->clockSeqHiAndReserved = uuid.Data4[0]; - orbisUuid->clockSeqLow = uuid.Data4[1]; - for (int i = 0; i < 6; i++) { - orbisUuid->node[i] = uuid.Data4[2 + i]; + if (UuidCreate(&uuid) != RPC_S_OK) { + return ORBIS_KERNEL_ERROR_EFAULT; } #else - LOG_ERROR(Kernel, "sceKernelUuidCreate: Add linux"); + uuid_t uuid; + uuid_generate(uuid); #endif - return 0; + std::memcpy(orbisUuid, &uuid, sizeof(OrbisKernelUuid)); + return ORBIS_OK; } int PS4_SYSV_ABI kernel_ioctl(int fd, u64 cmd, VA_ARGS) { @@ -205,6 +209,24 @@ int PS4_SYSV_ABI posix_getpagesize() { return 16_KB; } +int PS4_SYSV_ABI posix_getsockname(Libraries::Net::OrbisNetId s, + Libraries::Net::OrbisNetSockaddr* addr, u32* paddrlen) { + auto* netcall = Common::Singleton::Instance(); + auto sock = netcall->FindSocket(s); + if (!sock) { + *Libraries::Kernel::__Error() = ORBIS_NET_ERROR_EBADF; + LOG_ERROR(Lib_Net, "socket id is invalid = {}", s); + return -1; + } + int returncode = sock->GetSocketAddress(addr, paddrlen); + if (returncode >= 0) { + LOG_ERROR(Lib_Net, "return code : {:#x}", (u32)returncode); + return 0; + } + *Libraries::Kernel::__Error() = 0x20; + LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode); + return -1; +} void RegisterKernel(Core::Loader::SymbolsResolver* sym) { service_thread = std::jthread{KernelServiceThread}; @@ -242,8 +264,7 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("lUk6wrGXyMw", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_recvfrom); LIB_FUNCTION("fFxGkxF2bVo", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_setsockopt); - LIB_FUNCTION("RenI1lL1WFk", "libScePosix", 1, "libkernel", 1, 1, - Libraries::Net::sys_getsockname); + // LIB_FUNCTION("RenI1lL1WFk", "libScePosix", 1, "libkernel", 1, 1, posix_getsockname); LIB_FUNCTION("KuOmgKoqCdY", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_bind); LIB_FUNCTION("5jRCs2axtr4", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sceNetInetNtop); // TODO fix it to sys_ ... diff --git a/src/core/libraries/network/net.cpp b/src/core/libraries/network/net.cpp index 1f024277f..0ef4a84f5 100644 --- a/src/core/libraries/network/net.cpp +++ b/src/core/libraries/network/net.cpp @@ -886,6 +886,7 @@ int PS4_SYSV_ABI sceNetGetsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* pa } int PS4_SYSV_ABI sceNetGetsockopt(OrbisNetId s, int level, int optname, void* optval, u32* optlen) { + LOG_INFO(Lib_Net, "s={} level={} optname={}", s, level, optname); if (!g_isNetInitialized) { return ORBIS_NET_ERROR_ENOTINIT; } @@ -1449,6 +1450,7 @@ int PS4_SYSV_ABI sceNetSetDnsInfoToKernel() { int PS4_SYSV_ABI sceNetSetsockopt(OrbisNetId s, int level, int optname, const void* optval, u32 optlen) { + LOG_INFO(Lib_Net, "s={} level={} optname={} optlen={}", s, level, optname, optlen); if (!g_isNetInitialized) { return ORBIS_NET_ERROR_ENOTINIT; } diff --git a/src/core/libraries/network/p2p_sockets.cpp b/src/core/libraries/network/p2p_sockets.cpp index e9b710bb3..4f678dace 100644 --- a/src/core/libraries/network/p2p_sockets.cpp +++ b/src/core/libraries/network/p2p_sockets.cpp @@ -10,25 +10,25 @@ namespace Libraries::Net { int P2PSocket::Close() { LOG_ERROR(Lib_Net, "(STUBBED) called"); - return -1; + return 0; } int P2PSocket::SetSocketOptions(int level, int optname, const void* optval, u32 optlen) { LOG_ERROR(Lib_Net, "(STUBBED) called"); - return -1; + return 0; } int P2PSocket::GetSocketOptions(int level, int optname, void* optval, u32* optlen) { LOG_ERROR(Lib_Net, "(STUBBED) called"); - return -1; + return 0; } int P2PSocket::Bind(const OrbisNetSockaddr* addr, u32 addrlen) { LOG_ERROR(Lib_Net, "(STUBBED) called"); - return -1; + return 0; } int P2PSocket::Listen(int backlog) { LOG_ERROR(Lib_Net, "(STUBBED) called"); - return -1; + return 0; } int P2PSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to, @@ -49,12 +49,12 @@ SocketPtr P2PSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) { int P2PSocket::Connect(const OrbisNetSockaddr* addr, u32 namelen) { LOG_ERROR(Lib_Net, "(STUBBED) called"); - return -1; + return 0; } int P2PSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) { LOG_ERROR(Lib_Net, "(STUBBED) called"); - return -1; + return 0; } } // namespace Libraries::Net \ No newline at end of file diff --git a/src/core/libraries/network/posix_sockets.cpp b/src/core/libraries/network/posix_sockets.cpp index 140e4fd22..2df375262 100644 --- a/src/core/libraries/network/posix_sockets.cpp +++ b/src/core/libraries/network/posix_sockets.cpp @@ -143,6 +143,7 @@ static void convertPosixSockaddrToOrbis(sockaddr* src, OrbisNetSockaddr* dst) { } int PosixSocket::Close() { + std::scoped_lock lock{m_mutex}; #ifdef _WIN32 auto out = closesocket(sock); #else @@ -152,17 +153,20 @@ int PosixSocket::Close() { } int PosixSocket::Bind(const OrbisNetSockaddr* addr, u32 addrlen) { + std::scoped_lock lock{m_mutex}; sockaddr addr2; convertOrbisNetSockaddrToPosix(addr, &addr2); return ConvertReturnErrorCode(::bind(sock, &addr2, sizeof(sockaddr_in))); } int PosixSocket::Listen(int backlog) { + std::scoped_lock lock{m_mutex}; return ConvertReturnErrorCode(::listen(sock, backlog)); } int PosixSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to, u32 tolen) { + std::scoped_lock lock{m_mutex}; if (to != nullptr) { sockaddr addr; convertOrbisNetSockaddrToPosix(to, &addr); @@ -175,6 +179,7 @@ int PosixSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetS int PosixSocket::ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, u32* fromlen) { + std::scoped_lock lock{m_mutex}; if (from != nullptr) { sockaddr addr; int res = recvfrom(sock, (char*)buf, len, flags, &addr, (socklen_t*)fromlen); @@ -187,6 +192,7 @@ int PosixSocket::ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* } SocketPtr PosixSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) { + std::scoped_lock lock{m_mutex}; sockaddr addr2; net_socket new_socket = ::accept(sock, &addr2, (socklen_t*)addrlen); #ifdef _WIN32 @@ -202,12 +208,14 @@ SocketPtr PosixSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) { } int PosixSocket::Connect(const OrbisNetSockaddr* addr, u32 namelen) { + std::scoped_lock lock{m_mutex}; sockaddr addr2; convertOrbisNetSockaddrToPosix(addr, &addr2); return ::connect(sock, &addr2, sizeof(sockaddr_in)); } int PosixSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) { + std::scoped_lock lock{m_mutex}; sockaddr addr; convertOrbisNetSockaddrToPosix(name, &addr); if (name != nullptr) { @@ -234,13 +242,15 @@ int PosixSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) { return 0 int PosixSocket::SetSocketOptions(int level, int optname, const void* optval, u32 optlen) { + std::scoped_lock lock{m_mutex}; level = ConvertLevels(level); + ::linger native_linger; if (level == SOL_SOCKET) { switch (optname) { CASE_SETSOCKOPT(SO_REUSEADDR); CASE_SETSOCKOPT(SO_KEEPALIVE); CASE_SETSOCKOPT(SO_BROADCAST); - CASE_SETSOCKOPT(SO_LINGER); + // CASE_SETSOCKOPT(SO_LINGER); CASE_SETSOCKOPT(SO_SNDBUF); CASE_SETSOCKOPT(SO_RCVBUF); CASE_SETSOCKOPT(SO_SNDTIMEO); @@ -251,6 +261,24 @@ int PosixSocket::SetSocketOptions(int level, int optname, const void* optval, u3 CASE_SETSOCKOPT_VALUE(ORBIS_NET_SO_ONESBCAST, &sockopt_so_onesbcast); CASE_SETSOCKOPT_VALUE(ORBIS_NET_SO_USECRYPTO, &sockopt_so_usecrypto); CASE_SETSOCKOPT_VALUE(ORBIS_NET_SO_USESIGNATURE, &sockopt_so_usesignature); + case ORBIS_NET_SO_LINGER: { + if (socket_type != ORBIS_NET_SOCK_STREAM) { + return ORBIS_NET_EPROCUNAVAIL; + } + if (optlen < sizeof(OrbisNetLinger)) { + LOG_ERROR(Lib_Net, "size missmatched! optlen = {} OrbisNetLinger={}", optlen, + sizeof(OrbisNetLinger)); + return ORBIS_NET_ERROR_EINVAL; + } + + const void* native_val = &native_linger; + u32 native_len = sizeof(native_linger); + native_linger.l_onoff = reinterpret_cast(optval)->l_onoff; + native_linger.l_linger = reinterpret_cast(optval)->l_linger; + return ConvertReturnErrorCode( + setsockopt(sock, level, SO_LINGER, (const char*)native_val, native_len)); + } + case ORBIS_NET_SO_NAME: return ORBIS_NET_ERROR_EINVAL; // don't support set for name case ORBIS_NET_SO_NBIO: { @@ -269,7 +297,7 @@ int PosixSocket::SetSocketOptions(int level, int optname, const void* optval, u3 } } else if (level == IPPROTO_IP) { switch (optname) { - CASE_SETSOCKOPT(IP_HDRINCL); + // CASE_SETSOCKOPT(IP_HDRINCL); CASE_SETSOCKOPT(IP_TOS); CASE_SETSOCKOPT(IP_TTL); CASE_SETSOCKOPT(IP_MULTICAST_IF); @@ -279,6 +307,13 @@ int PosixSocket::SetSocketOptions(int level, int optname, const void* optval, u3 CASE_SETSOCKOPT(IP_DROP_MEMBERSHIP); CASE_SETSOCKOPT_VALUE(ORBIS_NET_IP_TTLCHK, &sockopt_ip_ttlchk); CASE_SETSOCKOPT_VALUE(ORBIS_NET_IP_MAXTTL, &sockopt_ip_maxttl); + case ORBIS_NET_IP_HDRINCL: { + if (socket_type != ORBIS_NET_SOCK_RAW) { + return ORBIS_NET_EPROCUNAVAIL; + } + return ConvertReturnErrorCode( + setsockopt(sock, level, optname, (const char*)optval, optlen)); + } } } else if (level == IPPROTO_TCP) { switch (optname) { @@ -311,6 +346,7 @@ int PosixSocket::SetSocketOptions(int level, int optname, const void* optval, u3 return 0; int PosixSocket::GetSocketOptions(int level, int optname, void* optval, u32* optlen) { + std::scoped_lock lock{m_mutex}; level = ConvertLevels(level); if (level == SOL_SOCKET) { switch (optname) { diff --git a/src/core/libraries/network/sockets.h b/src/core/libraries/network/sockets.h index e41671d88..c54e11e66 100644 --- a/src/core/libraries/network/sockets.h +++ b/src/core/libraries/network/sockets.h @@ -32,6 +32,10 @@ struct Socket; typedef std::shared_ptr SocketPtr; +struct OrbisNetLinger { + s32 l_onoff; + s32 l_linger; +}; struct Socket { explicit Socket(int domain, int type, int protocol) {} virtual ~Socket() = default; @@ -47,6 +51,7 @@ struct Socket { u32* fromlen) = 0; virtual int Connect(const OrbisNetSockaddr* addr, u32 namelen) = 0; virtual int GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) = 0; + std::mutex m_mutex; }; struct PosixSocket : public Socket { @@ -59,8 +64,11 @@ struct PosixSocket : public Socket { int sockopt_ip_ttlchk = 0; int sockopt_ip_maxttl = 0; int sockopt_tcp_mss_to_advertise = 0; + int socket_type; explicit PosixSocket(int domain, int type, int protocol) - : Socket(domain, type, protocol), sock(socket(domain, type, protocol)) {} + : Socket(domain, type, protocol), sock(socket(domain, type, protocol)) { + socket_type = type; + } explicit PosixSocket(net_socket sock) : Socket(0, 0, 0), sock(sock) {} int Close() override; int SetSocketOptions(int level, int optname, const void* optval, u32 optlen) override; diff --git a/src/core/libraries/network/sys_net.cpp b/src/core/libraries/network/sys_net.cpp index fbf2a2456..087632159 100644 --- a/src/core/libraries/network/sys_net.cpp +++ b/src/core/libraries/network/sys_net.cpp @@ -1,4 +1,3 @@ -#include "sys_net.h" // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 8fef8d102..6438670d3 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -649,19 +649,23 @@ s64 MemoryManager::ProtectBytes(VAddr addr, VirtualMemoryArea vma_base, size_t s s32 MemoryManager::Protect(VAddr addr, size_t size, MemoryProt prot) { std::scoped_lock lk{mutex}; s64 protected_bytes = 0; + + auto aligned_addr = Common::AlignDown(addr, 16_KB); + auto aligned_size = Common::AlignUp(size + addr - aligned_addr, 16_KB); do { - auto it = FindVMA(addr + protected_bytes); + auto it = FindVMA(aligned_addr + protected_bytes); auto& vma_base = it->second; ASSERT_MSG(vma_base.Contains(addr + protected_bytes, 0), "Address {:#x} is out of bounds", addr + protected_bytes); auto result = 0; - result = ProtectBytes(addr + protected_bytes, vma_base, size - protected_bytes, prot); + result = ProtectBytes(aligned_addr + protected_bytes, vma_base, + aligned_size - protected_bytes, prot); if (result < 0) { // ProtectBytes returned an error, return it return result; } protected_bytes += result; - } while (protected_bytes < size); + } while (protected_bytes < aligned_size); return ORBIS_OK; } diff --git a/src/video_core/buffer_cache/buffer_cache.cpp b/src/video_core/buffer_cache/buffer_cache.cpp index 5d7676df8..2abbcd22b 100644 --- a/src/video_core/buffer_cache/buffer_cache.cpp +++ b/src/video_core/buffer_cache/buffer_cache.cpp @@ -981,7 +981,15 @@ void BufferCache::InlineDataBuffer(Buffer& buffer, VAddr address, const void* va .bufferMemoryBarrierCount = 1, .pBufferMemoryBarriers = &pre_barrier, }); - cmdbuf.updateBuffer(buffer.Handle(), buffer.Offset(address), num_bytes, value); + // vkCmdUpdateBuffer can only copy up to 65536 bytes at a time. + static constexpr u32 UpdateBufferMaxSize = 65536; + const auto dst_offset = buffer.Offset(address); + for (u32 offset = 0; offset < num_bytes; offset += UpdateBufferMaxSize) { + const auto* update_src = static_cast(value) + offset; + const auto update_dst = dst_offset + offset; + const auto update_size = std::min(num_bytes - offset, UpdateBufferMaxSize); + cmdbuf.updateBuffer(buffer.Handle(), update_dst, update_size, update_src); + } cmdbuf.pipelineBarrier2(vk::DependencyInfo{ .dependencyFlags = vk::DependencyFlagBits::eByRegion, .bufferMemoryBarrierCount = 1, diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index 73bc6b88d..9584329f0 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -262,6 +262,8 @@ bool Instance::CreateDevice() { robustness2_features = feature_chain.get(); LOG_INFO(Render_Vulkan, "- robustBufferAccess2: {}", robustness2_features.robustBufferAccess2); + LOG_INFO(Render_Vulkan, "- robustImageAccess2: {}", + robustness2_features.robustImageAccess2); LOG_INFO(Render_Vulkan, "- nullDescriptor: {}", robustness2_features.nullDescriptor); } custom_border_color = add_extension(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); @@ -338,6 +340,7 @@ bool Instance::CreateDevice() { .independentBlend = features.independentBlend, .geometryShader = features.geometryShader, .tessellationShader = features.tessellationShader, + .dualSrcBlend = features.dualSrcBlend, .logicOp = features.logicOp, .multiDrawIndirect = features.multiDrawIndirect, .depthBiasClamp = features.depthBiasClamp, @@ -396,6 +399,7 @@ bool Instance::CreateDevice() { }, vk::PhysicalDeviceRobustness2FeaturesEXT{ .robustBufferAccess2 = robustness2_features.robustBufferAccess2, + .robustImageAccess2 = robustness2_features.robustImageAccess2, .nullDescriptor = robustness2_features.nullDescriptor, }, vk::PhysicalDeviceVertexInputDynamicStateFeaturesEXT{ diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 0a0c81d4c..d7ad47a3c 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -205,7 +205,8 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_, .supports_image_load_store_lod = instance_.IsImageLoadStoreLodSupported(), .supports_native_cube_calc = instance_.IsAmdGcnShaderSupported(), .supports_trinary_minmax = instance_.IsAmdShaderTrinaryMinMaxSupported(), - .supports_robust_buffer_access = instance_.IsRobustBufferAccess2Supported(), + // TODO: Emitted bounds checks cause problems with phi control flow; needs to be fixed. + .supports_robust_buffer_access = true, // instance_.IsRobustBufferAccess2Supported(), .supports_image_fp32_atomic_min_max = instance_.IsShaderAtomicFloatImage32MinMaxSupported(), .needs_manual_interpolation = instance.IsFragmentShaderBarycentricSupported() && instance.GetDriverID() == vk::DriverId::eNvidiaProprietary,