mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-08 09:00:48 +02:00
There were some problems in both of these implementations. Fixes #744 Fixes #745
823 lines
23 KiB
C++
823 lines
23 KiB
C++
/*
|
|
$info$
|
|
tags: LinuxSyscalls|syscalls-x86-32
|
|
$end_info$
|
|
*/
|
|
|
|
#include "Tests/LinuxSyscalls/Syscalls.h"
|
|
#include "Tests/LinuxSyscalls/x32/Syscalls.h"
|
|
|
|
#include <FEXCore/Utils/LogManager.h>
|
|
|
|
#include <sys/ipc.h>
|
|
#include <sys/msg.h>
|
|
#include <sys/sem.h>
|
|
#include <sys/shm.h>
|
|
#include <sys/types.h>
|
|
|
|
namespace FEX::HLE::x32 {
|
|
// Define the IPC ops
|
|
enum IPCOp {
|
|
OP_SEMOP = 1,
|
|
OP_SEMGET = 2,
|
|
OP_SEMCTL = 3,
|
|
OP_SEMTIMEDOP = 4,
|
|
OP_MSGSND = 11,
|
|
OP_MSGRCV = 12,
|
|
OP_MSGGET = 13,
|
|
OP_MSGCTL = 14,
|
|
OP_SHMAT = 21,
|
|
OP_SHMDT = 22,
|
|
OP_SHMGET = 23,
|
|
OP_SHMCTL = 24,
|
|
};
|
|
|
|
struct msgbuf_32 {
|
|
compat_long_t mtype;
|
|
char mtext[1];
|
|
};
|
|
|
|
struct ipc_perm_32 {
|
|
uint32_t key;
|
|
uint16_t uid;
|
|
uint16_t gid;
|
|
uint16_t cuid;
|
|
uint16_t cgid;
|
|
uint16_t mode;
|
|
uint16_t seq;
|
|
|
|
ipc_perm_32() = delete;
|
|
|
|
operator struct ipc_perm() const {
|
|
struct ipc_perm perm;
|
|
perm.__key = key;
|
|
perm.uid = uid;
|
|
perm.gid = gid;
|
|
perm.cuid = cuid;
|
|
perm.cgid = cgid;
|
|
perm.mode = mode;
|
|
perm.__seq = seq;
|
|
return perm;
|
|
}
|
|
|
|
ipc_perm_32(struct ipc_perm perm) {
|
|
key = perm.__key;
|
|
uid = perm.uid;
|
|
gid = perm.gid;
|
|
cuid = perm.cuid;
|
|
cgid = perm.cgid;
|
|
mode = perm.mode;
|
|
seq = perm.__seq;
|
|
}
|
|
};
|
|
|
|
static_assert(std::is_trivial<ipc_perm_32>::value, "Needs to be trivial");
|
|
static_assert(sizeof(ipc_perm_32) == 16, "Incorrect size");
|
|
|
|
struct ipc_perm_64 {
|
|
uint32_t key;
|
|
uint32_t uid;
|
|
uint32_t gid;
|
|
uint32_t cuid;
|
|
uint32_t cgid;
|
|
uint16_t mode;
|
|
uint16_t _pad1;
|
|
uint16_t seq;
|
|
uint16_t _pad2;
|
|
compat_ulong_t _pad[2];
|
|
|
|
ipc_perm_64() = delete;
|
|
|
|
operator struct ipc_perm() const {
|
|
struct ipc_perm perm;
|
|
perm.__key = key;
|
|
perm.uid = uid;
|
|
perm.gid = gid;
|
|
perm.cuid = cuid;
|
|
perm.cgid = cgid;
|
|
perm.mode = mode;
|
|
perm.__seq = seq;
|
|
return perm;
|
|
}
|
|
|
|
ipc_perm_64(struct ipc_perm perm) {
|
|
key = perm.__key;
|
|
uid = perm.uid;
|
|
gid = perm.gid;
|
|
cuid = perm.cuid;
|
|
cgid = perm.cgid;
|
|
mode = perm.mode;
|
|
seq = perm.__seq;
|
|
}
|
|
};
|
|
|
|
static_assert(std::is_trivial<ipc_perm_64>::value, "Needs to be trivial");
|
|
static_assert(sizeof(ipc_perm_64) == 36, "Incorrect size");
|
|
|
|
struct shmid_ds_32 {
|
|
ipc_perm_32 shm_perm;
|
|
int32_t shm_segsz;
|
|
int32_t shm_atime;
|
|
int32_t shm_dtime;
|
|
int32_t shm_ctime;
|
|
uint16_t shm_cpid;
|
|
uint16_t shm_lpid;
|
|
uint16_t shm_nattch;
|
|
uint16_t shm_unused;
|
|
uint32_t shm_unused2;
|
|
uint32_t shm_unused3;
|
|
|
|
shmid_ds_32() = delete;
|
|
|
|
operator struct shmid_ds() const {
|
|
struct shmid_ds buf;
|
|
buf.shm_perm = shm_perm;
|
|
|
|
buf.shm_segsz = shm_segsz;
|
|
buf.shm_atime = shm_atime;
|
|
buf.shm_dtime = shm_dtime;
|
|
buf.shm_ctime = shm_ctime;
|
|
buf.shm_cpid = shm_cpid;
|
|
buf.shm_lpid = shm_lpid;
|
|
buf.shm_nattch = shm_nattch;
|
|
return buf;
|
|
}
|
|
|
|
shmid_ds_32(struct shmid_ds buf)
|
|
: shm_perm {buf.shm_perm} {
|
|
shm_segsz = buf.shm_segsz;
|
|
shm_atime = buf.shm_atime;
|
|
shm_dtime = buf.shm_dtime;
|
|
shm_ctime = buf.shm_ctime;
|
|
shm_cpid = buf.shm_cpid;
|
|
shm_lpid = buf.shm_lpid;
|
|
shm_nattch = buf.shm_nattch;
|
|
}
|
|
};
|
|
|
|
static_assert(std::is_trivial<shmid_ds_32>::value, "Needs to be trivial");
|
|
static_assert(sizeof(shmid_ds_32) == 48, "Incorrect size");
|
|
|
|
struct shmid_ds_64 {
|
|
ipc_perm_64 shm_perm;
|
|
compat_size_t shm_segsz;
|
|
compat_ulong_t shm_atime;
|
|
compat_ulong_t shm_atime_high;
|
|
compat_ulong_t shm_dtime;
|
|
compat_ulong_t shm_dtime_high;
|
|
compat_ulong_t shm_ctime;
|
|
compat_ulong_t shm_ctime_high;
|
|
int32_t shm_cpid;
|
|
int32_t shm_lpid;
|
|
compat_ulong_t shm_nattch;
|
|
compat_ulong_t shm_unused4;
|
|
compat_ulong_t shm_unused5;
|
|
|
|
shmid_ds_64() = delete;
|
|
|
|
operator struct shmid_ds() const {
|
|
struct shmid_ds buf;
|
|
buf.shm_perm = shm_perm;
|
|
|
|
buf.shm_segsz = shm_segsz;
|
|
buf.shm_atime = shm_atime_high;
|
|
buf.shm_atime <<= 32;
|
|
buf.shm_atime |= shm_atime;
|
|
|
|
buf.shm_dtime = shm_dtime_high;
|
|
buf.shm_dtime <<= 32;
|
|
buf.shm_dtime |= shm_dtime;
|
|
|
|
buf.shm_ctime = shm_ctime_high;
|
|
buf.shm_ctime <<= 32;
|
|
buf.shm_ctime |= shm_ctime;
|
|
|
|
buf.shm_cpid = shm_cpid;
|
|
buf.shm_lpid = shm_lpid;
|
|
buf.shm_nattch = shm_nattch;
|
|
return buf;
|
|
}
|
|
|
|
shmid_ds_64(struct shmid_ds buf)
|
|
: shm_perm {buf.shm_perm} {
|
|
shm_segsz = buf.shm_segsz;
|
|
shm_atime = buf.shm_atime;
|
|
shm_atime_high = buf.shm_atime >> 32;
|
|
shm_dtime = buf.shm_dtime;
|
|
shm_dtime_high = buf.shm_dtime >> 32;
|
|
shm_ctime = buf.shm_ctime;
|
|
shm_ctime_high = buf.shm_ctime >> 32;
|
|
shm_cpid = buf.shm_cpid;
|
|
shm_lpid = buf.shm_lpid;
|
|
shm_nattch = buf.shm_nattch;
|
|
}
|
|
};
|
|
|
|
static_assert(std::is_trivial<shmid_ds_64>::value, "Needs to be trivial");
|
|
static_assert(sizeof(shmid_ds_64) == 84, "Incorrect size");
|
|
|
|
struct semid_ds_32 {
|
|
struct ipc_perm_32 sem_perm;
|
|
int32_t sem_otime;
|
|
int32_t sem_ctime;
|
|
uint32_t sem_base;
|
|
uint32_t sem_pending;
|
|
uint32_t sem_pending_last;
|
|
uint32_t undo;
|
|
uint16_t sem_nsems;
|
|
uint16_t _pad;
|
|
|
|
semid_ds_32() = delete;
|
|
|
|
operator struct semid_ds() const {
|
|
struct semid_ds buf{};
|
|
buf.sem_perm = sem_perm;
|
|
|
|
buf.sem_otime = sem_otime;
|
|
buf.sem_ctime = sem_ctime;
|
|
buf.sem_nsems = sem_nsems;
|
|
|
|
// sem_base, sem_pending, sem_pending_last, undo doesn't exist in the definition
|
|
// Kernel doesn't return anything in them
|
|
return buf;
|
|
}
|
|
|
|
semid_ds_32(struct semid_ds buf)
|
|
: sem_perm {buf.sem_perm} {
|
|
sem_otime = buf.sem_otime;
|
|
sem_ctime = buf.sem_ctime;
|
|
sem_nsems = buf.sem_nsems;
|
|
}
|
|
};
|
|
|
|
static_assert(std::is_trivial<semid_ds_32>::value, "Needs to be trivial");
|
|
static_assert(sizeof(semid_ds_32) == 44, "Incorrect size");
|
|
|
|
struct semid_ds_64 {
|
|
struct ipc_perm_64 sem_perm;
|
|
uint32_t sem_otime;
|
|
uint32_t sem_otime_high;
|
|
uint32_t sem_ctime;
|
|
uint32_t sem_ctime_high;
|
|
uint32_t sem_nsems;
|
|
uint32_t _pad[2];
|
|
|
|
semid_ds_64() = delete;
|
|
|
|
operator struct semid_ds() const {
|
|
struct semid_ds buf{};
|
|
buf.sem_perm = sem_perm;
|
|
|
|
buf.sem_otime = sem_otime_high;
|
|
buf.sem_otime <<= 32;
|
|
buf.sem_otime |= sem_otime;
|
|
buf.sem_ctime = sem_ctime_high;
|
|
buf.sem_ctime <<= 32;
|
|
buf.sem_ctime |= sem_ctime;
|
|
buf.sem_nsems = sem_nsems;
|
|
|
|
// sem_base, sem_pending, sem_pending_last, undo doesn't exist in the definition
|
|
// Kernel doesn't return anything in them
|
|
return buf;
|
|
}
|
|
|
|
semid_ds_64(struct semid_ds buf)
|
|
: sem_perm {buf.sem_perm} {
|
|
sem_otime = buf.sem_otime;
|
|
sem_otime_high = buf.sem_otime >> 32;
|
|
sem_ctime = buf.sem_ctime;
|
|
sem_ctime_high = buf.sem_ctime >> 32;
|
|
sem_nsems = buf.sem_nsems;
|
|
}
|
|
};
|
|
|
|
static_assert(std::is_trivial<semid_ds_64>::value, "Needs to be trivial");
|
|
static_assert(sizeof(semid_ds_64) == 64, "Incorrect size");
|
|
|
|
struct msqid_ds_32 {
|
|
struct ipc_perm_32 msg_perm;
|
|
compat_uptr_t msg_first;
|
|
compat_uptr_t msg_last;
|
|
uint32_t msg_stime;
|
|
uint32_t msg_rtime;
|
|
uint32_t msg_ctime;
|
|
uint32_t msg_lcbytes;
|
|
uint32_t msg_lqbytes;
|
|
uint16_t msg_cbytes;
|
|
uint16_t msg_qnum;
|
|
uint16_t msg_qbytes;
|
|
uint16_t msg_lspid;
|
|
uint16_t msg_lrpid;
|
|
|
|
msqid_ds_32() = delete;
|
|
msqid_ds_32(struct msqid_ds buf)
|
|
: msg_perm {buf.msg_perm} {
|
|
// msg_first and msg_last are unused and untouched
|
|
msg_stime = buf.msg_stime;
|
|
msg_rtime = buf.msg_rtime;
|
|
msg_ctime = buf.msg_ctime;
|
|
if (buf.msg_cbytes > std::numeric_limits<uint16_t>::max()) {
|
|
msg_cbytes = std::numeric_limits<uint16_t>::max();
|
|
}
|
|
else {
|
|
msg_cbytes = buf.msg_cbytes;
|
|
}
|
|
msg_lcbytes = buf.msg_cbytes;
|
|
|
|
if (buf.msg_qnum > std::numeric_limits<uint16_t>::max()) {
|
|
msg_qnum = std::numeric_limits<uint16_t>::max();
|
|
}
|
|
else {
|
|
msg_qnum = buf.msg_qnum;
|
|
}
|
|
|
|
if (buf.msg_cbytes > std::numeric_limits<uint16_t>::max()) {
|
|
msg_cbytes = std::numeric_limits<uint16_t>::max();
|
|
}
|
|
else {
|
|
msg_cbytes = buf.msg_cbytes;
|
|
}
|
|
msg_lqbytes = buf.msg_qbytes;
|
|
msg_lspid = buf.msg_lspid;
|
|
msg_lrpid = buf.msg_lrpid;
|
|
}
|
|
};
|
|
static_assert(std::is_trivial<msqid_ds_32>::value, "Needs to be trivial");
|
|
static_assert(sizeof(msqid_ds_32) == 56, "Incorrect size");
|
|
|
|
struct msqid_ds_64 {
|
|
struct ipc_perm_64 msg_perm;
|
|
uint32_t msg_stime;
|
|
uint32_t msg_stime_high;
|
|
uint32_t msg_rtime;
|
|
uint32_t msg_rtime_high;
|
|
uint32_t msg_ctime;
|
|
uint32_t msg_ctime_high;
|
|
uint32_t msg_cbytes;
|
|
uint32_t msg_qnum;
|
|
uint32_t msg_qbytes;
|
|
uint32_t msg_lspid;
|
|
uint32_t msg_lrpid;
|
|
uint32_t _pad[2];
|
|
|
|
msqid_ds_64() = delete;
|
|
msqid_ds_64(struct msqid_ds buf)
|
|
: msg_perm {buf.msg_perm} {
|
|
msg_stime = buf.msg_stime;
|
|
msg_stime_high = buf.msg_stime >> 32;
|
|
msg_rtime = buf.msg_rtime;
|
|
msg_rtime_high = buf.msg_rtime >> 32;
|
|
msg_ctime = buf.msg_ctime;
|
|
msg_ctime_high = buf.msg_ctime >> 32;
|
|
msg_cbytes = buf.msg_cbytes;
|
|
msg_qnum = buf.msg_qnum;
|
|
msg_qbytes = buf.msg_qbytes;
|
|
msg_lspid = buf.msg_lspid;
|
|
msg_lrpid = buf.msg_lrpid;
|
|
}
|
|
};
|
|
|
|
static_assert(std::is_trivial<msqid_ds_64>::value, "Needs to be trivial");
|
|
static_assert(sizeof(msqid_ds_64) == 88, "Incorrect size");
|
|
|
|
struct shminfo_32 {
|
|
uint32_t shmmax;
|
|
uint32_t shmmin;
|
|
uint32_t shmmni;
|
|
uint32_t shmseg;
|
|
uint32_t shmall;
|
|
|
|
shminfo_32() = delete;
|
|
|
|
operator struct shminfo() const {
|
|
struct shminfo si;
|
|
si.shmmax = shmmax;
|
|
si.shmmin = shmmin;
|
|
si.shmmni = shmmni;
|
|
si.shmseg = shmseg;
|
|
si.shmall = shmall;
|
|
return si;
|
|
}
|
|
|
|
shminfo_32(struct shminfo si) {
|
|
shmmax = si.shmmax;
|
|
shmmin = si.shmmin;
|
|
shmmni = si.shmmni;
|
|
shmseg = si.shmseg;
|
|
shmall = si.shmall;
|
|
}
|
|
};
|
|
|
|
static_assert(std::is_trivial<shminfo_32>::value, "Needs to be trivial");
|
|
static_assert(sizeof(shminfo_32) == 20, "Incorrect size");
|
|
|
|
struct shminfo_64 {
|
|
compat_ulong_t shmmax;
|
|
compat_ulong_t shmmin;
|
|
compat_ulong_t shmmni;
|
|
compat_ulong_t shmseg;
|
|
compat_ulong_t shmall;
|
|
compat_ulong_t __unused[4];
|
|
|
|
shminfo_64() = delete;
|
|
|
|
operator struct shminfo() const {
|
|
struct shminfo si;
|
|
si.shmmax = shmmax;
|
|
si.shmmin = shmmin;
|
|
si.shmmni = shmmni;
|
|
si.shmseg = shmseg;
|
|
si.shmall = shmall;
|
|
return si;
|
|
}
|
|
|
|
shminfo_64(struct shminfo si) {
|
|
shmmax = si.shmmax;
|
|
shmmin = si.shmmin;
|
|
shmmni = si.shmmni;
|
|
shmseg = si.shmseg;
|
|
shmall = si.shmall;
|
|
}
|
|
};
|
|
|
|
static_assert(std::is_trivial<shminfo_64>::value, "Needs to be trivial");
|
|
static_assert(sizeof(shminfo_64) == 36, "Incorrect size");
|
|
|
|
struct shm_info_32 {
|
|
int used_ids;
|
|
uint32_t shm_tot;
|
|
uint32_t shm_rss;
|
|
uint32_t shm_swp;
|
|
uint32_t swap_attempts;
|
|
uint32_t swap_successes;
|
|
|
|
shm_info_32() = delete;
|
|
|
|
shm_info_32(struct shm_info si) {
|
|
used_ids = si.used_ids;
|
|
shm_tot = si.shm_tot;
|
|
shm_rss = si.shm_rss;
|
|
shm_swp = si.shm_swp;
|
|
swap_attempts = si.swap_attempts;
|
|
swap_successes = si.swap_successes;
|
|
}
|
|
};
|
|
|
|
static_assert(std::is_trivial<shm_info_32>::value, "Needs to be trivial");
|
|
static_assert(sizeof(shm_info_32) == 24, "Incorrect size");
|
|
|
|
struct shm_info_64 {
|
|
int used_ids;
|
|
uint32_t _pad;
|
|
uint64_t shm_tot;
|
|
uint64_t shm_rss;
|
|
uint64_t shm_swp;
|
|
uint64_t swap_attempts;
|
|
uint64_t swap_successes;
|
|
|
|
shm_info_64() = delete;
|
|
|
|
shm_info_64(struct shm_info si) {
|
|
used_ids = si.used_ids;
|
|
shm_tot = si.shm_tot;
|
|
shm_rss = si.shm_rss;
|
|
shm_swp = si.shm_swp;
|
|
swap_attempts = si.swap_attempts;
|
|
swap_successes = si.swap_successes;
|
|
}
|
|
};
|
|
|
|
static_assert(std::is_trivial<shm_info_64>::value, "Needs to be trivial");
|
|
static_assert(sizeof(shm_info_64) == 48, "Incorrect size");
|
|
|
|
union semun_32 {
|
|
int32_t val; // Value for SETVAL
|
|
compat_ptr<semid_ds_32> buf32; // struct semid_ds* - Buffer ptr for IPC_STAT, IPC_SET
|
|
compat_ptr<semid_ds_64> buf64; // struct semid_ds* - Buffer ptr for IPC_STAT, IPC_SET
|
|
uint32_t array; // uint16_t array for GETALL, SETALL
|
|
compat_ptr<struct seminfo> __buf; // struct seminfo * - Buffer for IPC_INFO
|
|
};
|
|
|
|
union msgun_32 {
|
|
int32_t val; // Value for SETVAL
|
|
compat_ptr<msqid_ds_32> buf32; // struct msgid_ds* - Buffer ptr for IPC_STAT, IPC_SET
|
|
compat_ptr<msqid_ds_64> buf64; // struct msgid_ds* - Buffer ptr for IPC_STAT, IPC_SET
|
|
uint32_t array; // uint16_t array for GETALL, SETALL
|
|
compat_ptr<struct msginfo> __buf; // struct msginfo * - Buffer for IPC_INFO
|
|
};
|
|
|
|
union shmun_32 {
|
|
int32_t val; // Value for SETVAL
|
|
compat_ptr<shmid_ds_32> buf32; // struct shmid_ds* - Buffer ptr for IPC_STAT, IPC_SET
|
|
compat_ptr<shmid_ds_64> buf64; // struct shmid_ds* - Buffer ptr for IPC_STAT, IPC_SET
|
|
uint32_t array; // uint16_t array for GETALL, SETALL
|
|
compat_ptr<struct shminfo_32> __buf32; // struct shminfo * - Buffer for IPC_INFO
|
|
compat_ptr<struct shminfo_64> __buf64; // struct shminfo * - Buffer for IPC_INFO
|
|
|
|
compat_ptr<struct shm_info_32> __buf_info_32; // struct shm_info * - Buffer for SHM_INFO
|
|
compat_ptr<struct shm_info_64> __buf_info_64; // struct shm_info * - Buffer for SHM_INFO
|
|
};
|
|
|
|
union semun {
|
|
int val; /* value for SETVAL */
|
|
struct semid_ds_32 *buf; /* buffer for IPC_STAT & IPC_SET */
|
|
unsigned short *array; /* array for GETALL & SETALL */
|
|
struct seminfo *__buf; /* buffer for IPC_INFO */
|
|
void *__pad;
|
|
};
|
|
|
|
uint64_t _ipc(FEXCore::Core::CpuStateFrame *Frame, uint32_t call, uint32_t first, uint32_t second, uint32_t third, uint32_t ptr, uint32_t fifth) {
|
|
uint64_t Result{};
|
|
|
|
switch (static_cast<IPCOp>(call)) {
|
|
case OP_SEMOP: {
|
|
Result = ::semop(first, reinterpret_cast<struct sembuf*>(ptr), second);
|
|
break;
|
|
}
|
|
case OP_SEMGET: {
|
|
Result = ::semget(first, second, third);
|
|
break;
|
|
}
|
|
case OP_SEMCTL: {
|
|
uint32_t semid = first;
|
|
uint32_t semnum = second;
|
|
// Upper 16bits used for a different flag?
|
|
int32_t cmd = third & 0xFF;
|
|
compat_ptr<semun_32> semun(ptr);
|
|
bool IPC64 = third & 0x100;
|
|
#define UNHANDLED(x) case x: LOGMAN_MSG_A("Unhandled semctl cmd: " #x); break
|
|
switch (cmd) {
|
|
case IPC_SET: {
|
|
struct semid_ds buf{};
|
|
if (IPC64) {
|
|
buf = *semun->buf64;
|
|
}
|
|
else {
|
|
buf = *semun->buf32;
|
|
}
|
|
Result = ::semctl(semid, semnum, cmd, &buf);
|
|
if (Result != -1) {
|
|
if (IPC64) {
|
|
*semun->buf64 = buf;
|
|
}
|
|
else {
|
|
*semun->buf32 = buf;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SEM_STAT:
|
|
case SEM_STAT_ANY:
|
|
case IPC_STAT: {
|
|
struct semid_ds buf{};
|
|
Result = ::semctl(semid, semnum, cmd, &buf);
|
|
if (Result != -1) {
|
|
if (IPC64) {
|
|
*semun->buf64 = buf;
|
|
}
|
|
else {
|
|
*semun->buf32 = buf;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SEM_INFO:
|
|
case IPC_INFO: {
|
|
struct seminfo si{};
|
|
Result = ::semctl(semid, semnum, cmd, &si);
|
|
if (Result != -1) {
|
|
memcpy(semun->__buf, &si, sizeof(si));
|
|
}
|
|
break;
|
|
}
|
|
case GETALL:
|
|
case SETALL: {
|
|
// ptr is just a int32_t* in this case
|
|
Result = ::semctl(semid, semnum, cmd, semun->array);
|
|
break;
|
|
}
|
|
case SETVAL: {
|
|
// ptr is just a int32_t in this case
|
|
Result = ::semctl(semid, semnum, cmd, semun->val);
|
|
break;
|
|
}
|
|
case IPC_RMID:
|
|
case GETPID:
|
|
case GETNCNT:
|
|
case GETZCNT:
|
|
case GETVAL:
|
|
Result = ::semctl(semid, semnum, cmd);
|
|
break;
|
|
default: LOGMAN_MSG_A("Unhandled semctl cmd: %d", cmd); return -EINVAL; break;
|
|
}
|
|
#undef UNHANDLED
|
|
break;
|
|
}
|
|
case OP_SEMTIMEDOP: {
|
|
timespec32 *timeout = reinterpret_cast<timespec32*>(fifth);
|
|
struct timespec tp64{};
|
|
struct timespec *timed_ptr{};
|
|
if (timeout) {
|
|
tp64 = *timeout;
|
|
timed_ptr = &tp64;
|
|
}
|
|
|
|
Result = ::semtimedop(first, reinterpret_cast<struct sembuf*>(ptr), second, timed_ptr);
|
|
break;
|
|
}
|
|
case OP_MSGSND: {
|
|
// Requires a temporary buffer
|
|
std::vector<uint8_t> Tmp(second + sizeof(size_t));
|
|
struct msgbuf *TmpMsg = reinterpret_cast<struct msgbuf *>(&Tmp.at(0));
|
|
msgbuf_32 *src = reinterpret_cast<msgbuf_32*>(ptr);
|
|
TmpMsg->mtype = src->mtype;
|
|
memcpy(TmpMsg->mtext, src->mtext, second);
|
|
|
|
Result = ::msgsnd(first, TmpMsg, second, third);
|
|
break;
|
|
}
|
|
case OP_MSGRCV: {
|
|
std::vector<uint8_t> Tmp(second + sizeof(size_t));
|
|
struct msgbuf *TmpMsg = reinterpret_cast<struct msgbuf *>(&Tmp.at(0));
|
|
|
|
if (call >> 16) {
|
|
Result = ::msgrcv(first, TmpMsg, second, fifth, third);
|
|
if (Result != -1) {
|
|
msgbuf_32 *src = reinterpret_cast<msgbuf_32*>(ptr);
|
|
src->mtype = TmpMsg->mtype;
|
|
memcpy(src->mtext, TmpMsg->mtext, Result);
|
|
}
|
|
|
|
}
|
|
else {
|
|
struct compat_ipc_kludge {
|
|
compat_uptr_t msgp;
|
|
compat_long_t msgtyp;
|
|
};
|
|
compat_ipc_kludge *ipck = reinterpret_cast<compat_ipc_kludge*>(ptr);
|
|
Result = ::msgrcv(first, TmpMsg, second, ipck->msgtyp, third);
|
|
if (Result != -1) {
|
|
msgbuf_32 *src = reinterpret_cast<msgbuf_32*>(ipck->msgp);
|
|
ipck->msgtyp = TmpMsg->mtype;
|
|
memcpy(src->mtext, TmpMsg->mtext, Result);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case OP_MSGGET: {
|
|
Result = ::msgget(first, second);
|
|
break;
|
|
}
|
|
case OP_MSGCTL: {
|
|
uint32_t msqid = first;
|
|
int32_t cmd = second & 0xFF;
|
|
msgun_32 msgun{};
|
|
msgun.val = ptr;
|
|
bool IPC64 = second & 0x100;
|
|
#define UNHANDLED(x) case x: LOGMAN_MSG_A("Unhandled msgctl cmd: " #x); break
|
|
switch (cmd) {
|
|
UNHANDLED(IPC_SET);
|
|
case MSG_STAT:
|
|
case MSG_STAT_ANY:
|
|
case IPC_STAT: {
|
|
struct msqid_ds buf{};
|
|
Result = ::msgctl(msqid, cmd, &buf);
|
|
if (Result != -1) {
|
|
if (IPC64) {
|
|
*msgun.buf64 = buf;
|
|
}
|
|
else {
|
|
*msgun.buf32 = buf;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case MSG_INFO:
|
|
case IPC_INFO: {
|
|
struct msginfo mi{};
|
|
Result = ::msgctl(msqid, cmd, reinterpret_cast<struct msqid_ds*>(&mi));
|
|
if (Result != -1) {
|
|
memcpy(msgun.__buf, &mi, sizeof(mi));
|
|
}
|
|
break;
|
|
}
|
|
case IPC_RMID:
|
|
Result = ::msgctl(msqid, cmd, nullptr);
|
|
break;
|
|
default: LOGMAN_MSG_A("Unhandled msgctl cmd: %d", cmd); return -EINVAL; break;
|
|
}
|
|
#undef UNHANDLED
|
|
break;
|
|
}
|
|
case OP_SHMAT: {
|
|
Result = static_cast<FEX::HLE::x32::x32SyscallHandler*>(FEX::HLE::_SyscallHandler)->GetAllocator()->
|
|
shmat(first, reinterpret_cast<const void*>(ptr), second, reinterpret_cast<uint32_t*>(third));
|
|
break;
|
|
}
|
|
case OP_SHMDT: {
|
|
Result = static_cast<FEX::HLE::x32::x32SyscallHandler*>(FEX::HLE::_SyscallHandler)->GetAllocator()->
|
|
shmdt(reinterpret_cast<void*>(ptr));
|
|
break;
|
|
}
|
|
case OP_SHMGET: {
|
|
Result = ::shmget(first, second, third);
|
|
break;
|
|
}
|
|
case OP_SHMCTL: {
|
|
int32_t shmid = first;
|
|
int32_t shmcmd = second;
|
|
int32_t cmd = shmcmd & 0xFF;
|
|
bool IPC64 = shmcmd & 0x100;
|
|
shmun_32 *shmun = reinterpret_cast<shmun_32*>(ptr);
|
|
|
|
switch (cmd) {
|
|
case IPC_SET: {
|
|
struct shmid_ds buf{};
|
|
if (IPC64) {
|
|
buf = *shmun->buf64;
|
|
}
|
|
else {
|
|
buf = *shmun->buf32;
|
|
}
|
|
Result = ::shmctl(shmid, cmd, &buf);
|
|
if (Result != -1) {
|
|
if (IPC64) {
|
|
*shmun->buf64 = buf;
|
|
}
|
|
else {
|
|
*shmun->buf32 = buf;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SHM_STAT:
|
|
case SHM_STAT_ANY:
|
|
case IPC_STAT: {
|
|
struct shmid_ds buf{};
|
|
Result = ::shmctl(shmid, cmd, &buf);
|
|
if (Result != -1) {
|
|
if (IPC64) {
|
|
buf = *shmun->buf64;
|
|
}
|
|
else {
|
|
buf = *shmun->buf32;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case IPC_INFO: {
|
|
struct shminfo si{};
|
|
Result = ::shmctl(shmid, cmd, reinterpret_cast<struct shmid_ds*>(&si));
|
|
if (Result != -1) {
|
|
if (IPC64) {
|
|
*shmun->__buf64 = si;
|
|
}
|
|
else {
|
|
*shmun->__buf32 = si;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SHM_INFO: {
|
|
struct shm_info si{};
|
|
Result = ::shmctl(shmid, cmd, reinterpret_cast<struct shmid_ds*>(&si));
|
|
if (Result != -1) {
|
|
if (IPC64) {
|
|
*shmun->__buf_info_64 = si;
|
|
}
|
|
else {
|
|
*shmun->__buf_info_32 = si;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case SHM_LOCK:
|
|
Result = ::shmctl(shmid, cmd, nullptr);
|
|
break;
|
|
case SHM_UNLOCK:
|
|
Result = ::shmctl(shmid, cmd, nullptr);
|
|
break;
|
|
case IPC_RMID:
|
|
Result = ::shmctl(shmid, cmd, nullptr);
|
|
break;
|
|
|
|
default: LOGMAN_MSG_A("Unhandled shmctl cmd: %d", cmd); return -EINVAL; break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default: return -ENOSYS;
|
|
}
|
|
SYSCALL_ERRNO();
|
|
}
|
|
void RegisterSemaphore() {
|
|
REGISTER_SYSCALL_IMPL_X32(ipc, _ipc);
|
|
|
|
REGISTER_SYSCALL_IMPL_X32(semtimedop_time64, [](FEXCore::Core::CpuStateFrame *Frame, int semid, struct sembuf *sops, size_t nsops, const struct timespec *timeout) -> uint64_t {
|
|
uint64_t Result = ::semtimedop(semid, sops, nsops, timeout);
|
|
SYSCALL_ERRNO();
|
|
});
|
|
}
|
|
}
|