Merge branch 'shadps4-emu:main' into fs-fixes

This commit is contained in:
Stephen Miller 2025-04-30 17:02:45 -05:00 committed by GitHub
commit 218f151aa5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 2178 additions and 124 deletions

View File

@ -371,11 +371,19 @@ set(NETWORK_LIBS src/core/libraries/network/http.cpp
src/core/libraries/network/net_ctl_obj.cpp
src/core/libraries/network/net_ctl_obj.h
src/core/libraries/network/net_ctl_codes.h
src/core/libraries/network/net_util.cpp
src/core/libraries/network/net_util.h
src/core/libraries/network/net_error.h
src/core/libraries/network/net.h
src/core/libraries/network/ssl.cpp
src/core/libraries/network/ssl.h
src/core/libraries/network/ssl2.cpp
src/core/libraries/network/ssl2.h
src/core/libraries/network/sys_net.cpp
src/core/libraries/network/sys_net.h
src/core/libraries/network/posix_sockets.cpp
src/core/libraries/network/p2p_sockets.cpp
src/core/libraries/network/sockets.h
)
set(AVPLAYER_LIB src/core/libraries/avplayer/avplayer_common.cpp

2
externals/sirit vendored

@ -1 +1 @@
Subproject commit 427a42c9ed99b38204d9107bc3dc14e92458acf1
Subproject commit 09a1416ab1b59ddfebd2618412f118f2004f3b2c

View File

@ -23,7 +23,7 @@
namespace MemoryPatcher {
uintptr_t g_eboot_address;
EXPORT uintptr_t g_eboot_address;
uint64_t g_eboot_image_size;
std::string g_game_serial;
std::string patchFile;
@ -169,7 +169,8 @@ void OnGameLoaded() {
if (type == "mask_jump32")
patchMask = MemoryPatcher::PatchMask::Mask_Jump32;
if (type == "mask" || type == "mask_jump32" && !maskOffsetStr.empty()) {
if ((type == "mask" || type == "mask_jump32") &&
!maskOffsetStr.empty()) {
maskOffsetValue = std::stoi(maskOffsetStr, 0, 10);
}

View File

@ -6,9 +6,15 @@
#include <string>
#include <vector>
#if defined(WIN32)
#define EXPORT __declspec(dllexport)
#else
#define EXPORT __attribute__((visibility("default")))
#endif
namespace MemoryPatcher {
extern uintptr_t g_eboot_address;
extern EXPORT uintptr_t g_eboot_address;
extern uint64_t g_eboot_image_size;
extern std::string g_game_serial;
extern std::string patchFile;

View File

@ -40,6 +40,10 @@ public:
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual size_t pwritev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) {
return ORBIS_KERNEL_ERROR_EBADF;
}
virtual s64 lseek(s64 offset, int whence) {
return ORBIS_KERNEL_ERROR_EBADF;
}

View File

@ -920,7 +920,7 @@ s32 PS4_SYSV_ABI sceKernelGetdirentries(s32 fd, char* buf, s32 nbytes, s64* base
return result;
}
s64 PS4_SYSV_ABI posix_pwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
s64 PS4_SYSV_ABI posix_pwritev(s32 fd, const SceKernelIovec* iov, s32 iovcnt, s64 offset) {
if (offset < 0) {
*__Error() = POSIX_EINVAL;
return -1;
@ -936,7 +936,7 @@ s64 PS4_SYSV_ABI posix_pwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
std::scoped_lock lk{file->m_mutex};
if (file->type == Core::FileSys::FileType::Device) {
s64 result = file->device->pwrite(buf, nbytes, offset);
s64 result = file->device->pwritev(iov, iovcnt, offset);
if (result < 0) {
ErrSceToPosix(result);
return -1;
@ -951,7 +951,16 @@ s64 PS4_SYSV_ABI posix_pwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
*__Error() = POSIX_EIO;
return -1;
}
return file->f.WriteRaw<u8>(buf, nbytes);
size_t total_written = 0;
for (int i = 0; i < iovcnt; i++) {
total_written += file->f.WriteRaw<u8>(iov[i].iov_base, iov[i].iov_len);
}
return total_written;
}
s64 PS4_SYSV_ABI posix_pwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
SceKernelIovec iovec{buf, nbytes};
return posix_pwritev(fd, &iovec, 1, offset);
}
s64 PS4_SYSV_ABI sceKernelPwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
@ -963,6 +972,15 @@ s64 PS4_SYSV_ABI sceKernelPwrite(s32 fd, void* buf, size_t nbytes, s64 offset) {
return result;
}
s64 PS4_SYSV_ABI sceKernelPwritev(s32 fd, const SceKernelIovec* iov, s32 iovcnt, s64 offset) {
s64 result = posix_pwritev(fd, iov, iovcnt, offset);
if (result < 0) {
LOG_ERROR(Kernel_Fs, "error = {}", *__Error());
return ErrnoToSceKernelError(*__Error());
}
return result;
}
s32 PS4_SYSV_ABI posix_unlink(const char* path) {
if (path == nullptr) {
*__Error() = POSIX_EINVAL;
@ -1060,7 +1078,10 @@ void RegisterFileSystem(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("sfKygSjIbI8", "libkernel", 1, "libkernel", 1, 1, getdirentries);
LIB_FUNCTION("taRWhTJFTgE", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdirentries);
LIB_FUNCTION("C2kJ-byS5rM", "libkernel", 1, "libkernel", 1, 1, posix_pwrite);
LIB_FUNCTION("FCcmRZhWtOk", "libScePosix", 1, "libkernel", 1, 1, posix_pwritev);
LIB_FUNCTION("FCcmRZhWtOk", "libkernel", 1, "libkernel", 1, 1, posix_pwritev);
LIB_FUNCTION("nKWi-N2HBV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPwrite);
LIB_FUNCTION("mBd4AfLP+u8", "libkernel", 1, "libkernel", 1, 1, sceKernelPwritev);
LIB_FUNCTION("AUXVxWeJU-A", "libkernel", 1, "libkernel", 1, 1, sceKernelUnlink);
}

View File

@ -24,6 +24,7 @@
#include "core/libraries/kernel/threads/exception.h"
#include "core/libraries/kernel/time.h"
#include "core/libraries/libs.h"
#include "core/libraries/network/sys_net.h"
#ifdef _WIN64
#include <Rpc.h>
@ -196,10 +197,6 @@ const char* PS4_SYSV_ABI sceKernelGetFsSandboxRandomWord() {
return path;
}
int PS4_SYSV_ABI posix_connect() {
return -1;
}
int PS4_SYSV_ABI _sigprocmask() {
return ORBIS_OK;
}
@ -225,7 +222,6 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard);
LIB_FUNCTION("PfccT7qURYE", "libkernel", 1, "libkernel", 1, 1, kernel_ioctl);
LIB_FUNCTION("JGfTMBOdUJo", "libkernel", 1, "libkernel", 1, 1, sceKernelGetFsSandboxRandomWord);
LIB_FUNCTION("XVL8So3QJUk", "libkernel", 1, "libkernel", 1, 1, posix_connect);
LIB_FUNCTION("6xVpy0Fdq+I", "libkernel", 1, "libkernel", 1, 1, _sigprocmask);
LIB_FUNCTION("Xjoosiw+XPI", "libkernel", 1, "libkernel", 1, 1, sceKernelUuidCreate);
LIB_FUNCTION("Ou3iL1abvng", "libkernel", 1, "libkernel", 1, 1, stack_chk_fail);
@ -234,6 +230,25 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("k+AXqu2-eBc", "libScePosix", 1, "libkernel", 1, 1, posix_getpagesize);
LIB_FUNCTION("NWtTN10cJzE", "libSceLibcInternalExt", 1, "libSceLibcInternal", 1, 1,
sceLibcHeapGetTraceInfo);
// network
LIB_FUNCTION("XVL8So3QJUk", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_connect);
LIB_FUNCTION("TU-d9PfIHPM", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_socketex);
LIB_FUNCTION("KuOmgKoqCdY", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_bind);
LIB_FUNCTION("pxnCmagrtao", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_listen);
LIB_FUNCTION("3e+4Iv7IJ8U", "libkernel", 1, "libkernel", 1, 1, Libraries::Net::sys_accept);
LIB_FUNCTION("TU-d9PfIHPM", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_socket);
LIB_FUNCTION("oBr313PppNE", "libScePosix", 1, "libkernel", 1, 1, Libraries::Net::sys_sendto);
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("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_ ...
LIB_FUNCTION("4n51s0zEf0c", "libScePosix", 1, "libkernel", 1, 1,
Libraries::Net::sceNetInetPton); // TODO fix it to sys_ ...
}
} // namespace Libraries::Kernel

View File

@ -18,6 +18,7 @@ namespace Libraries::Kernel {
void ErrSceToPosix(int result);
int ErrnoToSceKernelError(int e);
void SetPosixErrno(int e);
int* PS4_SYSV_ABI __Error();
template <StringLiteral name, class F, F f>
struct WrapperImpl;

View File

@ -10,16 +10,24 @@
#include <arpa/inet.h>
#endif
#include <core/libraries/kernel/kernel.h>
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/singleton.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
#include "core/libraries/network/net.h"
#include "net_error.h"
#include "net_util.h"
#include "netctl.h"
#include "sys_net.h"
namespace Libraries::Net {
static thread_local int32_t net_errno = 0;
static bool g_isNetInitialized = true; // TODO init it properly
int PS4_SYSV_ABI in6addr_any() {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
@ -61,8 +69,45 @@ int PS4_SYSV_ABI sce_net_in6addr_nodelocal_allnodes() {
}
OrbisNetId PS4_SYSV_ABI sceNetAccept(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT;
}
int result;
int err;
int positiveErr;
do {
result = sys_accept(s, addr, paddrlen);
if (result >= 0) {
return result; // Success
}
err = *Libraries::Kernel::__Error(); // Standard errno
// Convert to positive error for comparison
int positiveErr = (err < 0) ? -err : err;
if ((positiveErr & 0xfff0000) != 0) {
// Unknown/fatal error range
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
return -positiveErr;
}
// Retry if interrupted
} while (positiveErr == ORBIS_NET_EINTR);
if (positiveErr == ORBIS_NET_EADDRINUSE) {
result = -ORBIS_NET_EBADF;
} else if (positiveErr == ORBIS_NET_EALREADY) {
result = -ORBIS_NET_EINTR;
} else {
result = -positiveErr;
}
*sceNetErrnoLoc() = -result;
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetAddrConfig6GetInfo() {
@ -121,8 +166,45 @@ int PS4_SYSV_ABI sceNetBandwidthControlSetPolicy() {
}
int PS4_SYSV_ABI sceNetBind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT;
}
int result;
int err;
int positiveErr;
do {
result = sys_bind(s, addr, addrlen);
if (result >= 0) {
return result; // Success
}
err = *Libraries::Kernel::__Error(); // Standard errno
// Convert to positive error for comparison
int positiveErr = (err < 0) ? -err : err;
if ((positiveErr & 0xfff0000) != 0) {
// Unknown/fatal error range
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
return -positiveErr;
}
// Retry if interrupted
} while (positiveErr == ORBIS_NET_EINTR);
if (positiveErr == ORBIS_NET_EADDRINUSE) {
result = -ORBIS_NET_EBADF;
} else if (positiveErr == ORBIS_NET_EALREADY) {
result = -ORBIS_NET_EINTR;
} else {
result = -positiveErr;
}
*sceNetErrnoLoc() = -result;
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetClearDnsCache() {
@ -465,9 +547,46 @@ int PS4_SYSV_ABI sceNetConfigWlanSetDeviceConfig() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNetConnect() {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceNetConnect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) {
if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT;
}
int result;
int err;
int positiveErr;
do {
result = sys_connect(s, addr, addrlen);
if (result >= 0) {
return result; // Success
}
err = *Libraries::Kernel::__Error(); // Standard errno
// Convert to positive error for comparison
int positiveErr = (err < 0) ? -err : err;
if ((positiveErr & 0xfff0000) != 0) {
// Unknown/fatal error range
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
return -positiveErr;
}
// Retry if interrupted
} while (positiveErr == ORBIS_NET_EINTR);
if (positiveErr == ORBIS_NET_EADDRINUSE) {
result = -ORBIS_NET_EBADF;
} else if (positiveErr == ORBIS_NET_EALREADY) {
result = -ORBIS_NET_EINTR;
} else {
result = -positiveErr;
}
*sceNetErrnoLoc() = -result;
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetControl() {
@ -640,8 +759,15 @@ int PS4_SYSV_ABI sceNetGetIfnameNumList() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNetGetMacAddress() {
LOG_ERROR(Lib_Net, "(STUBBED) called");
int PS4_SYSV_ABI sceNetGetMacAddress(Libraries::NetCtl::OrbisNetEtherAddr* addr, int flags) {
if (addr == nullptr) {
LOG_ERROR(Lib_Net, "addr is null!");
return ORBIS_NET_EINVAL;
}
auto* netinfo = Common::Singleton<NetUtil::NetUtilInternal>::Instance();
netinfo->RetrieveEthernetAddr();
memcpy(addr->data, netinfo->GetEthernetAddr().data(), 6);
return ORBIS_OK;
}
@ -655,9 +781,46 @@ int PS4_SYSV_ABI sceNetGetNameToIndex() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNetGetpeername() {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceNetGetpeername(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) {
if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT;
}
int result;
int err;
int positiveErr;
do {
result = sys_getpeername(s, addr, paddrlen);
if (result >= 0) {
return result; // Success
}
err = *Libraries::Kernel::__Error(); // Standard errno
// Convert to positive error for comparison
int positiveErr = (err < 0) ? -err : err;
if ((positiveErr & 0xfff0000) != 0) {
// Unknown/fatal error range
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
return -positiveErr;
}
// Retry if interrupted
} while (positiveErr == ORBIS_NET_EINTR);
if (positiveErr == ORBIS_NET_EADDRINUSE) {
result = -ORBIS_NET_EBADF;
} else if (positiveErr == ORBIS_NET_EALREADY) {
result = -ORBIS_NET_EINTR;
} else {
result = -positiveErr;
}
*sceNetErrnoLoc() = -result;
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetGetRandom() {
@ -681,13 +844,87 @@ int PS4_SYSV_ABI sceNetGetSockInfo6() {
}
int PS4_SYSV_ABI sceNetGetsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT;
}
int result;
int err;
int positiveErr;
do {
result = sys_getsockname(s, addr, paddrlen);
if (result >= 0) {
return result; // Success
}
err = *Libraries::Kernel::__Error(); // Standard errno
// Convert to positive error for comparison
int positiveErr = (err < 0) ? -err : err;
if ((positiveErr & 0xfff0000) != 0) {
// Unknown/fatal error range
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
return -positiveErr;
}
// Retry if interrupted
} while (positiveErr == ORBIS_NET_EINTR);
if (positiveErr == ORBIS_NET_EADDRINUSE) {
result = -ORBIS_NET_EBADF;
} else if (positiveErr == ORBIS_NET_EALREADY) {
result = -ORBIS_NET_EINTR;
} else {
result = -positiveErr;
}
*sceNetErrnoLoc() = -result;
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetGetsockopt(OrbisNetId s, int level, int optname, void* optval, u32* optlen) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT;
}
int result;
int err;
int positiveErr;
do {
result = sys_getsockopt(s, level, optname, optval, optlen);
if (result >= 0) {
return result; // Success
}
err = *Libraries::Kernel::__Error(); // Standard errno
// Convert to positive error for comparison
int positiveErr = (err < 0) ? -err : err;
if ((positiveErr & 0xfff0000) != 0) {
// Unknown/fatal error range
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
return -positiveErr;
}
// Retry if interrupted
} while (positiveErr == ORBIS_NET_EINTR);
if (positiveErr == ORBIS_NET_EADDRINUSE) {
result = -ORBIS_NET_EBADF;
} else if (positiveErr == ORBIS_NET_EALREADY) {
result = -ORBIS_NET_EINTR;
} else {
result = -positiveErr;
}
*sceNetErrnoLoc() = -result;
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetGetStatisticsInfo() {
@ -781,9 +1018,46 @@ int PS4_SYSV_ABI sceNetIoctl() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNetListen() {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceNetListen(OrbisNetId s, int backlog) {
if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT;
}
int result;
int err;
int positiveErr;
do {
result = sys_listen(s, backlog);
if (result >= 0) {
return result; // Success
}
err = *Libraries::Kernel::__Error(); // Standard errno
// Convert to positive error for comparison
int positiveErr = (err < 0) ? -err : err;
if ((positiveErr & 0xfff0000) != 0) {
// Unknown/fatal error range
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
return -positiveErr;
}
// Retry if interrupted
} while (positiveErr == ORBIS_NET_EINTR);
if (positiveErr == ORBIS_NET_EADDRINUSE) {
result = -ORBIS_NET_EBADF;
} else if (positiveErr == ORBIS_NET_EALREADY) {
result = -ORBIS_NET_EINTR;
} else {
result = -positiveErr;
}
*sceNetErrnoLoc() = -result;
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetMemoryAllocate() {
@ -829,20 +1103,131 @@ int PS4_SYSV_ABI sceNetPppoeStop() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNetRecv() {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceNetRecv(OrbisNetId s, void* buf, u64 len, int flags) {
if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT;
}
int result;
int err;
int positiveErr;
do {
result = sys_recvfrom(s, buf, len, flags | 0x40000000, nullptr, 0);
if (result >= 0) {
return result; // Success
}
err = *Libraries::Kernel::__Error(); // Standard errno
// Convert to positive error for comparison
int positiveErr = (err < 0) ? -err : err;
if ((positiveErr & 0xfff0000) != 0) {
// Unknown/fatal error range
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
return -positiveErr;
}
// Retry if interrupted
} while (positiveErr == ORBIS_NET_EINTR);
if (positiveErr == ORBIS_NET_EADDRINUSE) {
result = -ORBIS_NET_EBADF;
} else if (positiveErr == ORBIS_NET_EALREADY) {
result = -ORBIS_NET_EINTR;
} else {
result = -positiveErr;
}
*sceNetErrnoLoc() = -result;
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, size_t len, int flags,
OrbisNetSockaddr* addr, u32* paddrlen) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr,
u32* paddrlen) {
if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT;
}
int result;
int err;
int positiveErr;
do {
result = sys_recvfrom(s, buf, len, flags | 0x40000000, addr, paddrlen);
if (result >= 0) {
return result; // Success
}
err = *Libraries::Kernel::__Error(); // Standard errno
// Convert to positive error for comparison
int positiveErr = (err < 0) ? -err : err;
if ((positiveErr & 0xfff0000) != 0) {
// Unknown/fatal error range
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
return -positiveErr;
}
// Retry if interrupted
} while (positiveErr == ORBIS_NET_EINTR);
if (positiveErr == ORBIS_NET_EADDRINUSE) {
result = -ORBIS_NET_EBADF;
} else if (positiveErr == ORBIS_NET_EALREADY) {
result = -ORBIS_NET_EINTR;
} else {
result = -positiveErr;
}
*sceNetErrnoLoc() = -result;
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetRecvmsg() {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceNetRecvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags) {
if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT;
}
int result;
int err;
int positiveErr;
do {
result = sys_recvmsg(s, msg, flags | 0x40000000);
if (result >= 0) {
return result; // Success
}
err = *Libraries::Kernel::__Error(); // Standard errno
// Convert to positive error for comparison
int positiveErr = (err < 0) ? -err : err;
if ((positiveErr & 0xfff0000) != 0) {
// Unknown/fatal error range
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
return -positiveErr;
}
// Retry if interrupted
} while (positiveErr == ORBIS_NET_EINTR);
if (positiveErr == ORBIS_NET_EADDRINUSE) {
result = -ORBIS_NET_EBADF;
} else if (positiveErr == ORBIS_NET_EALREADY) {
result = -ORBIS_NET_EINTR;
} else {
result = -positiveErr;
}
*sceNetErrnoLoc() = -result;
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetResolverAbort() {
@ -915,19 +1300,131 @@ int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecordsEx() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNetSend() {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceNetSend(OrbisNetId s, const void* buf, u64 len, int flags) {
if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT;
}
int result;
int err;
int positiveErr;
do {
result = sys_sendto(s, buf, len, flags | 0x40020000, nullptr, 0);
if (result >= 0) {
return result; // Success
}
err = *Libraries::Kernel::__Error(); // Standard errno
// Convert to positive error for comparison
int positiveErr = (err < 0) ? -err : err;
if ((positiveErr & 0xfff0000) != 0) {
// Unknown/fatal error range
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
return -positiveErr;
}
// Retry if interrupted
} while (positiveErr == ORBIS_NET_EINTR);
if (positiveErr == ORBIS_NET_EADDRINUSE) {
result = -ORBIS_NET_EBADF;
} else if (positiveErr == ORBIS_NET_EALREADY) {
result = -ORBIS_NET_EINTR;
} else {
result = -positiveErr;
}
*sceNetErrnoLoc() = -result;
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetSendmsg() {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceNetSendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags) {
if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT;
}
int result;
int err;
int positiveErr;
do {
result = sys_sendmsg(s, msg, flags | 0x40020000);
if (result >= 0) {
return result; // Success
}
err = *Libraries::Kernel::__Error(); // Standard errno
// Convert to positive error for comparison
int positiveErr = (err < 0) ? -err : err;
if ((positiveErr & 0xfff0000) != 0) {
// Unknown/fatal error range
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
return -positiveErr;
}
// Retry if interrupted
} while (positiveErr == ORBIS_NET_EINTR);
if (positiveErr == ORBIS_NET_EADDRINUSE) {
result = -ORBIS_NET_EBADF;
} else if (positiveErr == ORBIS_NET_EALREADY) {
result = -ORBIS_NET_EINTR;
} else {
result = -positiveErr;
}
*sceNetErrnoLoc() = -result;
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetSendto() {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceNetSendto(OrbisNetId s, const void* buf, u64 len, int flags,
const OrbisNetSockaddr* addr, u32 addrlen) {
if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT;
}
int result;
int err;
int positiveErr;
do {
result = sys_sendto(s, buf, len, flags | 0x40020000, addr, addrlen);
if (result >= 0) {
return result; // Success
}
err = *Libraries::Kernel::__Error(); // Standard errno
// Convert to positive error for comparison
int positiveErr = (err < 0) ? -err : err;
if ((positiveErr & 0xfff0000) != 0) {
// Unknown/fatal error range
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
return -positiveErr;
}
// Retry if interrupted
} while (positiveErr == ORBIS_NET_EINTR);
if (positiveErr == ORBIS_NET_EADDRINUSE) {
result = -ORBIS_NET_EBADF;
} else if (positiveErr == ORBIS_NET_EALREADY) {
result = -ORBIS_NET_EINTR;
} else {
result = -positiveErr;
}
*sceNetErrnoLoc() = -result;
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetSetDns6Info() {
@ -950,9 +1447,47 @@ int PS4_SYSV_ABI sceNetSetDnsInfoToKernel() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNetSetsockopt() {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceNetSetsockopt(OrbisNetId s, int level, int optname, const void* optval,
u32 optlen) {
if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT;
}
int result;
int err;
int positiveErr;
do {
result = sys_setsockopt(s, level, optname, optval, optlen);
if (result >= 0) {
return result; // Success
}
err = *Libraries::Kernel::__Error(); // Standard errno
// Convert to positive error for comparison
int positiveErr = (err < 0) ? -err : err;
if ((positiveErr & 0xfff0000) != 0) {
// Unknown/fatal error range
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
return -positiveErr;
}
// Retry if interrupted
} while (positiveErr == ORBIS_NET_EINTR);
if (positiveErr == ORBIS_NET_EADDRINUSE) {
result = -ORBIS_NET_EBADF;
} else if (positiveErr == ORBIS_NET_EALREADY) {
result = -ORBIS_NET_EINTR;
} else {
result = -positiveErr;
}
*sceNetErrnoLoc() = -result;
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetShowIfconfig() {
@ -1035,24 +1570,172 @@ int PS4_SYSV_ABI sceNetShowRouteWithMemory() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNetShutdown() {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceNetShutdown(OrbisNetId s, int how) {
if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT;
}
int result;
int err;
int positiveErr;
do {
result = sys_shutdown(s, how);
if (result >= 0) {
return result; // Success
}
err = *Libraries::Kernel::__Error(); // Standard errno
// Convert to positive error for comparison
int positiveErr = (err < 0) ? -err : err;
if ((positiveErr & 0xfff0000) != 0) {
// Unknown/fatal error range
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
return -positiveErr;
}
// Retry if interrupted
} while (positiveErr == ORBIS_NET_EINTR);
if (positiveErr == ORBIS_NET_EADDRINUSE) {
result = -ORBIS_NET_EBADF;
} else if (positiveErr == ORBIS_NET_EALREADY) {
result = -ORBIS_NET_EINTR;
} else {
result = -positiveErr;
}
*sceNetErrnoLoc() = -result;
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int protocol) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
OrbisNetId PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int protocol) {
if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT;
}
int result;
int err;
int positiveErr;
do {
result = sys_socketex(name, family, type, protocol);
if (result >= 0) {
return result; // Success
}
err = *Libraries::Kernel::__Error(); // Standard errno
// Convert to positive error for comparison
int positiveErr = (err < 0) ? -err : err;
if ((positiveErr & 0xfff0000) != 0) {
// Unknown/fatal error range
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
return -positiveErr;
}
// Retry if interrupted
} while (positiveErr == ORBIS_NET_EINTR);
if (positiveErr == ORBIS_NET_EADDRINUSE) {
result = -ORBIS_NET_EBADF;
} else if (positiveErr == ORBIS_NET_EALREADY) {
result = -ORBIS_NET_EINTR;
} else {
result = -positiveErr;
}
*sceNetErrnoLoc() = -result;
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetSocketAbort() {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceNetSocketAbort(OrbisNetId s, int flags) {
if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT;
}
int result;
int err;
int positiveErr;
do {
result = sys_netabort(s, flags);
if (result >= 0) {
return result; // Success
}
err = *Libraries::Kernel::__Error(); // Standard errno
// Convert to positive error for comparison
int positiveErr = (err < 0) ? -err : err;
if ((positiveErr & 0xfff0000) != 0) {
// Unknown/fatal error range
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
return -positiveErr;
}
// Retry if interrupted
} while (positiveErr == ORBIS_NET_EINTR);
if (positiveErr == ORBIS_NET_EADDRINUSE) {
result = -ORBIS_NET_EBADF;
} else if (positiveErr == ORBIS_NET_EALREADY) {
result = -ORBIS_NET_EINTR;
} else {
result = -positiveErr;
}
*sceNetErrnoLoc() = -result;
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetSocketClose() {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI sceNetSocketClose(OrbisNetId s) {
if (!g_isNetInitialized) {
return ORBIS_NET_ERROR_ENOTINIT;
}
int result;
int err;
int positiveErr;
do {
result = sys_socketclose(s);
if (result >= 0) {
return result; // Success
}
err = *Libraries::Kernel::__Error(); // Standard errno
// Convert to positive error for comparison
int positiveErr = (err < 0) ? -err : err;
if ((positiveErr & 0xfff0000) != 0) {
// Unknown/fatal error range
*sceNetErrnoLoc() = ORBIS_NET_ERETURN;
return -positiveErr;
}
// Retry if interrupted
} while (positiveErr == ORBIS_NET_EINTR);
if (positiveErr == ORBIS_NET_EADDRINUSE) {
result = -ORBIS_NET_EBADF;
} else if (positiveErr == ORBIS_NET_EALREADY) {
result = -ORBIS_NET_EINTR;
} else {
result = -positiveErr;
}
*sceNetErrnoLoc() = -result;
return (-result) | ORBIS_NET_ERROR_BASE; // Convert to official ORBIS_NET_ERROR code
}
int PS4_SYSV_ABI sceNetSyncCreate() {

View File

@ -4,6 +4,7 @@
#pragma once
#include "common/types.h"
#include "netctl.h"
namespace Core::Loader {
class SymbolsResolver;
@ -19,6 +20,63 @@ class SymbolsResolver;
namespace Libraries::Net {
enum OrbisNetSocketType : u32 {
ORBIS_NET_SOCK_STREAM = 1,
ORBIS_NET_SOCK_DGRAM = 2,
ORBIS_NET_SOCK_RAW = 3,
ORBIS_NET_SOCK_DGRAM_P2P = 6,
ORBIS_NET_SOCK_STREAM_P2P = 10
};
enum OrbisNetProtocol : u32 {
ORBIS_NET_IPPROTO_IP = 0,
ORBIS_NET_IPPROTO_ICMP = 1,
ORBIS_NET_IPPROTO_IGMP = 2,
ORBIS_NET_IPPROTO_TCP = 6,
ORBIS_NET_IPPROTO_UDP = 17,
ORBIS_NET_SOL_SOCKET = 0xFFFF
};
enum OrbisNetSocketOption : u32 {
/* IP */
ORBIS_NET_IP_HDRINCL = 2,
ORBIS_NET_IP_TOS = 3,
ORBIS_NET_IP_TTL = 4,
ORBIS_NET_IP_MULTICAST_IF = 9,
ORBIS_NET_IP_MULTICAST_TTL = 10,
ORBIS_NET_IP_MULTICAST_LOOP = 11,
ORBIS_NET_IP_ADD_MEMBERSHIP = 12,
ORBIS_NET_IP_DROP_MEMBERSHIP = 13,
ORBIS_NET_IP_TTLCHK = 23,
ORBIS_NET_IP_MAXTTL = 24,
/* TCP */
ORBIS_NET_TCP_NODELAY = 1,
ORBIS_NET_TCP_MAXSEG = 2,
ORBIS_NET_TCP_MSS_TO_ADVERTISE = 3,
/* SOCKET */
ORBIS_NET_SO_REUSEADDR = 0x00000004,
ORBIS_NET_SO_KEEPALIVE = 0x00000008,
ORBIS_NET_SO_BROADCAST = 0x00000020,
ORBIS_NET_SO_LINGER = 0x00000080,
ORBIS_NET_SO_REUSEPORT = 0x00000200,
ORBIS_NET_SO_ONESBCAST = 0x00010000,
ORBIS_NET_SO_USECRYPTO = 0x00020000,
ORBIS_NET_SO_USESIGNATURE = 0x00040000,
ORBIS_NET_SO_SNDBUF = 0x1001,
ORBIS_NET_SO_RCVBUF = 0x1002,
ORBIS_NET_SO_ERROR = 0x1007,
ORBIS_NET_SO_TYPE = 0x1008,
ORBIS_NET_SO_SNDTIMEO = 0x1105,
ORBIS_NET_SO_RCVTIMEO = 0x1106,
ORBIS_NET_SO_ERROR_EX = 0x1107,
ORBIS_NET_SO_ACCEPTTIMEO = 0x1108,
ORBIS_NET_SO_CONNECTTIMEO = 0x1109,
ORBIS_NET_SO_NBIO = 0x1200,
ORBIS_NET_SO_POLICY = 0x1201,
ORBIS_NET_SO_NAME = 0x1202,
ORBIS_NET_SO_PRIORITY = 0x1203
};
using OrbisNetId = s32;
struct OrbisNetSockaddr {
@ -27,6 +85,30 @@ struct OrbisNetSockaddr {
char sa_data[14];
};
struct OrbisNetSockaddrIn {
u8 sin_len;
u8 sin_family;
u16 sin_port;
u32 sin_addr;
u16 sin_vport;
char sin_zero[6];
};
struct OrbisNetIovec {
void* iov_base;
u64 iov_len;
};
struct OrbisNetMsghdr {
void* msg_name;
u32 msg_namelen;
OrbisNetIovec* msg_iov;
int msg_iovlen;
void* msg_control;
u32 msg_controllen;
int msg_flags;
};
int PS4_SYSV_ABI in6addr_any();
int PS4_SYSV_ABI in6addr_loopback();
int PS4_SYSV_ABI sce_net_dummy();
@ -116,7 +198,7 @@ int PS4_SYSV_ABI sceNetConfigWlanInfraLeave();
int PS4_SYSV_ABI sceNetConfigWlanInfraScanJoin();
int PS4_SYSV_ABI sceNetConfigWlanScan();
int PS4_SYSV_ABI sceNetConfigWlanSetDeviceConfig();
int PS4_SYSV_ABI sceNetConnect();
int PS4_SYSV_ABI sceNetConnect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen);
int PS4_SYSV_ABI sceNetControl();
int PS4_SYSV_ABI sceNetDhcpdStart();
int PS4_SYSV_ABI sceNetDhcpdStop();
@ -151,10 +233,10 @@ int PS4_SYSV_ABI sceNetGetIfList();
int PS4_SYSV_ABI sceNetGetIfListOnce();
int PS4_SYSV_ABI sceNetGetIfName();
int PS4_SYSV_ABI sceNetGetIfnameNumList();
int PS4_SYSV_ABI sceNetGetMacAddress();
int PS4_SYSV_ABI sceNetGetMacAddress(Libraries::NetCtl::OrbisNetEtherAddr* addr, int flags);
int PS4_SYSV_ABI sceNetGetMemoryPoolStats();
int PS4_SYSV_ABI sceNetGetNameToIndex();
int PS4_SYSV_ABI sceNetGetpeername();
int PS4_SYSV_ABI sceNetGetpeername(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen);
int PS4_SYSV_ABI sceNetGetRandom();
int PS4_SYSV_ABI sceNetGetRouteInfo();
int PS4_SYSV_ABI sceNetGetSockInfo();
@ -177,7 +259,7 @@ int PS4_SYSV_ABI sceNetInfoDumpStop();
int PS4_SYSV_ABI sceNetInit();
int PS4_SYSV_ABI sceNetInitParam();
int PS4_SYSV_ABI sceNetIoctl();
int PS4_SYSV_ABI sceNetListen();
int PS4_SYSV_ABI sceNetListen(OrbisNetId s, int backlog);
int PS4_SYSV_ABI sceNetMemoryAllocate();
int PS4_SYSV_ABI sceNetMemoryFree();
u32 PS4_SYSV_ABI sceNetNtohl(u32 net32);
@ -187,10 +269,10 @@ int PS4_SYSV_ABI sceNetPoolCreate(const char* name, int size, int flags);
int PS4_SYSV_ABI sceNetPoolDestroy();
int PS4_SYSV_ABI sceNetPppoeStart();
int PS4_SYSV_ABI sceNetPppoeStop();
int PS4_SYSV_ABI sceNetRecv();
int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, size_t len, int flags,
OrbisNetSockaddr* addr, u32* paddrlen);
int PS4_SYSV_ABI sceNetRecvmsg();
int PS4_SYSV_ABI sceNetRecv(OrbisNetId s, void* buf, u64 len, int flags);
int PS4_SYSV_ABI sceNetRecvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr,
u32* paddrlen);
int PS4_SYSV_ABI sceNetRecvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags);
int PS4_SYSV_ABI sceNetResolverAbort();
int PS4_SYSV_ABI sceNetResolverConnect();
int PS4_SYSV_ABI sceNetResolverConnectAbort();
@ -205,14 +287,16 @@ int PS4_SYSV_ABI sceNetResolverStartNtoa();
int PS4_SYSV_ABI sceNetResolverStartNtoa6();
int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecords();
int PS4_SYSV_ABI sceNetResolverStartNtoaMultipleRecordsEx();
int PS4_SYSV_ABI sceNetSend();
int PS4_SYSV_ABI sceNetSendmsg();
int PS4_SYSV_ABI sceNetSendto();
int PS4_SYSV_ABI sceNetSend(OrbisNetId s, const void* buf, u64 len, int flags);
int PS4_SYSV_ABI sceNetSendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags);
int PS4_SYSV_ABI sceNetSendto(OrbisNetId s, const void* buf, u64 len, int flags,
const OrbisNetSockaddr* addr, u32 addrlen);
int PS4_SYSV_ABI sceNetSetDns6Info();
int PS4_SYSV_ABI sceNetSetDns6InfoToKernel();
int PS4_SYSV_ABI sceNetSetDnsInfo();
int PS4_SYSV_ABI sceNetSetDnsInfoToKernel();
int PS4_SYSV_ABI sceNetSetsockopt();
int PS4_SYSV_ABI sceNetSetsockopt(OrbisNetId s, int level, int optname, const void* optval,
u32 optlen);
int PS4_SYSV_ABI sceNetShowIfconfig();
int PS4_SYSV_ABI sceNetShowIfconfigForBuffer();
int PS4_SYSV_ABI sceNetShowIfconfigWithMemory();
@ -229,10 +313,10 @@ int PS4_SYSV_ABI sceNetShowRoute6ForBuffer();
int PS4_SYSV_ABI sceNetShowRoute6WithMemory();
int PS4_SYSV_ABI sceNetShowRouteForBuffer();
int PS4_SYSV_ABI sceNetShowRouteWithMemory();
int PS4_SYSV_ABI sceNetShutdown();
int PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int protocol);
int PS4_SYSV_ABI sceNetSocketAbort();
int PS4_SYSV_ABI sceNetSocketClose();
int PS4_SYSV_ABI sceNetShutdown(OrbisNetId s, int how);
OrbisNetId PS4_SYSV_ABI sceNetSocket(const char* name, int family, int type, int protocol);
int PS4_SYSV_ABI sceNetSocketAbort(OrbisNetId s, int flags);
int PS4_SYSV_ABI sceNetSocketClose(OrbisNetId s);
int PS4_SYSV_ABI sceNetSyncCreate();
int PS4_SYSV_ABI sceNetSyncDestroy();
int PS4_SYSV_ABI sceNetSyncGet();

View File

@ -0,0 +1,162 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
// net errno codes
constexpr int ORBIS_NET_EPERM = 1;
constexpr int ORBIS_NET_ENOENT = 2;
constexpr int ORBIS_NET_EINTR = 4;
constexpr int ORBIS_NET_EBADF = 9;
constexpr int ORBIS_NET_EACCES = 13;
constexpr int ORBIS_NET_EFAULT = 14;
constexpr int ORBIS_NET_ENOTBLK = 15;
constexpr int ORBIS_NET_EBUSY = 16;
constexpr int ORBIS_NET_EEXIST = 17;
constexpr int ORBIS_NET_ENODEV = 19;
constexpr int ORBIS_NET_EINVAL = 22;
constexpr int ORBIS_NET_EMFILE = 24;
constexpr int ORBIS_NET_ENOSPC = 28;
constexpr int ORBIS_NET_EPIPE = 32;
constexpr int ORBIS_NET_EAGAIN = 35;
constexpr int ORBIS_NET_EWOULDBLOCK = 35;
constexpr int ORBIS_NET_EINPROGRESS = 36;
constexpr int ORBIS_NET_EALREADY = 37;
constexpr int ORBIS_NET_ENOTSOCK = 38;
constexpr int ORBIS_NET_EDESTADDRREQ = 39;
constexpr int ORBIS_NET_EMSGSIZE = 40;
constexpr int ORBIS_NET_EPROTOTYPE = 41;
constexpr int ORBIS_NET_ENOPROTOOPT = 42;
constexpr int ORBIS_NET_EPROTONOSUPPORT = 43;
constexpr int ORBIS_NET_EOPNOTSUPP = 45;
constexpr int ORBIS_NET_EAFNOSUPPORT = 47;
constexpr int ORBIS_NET_EADDRINUSE = 48;
constexpr int ORBIS_NET_EADDRNOTAVAIL = 49;
constexpr int ORBIS_NET_ENETDOWN = 50;
constexpr int ORBIS_NET_ENETUNREACH = 51;
constexpr int ORBIS_NET_ENETRESET = 52;
constexpr int ORBIS_NET_ECONNABORTED = 53;
constexpr int ORBIS_NET_ECONNRESET = 54;
constexpr int ORBIS_NET_EISCONN = 56;
constexpr int ORBIS_NET_ENOTCONN = 57;
constexpr int ORBIS_NET_ETOOMANYREFS = 59;
constexpr int ORBIS_NET_ETIMEDOUT = 60;
constexpr int ORBIS_NET_ECONNREFUSED = 61;
constexpr int ORBIS_NET_ELOOP = 62;
constexpr int ORBIS_NET_ENAMETOOLONG = 63;
constexpr int ORBIS_NET_EHOSTDOWN = 64;
constexpr int ORBIS_NET_EHOSTUNREACH = 65;
constexpr int ORBIS_NET_ENOTEMPTY = 66;
constexpr int ORBIS_NET_EPROCUNAVAIL = 76;
constexpr int ORBIS_NET_EPROTO = 92;
constexpr int ORBIS_NET_EADHOC = 160;
constexpr int ORBIS_NET_EINACTIVEDISABLED = 163;
constexpr int ORBIS_NET_ENODATA = 164;
constexpr int ORBIS_NET_EDESC = 165;
constexpr int ORBIS_NET_EDESCTIMEDOUT = 166;
constexpr int ORBIS_NET_ENOTINIT = 200;
constexpr int ORBIS_NET_ENOLIBMEM = 201;
constexpr int ORBIS_NET_ECALLBACK = 203;
constexpr int ORBIS_NET_EINTERNAL = 204;
constexpr int ORBIS_NET_ERETURN = 205;
constexpr int ORBIS_NET_ENOALLOCMEM = 206;
// errno for dns resolver
constexpr int ORBIS_NET_RESOLVER_EINTERNAL = 220;
constexpr int ORBIS_NET_RESOLVER_EBUSY = 221;
constexpr int ORBIS_NET_RESOLVER_ENOSPACE = 222;
constexpr int ORBIS_NET_RESOLVER_EPACKET = 223;
constexpr int ORBIS_NET_RESOLVER_ENODNS = 225;
constexpr int ORBIS_NET_RESOLVER_ETIMEDOUT = 226;
constexpr int ORBIS_NET_RESOLVER_ENOSUPPORT = 227;
constexpr int ORBIS_NET_RESOLVER_EFORMAT = 228;
constexpr int ORBIS_NET_RESOLVER_ESERVERFAILURE = 229;
constexpr int ORBIS_NET_RESOLVER_ENOHOST = 230;
constexpr int ORBIS_NET_RESOLVER_ENOTIMPLEMENTED = 231;
constexpr int ORBIS_NET_RESOLVER_ESERVERREFUSED = 232;
constexpr int ORBIS_NET_RESOLVER_ENORECORD = 233;
constexpr int ORBIS_NET_RESOLVER_EALIGNMENT = 234;
// common errno
constexpr int ORBIS_NET_ENOMEM = 12;
constexpr int ORBIS_NET_ENOBUFS = 55;
// error codes
constexpr int ORBIS_NET_ERROR_BASE = 0x80410100; // not existed used for calculation
constexpr int ORBIS_NET_ERROR_EPERM = 0x80410101;
constexpr int ORBIS_NET_ERROR_ENOENT = 0x80410102;
constexpr int ORBIS_NET_ERROR_EINTR = 0x80410104;
constexpr int ORBIS_NET_ERROR_EBADF = 0x80410109;
constexpr int ORBIS_NET_ERROR_ENOMEM = 0x8041010c;
constexpr int ORBIS_NET_ERROR_EACCES = 0x8041010d;
constexpr int ORBIS_NET_ERROR_EFAULT = 0x8041010e;
constexpr int ORBIS_NET_ERROR_ENOTBLK = 0x8041010f;
constexpr int ORBIS_NET_ERROR_EEXIST = 0x80410111;
constexpr int ORBIS_NET_ERROR_ENODEV = 0x80410113;
constexpr int ORBIS_NET_ERROR_EINVAL = 0x80410116;
constexpr int ORBIS_NET_ERROR_ENFILE = 0x80410117;
constexpr int ORBIS_NET_ERROR_EMFILE = 0x80410118;
constexpr int ORBIS_NET_ERROR_ENOSPC = 0x8041011c;
constexpr int ORBIS_NET_ERROR_EPIPE = 0x80410120;
constexpr int ORBIS_NET_ERROR_EAGAIN = 0x80410123;
constexpr int ORBIS_NET_ERROR_EWOULDBLOCK = 0x80410123;
constexpr int ORBIS_NET_ERROR_EINPROGRESS = 0x80410124;
constexpr int ORBIS_NET_ERROR_EALREADY = 0x80410125;
constexpr int ORBIS_NET_ERROR_ENOTSOCK = 0x80410126;
constexpr int ORBIS_NET_ERROR_EDESTADDRREQ = 0x80410127;
constexpr int ORBIS_NET_ERROR_EMSGSIZE = 0x80410128;
constexpr int ORBIS_NET_ERROR_EPROTOTYPE = 0x80410129;
constexpr int ORBIS_NET_ERROR_ENOPROTOOPT = 0x8041012a;
constexpr int ORBIS_NET_ERROR_EPROTONOSUPPORT = 0x8041012b;
constexpr int ORBIS_NET_ERROR_EOPNOTSUPP = 0x8041012d;
constexpr int ORBIS_NET_ERROR_EPFNOSUPPORT = 0x8041012e;
constexpr int ORBIS_NET_ERROR_EAFNOSUPPORT = 0x8041012f;
constexpr int ORBIS_NET_ERROR_EADDRINUSE = 0x80410130;
constexpr int ORBIS_NET_ERROR_EADDRNOTAVAIL = 0x80410131;
constexpr int ORBIS_NET_ERROR_ENETDOWN = 0x80410132;
constexpr int ORBIS_NET_ERROR_ENETUNREACH = 0x80410133;
constexpr int ORBIS_NET_ERROR_ENETRESET = 0x80410134;
constexpr int ORBIS_NET_ERROR_ECONNABORTED = 0x80410135;
constexpr int ORBIS_NET_ERROR_ECONNRESET = 0x80410136;
constexpr int ORBIS_NET_ERROR_ENOBUFS = 0x80410137;
constexpr int ORBIS_NET_ERROR_EISCONN = 0x80410138;
constexpr int ORBIS_NET_ERROR_ENOTCONN = 0x80410139;
constexpr int ORBIS_NET_ERROR_ESHUTDOWN = 0x8041013a;
constexpr int ORBIS_NET_ERROR_ETOOMANYREFS = 0x8041013b;
constexpr int ORBIS_NET_ERROR_ETIMEDOUT = 0x8041013c;
constexpr int ORBIS_NET_ERROR_ECONNREFUSED = 0x8041013d;
constexpr int ORBIS_NET_ERROR_ELOOP = 0x8041013e;
constexpr int ORBIS_NET_ERROR_ENAMETOOLONG = 0x8041013f;
constexpr int ORBIS_NET_ERROR_EHOSTDOWN = 0x80410140;
constexpr int ORBIS_NET_ERROR_EHOSTUNREACH = 0x80410141;
constexpr int ORBIS_NET_ERROR_ENOTEMPTY = 0x80410142;
constexpr int ORBIS_NET_ERROR_EPROCUNAVAIL = 0x8041014C;
constexpr int ORBIS_NET_ERROR_ECANCELED = 0x80410157;
constexpr int ORBIS_NET_ERROR_EPROTO = 0x8041015C;
constexpr int ORBIS_NET_ERROR_EADHOC = 0x804101a0;
constexpr int ORBIS_NET_ERROR_ERESERVED161 = 0x804101a1;
constexpr int ORBIS_NET_ERROR_ERESERVED162 = 0x804101a2;
constexpr int ORBIS_NET_ERROR_EINACTIVEDISABLED = 0x804101a3;
constexpr int ORBIS_NET_ERROR_ENODATA = 0x804101a4;
constexpr int ORBIS_NET_ERROR_EDESC = 0x804101a5;
constexpr int ORBIS_NET_ERROR_EDESCTIMEDOUT = 0x804101a6;
constexpr int ORBIS_NET_ERROR_ENOTINIT = 0x804101c8;
constexpr int ORBIS_NET_ERROR_ENOLIBMEM = 0x804101c9;
constexpr int ORBIS_NET_ERROR_ECALLBACK = 0x804101cb;
constexpr int ORBIS_NET_ERROR_EINTERNAL = 0x804101cc;
constexpr int ORBIS_NET_ERROR_ERETURN = 0x804101cd;
constexpr int ORBIS_NET_ERROR_ENOALLOCMEM = 0x804101ce;
constexpr int ORBIS_NET_ERROR_RESOLVER_EINTERNAL = 0x804101dc;
constexpr int ORBIS_NET_ERROR_RESOLVER_EBUSY = 0x804101dd;
constexpr int ORBIS_NET_ERROR_RESOLVER_ENOSPACE = 0x804101de;
constexpr int ORBIS_NET_ERROR_RESOLVER_EPACKET = 0x804101df;
constexpr int ORBIS_NET_ERROR_RESOLVER_ENODNS = 0x804101e1;
constexpr int ORBIS_NET_ERROR_RESOLVER_ETIMEDOUT = 0x804101e2;
constexpr int ORBIS_NET_ERROR_RESOLVER_ENOSUPPORT = 0x804101e3;
constexpr int ORBIS_NET_ERROR_RESOLVER_EFORMAT = 0x804101e4;
constexpr int ORBIS_NET_ERROR_RESOLVER_ESERVERFAILURE = 0x804101e5;
constexpr int ORBIS_NET_ERROR_RESOLVER_ENOHOST = 0x804101e6;
constexpr int ORBIS_NET_ERROR_RESOLVER_ENOTIMPLEMENTED = 0x804101e7;
constexpr int ORBIS_NET_ERROR_RESOLVER_ESERVERREFUSED = 0x804101e8;
constexpr int ORBIS_NET_ERROR_RESOLVER_ENORECORD = 0x804101e9;
constexpr int ORBIS_NET_ERROR_RESOLVER_EALIGNMENT = 0x804101ea;

View File

@ -0,0 +1,110 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#ifdef _WIN32
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <Ws2tcpip.h>
#include <iphlpapi.h>
#include <winsock2.h>
typedef SOCKET net_socket;
typedef int socklen_t;
#else
#include <cerrno>
#include <arpa/inet.h>
#include <net/if.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
typedef int net_socket;
#endif
#if defined(__APPLE__)
#include <ifaddrs.h>
#include <net/if_dl.h>
#endif
#include <map>
#include <memory>
#include <mutex>
#include <vector>
#include <string.h>
#include "net_util.h"
namespace NetUtil {
const std::array<u8, 6>& NetUtilInternal::GetEthernetAddr() const {
return ether_address;
}
bool NetUtilInternal::RetrieveEthernetAddr() {
std::scoped_lock lock{m_mutex};
#ifdef _WIN32
std::vector<u8> adapter_infos(sizeof(IP_ADAPTER_INFO));
ULONG size_infos = sizeof(IP_ADAPTER_INFO);
if (GetAdaptersInfo(reinterpret_cast<PIP_ADAPTER_INFO>(adapter_infos.data()), &size_infos) ==
ERROR_BUFFER_OVERFLOW)
adapter_infos.resize(size_infos);
if (GetAdaptersInfo(reinterpret_cast<PIP_ADAPTER_INFO>(adapter_infos.data()), &size_infos) ==
NO_ERROR &&
size_infos) {
PIP_ADAPTER_INFO info = reinterpret_cast<PIP_ADAPTER_INFO>(adapter_infos.data());
memcpy(ether_address.data(), info[0].Address, 6);
return true;
}
#elif defined(__APPLE__)
ifaddrs* ifap;
if (getifaddrs(&ifap) == 0) {
ifaddrs* p;
for (p = ifap; p; p = p->ifa_next) {
if (p->ifa_addr->sa_family == AF_LINK) {
sockaddr_dl* sdp = reinterpret_cast<sockaddr_dl*>(p->ifa_addr);
memcpy(ether_address.data(), sdp->sdl_data + sdp->sdl_nlen, 6);
freeifaddrs(ifap);
return true;
}
}
freeifaddrs(ifap);
}
#else
ifreq ifr;
ifconf ifc;
char buf[1024];
int success = 0;
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock == -1)
return false;
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if (ioctl(sock, SIOCGIFCONF, &ifc) == -1)
return false;
ifreq* it = ifc.ifc_req;
const ifreq* const end = it + (ifc.ifc_len / sizeof(ifreq));
for (; it != end; ++it) {
strcpy(ifr.ifr_name, it->ifr_name);
if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) {
if (!(ifr.ifr_flags & IFF_LOOPBACK)) {
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) {
success = 1;
break;
}
}
}
}
if (success) {
memcpy(ether_address.data(), ifr.ifr_hwaddr.sa_data, 6);
return true;
}
#endif
return false;
}
} // namespace NetUtil

View File

@ -0,0 +1,24 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <mutex>
#include "common/types.h"
namespace NetUtil {
class NetUtilInternal {
public:
explicit NetUtilInternal() = default;
~NetUtilInternal() = default;
private:
std::array<u8, 6> ether_address{};
std::mutex m_mutex;
public:
const std::array<u8, 6>& GetEthernetAddr() const;
bool RetrieveEthernetAddr();
};
} // namespace NetUtil

View File

@ -12,11 +12,13 @@
#include <unistd.h>
#endif
#include <common/singleton.h>
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
#include "core/libraries/network/net_ctl_codes.h"
#include "core/libraries/network/netctl.h"
#include "net_util.h"
namespace Libraries::NetCtl {
@ -162,6 +164,14 @@ int PS4_SYSV_ABI sceNetCtlGetInfo(int code, OrbisNetCtlInfo* info) {
case ORBIS_NET_CTL_INFO_DEVICE:
info->device = ORBIS_NET_CTL_DEVICE_WIRED;
break;
case ORBIS_NET_CTL_INFO_ETHER_ADDR: {
auto* netinfo = Common::Singleton<NetUtil::NetUtilInternal>::Instance();
netinfo->RetrieveEthernetAddr();
memcpy(info->ether_addr.data, netinfo->GetEthernetAddr().data(), 6);
} break;
case ORBIS_NET_CTL_INFO_MTU:
info->mtu = 1500; // default value
break;
case ORBIS_NET_CTL_INFO_LINK:
info->link = ORBIS_NET_CTL_LINK_DISCONNECTED;
break;
@ -183,6 +193,7 @@ int PS4_SYSV_ABI sceNetCtlGetInfo(int code, OrbisNetCtlInfo* info) {
}
break;
}
default:
LOG_ERROR(Lib_NetCtl, "{} unsupported code", code);
}

View File

@ -49,8 +49,26 @@ union OrbisNetCtlInfo {
// GetInfo codes
constexpr int ORBIS_NET_CTL_INFO_DEVICE = 1;
constexpr int ORBIS_NET_CTL_INFO_ETHER_ADDR = 2;
constexpr int ORBIS_NET_CTL_INFO_MTU = 3;
constexpr int ORBIS_NET_CTL_INFO_LINK = 4;
constexpr int ORBIS_NET_CTL_INFO_BSSID = 5;
constexpr int ORBIS_NET_CTL_INFO_SSID = 6;
constexpr int ORBIS_NET_CTL_INFO_WIFI_SECURITY = 7;
constexpr int ORBIS_NET_CTL_INFO_RSSI_DBM = 8;
constexpr int ORBIS_NET_CTL_INFO_RSSI_PERCENTAGE = 9;
constexpr int ORBIS_NET_CTL_INFO_CHANNEL = 10;
constexpr int ORBIS_NET_CTL_INFO_IP_CONFIG = 11;
constexpr int ORBIS_NET_CTL_INFO_DHCP_HOSTNAME = 12;
constexpr int ORBIS_NET_CTL_INFO_PPPOE_AUTH_NAME = 13;
constexpr int ORBIS_NET_CTL_INFO_IP_ADDRESS = 14;
constexpr int ORBIS_NET_CTL_INFO_NETMASK = 15;
constexpr int ORBIS_NET_CTL_INFO_DEFAULT_ROUTE = 16;
constexpr int ORBIS_NET_CTL_INFO_PRIMARY_DNS = 17;
constexpr int ORBIS_NET_CTL_INFO_SECONDARY_DNS = 18;
constexpr int ORBIS_NET_CTL_INFO_HTTP_PROXY_CONFIG = 19;
constexpr int ORBIS_NET_CTL_INFO_HTTP_PROXY_SERVER = 20;
constexpr int ORBIS_NET_CTL_INFO_HTTP_PROXY_PORT = 21;
int PS4_SYSV_ABI sceNetBweCheckCallbackIpcInt();
int PS4_SYSV_ABI sceNetBweClearEventIpcInt();

View File

@ -0,0 +1,60 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <common/assert.h>
#include "net.h"
#include "net_error.h"
#include "sockets.h"
namespace Libraries::Net {
int P2PSocket::Close() {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return -1;
}
int P2PSocket::SetSocketOptions(int level, int optname, const void* optval, u32 optlen) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return -1;
}
int P2PSocket::GetSocketOptions(int level, int optname, void* optval, u32* optlen) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return -1;
}
int P2PSocket::Bind(const OrbisNetSockaddr* addr, u32 addrlen) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return -1;
}
int P2PSocket::Listen(int backlog) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return -1;
}
int P2PSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to,
u32 tolen) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return -1;
}
int P2PSocket::ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, u32* fromlen) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return -1;
}
SocketPtr P2PSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return nullptr;
}
int P2PSocket::Connect(const OrbisNetSockaddr* addr, u32 namelen) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return -1;
}
int P2PSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return -1;
}
} // namespace Libraries::Net

View File

@ -0,0 +1,359 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <common/assert.h>
#include "net.h"
#include "net_error.h"
#include "sockets.h"
namespace Libraries::Net {
#ifdef _WIN32
#define ERROR_CASE(errname) \
case (WSA##errname): \
return ORBIS_NET_ERROR_##errname;
#else
#define ERROR_CASE(errname) \
case (errname): \
return ORBIS_NET_ERROR_##errname;
#endif
static int ConvertReturnErrorCode(int retval) {
if (retval < 0) {
#ifdef _WIN32
switch (WSAGetLastError()) {
#else
switch (errno) {
#endif
#ifndef _WIN32 // These errorcodes don't exist in WinSock
ERROR_CASE(EPERM)
ERROR_CASE(ENOENT)
// ERROR_CASE(ESRCH)
// ERROR_CASE(EIO)
// ERROR_CASE(ENXIO)
// ERROR_CASE(E2BIG)
// ERROR_CASE(ENOEXEC)
// ERROR_CASE(EDEADLK)
ERROR_CASE(ENOMEM)
// ERROR_CASE(ECHILD)
// ERROR_CASE(EBUSY)
ERROR_CASE(EEXIST)
// ERROR_CASE(EXDEV)
ERROR_CASE(ENODEV)
// ERROR_CASE(ENOTDIR)
// ERROR_CASE(EISDIR)
ERROR_CASE(ENFILE)
// ERROR_CASE(ENOTTY)
// ERROR_CASE(ETXTBSY)
// ERROR_CASE(EFBIG)
ERROR_CASE(ENOSPC)
// ERROR_CASE(ESPIPE)
// ERROR_CASE(EROFS)
// ERROR_CASE(EMLINK)
ERROR_CASE(EPIPE)
// ERROR_CASE(EDOM)
// ERROR_CASE(ERANGE)
// ERROR_CASE(ENOLCK)
// ERROR_CASE(ENOSYS)
// ERROR_CASE(EIDRM)
// ERROR_CASE(EOVERFLOW)
// ERROR_CASE(EILSEQ)
// ERROR_CASE(ENOTSUP)
ERROR_CASE(ECANCELED)
// ERROR_CASE(EBADMSG)
ERROR_CASE(ENODATA)
// ERROR_CASE(ENOSR)
// ERROR_CASE(ENOSTR)
// ERROR_CASE(ETIME)
#endif
ERROR_CASE(EINTR)
ERROR_CASE(EBADF)
ERROR_CASE(EACCES)
ERROR_CASE(EFAULT)
ERROR_CASE(EINVAL)
ERROR_CASE(EMFILE)
ERROR_CASE(EWOULDBLOCK)
ERROR_CASE(EINPROGRESS)
ERROR_CASE(EALREADY)
ERROR_CASE(ENOTSOCK)
ERROR_CASE(EDESTADDRREQ)
ERROR_CASE(EMSGSIZE)
ERROR_CASE(EPROTOTYPE)
ERROR_CASE(ENOPROTOOPT)
ERROR_CASE(EPROTONOSUPPORT)
#if defined(__APPLE__) || defined(_WIN32)
ERROR_CASE(EOPNOTSUPP)
#endif
ERROR_CASE(EAFNOSUPPORT)
ERROR_CASE(EADDRINUSE)
ERROR_CASE(EADDRNOTAVAIL)
ERROR_CASE(ENETDOWN)
ERROR_CASE(ENETUNREACH)
ERROR_CASE(ENETRESET)
ERROR_CASE(ECONNABORTED)
ERROR_CASE(ECONNRESET)
ERROR_CASE(ENOBUFS)
ERROR_CASE(EISCONN)
ERROR_CASE(ENOTCONN)
ERROR_CASE(ETIMEDOUT)
ERROR_CASE(ECONNREFUSED)
ERROR_CASE(ELOOP)
ERROR_CASE(ENAMETOOLONG)
ERROR_CASE(EHOSTUNREACH)
ERROR_CASE(ENOTEMPTY)
}
return ORBIS_NET_ERROR_EINTERNAL;
}
// if it is 0 or positive return it as it is
return retval;
}
static int ConvertLevels(int level) {
switch (level) {
case ORBIS_NET_SOL_SOCKET:
return SOL_SOCKET;
case ORBIS_NET_IPPROTO_IP:
return IPPROTO_IP;
case ORBIS_NET_IPPROTO_TCP:
return IPPROTO_TCP;
}
return -1;
}
static void convertOrbisNetSockaddrToPosix(const OrbisNetSockaddr* src, sockaddr* dst) {
if (src == nullptr || dst == nullptr)
return;
memset(dst, 0, sizeof(sockaddr));
const OrbisNetSockaddrIn* src_in = (const OrbisNetSockaddrIn*)src;
sockaddr_in* dst_in = (sockaddr_in*)dst;
dst_in->sin_family = src_in->sin_family;
dst_in->sin_port = src_in->sin_port;
memcpy(&dst_in->sin_addr, &src_in->sin_addr, 4);
}
static void convertPosixSockaddrToOrbis(sockaddr* src, OrbisNetSockaddr* dst) {
if (src == nullptr || dst == nullptr)
return;
memset(dst, 0, sizeof(OrbisNetSockaddr));
OrbisNetSockaddrIn* dst_in = (OrbisNetSockaddrIn*)dst;
sockaddr_in* src_in = (sockaddr_in*)src;
dst_in->sin_family = static_cast<unsigned char>(src_in->sin_family);
dst_in->sin_port = src_in->sin_port;
memcpy(&dst_in->sin_addr, &src_in->sin_addr, 4);
}
int PosixSocket::Close() {
#ifdef _WIN32
auto out = closesocket(sock);
#else
auto out = ::close(sock);
#endif
return ConvertReturnErrorCode(out);
}
int PosixSocket::Bind(const OrbisNetSockaddr* addr, u32 addrlen) {
sockaddr addr2;
convertOrbisNetSockaddrToPosix(addr, &addr2);
return ConvertReturnErrorCode(::bind(sock, &addr2, sizeof(sockaddr_in)));
}
int PosixSocket::Listen(int backlog) {
return ConvertReturnErrorCode(::listen(sock, backlog));
}
int PosixSocket::SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to,
u32 tolen) {
if (to != nullptr) {
sockaddr addr;
convertOrbisNetSockaddrToPosix(to, &addr);
return ConvertReturnErrorCode(
sendto(sock, (const char*)msg, len, flags, &addr, sizeof(sockaddr_in)));
} else {
return ConvertReturnErrorCode(send(sock, (const char*)msg, len, flags));
}
}
int PosixSocket::ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from,
u32* fromlen) {
if (from != nullptr) {
sockaddr addr;
int res = recvfrom(sock, (char*)buf, len, flags, &addr, (socklen_t*)fromlen);
convertPosixSockaddrToOrbis(&addr, from);
*fromlen = sizeof(OrbisNetSockaddrIn);
return ConvertReturnErrorCode(res);
} else {
return ConvertReturnErrorCode(recv(sock, (char*)buf, len, flags));
}
}
SocketPtr PosixSocket::Accept(OrbisNetSockaddr* addr, u32* addrlen) {
sockaddr addr2;
net_socket new_socket = ::accept(sock, &addr2, (socklen_t*)addrlen);
#ifdef _WIN32
if (new_socket != INVALID_SOCKET) {
#else
if (new_socket >= 0) {
#endif
convertPosixSockaddrToOrbis(&addr2, addr);
*addrlen = sizeof(OrbisNetSockaddrIn);
return std::make_shared<PosixSocket>(new_socket);
}
return nullptr;
}
int PosixSocket::Connect(const OrbisNetSockaddr* addr, u32 namelen) {
sockaddr addr2;
convertOrbisNetSockaddrToPosix(addr, &addr2);
return ::connect(sock, &addr2, sizeof(sockaddr_in));
}
int PosixSocket::GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) {
sockaddr addr;
convertOrbisNetSockaddrToPosix(name, &addr);
if (name != nullptr) {
*namelen = sizeof(sockaddr_in);
}
int res = getsockname(sock, &addr, (socklen_t*)namelen);
if (res >= 0) {
convertPosixSockaddrToOrbis(&addr, name);
*namelen = sizeof(OrbisNetSockaddrIn);
}
return res;
}
#define CASE_SETSOCKOPT(opt) \
case ORBIS_NET_##opt: \
return ConvertReturnErrorCode(setsockopt(sock, level, opt, (const char*)optval, optlen))
#define CASE_SETSOCKOPT_VALUE(opt, value) \
case opt: \
if (optlen != sizeof(*value)) { \
return ORBIS_NET_ERROR_EFAULT; \
} \
memcpy(value, optval, optlen); \
return 0
int PosixSocket::SetSocketOptions(int level, int optname, const void* optval, u32 optlen) {
level = ConvertLevels(level);
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_SNDBUF);
CASE_SETSOCKOPT(SO_RCVBUF);
CASE_SETSOCKOPT(SO_SNDTIMEO);
CASE_SETSOCKOPT(SO_RCVTIMEO);
CASE_SETSOCKOPT(SO_ERROR);
CASE_SETSOCKOPT(SO_TYPE);
CASE_SETSOCKOPT_VALUE(ORBIS_NET_SO_REUSEPORT, &sockopt_so_reuseport);
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_NAME:
return ORBIS_NET_ERROR_EINVAL; // don't support set for name
case ORBIS_NET_SO_NBIO: {
if (optlen != sizeof(sockopt_so_nbio)) {
return ORBIS_NET_ERROR_EFAULT;
}
memcpy(&sockopt_so_nbio, optval, optlen);
#ifdef _WIN32
static_assert(sizeof(u_long) == sizeof(sockopt_so_nbio),
"type used for ioctlsocket value does not have the expected size");
return ConvertReturnErrorCode(ioctlsocket(sock, FIONBIO, (u_long*)&sockopt_so_nbio));
#else
return ConvertReturnErrorCode(ioctl(sock, FIONBIO, &sockopt_so_nbio));
#endif
}
}
} else if (level == IPPROTO_IP) {
switch (optname) {
CASE_SETSOCKOPT(IP_HDRINCL);
CASE_SETSOCKOPT(IP_TOS);
CASE_SETSOCKOPT(IP_TTL);
CASE_SETSOCKOPT(IP_MULTICAST_IF);
CASE_SETSOCKOPT(IP_MULTICAST_TTL);
CASE_SETSOCKOPT(IP_MULTICAST_LOOP);
CASE_SETSOCKOPT(IP_ADD_MEMBERSHIP);
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);
}
} else if (level == IPPROTO_TCP) {
switch (optname) {
CASE_SETSOCKOPT(TCP_NODELAY);
CASE_SETSOCKOPT(TCP_MAXSEG);
CASE_SETSOCKOPT_VALUE(ORBIS_NET_TCP_MSS_TO_ADVERTISE, &sockopt_tcp_mss_to_advertise);
}
}
UNREACHABLE_MSG("Unknown level ={} optname ={}", level, optname);
return 0;
}
#define CASE_GETSOCKOPT(opt) \
case ORBIS_NET_##opt: { \
socklen_t optlen_temp = *optlen; \
auto retval = \
ConvertReturnErrorCode(getsockopt(sock, level, opt, (char*)optval, &optlen_temp)); \
*optlen = optlen_temp; \
return retval; \
}
#define CASE_GETSOCKOPT_VALUE(opt, value) \
case opt: \
if (*optlen < sizeof(value)) { \
*optlen = sizeof(value); \
return ORBIS_NET_ERROR_EFAULT; \
} \
*optlen = sizeof(value); \
*(decltype(value)*)optval = value; \
return 0;
int PosixSocket::GetSocketOptions(int level, int optname, void* optval, u32* optlen) {
level = ConvertLevels(level);
if (level == SOL_SOCKET) {
switch (optname) {
CASE_GETSOCKOPT(SO_REUSEADDR);
CASE_GETSOCKOPT(SO_KEEPALIVE);
CASE_GETSOCKOPT(SO_BROADCAST);
CASE_GETSOCKOPT(SO_LINGER);
CASE_GETSOCKOPT(SO_SNDBUF);
CASE_GETSOCKOPT(SO_RCVBUF);
CASE_GETSOCKOPT(SO_SNDTIMEO);
CASE_GETSOCKOPT(SO_RCVTIMEO);
CASE_GETSOCKOPT(SO_ERROR);
CASE_GETSOCKOPT(SO_TYPE);
CASE_GETSOCKOPT_VALUE(ORBIS_NET_SO_NBIO, sockopt_so_nbio);
CASE_GETSOCKOPT_VALUE(ORBIS_NET_SO_REUSEPORT, sockopt_so_reuseport);
CASE_GETSOCKOPT_VALUE(ORBIS_NET_SO_ONESBCAST, sockopt_so_onesbcast);
CASE_GETSOCKOPT_VALUE(ORBIS_NET_SO_USECRYPTO, sockopt_so_usecrypto);
CASE_GETSOCKOPT_VALUE(ORBIS_NET_SO_USESIGNATURE, sockopt_so_usesignature);
CASE_GETSOCKOPT_VALUE(ORBIS_NET_SO_NAME,
(char)0); // writes an empty string to the output buffer
}
} else if (level == IPPROTO_IP) {
switch (optname) {
CASE_GETSOCKOPT(IP_HDRINCL);
CASE_GETSOCKOPT(IP_TOS);
CASE_GETSOCKOPT(IP_TTL);
CASE_GETSOCKOPT(IP_MULTICAST_IF);
CASE_GETSOCKOPT(IP_MULTICAST_TTL);
CASE_GETSOCKOPT(IP_MULTICAST_LOOP);
CASE_GETSOCKOPT(IP_ADD_MEMBERSHIP);
CASE_GETSOCKOPT(IP_DROP_MEMBERSHIP);
CASE_GETSOCKOPT_VALUE(ORBIS_NET_IP_TTLCHK, sockopt_ip_ttlchk);
CASE_GETSOCKOPT_VALUE(ORBIS_NET_IP_MAXTTL, sockopt_ip_maxttl);
}
} else if (level == IPPROTO_TCP) {
switch (optname) {
CASE_GETSOCKOPT(TCP_NODELAY);
CASE_GETSOCKOPT(TCP_MAXSEG);
CASE_GETSOCKOPT_VALUE(ORBIS_NET_TCP_MSS_TO_ADVERTISE, sockopt_tcp_mss_to_advertise);
}
}
UNREACHABLE_MSG("Unknown level ={} optname ={}", level, optname);
return 0;
}
} // namespace Libraries::Net

View File

@ -0,0 +1,112 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#ifdef _WIN32
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <Ws2tcpip.h>
#include <iphlpapi.h>
#include <winsock2.h>
typedef SOCKET net_socket;
typedef int socklen_t;
#else
#include <cerrno>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
typedef int net_socket;
#endif
#include <map>
#include <memory>
#include <mutex>
#include "net.h"
namespace Libraries::Net {
struct Socket;
typedef std::shared_ptr<Socket> SocketPtr;
struct Socket {
explicit Socket(int domain, int type, int protocol) {}
virtual ~Socket() = default;
virtual int Close() = 0;
virtual int SetSocketOptions(int level, int optname, const void* optval, u32 optlen) = 0;
virtual int GetSocketOptions(int level, int optname, void* optval, u32* optlen) = 0;
virtual int Bind(const OrbisNetSockaddr* addr, u32 addrlen) = 0;
virtual int Listen(int backlog) = 0;
virtual int SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to,
u32 tolen) = 0;
virtual SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) = 0;
virtual int ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from,
u32* fromlen) = 0;
virtual int Connect(const OrbisNetSockaddr* addr, u32 namelen) = 0;
virtual int GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) = 0;
};
struct PosixSocket : public Socket {
net_socket sock;
int sockopt_so_reuseport = 0;
int sockopt_so_onesbcast = 0;
int sockopt_so_usecrypto = 0;
int sockopt_so_usesignature = 0;
int sockopt_so_nbio = 0;
int sockopt_ip_ttlchk = 0;
int sockopt_ip_maxttl = 0;
int sockopt_tcp_mss_to_advertise = 0;
explicit PosixSocket(int domain, int type, int protocol)
: Socket(domain, type, protocol), sock(socket(domain, type, protocol)) {}
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;
int GetSocketOptions(int level, int optname, void* optval, u32* optlen) override;
int Bind(const OrbisNetSockaddr* addr, u32 addrlen) override;
int Listen(int backlog) override;
int SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to,
u32 tolen) override;
int ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, u32* fromlen) override;
SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) override;
int Connect(const OrbisNetSockaddr* addr, u32 namelen) override;
int GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) override;
};
struct P2PSocket : public Socket {
explicit P2PSocket(int domain, int type, int protocol) : Socket(domain, type, protocol) {}
int Close() override;
int SetSocketOptions(int level, int optname, const void* optval, u32 optlen) override;
int GetSocketOptions(int level, int optname, void* optval, u32* optlen) override;
int Bind(const OrbisNetSockaddr* addr, u32 addrlen) override;
int Listen(int backlog) override;
int SendPacket(const void* msg, u32 len, int flags, const OrbisNetSockaddr* to,
u32 tolen) override;
int ReceivePacket(void* buf, u32 len, int flags, OrbisNetSockaddr* from, u32* fromlen) override;
SocketPtr Accept(OrbisNetSockaddr* addr, u32* addrlen) override;
int Connect(const OrbisNetSockaddr* addr, u32 namelen) override;
int GetSocketAddress(OrbisNetSockaddr* name, u32* namelen) override;
};
class NetInternal {
public:
explicit NetInternal() = default;
~NetInternal() = default;
SocketPtr FindSocket(int sockid) {
std::scoped_lock lock{m_mutex};
const auto it = socks.find(sockid);
if (it != socks.end()) {
return it->second;
}
return 0;
}
public:
std::mutex m_mutex;
typedef std::map<int, SocketPtr> NetSockets;
NetSockets socks;
int next_sock_id = 0;
};
} // namespace Libraries::Net

View File

@ -0,0 +1,229 @@
#include "sys_net.h"
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <common/assert.h>
#include <common/logging/log.h>
#include <core/libraries/kernel/kernel.h>
#include "common/singleton.h"
#include "net_error.h"
#include "sockets.h"
#include "sys_net.h"
namespace Libraries::Net {
int PS4_SYSV_ABI sys_connect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) {
auto* netcall = Common::Singleton<NetInternal>::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->Connect(addr, addrlen);
if (returncode >= 0) {
return returncode;
}
*Libraries::Kernel::__Error() = returncode;
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
return -1;
}
int PS4_SYSV_ABI sys_bind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen) {
auto* netcall = Common::Singleton<NetInternal>::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->Bind(addr, addrlen);
if (returncode >= 0) {
return returncode;
}
*Libraries::Kernel::__Error() = returncode;
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
return -1;
}
int PS4_SYSV_ABI sys_accept(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) {
auto* netcall = Common::Singleton<NetInternal>::Instance();
auto sock = netcall->FindSocket(s);
if (!sock) {
*Libraries::Kernel::__Error() = ORBIS_NET_EBADF;
LOG_ERROR(Lib_Net, "socket id is invalid = {}", s);
return -1;
}
auto new_sock = sock->Accept(addr, paddrlen);
if (!new_sock) {
*Libraries::Kernel::__Error() = ORBIS_NET_EBADF;
LOG_ERROR(Lib_Net, "error creating new socket for accepting");
return -1;
}
auto id = ++netcall->next_sock_id;
netcall->socks.emplace(id, new_sock);
return id;
}
int PS4_SYSV_ABI sys_getpeername(OrbisNetId s, const OrbisNetSockaddr* addr, u32* paddrlen) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return -1;
}
int PS4_SYSV_ABI sys_getsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen) {
auto* netcall = Common::Singleton<NetInternal>::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) {
return returncode;
}
*Libraries::Kernel::__Error() = returncode;
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
return -1;
}
int PS4_SYSV_ABI sys_getsockopt(OrbisNetId s, int level, int optname, void* optval, u32* optlen) {
auto* netcall = Common::Singleton<NetInternal>::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->GetSocketOptions(level, optname, optval, optlen);
if (returncode >= 0) {
return returncode;
}
*Libraries::Kernel::__Error() = returncode;
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
return -1;
}
int PS4_SYSV_ABI sys_listen(OrbisNetId s, int backlog) {
auto* netcall = Common::Singleton<NetInternal>::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->Listen(backlog);
if (returncode >= 0) {
return returncode;
}
*Libraries::Kernel::__Error() = returncode;
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
return -1;
}
int PS4_SYSV_ABI sys_setsockopt(OrbisNetId s, int level, int optname, const void* optval,
u32 optlen) {
auto* netcall = Common::Singleton<NetInternal>::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->SetSocketOptions(level, optname, optval, optlen);
if (returncode >= 0) {
return returncode;
}
*Libraries::Kernel::__Error() = returncode;
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
return -1;
}
int PS4_SYSV_ABI sys_shutdown(OrbisNetId s, int how) {
return -1;
}
int PS4_SYSV_ABI sys_socketex(const char* name, int family, int type, int protocol) {
if (name == nullptr) {
LOG_INFO(Lib_Net, "name = no-named family = {} type = {} protocol = {}", family, type,
protocol);
} else {
LOG_INFO(Lib_Net, "name = {} family = {} type = {} protocol = {}", std::string(name),
family, type, protocol);
}
SocketPtr sock;
switch (type) {
case ORBIS_NET_SOCK_STREAM:
case ORBIS_NET_SOCK_DGRAM:
case ORBIS_NET_SOCK_RAW:
sock = std::make_shared<PosixSocket>(family, type, protocol);
break;
case ORBIS_NET_SOCK_DGRAM_P2P:
case ORBIS_NET_SOCK_STREAM_P2P:
sock = std::make_shared<P2PSocket>(family, type, protocol);
break;
default:
UNREACHABLE_MSG("Unknown type {}", type);
}
auto* netcall = Common::Singleton<NetInternal>::Instance();
auto id = ++netcall->next_sock_id;
netcall->socks.emplace(id, sock);
return id;
}
int PS4_SYSV_ABI sys_socket(int family, int type, int protocol) {
return sys_socketex(nullptr, family, type, protocol);
}
int PS4_SYSV_ABI sys_netabort(OrbisNetId s, int flags) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return -1;
}
int PS4_SYSV_ABI sys_socketclose(OrbisNetId s) {
auto* netcall = Common::Singleton<NetInternal>::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->Close();
if (returncode >= 0) {
return returncode;
}
*Libraries::Kernel::__Error() = returncode;
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
return -1;
}
int PS4_SYSV_ABI sys_sendto(OrbisNetId s, const void* buf, u64 len, int flags,
const OrbisNetSockaddr* addr, u32 addrlen) {
auto* netcall = Common::Singleton<NetInternal>::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->SendPacket(buf, len, flags, addr, addrlen);
if (returncode >= 0) {
return returncode;
}
*Libraries::Kernel::__Error() = returncode;
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
return -1;
}
int PS4_SYSV_ABI sys_sendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return -1;
}
int PS4_SYSV_ABI sys_recvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr,
u32* paddrlen) {
auto* netcall = Common::Singleton<NetInternal>::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->ReceivePacket(buf, len, flags, addr, paddrlen);
if (returncode >= 0) {
return returncode;
}
*Libraries::Kernel::__Error() = returncode;
LOG_ERROR(Lib_Net, "error code returned : {:#x}", (u32)returncode);
return -1;
}
int PS4_SYSV_ABI sys_recvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags) {
LOG_ERROR(Lib_Net, "(STUBBED) called");
return -1;
}
} // namespace Libraries::Net

View File

@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/types.h"
#include "net.h"
namespace Libraries::Net {
int PS4_SYSV_ABI sys_connect(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen);
int PS4_SYSV_ABI sys_bind(OrbisNetId s, const OrbisNetSockaddr* addr, u32 addrlen);
int PS4_SYSV_ABI sys_accept(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen);
int PS4_SYSV_ABI sys_getpeername(OrbisNetId s, const OrbisNetSockaddr* addr, u32* paddrlen);
int PS4_SYSV_ABI sys_getsockname(OrbisNetId s, OrbisNetSockaddr* addr, u32* paddrlen);
int PS4_SYSV_ABI sys_getsockopt(OrbisNetId s, int level, int optname, void* optval, u32* optlen);
int PS4_SYSV_ABI sys_listen(OrbisNetId s, int backlog);
int PS4_SYSV_ABI sys_setsockopt(OrbisNetId s, int level, int optname, const void* optval,
u32 optlen);
int PS4_SYSV_ABI sys_shutdown(OrbisNetId s, int how);
int PS4_SYSV_ABI sys_socketex(const char* name, int family, int type, int protocol);
int PS4_SYSV_ABI sys_socket(int family, int type, int protocol);
int PS4_SYSV_ABI sys_netabort(OrbisNetId s, int flags);
int PS4_SYSV_ABI sys_socketclose(OrbisNetId s);
int PS4_SYSV_ABI sys_sendto(OrbisNetId s, const void* buf, u64 len, int flags,
const OrbisNetSockaddr* addr, u32 addrlen);
int PS4_SYSV_ABI sys_sendmsg(OrbisNetId s, const OrbisNetMsghdr* msg, int flags);
int PS4_SYSV_ABI sys_recvfrom(OrbisNetId s, void* buf, u64 len, int flags, OrbisNetSockaddr* addr,
u32* paddrlen);
int PS4_SYSV_ABI sys_recvmsg(OrbisNetId s, OrbisNetMsghdr* msg, int flags);
} // namespace Libraries::Net

View File

@ -16,6 +16,9 @@
#ifdef ENABLE_DISCORD_RPC
#include "common/discord_rpc_handler.h"
#endif
#ifdef _WIN32
#include <WinSock2.h>
#endif
#include "common/elf_info.h"
#include "common/ntapi.h"
#include "common/path_util.h"
@ -46,6 +49,10 @@ Emulator::Emulator() {
#ifdef _WIN32
Common::NtApi::Initialize();
SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
// need to init this in order for winsock2 to work
WORD versionWanted = MAKEWORD(2, 2);
WSADATA wsaData;
WSAStartup(versionWanted, &wsaData);
#endif
// Create stdin/stdout/stderr

View File

@ -1387,7 +1387,7 @@ void CheatsPatches::applyPatch(const QString& patchName, bool enabled) {
if (type == "mask_jump32")
patchMask = MemoryPatcher::PatchMask::Mask_Jump32;
if (type == "mask" || type == "mask_jump32" && !maskOffsetStr.toStdString().empty()) {
if ((type == "mask" || type == "mask_jump32") && !maskOffsetStr.toStdString().empty()) {
maskOffsetValue = std::stoi(maskOffsetStr.toStdString(), 0, 10);
}

View File

@ -384,23 +384,23 @@
</message>
<message>
<source>Nothing</source>
<translation>Không có </translation>
<translation>Không chạy đưc</translation>
</message>
<message>
<source>Boots</source>
<translation>Giày ng</translation>
<translation>Chạy đưc</translation>
</message>
<message>
<source>Menus</source>
<translation>Menu</translation>
<translation>Vào đưc menu</translation>
</message>
<message>
<source>Ingame</source>
<translation>Trong game</translation>
<translation>Vào đưc trò chơi</translation>
</message>
<message>
<source>Playable</source>
<translation>Có thể chơi</translation>
<translation>Chơi đưc</translation>
</message>
</context>
<context>
@ -411,7 +411,7 @@
</message>
<message>
<source>D-Pad</source>
<translation type="unfinished">D-Pad</translation>
<translation>D-Pad</translation>
</message>
<message>
<source>Up</source>
@ -447,7 +447,7 @@
</message>
<message>
<source>Common Config</source>
<translation type="unfinished">Common Config</translation>
<translation>Cài Đt Chung</translation>
</message>
<message>
<source>Use per-game configs</source>
@ -551,26 +551,26 @@
</message>
<message>
<source>Save</source>
<translation type="unfinished">Save</translation>
<translation>Lưu</translation>
</message>
<message>
<source>Apply</source>
<translation type="unfinished">Apply</translation>
<translation>Áp dụng</translation>
</message>
<message>
<source>Restore Defaults</source>
<translation type="unfinished">Restore Defaults</translation>
<translation>Khôi Phục Mặc Đnh</translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished">Cancel</translation>
<translation>Hủy</translation>
</message>
</context>
<context>
<name>EditorDialog</name>
<message>
<source>Edit Keyboard + Mouse and Controller input bindings</source>
<translation type="unfinished">Edit Keyboard + Mouse and Controller input bindings</translation>
<translation>Tùy chỉnh phím đưc gán cho Bàn phím + Chuột Tay cầm</translation>
</message>
<message>
<source>Use Per-Game configs</source>
@ -578,7 +578,7 @@
</message>
<message>
<source>Error</source>
<translation type="unfinished">Error</translation>
<translation>Lỗi</translation>
</message>
<message>
<source>Could not open the file for reading</source>
@ -590,15 +590,15 @@
</message>
<message>
<source>Save Changes</source>
<translation type="unfinished">Save Changes</translation>
<translation>Lưu Thay Đi</translation>
</message>
<message>
<source>Do you want to save changes?</source>
<translation type="unfinished">Do you want to save changes?</translation>
<translation>Bạn muốn lưu thay đi?</translation>
</message>
<message>
<source>Help</source>
<translation type="unfinished">Help</translation>
<translation>Trợ giúp</translation>
</message>
<message>
<source>Do you want to reset your custom default config to the original default config?</source>
@ -706,15 +706,15 @@
</message>
<message>
<source>h</source>
<translation type="unfinished">h</translation>
<translation>giờ</translation>
</message>
<message>
<source>m</source>
<translation type="unfinished">m</translation>
<translation>phút</translation>
</message>
<message>
<source>s</source>
<translation type="unfinished">s</translation>
<translation>giây</translation>
</message>
<message>
<source>Compatibility is untested</source>
@ -722,23 +722,23 @@
</message>
<message>
<source>Game does not initialize properly / crashes the emulator</source>
<translation type="unfinished">Game does not initialize properly / crashes the emulator</translation>
<translation>Trò chơi không đưc khởi chạy đúng cách / khiến giả lập bị văng</translation>
</message>
<message>
<source>Game boots, but only displays a blank screen</source>
<translation type="unfinished">Game boots, but only displays a blank screen</translation>
<translation>Trò chơi thể khởi chạy, nhưng chẳng hiện cả</translation>
</message>
<message>
<source>Game displays an image but does not go past the menu</source>
<translation type="unfinished">Game displays an image but does not go past the menu</translation>
<translation>Trò chơi hiển thị đưc hình nh, nhưng không thể tiếp tục từ menu</translation>
</message>
<message>
<source>Game has game-breaking glitches or unplayable performance</source>
<translation type="unfinished">Game has game-breaking glitches or unplayable performance</translation>
<translation>Trò chơi lỗi nh hưởng đến trải nghiệm, hoặc hiệu năng khi chơi không n đnh</translation>
</message>
<message>
<source>Game can be completed with playable performance and no major glitches</source>
<translation type="unfinished">Game can be completed with playable performance and no major glitches</translation>
<translation>Trò chơi thể đưc hoàn thành từ đu đến cuối, hiệu năng n đnh không lỗi nh hưởng đến trải nghiệm</translation>
</message>
<message>
<source>Click to see details on github</source>
@ -1170,19 +1170,19 @@
</message>
<message>
<source>Save</source>
<translation type="unfinished">Save</translation>
<translation>Lưu</translation>
</message>
<message>
<source>Apply</source>
<translation type="unfinished">Apply</translation>
<translation>Áp dụng</translation>
</message>
<message>
<source>Restore Defaults</source>
<translation type="unfinished">Restore Defaults</translation>
<translation>Khôi Phục Mặc Đnh</translation>
</message>
<message>
<source>Cancel</source>
<translation type="unfinished">Cancel</translation>
<translation>Hủy</translation>
</message>
</context>
<context>
@ -1193,7 +1193,7 @@
</message>
<message>
<source>Boot Game</source>
<translation type="unfinished">Boot Game</translation>
<translation>Khởi Chạy Trò Chơi</translation>
</message>
<message>
<source>Check for Updates</source>
@ -1201,7 +1201,7 @@
</message>
<message>
<source>About shadPS4</source>
<translation type="unfinished">About shadPS4</translation>
<translation>Thông Tin Về shadPS4</translation>
</message>
<message>
<source>Configure...</source>
@ -1213,23 +1213,23 @@
</message>
<message>
<source>Open shadPS4 Folder</source>
<translation type="unfinished">Open shadPS4 Folder</translation>
<translation>Mở Thư Mục Của shadPS4</translation>
</message>
<message>
<source>Exit</source>
<translation type="unfinished">Exit</translation>
<translation>Thoát</translation>
</message>
<message>
<source>Exit shadPS4</source>
<translation type="unfinished">Exit shadPS4</translation>
<translation>Thoát shadPS4</translation>
</message>
<message>
<source>Exit the application.</source>
<translation type="unfinished">Exit the application.</translation>
<translation>Thoát ng dụng.</translation>
</message>
<message>
<source>Show Game List</source>
<translation type="unfinished">Show Game List</translation>
<translation>Hiển Thị Danh Sách Trò Chơi</translation>
</message>
<message>
<source>Game List Refresh</source>

View File

@ -270,6 +270,10 @@ void SetupCapabilities(const Info& info, const Profile& profile, EmitContext& ct
if (info.has_image_query) {
ctx.AddCapability(spv::Capability::ImageQuery);
}
if (info.uses_atomic_float_min_max && profile.supports_image_fp32_atomic_min_max) {
ctx.AddExtension("SPV_EXT_shader_atomic_float_min_max");
ctx.AddCapability(spv::Capability::AtomicFloat32MinMaxEXT);
}
if (info.uses_lane_id) {
ctx.AddCapability(spv::Capability::GroupNonUniform);
}

View File

@ -75,6 +75,14 @@ Id ImageAtomicU32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id va
const auto [scope, semantics]{AtomicArgs(ctx)};
return (ctx.*atomic_func)(ctx.U32[1], pointer, scope, semantics, value);
}
Id ImageAtomicF32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value,
Id (Sirit::Module::*atomic_func)(Id, Id, Id, Id, Id)) {
const auto& texture = ctx.images[handle & 0xFFFF];
const Id pointer{ctx.OpImageTexelPointer(ctx.image_f32, texture.id, coords, ctx.ConstU32(0U))};
const auto [scope, semantics]{AtomicArgs(ctx)};
return (ctx.*atomic_func)(ctx.F32[1], pointer, scope, semantics, value);
}
} // Anonymous namespace
Id EmitSharedAtomicIAdd32(EmitContext& ctx, Id offset, Id value) {
@ -187,6 +195,40 @@ Id EmitImageAtomicUMax32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords
return ImageAtomicU32(ctx, inst, handle, coords, value, &Sirit::Module::OpAtomicUMax);
}
Id EmitImageAtomicFMax32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value) {
if (ctx.profile.supports_image_fp32_atomic_min_max) {
return ImageAtomicF32(ctx, inst, handle, coords, value, &Sirit::Module::OpAtomicFMax);
}
const auto u32_value = ctx.OpBitcast(ctx.U32[1], value);
const auto sign_bit_set =
ctx.OpBitFieldUExtract(ctx.U32[1], u32_value, ctx.ConstU32(31u), ctx.ConstU32(1u));
const auto result = ctx.OpSelect(
ctx.F32[1], sign_bit_set,
EmitBitCastF32U32(ctx, EmitImageAtomicUMin32(ctx, inst, handle, coords, u32_value)),
EmitBitCastF32U32(ctx, EmitImageAtomicSMax32(ctx, inst, handle, coords, u32_value)));
return result;
}
Id EmitImageAtomicFMin32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value) {
if (ctx.profile.supports_image_fp32_atomic_min_max) {
return ImageAtomicF32(ctx, inst, handle, coords, value, &Sirit::Module::OpAtomicFMin);
}
const auto u32_value = ctx.OpBitcast(ctx.U32[1], value);
const auto sign_bit_set =
ctx.OpBitFieldUExtract(ctx.U32[1], u32_value, ctx.ConstU32(31u), ctx.ConstU32(1u));
const auto result = ctx.OpSelect(
ctx.F32[1], sign_bit_set,
EmitBitCastF32U32(ctx, EmitImageAtomicUMax32(ctx, inst, handle, coords, u32_value)),
EmitBitCastF32U32(ctx, EmitImageAtomicSMin32(ctx, inst, handle, coords, u32_value)));
return result;
}
Id EmitImageAtomicInc32(EmitContext&, IR::Inst*, u32, Id, Id) {
// TODO: This is not yet implemented
throw NotImplementedException("SPIR-V Instruction");

View File

@ -529,7 +529,7 @@ void EmitStoreBufferBoundsCheck(EmitContext& ctx, Id index, Id buffer_size, auto
// Bounds checking enabled, wrap in a conditional branch.
auto compare_index = index;
if (N > 1) {
index = ctx.OpIAdd(ctx.U32[1], index, ctx.ConstU32(N - 1));
compare_index = ctx.OpIAdd(ctx.U32[1], index, ctx.ConstU32(N - 1));
}
const Id in_bounds = ctx.OpULessThan(ctx.U1[1], compare_index, buffer_size);
const Id in_bounds_label = ctx.OpLabel();

View File

@ -482,6 +482,8 @@ Id EmitImageAtomicSMin32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords
Id EmitImageAtomicUMin32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value);
Id EmitImageAtomicSMax32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value);
Id EmitImageAtomicUMax32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value);
Id EmitImageAtomicFMax32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value);
Id EmitImageAtomicFMin32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value);
Id EmitImageAtomicInc32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value);
Id EmitImageAtomicDec32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value);
Id EmitImageAtomicAnd32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value);

View File

@ -869,6 +869,7 @@ void EmitContext::DefineImagesAndSamplers() {
}
if (std::ranges::any_of(info.images, &ImageResource::is_atomic)) {
image_u32 = TypePointer(spv::StorageClass::Image, U32[1]);
image_f32 = TypePointer(spv::StorageClass::Image, F32[1]);
}
if (info.samplers.empty()) {
return;

View File

@ -207,6 +207,7 @@ public:
Id invocation_id{};
Id subgroup_local_invocation_id{};
Id image_u32{};
Id image_f32{};
Id shared_memory_u8{};
Id shared_memory_u16{};

View File

@ -115,8 +115,12 @@ void Translator::EmitVectorMemory(const GcnInst& inst) {
return IMAGE_ATOMIC(AtomicOp::Smin, inst);
case Opcode::IMAGE_ATOMIC_UMIN:
return IMAGE_ATOMIC(AtomicOp::Umin, inst);
case Opcode::IMAGE_ATOMIC_FMIN:
return IMAGE_ATOMIC(AtomicOp::Fmin, inst);
case Opcode::IMAGE_ATOMIC_SMAX:
return IMAGE_ATOMIC(AtomicOp::Smax, inst);
case Opcode::IMAGE_ATOMIC_FMAX:
return IMAGE_ATOMIC(AtomicOp::Fmax, inst);
case Opcode::IMAGE_ATOMIC_UMAX:
return IMAGE_ATOMIC(AtomicOp::Umax, inst);
case Opcode::IMAGE_ATOMIC_AND:
@ -466,6 +470,10 @@ void Translator::IMAGE_ATOMIC(AtomicOp op, const GcnInst& inst) {
return ir.ImageAtomicIMax(handle, body, value, true, info);
case AtomicOp::Umax:
return ir.ImageAtomicUMax(handle, body, value, info);
case AtomicOp::Fmax:
return ir.ImageAtomicFMax(handle, body, value, info);
case AtomicOp::Fmin:
return ir.ImageAtomicFMin(handle, body, value, info);
case AtomicOp::And:
return ir.ImageAtomicAnd(handle, body, value, info);
case AtomicOp::Or:

View File

@ -196,6 +196,7 @@ struct Info {
bool has_discard{};
bool has_image_gather{};
bool has_image_query{};
bool uses_atomic_float_min_max{};
bool uses_lane_id{};
bool uses_group_quad{};
bool uses_group_ballot{};

View File

@ -1870,6 +1870,16 @@ Value IREmitter::ImageAtomicUMax(const Value& handle, const Value& coords, const
return Inst(Opcode::ImageAtomicUMax32, Flags{info}, handle, coords, value);
}
Value IREmitter::ImageAtomicFMax(const Value& handle, const Value& coords, const Value& value,
TextureInstInfo info) {
return Inst(Opcode::ImageAtomicFMax32, Flags{info}, handle, coords, value);
}
Value IREmitter::ImageAtomicFMin(const Value& handle, const Value& coords, const Value& value,
TextureInstInfo info) {
return Inst(Opcode::ImageAtomicFMin32, Flags{info}, handle, coords, value);
}
Value IREmitter::ImageAtomicIMax(const Value& handle, const Value& coords, const Value& value,
bool is_signed, TextureInstInfo info) {
return is_signed ? ImageAtomicSMax(handle, coords, value, info)

View File

@ -321,6 +321,10 @@ public:
const Value& value, TextureInstInfo info);
[[nodiscard]] Value ImageAtomicUMax(const Value& handle, const Value& coords,
const Value& value, TextureInstInfo info);
[[nodiscard]] Value ImageAtomicFMax(const Value& handle, const Value& coords,
const Value& value, TextureInstInfo info);
[[nodiscard]] Value ImageAtomicFMin(const Value& handle, const Value& coords,
const Value& value, TextureInstInfo info);
[[nodiscard]] Value ImageAtomicIMax(const Value& handle, const Value& coords,
const Value& value, bool is_signed, TextureInstInfo info);
[[nodiscard]] Value ImageAtomicInc(const Value& handle, const Value& coords, const Value& value,

View File

@ -420,6 +420,8 @@ OPCODE(ImageAtomicSMin32, U32, Opaq
OPCODE(ImageAtomicUMin32, U32, Opaque, Opaque, U32, )
OPCODE(ImageAtomicSMax32, U32, Opaque, Opaque, U32, )
OPCODE(ImageAtomicUMax32, U32, Opaque, Opaque, U32, )
OPCODE(ImageAtomicFMax32, F32, Opaque, Opaque, F32, )
OPCODE(ImageAtomicFMin32, F32, Opaque, Opaque, F32, )
OPCODE(ImageAtomicInc32, U32, Opaque, Opaque, U32, )
OPCODE(ImageAtomicDec32, U32, Opaque, Opaque, U32, )
OPCODE(ImageAtomicAnd32, U32, Opaque, Opaque, U32, )

View File

@ -71,6 +71,10 @@ void Visit(Info& info, const IR::Inst& inst) {
case IR::Opcode::ImageQueryLod:
info.has_image_query = true;
break;
case IR::Opcode::ImageAtomicFMax32:
case IR::Opcode::ImageAtomicFMin32:
info.uses_atomic_float_min_max = true;
break;
case IR::Opcode::LaneId:
info.uses_lane_id = true;
break;

View File

@ -29,6 +29,7 @@ struct Profile {
bool supports_native_cube_calc{};
bool supports_trinary_minmax{};
bool supports_robust_buffer_access{};
bool supports_image_fp32_atomic_min_max{};
bool has_broken_spirv_clamp{};
bool lower_left_origin_mode{};
bool needs_manual_interpolation{};

View File

@ -210,7 +210,8 @@ bool Instance::CreateDevice() {
vk::PhysicalDeviceRobustness2FeaturesEXT,
vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT,
vk::PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT,
vk::PhysicalDevicePortabilitySubsetFeaturesKHR>();
vk::PhysicalDevicePortabilitySubsetFeaturesKHR,
vk::PhysicalDeviceShaderAtomicFloat2FeaturesEXT>();
features = feature_chain.get().features;
const vk::StructureChain properties_chain = physical_device.getProperties2<
@ -272,6 +273,13 @@ bool Instance::CreateDevice() {
image_load_store_lod = add_extension(VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_EXTENSION_NAME);
amd_gcn_shader = add_extension(VK_AMD_GCN_SHADER_EXTENSION_NAME);
amd_shader_trinary_minmax = add_extension(VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME);
shader_atomic_float2 = add_extension(VK_EXT_SHADER_ATOMIC_FLOAT_2_EXTENSION_NAME);
if (shader_atomic_float2) {
shader_atomic_float2_features =
feature_chain.get<vk::PhysicalDeviceShaderAtomicFloat2FeaturesEXT>();
LOG_INFO(Render_Vulkan, "- shaderImageFloat32AtomicMinMax: {}",
shader_atomic_float2_features.shaderImageFloat32AtomicMinMax);
}
const bool calibrated_timestamps =
TRACY_GPU_ENABLED ? add_extension(VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME) : false;
@ -401,6 +409,10 @@ bool Instance::CreateDevice() {
vk::PhysicalDeviceLegacyVertexAttributesFeaturesEXT{
.legacyVertexAttributes = true,
},
vk::PhysicalDeviceShaderAtomicFloat2FeaturesEXT{
.shaderImageFloat32AtomicMinMax =
shader_atomic_float2_features.shaderImageFloat32AtomicMinMax,
},
#ifdef __APPLE__
portability_features,
#endif
@ -430,6 +442,9 @@ bool Instance::CreateDevice() {
if (!legacy_vertex_attributes) {
device_chain.unlink<vk::PhysicalDeviceLegacyVertexAttributesFeaturesEXT>();
}
if (!shader_atomic_float2) {
device_chain.unlink<vk::PhysicalDeviceShaderAtomicFloat2FeaturesEXT>();
}
auto [device_result, dev] = physical_device.createDeviceUnique(device_chain.get());
if (device_result != vk::Result::eSuccess) {

View File

@ -165,6 +165,12 @@ public:
return amd_shader_trinary_minmax;
}
/// Returns true when the shaderImageFloat32AtomicMinMax feature of
/// VK_EXT_shader_atomic_float2 is supported.
bool IsShaderAtomicFloatImage32MinMaxSupported() const {
return shader_atomic_float2 && shader_atomic_float2_features.shaderImageFloat32AtomicMinMax;
}
/// Returns true when geometry shaders are supported by the device
bool IsGeometryStageSupported() const {
return features.geometryShader;
@ -336,6 +342,7 @@ private:
vk::PhysicalDevicePortabilitySubsetFeaturesKHR portability_features;
vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT dynamic_state_3_features;
vk::PhysicalDeviceRobustness2FeaturesEXT robustness2_features;
vk::PhysicalDeviceShaderAtomicFloat2FeaturesEXT shader_atomic_float2_features;
vk::DriverIdKHR driver_id;
vk::UniqueDebugUtilsMessengerEXT debug_callback{};
std::string vendor_name;
@ -360,6 +367,7 @@ private:
bool image_load_store_lod{};
bool amd_gcn_shader{};
bool amd_shader_trinary_minmax{};
bool shader_atomic_float2{};
bool portability_subset{};
};

View File

@ -206,6 +206,7 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_,
.supports_native_cube_calc = instance_.IsAmdGcnShaderSupported(),
.supports_trinary_minmax = instance_.IsAmdShaderTrinaryMinMaxSupported(),
.supports_robust_buffer_access = instance_.IsRobustBufferAccess2Supported(),
.supports_image_fp32_atomic_min_max = instance_.IsShaderAtomicFloatImage32MinMaxSupported(),
.needs_manual_interpolation = instance.IsFragmentShaderBarycentricSupported() &&
instance.GetDriverID() == vk::DriverId::eNvidiaProprietary,
.needs_lds_barriers = instance.GetDriverID() == vk::DriverId::eNvidiaProprietary ||

View File

@ -696,14 +696,19 @@ void Rasterizer::BindTextures(const Shader::Info& stage, Shader::Backend::Bindin
void Rasterizer::BeginRendering(const GraphicsPipeline& pipeline, RenderState& state) {
int cb_index = 0;
for (auto& [image_id, desc] : cb_descs) {
for (auto attach_idx = 0u; attach_idx < state.num_color_attachments; ++attach_idx) {
if (state.color_attachments[attach_idx].imageView == VK_NULL_HANDLE) {
continue;
}
auto& [image_id, desc] = cb_descs[cb_index++];
if (auto& old_img = texture_cache.GetImage(image_id); old_img.binding.needs_rebind) {
auto& view = texture_cache.FindRenderTarget(desc);
ASSERT(view.image_id != image_id);
image_id = bound_images.emplace_back(view.image_id);
auto& image = texture_cache.GetImage(view.image_id);
state.color_attachments[cb_index].imageView = *view.image_view;
state.color_attachments[cb_index].imageLayout = image.last_state.layout;
state.color_attachments[attach_idx].imageView = *view.image_view;
state.color_attachments[attach_idx].imageLayout = image.last_state.layout;
const auto mip = view.info.range.base.level;
state.width = std::min<u32>(state.width, std::max(image.info.size.width >> mip, 1u));
@ -722,8 +727,7 @@ void Rasterizer::BeginRendering(const GraphicsPipeline& pipeline, RenderState& s
desc.view_info.range);
}
image.usage.render_target = 1u;
state.color_attachments[cb_index].imageLayout = image.last_state.layout;
++cb_index;
state.color_attachments[attach_idx].imageLayout = image.last_state.layout;
}
if (db_desc) {