mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-12-11 07:34:08 +00:00
286 lines
7.5 KiB
C++
286 lines
7.5 KiB
C++
// Copyright (c) 2012- PPSSPP Project.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official git repository and contact information can be found at
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
#include "HLE.h"
|
|
#include "sceKernel.h"
|
|
#include "sceKernelMsgPipe.h"
|
|
#include "sceKernelThread.h"
|
|
|
|
struct NativeMsgPipe
|
|
{
|
|
SceSize size;
|
|
char name[32];
|
|
SceUInt attr;
|
|
int bufSize;
|
|
int freeSize;
|
|
int numSendWaitThreads;
|
|
int numReceiveWaitThreads;
|
|
};
|
|
|
|
struct MsgPipe : public KernelObject
|
|
{
|
|
const char *GetName() {return nmp.name;}
|
|
const char *GetTypeName() {return "MsgPipe";}
|
|
static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_MPPID; }
|
|
int GetIDType() const { return SCE_KERNEL_TMID_Mpipe; }
|
|
|
|
NativeMsgPipe nmp;
|
|
|
|
std::vector<SceUID> sendWaitingThreads;
|
|
std::vector<SceUID> receiveWaitingThreads;
|
|
|
|
// Ring buffer
|
|
u8 *buffer;
|
|
int writePos;
|
|
int readPos;
|
|
};
|
|
|
|
void sceKernelCreateMsgPipe()
|
|
{
|
|
const char *name = Memory::GetCharPointer(PARAM(0));
|
|
int memoryPartition = PARAM(1);
|
|
SceUInt attr = PARAM(2);
|
|
int size = PARAM(3);
|
|
int opt = PARAM(4);
|
|
|
|
MsgPipe *m = new MsgPipe();
|
|
SceUID id = kernelObjects.Create(m);
|
|
|
|
m->nmp.size = sizeof(NativeMsgPipe);
|
|
strncpy(m->nmp.name, name, sizeof(m->nmp.name));
|
|
m->nmp.attr = attr;
|
|
m->nmp.bufSize = size;
|
|
m->nmp.freeSize = size;
|
|
m->nmp.numSendWaitThreads = 0;
|
|
m->nmp.numReceiveWaitThreads = 0;
|
|
|
|
m->buffer = new u8[size];
|
|
m->writePos = 0;
|
|
m->readPos = 0;
|
|
|
|
RETURN(id);
|
|
}
|
|
|
|
void sceKernelDeleteMsgPipe()
|
|
{
|
|
SceUInt uid = PARAM(0);
|
|
u32 error;
|
|
MsgPipe *p = kernelObjects.Get<MsgPipe>(uid, error);
|
|
if (!p)
|
|
{
|
|
ERROR_LOG(HLE, "sceKernelDeleteMsgPipe(%i) - ERROR %08x", uid, error);
|
|
return;
|
|
}
|
|
delete [] p->buffer;
|
|
ERROR_LOG(HLE, "sceKernelDeleteMsgPipe(%i)", uid);
|
|
RETURN(kernelObjects.Destroy<MsgPipe>(uid));
|
|
}
|
|
|
|
void sceKernelSendMsgPipe()
|
|
{
|
|
SceUInt uid = PARAM(0);
|
|
u32 sendBufAddr = PARAM(1);
|
|
u32 sendSize = PARAM(2);
|
|
int waitMode = PARAM(3);
|
|
u32 resultAddr = PARAM(4);
|
|
u32 timeoutPtr = PARAM(5);
|
|
|
|
u32 error;
|
|
MsgPipe *pipe = kernelObjects.Get<MsgPipe>(uid, error);
|
|
if (!pipe) {
|
|
ERROR_LOG(HLE, "sceKernelSendMsgPipe(%i) - ERROR %08x", uid, error);
|
|
RETURN(error);
|
|
return;
|
|
}
|
|
|
|
if (sendSize > pipe->nmp.freeSize) {
|
|
// TODO: Block
|
|
ERROR_LOG(HLE, "sceKernelSendMsgPipe(%i) - Message won't fit", uid, error);
|
|
RETURN(SCE_KERNEL_ERROR_MPP_FULL);
|
|
return;
|
|
}
|
|
|
|
const u8 *source = Memory::GetPointer(sendBufAddr);
|
|
|
|
int destIndex = pipe->writePos;
|
|
if (pipe->writePos + sendSize > pipe->nmp.size) {
|
|
// Split in two
|
|
int firstCopySize = pipe->nmp.size - pipe->writePos;
|
|
memcpy(pipe->buffer + pipe->writePos, source, firstCopySize);
|
|
memcpy(pipe->buffer, source + firstCopySize, sendSize - firstCopySize);
|
|
} else {
|
|
memcpy(pipe->buffer + pipe->writePos, source, sendSize);
|
|
}
|
|
pipe->writePos += sendSize;
|
|
pipe->writePos %= pipe->nmp.size;
|
|
|
|
ERROR_LOG(HLE, "UNIMPL sceKernelSendMsgPipe(%i, %08x, %i, %i, %08x, %08x)", uid, sendBufAddr, sendSize, waitMode, resultAddr, timeoutPtr);
|
|
RETURN(0);
|
|
}
|
|
|
|
void sceKernelSendMsgPipeCB()
|
|
{
|
|
SceUInt uid = PARAM(0);
|
|
u32 sendBufAddr = PARAM(1);
|
|
u32 sendSize = PARAM(2);
|
|
int waitMode = PARAM(3);
|
|
u32 resultAddr = PARAM(4);
|
|
u32 timeoutPtr = PARAM(5);
|
|
|
|
u32 error;
|
|
MsgPipe *pipe = kernelObjects.Get<MsgPipe>(uid, error);
|
|
if (!pipe) {
|
|
ERROR_LOG(HLE, "sceKernelSendMsgPipe(%i) - ERROR %08x", uid, error);
|
|
RETURN(error);
|
|
return;
|
|
}
|
|
|
|
if (sendSize > pipe->nmp.freeSize) {
|
|
// TODO: Block
|
|
ERROR_LOG(HLE, "sceKernelSendMsgPipe(%i) - Message won't fit", uid, error);
|
|
RETURN(SCE_KERNEL_ERROR_MPP_FULL);
|
|
return;
|
|
}
|
|
|
|
const u8 *source = Memory::GetPointer(sendBufAddr);
|
|
|
|
int destIndex = pipe->writePos;
|
|
if (pipe->writePos + sendSize > pipe->nmp.size) {
|
|
// Split in two
|
|
int firstCopySize = pipe->nmp.size - pipe->writePos;
|
|
memcpy(pipe->buffer + pipe->writePos, source, firstCopySize);
|
|
memcpy(pipe->buffer, source + firstCopySize, sendSize - firstCopySize);
|
|
} else {
|
|
memcpy(pipe->buffer + pipe->writePos, source, sendSize);
|
|
}
|
|
pipe->writePos += sendSize;
|
|
pipe->writePos %= pipe->nmp.size;
|
|
|
|
ERROR_LOG(HLE, "UNIMPL sceKernelSendMsgPipe(%i, %08x, %i, %i, %08x, %08x)", uid, sendBufAddr, sendSize, waitMode, resultAddr, timeoutPtr);
|
|
RETURN(0);
|
|
__KernelCheckCallbacks();
|
|
}
|
|
|
|
void sceKernelTrySendMsgPipe()
|
|
{
|
|
SceUInt uid = PARAM(0);
|
|
u32 sendBufAddr = PARAM(1);
|
|
u32 sendSize = PARAM(2);
|
|
int waitMode = PARAM(3);
|
|
u32 resultAddr = PARAM(4);
|
|
u32 timeoutPtr = PARAM(5);
|
|
|
|
u32 error;
|
|
MsgPipe *pipe = kernelObjects.Get<MsgPipe>(uid, error);
|
|
if (!pipe) {
|
|
ERROR_LOG(HLE, "sceKernelSendMsgPipe(%i) - ERROR %08x", uid, error);
|
|
RETURN(error);
|
|
return;
|
|
}
|
|
|
|
if (sendSize > pipe->nmp.freeSize) {
|
|
// TODO: Block
|
|
ERROR_LOG(HLE, "sceKernelSendMsgPipe(%i) - Message won't fit", uid, error);
|
|
RETURN(SCE_KERNEL_ERROR_MPP_FULL);
|
|
return;
|
|
}
|
|
|
|
const u8 *source = Memory::GetPointer(sendBufAddr);
|
|
|
|
int destIndex = pipe->writePos;
|
|
if (pipe->writePos + sendSize > pipe->nmp.size) {
|
|
// Split in two
|
|
int firstCopySize = pipe->nmp.size - pipe->writePos;
|
|
memcpy(pipe->buffer + pipe->writePos, source, firstCopySize);
|
|
memcpy(pipe->buffer, source + firstCopySize, sendSize - firstCopySize);
|
|
} else {
|
|
memcpy(pipe->buffer + pipe->writePos, source, sendSize);
|
|
}
|
|
pipe->writePos += sendSize;
|
|
pipe->writePos %= pipe->nmp.size;
|
|
|
|
ERROR_LOG(HLE, "UNIMPL sceKernelSendMsgPipe(%i, %08x, %i, %i, %08x, %08x)", uid, sendBufAddr, sendSize, waitMode, resultAddr, timeoutPtr);
|
|
RETURN(0);
|
|
}
|
|
|
|
void sceKernelReceiveMsgPipe()
|
|
{
|
|
SceUInt uid = PARAM(0);
|
|
u32 receiveBufAddr = PARAM(1);
|
|
u32 receiveSize = PARAM(2);
|
|
int waitMode = PARAM(3);
|
|
u32 resultAddr = PARAM(4);
|
|
u32 timeoutPtr = PARAM(5);
|
|
|
|
ERROR_LOG(HLE, "UNIMPL sceKernelReceiveMsgPipe(%i, %08x, %i, %i, %08x, %08x)", uid, receiveBufAddr, receiveSize, waitMode, resultAddr, timeoutPtr);
|
|
RETURN(SCE_KERNEL_ERROR_MPP_EMPTY);
|
|
}
|
|
|
|
void sceKernelReceiveMsgPipeCB()
|
|
{
|
|
SceUInt uid = PARAM(0);
|
|
u32 receiveBufAddr = PARAM(1);
|
|
u32 receiveSize = PARAM(2);
|
|
int waitMode = PARAM(3);
|
|
u32 resultAddr = PARAM(4);
|
|
u32 timeoutPtr = PARAM(5);
|
|
|
|
ERROR_LOG(HLE, "UNIMPL sceKernelReceiveMsgPipeCB(%i, %08x, %i, %i, %08x, %08x)", uid, receiveBufAddr, receiveSize, waitMode, resultAddr, timeoutPtr);
|
|
RETURN(SCE_KERNEL_ERROR_MPP_EMPTY);
|
|
}
|
|
|
|
void sceKernelTryReceiveMsgPipe()
|
|
{
|
|
SceUInt uid = PARAM(0);
|
|
u32 receiveBufAddr = PARAM(1);
|
|
u32 receiveSize = PARAM(2);
|
|
int waitMode = PARAM(3);
|
|
u32 resultAddr = PARAM(4);
|
|
|
|
ERROR_LOG(HLE, "UNIMPL sceKernelTryReceiveMsgPipe(%i, %08x, %i, %i, %08x)", uid, receiveBufAddr, receiveSize, waitMode, resultAddr);
|
|
RETURN(SCE_KERNEL_ERROR_MPP_EMPTY);
|
|
}
|
|
|
|
void sceKernelCancelMsgPipe()
|
|
{
|
|
SceUInt uid = PARAM(0);
|
|
u32 numSendThreads = PARAM(1);
|
|
u32 numReceiveThreads = PARAM(2);
|
|
|
|
ERROR_LOG(HLE, "UNIMPL sceKernelCancelMsgPipe(%i, %i, %i)", uid, numSendThreads, numReceiveThreads);
|
|
RETURN(0);
|
|
}
|
|
|
|
void sceKernelReferMsgPipeStatus()
|
|
{
|
|
SceUID uid = PARAM(0);
|
|
u32 msgPipeStatusAddr = PARAM(1);
|
|
|
|
DEBUG_LOG(HLE,"sceKernelReferMsgPipeStatus(%i, %08x)", uid, msgPipeStatusAddr);
|
|
u32 error;
|
|
MsgPipe *mp = kernelObjects.Get<MsgPipe>(uid, error);
|
|
if (mp)
|
|
{
|
|
Memory::WriteStruct(msgPipeStatusAddr, &mp->nmp);
|
|
RETURN(0);
|
|
}
|
|
else
|
|
{
|
|
RETURN(error);
|
|
}
|
|
}
|