Some small fixes related to receive list buffers and error cases

This commit is contained in:
gdkchan 2018-12-29 23:11:37 -03:00
commit 4c4f6c6702

View file

@ -48,6 +48,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
private struct MessageHeader private struct MessageHeader
{ {
public uint Word0 { get; }
public uint Word1 { get; }
public uint Word2 { get; }
public uint PointerBuffersCount { get; } public uint PointerBuffersCount { get; }
public uint SendBuffersCount { get; } public uint SendBuffersCount { get; }
public uint ReceiveBuffersCount { get; } public uint ReceiveBuffersCount { get; }
@ -70,6 +74,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
public MessageHeader(uint word0, uint word1, uint word2) public MessageHeader(uint word0, uint word1, uint word2)
{ {
Word0 = word0;
Word1 = word1;
Word2 = word2;
HasHandles = word1 >> 31 != 0; HasHandles = word1 >> 31 != 0;
uint handleDescSizeInWords = 0; uint handleDescSizeInWords = 0;
@ -241,16 +249,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
request.CustomCmdBuffAddr, request.CustomCmdBuffAddr,
request.CustomCmdBuffSize); request.CustomCmdBuffSize);
Message serverMsg = new Message( Message serverMsg = new Message(serverThread, customCmdBuffAddr, customCmdBuffSize);
serverThread,
customCmdBuffAddr,
customCmdBuffSize);
uint word0 = System.Device.Memory.ReadUInt32((long)clientMsg.DramAddress + 0); MessageHeader header = GetClientMessageHeader(clientMsg);
uint word1 = System.Device.Memory.ReadUInt32((long)clientMsg.DramAddress + 4);
uint word2 = System.Device.Memory.ReadUInt32((long)clientMsg.DramAddress + 8);
MessageHeader header = new MessageHeader(word0, word1, word2);
KernelResult serverResult = KernelResult.NotFound; KernelResult serverResult = KernelResult.NotFound;
KernelResult clientResult = KernelResult.Success; KernelResult clientResult = KernelResult.Success;
@ -278,19 +279,22 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
WakeClient(request, clientResult); WakeClient(request, clientResult);
} }
if (header.ReceiveListType < 2 && header.ReceiveListOffset > clientMsg.Size) if (header.ReceiveListType < 2 &&
header.ReceiveListOffset > clientMsg.Size)
{ {
CleanUpForError(); CleanUpForError();
return KernelResult.InvalidCombination; return KernelResult.InvalidCombination;
} }
else if (header.ReceiveListType == 2 && header.ReceiveListOffset + 8 > clientMsg.Size) else if (header.ReceiveListType == 2 &&
header.ReceiveListOffset + 8 > clientMsg.Size)
{ {
CleanUpForError(); CleanUpForError();
return KernelResult.InvalidCombination; return KernelResult.InvalidCombination;
} }
else if (header.ReceiveListType * 8 - 0x10 + header.ReceiveListOffset > clientMsg.Size) else if (header.ReceiveListType > 2 &&
header.ReceiveListType * 8 - 0x10 + header.ReceiveListOffset > clientMsg.Size)
{ {
CleanUpForError(); CleanUpForError();
@ -311,28 +315,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
return KernelResult.CmdBufferTooSmall; return KernelResult.CmdBufferTooSmall;
} }
int recvListSize = 0; ulong[] receiveList = GetReceiveList(clientMsg, header.ReceiveListType, header.ReceiveListOffset);
if (header.ReceiveListType >= 3) serverProcess.CpuMemory.WriteUInt32((long)serverMsg.Address + 0, header.Word0);
{ serverProcess.CpuMemory.WriteUInt32((long)serverMsg.Address + 4, header.Word1);
recvListSize = (int)header.ReceiveListType - 2;
}
else if (header.ReceiveListType == 2)
{
recvListSize = 1;
}
ulong[] receiveList = new ulong[recvListSize];
long recvListAddress = (long)serverMsg.Address + header.ReceiveListOffset;
for (int index = 0; index < recvListSize; index++)
{
receiveList[index] = serverProcess.CpuMemory.ReadUInt64(recvListAddress + index * 8);
}
serverProcess.CpuMemory.WriteUInt32((long)serverMsg.Address + 0, word0);
serverProcess.CpuMemory.WriteUInt32((long)serverMsg.Address + 4, word1);
uint offset; uint offset;
@ -346,7 +332,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
return KernelResult.InvalidCombination; return KernelResult.InvalidCombination;
} }
serverProcess.CpuMemory.WriteUInt32((long)serverMsg.Address + 8, word2); serverProcess.CpuMemory.WriteUInt32((long)serverMsg.Address + 8, header.Word2);
offset = 3; offset = 3;
@ -417,7 +403,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
if (descriptor.BufferSize != 0) if (descriptor.BufferSize != 0)
{ {
clientResult = GetReceiveListAddress(serverMsg, header, descriptor, receiveList, out ulong recvListBufferAddress); clientResult = GetReceiveListAddress(
descriptor,
serverMsg,
header.ReceiveListType,
header.MessageSizeInWords,
receiveList,
out ulong recvListBufferAddress);
if (clientResult != KernelResult.Success) if (clientResult != KernelResult.Success)
{ {
@ -627,10 +619,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
request.CustomCmdBuffAddr, request.CustomCmdBuffAddr,
request.CustomCmdBuffSize); request.CustomCmdBuffSize);
Message serverMsg = new Message( Message serverMsg = new Message(serverThread, customCmdBuffAddr, customCmdBuffSize);
serverThread,
customCmdBuffAddr,
customCmdBuffSize);
uint word0 = serverProcess.CpuMemory.ReadUInt32((long)serverMsg.Address + 0); uint word0 = serverProcess.CpuMemory.ReadUInt32((long)serverMsg.Address + 0);
uint word1 = serverProcess.CpuMemory.ReadUInt32((long)serverMsg.Address + 4); uint word1 = serverProcess.CpuMemory.ReadUInt32((long)serverMsg.Address + 4);
@ -638,6 +627,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
MessageHeader header = new MessageHeader(word0, word1, word2); MessageHeader header = new MessageHeader(word0, word1, word2);
MessageHeader clientHeader = GetClientMessageHeader(clientMsg);
KernelResult clientResult = KernelResult.Success; KernelResult clientResult = KernelResult.Success;
KernelResult serverResult = KernelResult.Success; KernelResult serverResult = KernelResult.Success;
@ -648,26 +639,29 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
CancelRequest(request, clientResult); CancelRequest(request, clientResult);
} }
if (header.ReceiveListType < 2 && header.ReceiveListOffset > clientMsg.Size) if (clientHeader.ReceiveListType < 2 &&
clientHeader.ReceiveListOffset > clientMsg.Size)
{ {
CleanUpForError(); CleanUpForError();
return KernelResult.InvalidCombination; return KernelResult.InvalidCombination;
} }
else if (header.ReceiveListType == 2 && header.ReceiveListOffset + 8 > clientMsg.Size) else if (clientHeader.ReceiveListType == 2 &&
clientHeader.ReceiveListOffset + 8 > clientMsg.Size)
{ {
CleanUpForError(); CleanUpForError();
return KernelResult.InvalidCombination; return KernelResult.InvalidCombination;
} }
else if (header.ReceiveListType * 8 - 0x10 + header.ReceiveListOffset > clientMsg.Size) else if (clientHeader.ReceiveListType > 2 &&
clientHeader.ReceiveListType * 8 - 0x10 + clientHeader.ReceiveListOffset > clientMsg.Size)
{ {
CleanUpForError(); CleanUpForError();
return KernelResult.InvalidCombination; return KernelResult.InvalidCombination;
} }
if (header.ReceiveListOffsetInWords < header.MessageSizeInWords) if (clientHeader.ReceiveListOffsetInWords < clientHeader.MessageSizeInWords)
{ {
CleanUpForError(); CleanUpForError();
@ -681,24 +675,20 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
return KernelResult.CmdBufferTooSmall; return KernelResult.CmdBufferTooSmall;
} }
if (header.SendBuffersCount != 0 ||
header.ReceiveBuffersCount != 0 ||
header.ExchangeBuffersCount != 0)
{
CleanUpForError();
return KernelResult.InvalidCombination;
}
//Read receive list. //Read receive list.
ulong[] receiveList = null; ulong[] receiveList = GetReceiveList(
clientMsg,
if (header.ReceiveListType >= 2) clientHeader.ReceiveListType,
{ clientHeader.ReceiveListOffset);
uint count = header.ReceiveListType == 2 ? 1 : header.ReceiveListType - 2;
receiveList = new ulong[count];
ulong receiveListAddress = clientMsg.DramAddress + header.ReceiveListOffset;
for (uint index = 0; index < count; index++)
{
ulong dword = System.Device.Memory.ReadUInt64((long)receiveListAddress + index * 8);
receiveList[index] = dword;
}
}
//Copy receive and exchange buffers. //Copy receive and exchange buffers.
clientResult = request.BufferDescriptorTable.CopyBuffersToClient(clientProcess.MemoryManager); clientResult = request.BufferDescriptorTable.CopyBuffersToClient(clientProcess.MemoryManager);
@ -783,7 +773,13 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
if (descriptor.BufferSize != 0) if (descriptor.BufferSize != 0)
{ {
clientResult = GetReceiveListAddress(serverMsg, header, descriptor, receiveList, out ulong recvListBufferAddress); clientResult = GetReceiveListAddress(
descriptor,
clientMsg,
clientHeader.ReceiveListType,
header.MessageSizeInWords,
receiveList,
out ulong recvListBufferAddress);
if (clientResult != KernelResult.Success) if (clientResult != KernelResult.Success)
{ {
@ -878,6 +874,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
return serverResult; return serverResult;
} }
private MessageHeader GetClientMessageHeader(Message clientMsg)
{
uint word0 = System.Device.Memory.ReadUInt32((long)clientMsg.DramAddress + 0);
uint word1 = System.Device.Memory.ReadUInt32((long)clientMsg.DramAddress + 4);
uint word2 = System.Device.Memory.ReadUInt32((long)clientMsg.DramAddress + 8);
return new MessageHeader(word0, word1, word2);
}
private KernelResult GetCopyObjectHandle( private KernelResult GetCopyObjectHandle(
KThread srcThread, KThread srcThread,
KProcess dstProcess, KProcess dstProcess,
@ -937,27 +942,53 @@ namespace Ryujinx.HLE.HOS.Kernel.Ipc
} }
} }
private ulong[] GetReceiveList(Message message, uint recvListType, uint recvListOffset)
{
int recvListSize = 0;
if (recvListType >= 3)
{
recvListSize = (int)recvListType - 2;
}
else if (recvListType == 2)
{
recvListSize = 1;
}
ulong[] receiveList = new ulong[recvListSize];
long recvListAddress = (long)message.DramAddress + recvListOffset;
for (int index = 0; index < recvListSize; index++)
{
receiveList[index] = System.Device.Memory.ReadUInt64(recvListAddress + index * 8);
}
return receiveList;
}
private KernelResult GetReceiveListAddress( private KernelResult GetReceiveListAddress(
Message message,
MessageHeader header,
PointerBufferDesc descriptor, PointerBufferDesc descriptor,
Message message,
uint recvListType,
uint messageSizeInWords,
ulong[] receiveList, ulong[] receiveList,
out ulong address) out ulong address)
{ {
ulong recvListBufferAddress = address = 0; ulong recvListBufferAddress = address = 0;
if (header.ReceiveListType == 0) if (recvListType == 0)
{ {
return KernelResult.OutOfResource; return KernelResult.OutOfResource;
} }
else if (header.ReceiveListType == 1 || header.ReceiveListType == 2) else if (recvListType == 1 || recvListType == 2)
{ {
ulong recvListBaseAddr; ulong recvListBaseAddr;
ulong recvListEndAddr; ulong recvListEndAddr;
if (header.ReceiveListType == 1) if (recvListType == 1)
{ {
recvListBaseAddr = message.Address + header.MessageSizeInWords * 4; recvListBaseAddr = message.Address + messageSizeInWords * 4;
recvListEndAddr = message.Address + message.Size; recvListEndAddr = message.Address + message.Size;
} }
else /* if (recvListType == 2) */ else /* if (recvListType == 2) */