diff --git a/Source/Tests/LinuxSyscalls/Syscalls/Msg.cpp b/Source/Tests/LinuxSyscalls/Syscalls/Msg.cpp index 40c0e55d48..1085670d41 100644 --- a/Source/Tests/LinuxSyscalls/Syscalls/Msg.cpp +++ b/Source/Tests/LinuxSyscalls/Syscalls/Msg.cpp @@ -32,8 +32,11 @@ namespace FEX::HLE { SYSCALL_ERRNO(); }); - // XXX: msqid_ds is definitely not correct for 32-bit REGISTER_SYSCALL_IMPL_PASS(msgctl, [](FEXCore::Core::CpuStateFrame *Frame, int msqid, int cmd, struct msqid_ds *buf) -> uint64_t { + // A quirk of this syscall + // On 32-bit this syscall ONLY supports IPC_64 msqid_ds encoding + // If an application want to use the old style encoding then it needs to use the ipc syscall with MSGCTL command + // ipc syscall supports both IPC_64 and old encoding uint64_t Result = ::msgctl(msqid, cmd, buf); SYSCALL_ERRNO(); }); diff --git a/Source/Tests/LinuxSyscalls/x32/Semaphore.cpp b/Source/Tests/LinuxSyscalls/x32/Semaphore.cpp index b5a621ccbd..4dc3afe244 100644 --- a/Source/Tests/LinuxSyscalls/x32/Semaphore.cpp +++ b/Source/Tests/LinuxSyscalls/x32/Semaphore.cpp @@ -105,7 +105,6 @@ namespace FEX::HLE::x32 { int32_t cmd = third & 0xFF; compat_ptr semun(ptr); bool IPC64 = third & 0x100; -#define UNHANDLED(x) case x: LOGMAN_MSG_A_FMT("Unhandled semctl cmd: " #x); break switch (cmd) { case IPC_SET: { struct semid_ds buf{}; @@ -172,7 +171,6 @@ namespace FEX::HLE::x32 { LOGMAN_MSG_A_FMT("Unhandled semctl cmd: {}", cmd); return -EINVAL; } -#undef UNHANDLED break; } case OP_SEMTIMEDOP: { @@ -237,9 +235,18 @@ namespace FEX::HLE::x32 { msgun_32 msgun{}; msgun.val = ptr; bool IPC64 = second & 0x100; -#define UNHANDLED(x) case x: LOGMAN_MSG_A_FMT("Unhandled msgctl cmd: " #x); break switch (cmd) { - UNHANDLED(IPC_SET); + case IPC_SET: { + struct msqid_ds buf{}; + if (IPC64) { + buf = *msgun.buf64; + } + else { + buf = *msgun.buf32; + } + Result = ::msgctl(msqid, cmd, &buf); + break; + } case MSG_STAT: case MSG_STAT_ANY: case IPC_STAT: { @@ -271,7 +278,6 @@ namespace FEX::HLE::x32 { LOGMAN_MSG_A_FMT("Unhandled msgctl cmd: {}", cmd); return -EINVAL; } -#undef UNHANDLED break; } case OP_SHMAT: { diff --git a/Source/Tests/LinuxSyscalls/x32/Types.h b/Source/Tests/LinuxSyscalls/x32/Types.h index 1722e0d0a5..f41ad7e3bc 100644 --- a/Source/Tests/LinuxSyscalls/x32/Types.h +++ b/Source/Tests/LinuxSyscalls/x32/Types.h @@ -1557,6 +1557,22 @@ struct msqid_ds_32 { uint16_t msg_lrpid; msqid_ds_32() = delete; + operator struct msqid_ds() const { + struct msqid_ds val{}; + // msg_first and msg_last are unused and untouched + val.msg_perm = msg_perm; + val.msg_stime = msg_stime; + val.msg_rtime = msg_rtime; + val.msg_ctime = msg_ctime; + + val.msg_cbytes = msg_cbytes; + val.msg_qnum = msg_qnum; + val.msg_qbytes = msg_qbytes; + val.msg_lspid = msg_lspid; + val.msg_lrpid = msg_lrpid; + return val; + } + msqid_ds_32(struct msqid_ds buf) : msg_perm {buf.msg_perm} { // msg_first and msg_last are unused and untouched @@ -1608,6 +1624,29 @@ struct msqid_ds_64 { uint32_t _pad[2]; msqid_ds_64() = delete; + operator struct msqid_ds() const { + struct msqid_ds val{}; + val.msg_perm = msg_perm; + val.msg_stime = msg_stime_high; + val.msg_stime <<= 32; + val.msg_stime |= msg_stime; + + val.msg_rtime = msg_rtime_high; + val.msg_rtime <<= 32; + val.msg_rtime |= msg_rtime; + + val.msg_ctime = msg_ctime_high; + val.msg_ctime <<= 32; + val.msg_ctime |= msg_ctime; + + val.msg_cbytes = msg_cbytes; + val.msg_qnum = msg_qnum; + val.msg_qbytes = msg_qbytes; + val.msg_lspid = msg_lspid; + val.msg_lrpid = msg_lrpid; + return val; + } + msqid_ds_64(struct msqid_ds buf) : msg_perm {buf.msg_perm} { msg_stime = buf.msg_stime;