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
parent 6b9f4d38e4
commit 4c4f6c6702

View file

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