KServerSession.cs 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265
  1. using Ryujinx.Common;
  2. using Ryujinx.HLE.HOS.Kernel.Common;
  3. using Ryujinx.HLE.HOS.Kernel.Memory;
  4. using Ryujinx.HLE.HOS.Kernel.Process;
  5. using Ryujinx.HLE.HOS.Kernel.Threading;
  6. using System.Collections.Generic;
  7. namespace Ryujinx.HLE.HOS.Kernel.Ipc
  8. {
  9. class KServerSession : KSynchronizationObject
  10. {
  11. private static readonly MemoryState[] IpcMemoryStates = new MemoryState[]
  12. {
  13. MemoryState.IpcBuffer3,
  14. MemoryState.IpcBuffer0,
  15. MemoryState.IpcBuffer1,
  16. (MemoryState)0xfffce5d4 //This is invalid, shouldn't be accessed.
  17. };
  18. private struct Message
  19. {
  20. public ulong Address { get; }
  21. public ulong DramAddress { get; }
  22. public ulong Size { get; }
  23. public bool IsCustom { get; }
  24. public Message(KThread thread, ulong customCmdBuffAddress, ulong customCmdBuffSize)
  25. {
  26. IsCustom = customCmdBuffAddress != 0;
  27. if (IsCustom)
  28. {
  29. Address = customCmdBuffAddress;
  30. Size = customCmdBuffSize;
  31. KProcess process = thread.Owner;
  32. DramAddress = process.MemoryManager.GetDramAddressFromVa(Address);
  33. }
  34. else
  35. {
  36. Address = thread.TlsAddress;
  37. DramAddress = thread.TlsDramAddress;
  38. Size = 0x100;
  39. }
  40. }
  41. public Message(KSessionRequest request) : this(
  42. request.ClientThread,
  43. request.CustomCmdBuffAddr,
  44. request.CustomCmdBuffSize) { }
  45. }
  46. private struct MessageHeader
  47. {
  48. public uint Word0 { get; }
  49. public uint Word1 { get; }
  50. public uint Word2 { get; }
  51. public uint PointerBuffersCount { get; }
  52. public uint SendBuffersCount { get; }
  53. public uint ReceiveBuffersCount { get; }
  54. public uint ExchangeBuffersCount { get; }
  55. public uint RawDataSizeInWords { get; }
  56. public uint ReceiveListType { get; }
  57. public uint MessageSizeInWords { get; }
  58. public uint ReceiveListOffsetInWords { get; }
  59. public uint ReceiveListOffset { get; }
  60. public bool HasHandles { get; }
  61. public bool HasPid { get; }
  62. public uint CopyHandlesCount { get; }
  63. public uint MoveHandlesCount { get; }
  64. public MessageHeader(uint word0, uint word1, uint word2)
  65. {
  66. Word0 = word0;
  67. Word1 = word1;
  68. Word2 = word2;
  69. HasHandles = word1 >> 31 != 0;
  70. uint handleDescSizeInWords = 0;
  71. if (HasHandles)
  72. {
  73. uint pidSize = (word2 & 1) * 8;
  74. HasPid = pidSize != 0;
  75. CopyHandlesCount = (word2 >> 1) & 0xf;
  76. MoveHandlesCount = (word2 >> 5) & 0xf;
  77. handleDescSizeInWords = (pidSize + CopyHandlesCount * 4 + MoveHandlesCount * 4) / 4;
  78. }
  79. else
  80. {
  81. HasPid = false;
  82. CopyHandlesCount = 0;
  83. MoveHandlesCount = 0;
  84. }
  85. PointerBuffersCount = (word0 >> 16) & 0xf;
  86. SendBuffersCount = (word0 >> 20) & 0xf;
  87. ReceiveBuffersCount = (word0 >> 24) & 0xf;
  88. ExchangeBuffersCount = word0 >> 28;
  89. uint pointerDescSizeInWords = PointerBuffersCount * 2;
  90. uint sendDescSizeInWords = SendBuffersCount * 3;
  91. uint receiveDescSizeInWords = ReceiveBuffersCount * 3;
  92. uint exchangeDescSizeInWords = ExchangeBuffersCount * 3;
  93. RawDataSizeInWords = word1 & 0x3ff;
  94. ReceiveListType = (word1 >> 10) & 0xf;
  95. ReceiveListOffsetInWords = (word1 >> 20) & 0x7ff;
  96. uint paddingSizeInWords = HasHandles ? 3u : 2u;
  97. MessageSizeInWords = pointerDescSizeInWords +
  98. sendDescSizeInWords +
  99. receiveDescSizeInWords +
  100. exchangeDescSizeInWords +
  101. RawDataSizeInWords +
  102. paddingSizeInWords +
  103. handleDescSizeInWords;
  104. if (ReceiveListOffsetInWords == 0)
  105. {
  106. ReceiveListOffsetInWords = MessageSizeInWords;
  107. }
  108. ReceiveListOffset = ReceiveListOffsetInWords * 4;
  109. }
  110. }
  111. private struct PointerBufferDesc
  112. {
  113. public uint ReceiveIndex { get; }
  114. public uint BufferSize { get; }
  115. public ulong BufferAddress { get; set; }
  116. public PointerBufferDesc(ulong dword)
  117. {
  118. ReceiveIndex = (uint)dword & 0xf;
  119. BufferSize = (uint)dword >> 16;
  120. BufferAddress = (dword >> 2) & 0x70;
  121. BufferAddress |= (dword >> 12) & 0xf;
  122. BufferAddress = (BufferAddress << 32) | (dword >> 32);
  123. }
  124. public ulong Pack()
  125. {
  126. ulong dword = (ReceiveIndex & 0xf) | ((BufferSize & 0xffff) << 16);
  127. dword |= BufferAddress << 32;
  128. dword |= (BufferAddress >> 20) & 0xf000;
  129. dword |= (BufferAddress >> 30) & 0xffc0;
  130. return dword;
  131. }
  132. }
  133. private KSession _parent;
  134. private LinkedList<KSessionRequest> _requests;
  135. private KSessionRequest _activeRequest;
  136. public KServerSession(KernelContext context, KSession parent) : base(context)
  137. {
  138. _parent = parent;
  139. _requests = new LinkedList<KSessionRequest>();
  140. }
  141. public KernelResult EnqueueRequest(KSessionRequest request)
  142. {
  143. if (_parent.ClientSession.State != ChannelState.Open)
  144. {
  145. return KernelResult.PortRemoteClosed;
  146. }
  147. if (request.AsyncEvent == null)
  148. {
  149. if (request.ClientThread.ShallBeTerminated ||
  150. request.ClientThread.SchedFlags == ThreadSchedState.TerminationPending)
  151. {
  152. return KernelResult.ThreadTerminating;
  153. }
  154. request.ClientThread.Reschedule(ThreadSchedState.Paused);
  155. }
  156. _requests.AddLast(request);
  157. if (_requests.Count == 1)
  158. {
  159. Signal();
  160. }
  161. return KernelResult.Success;
  162. }
  163. public KernelResult Receive(ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
  164. {
  165. KThread serverThread = KernelContext.Scheduler.GetCurrentThread();
  166. KProcess serverProcess = serverThread.Owner;
  167. KernelContext.CriticalSection.Enter();
  168. if (_parent.ClientSession.State != ChannelState.Open)
  169. {
  170. KernelContext.CriticalSection.Leave();
  171. return KernelResult.PortRemoteClosed;
  172. }
  173. if (_activeRequest != null || !DequeueRequest(out KSessionRequest request))
  174. {
  175. KernelContext.CriticalSection.Leave();
  176. return KernelResult.NotFound;
  177. }
  178. if (request.ClientThread == null)
  179. {
  180. KernelContext.CriticalSection.Leave();
  181. return KernelResult.PortRemoteClosed;
  182. }
  183. KThread clientThread = request.ClientThread;
  184. KProcess clientProcess = clientThread.Owner;
  185. KernelContext.CriticalSection.Leave();
  186. _activeRequest = request;
  187. request.ServerProcess = serverProcess;
  188. Message clientMsg = new Message(request);
  189. Message serverMsg = new Message(serverThread, customCmdBuffAddr, customCmdBuffSize);
  190. MessageHeader clientHeader = GetClientMessageHeader(clientMsg);
  191. MessageHeader serverHeader = GetServerMessageHeader(serverMsg);
  192. KernelResult serverResult = KernelResult.NotFound;
  193. KernelResult clientResult = KernelResult.Success;
  194. void CleanUpForError()
  195. {
  196. if (request.BufferDescriptorTable.UnmapServerBuffers(serverProcess.MemoryManager) == KernelResult.Success)
  197. {
  198. request.BufferDescriptorTable.RestoreClientBuffers(clientProcess.MemoryManager);
  199. }
  200. CloseAllHandles(serverMsg, clientHeader, serverProcess);
  201. KernelContext.CriticalSection.Enter();
  202. _activeRequest = null;
  203. if (_requests.Count != 0)
  204. {
  205. Signal();
  206. }
  207. KernelContext.CriticalSection.Leave();
  208. WakeClientThread(request, clientResult);
  209. }
  210. if (clientHeader.ReceiveListType < 2 &&
  211. clientHeader.ReceiveListOffset > clientMsg.Size)
  212. {
  213. CleanUpForError();
  214. return KernelResult.InvalidCombination;
  215. }
  216. else if (clientHeader.ReceiveListType == 2 &&
  217. clientHeader.ReceiveListOffset + 8 > clientMsg.Size)
  218. {
  219. CleanUpForError();
  220. return KernelResult.InvalidCombination;
  221. }
  222. else if (clientHeader.ReceiveListType > 2 &&
  223. clientHeader.ReceiveListType * 8 - 0x10 + clientHeader.ReceiveListOffset > clientMsg.Size)
  224. {
  225. CleanUpForError();
  226. return KernelResult.InvalidCombination;
  227. }
  228. if (clientHeader.ReceiveListOffsetInWords < clientHeader.MessageSizeInWords)
  229. {
  230. CleanUpForError();
  231. return KernelResult.InvalidCombination;
  232. }
  233. if (clientHeader.MessageSizeInWords * 4 > clientMsg.Size)
  234. {
  235. CleanUpForError();
  236. return KernelResult.CmdBufferTooSmall;
  237. }
  238. ulong[] receiveList = GetReceiveList(
  239. serverMsg,
  240. serverHeader.ReceiveListType,
  241. serverHeader.ReceiveListOffset);
  242. serverProcess.CpuMemory.Write(serverMsg.Address + 0, clientHeader.Word0);
  243. serverProcess.CpuMemory.Write(serverMsg.Address + 4, clientHeader.Word1);
  244. uint offset;
  245. // Copy handles.
  246. if (clientHeader.HasHandles)
  247. {
  248. if (clientHeader.MoveHandlesCount != 0)
  249. {
  250. CleanUpForError();
  251. return KernelResult.InvalidCombination;
  252. }
  253. serverProcess.CpuMemory.Write(serverMsg.Address + 8, clientHeader.Word2);
  254. offset = 3;
  255. if (clientHeader.HasPid)
  256. {
  257. serverProcess.CpuMemory.Write(serverMsg.Address + offset * 4, clientProcess.Pid);
  258. offset += 2;
  259. }
  260. for (int index = 0; index < clientHeader.CopyHandlesCount; index++)
  261. {
  262. int newHandle = 0;
  263. int handle = KernelContext.Memory.Read<int>(clientMsg.DramAddress + offset * 4);
  264. if (clientResult == KernelResult.Success && handle != 0)
  265. {
  266. clientResult = GetCopyObjectHandle(clientThread, serverProcess, handle, out newHandle);
  267. }
  268. serverProcess.CpuMemory.Write(serverMsg.Address + offset * 4, newHandle);
  269. offset++;
  270. }
  271. for (int index = 0; index < clientHeader.MoveHandlesCount; index++)
  272. {
  273. int newHandle = 0;
  274. int handle = KernelContext.Memory.Read<int>(clientMsg.DramAddress + offset * 4);
  275. if (handle != 0)
  276. {
  277. if (clientResult == KernelResult.Success)
  278. {
  279. clientResult = GetMoveObjectHandle(clientProcess, serverProcess, handle, out newHandle);
  280. }
  281. else
  282. {
  283. clientProcess.HandleTable.CloseHandle(handle);
  284. }
  285. }
  286. serverProcess.CpuMemory.Write(serverMsg.Address + offset * 4, newHandle);
  287. offset++;
  288. }
  289. if (clientResult != KernelResult.Success)
  290. {
  291. CleanUpForError();
  292. return serverResult;
  293. }
  294. }
  295. else
  296. {
  297. offset = 2;
  298. }
  299. // Copy pointer/receive list buffers.
  300. uint recvListDstOffset = 0;
  301. for (int index = 0; index < clientHeader.PointerBuffersCount; index++)
  302. {
  303. ulong pointerDesc = KernelContext.Memory.Read<ulong>(clientMsg.DramAddress + offset * 4);
  304. PointerBufferDesc descriptor = new PointerBufferDesc(pointerDesc);
  305. if (descriptor.BufferSize != 0)
  306. {
  307. clientResult = GetReceiveListAddress(
  308. descriptor,
  309. serverMsg,
  310. serverHeader.ReceiveListType,
  311. clientHeader.MessageSizeInWords,
  312. receiveList,
  313. ref recvListDstOffset,
  314. out ulong recvListBufferAddress);
  315. if (clientResult != KernelResult.Success)
  316. {
  317. CleanUpForError();
  318. return serverResult;
  319. }
  320. clientResult = clientProcess.MemoryManager.CopyDataToCurrentProcess(
  321. recvListBufferAddress,
  322. descriptor.BufferSize,
  323. descriptor.BufferAddress,
  324. MemoryState.IsPoolAllocated,
  325. MemoryState.IsPoolAllocated,
  326. MemoryPermission.Read,
  327. MemoryAttribute.Uncached,
  328. MemoryAttribute.None);
  329. if (clientResult != KernelResult.Success)
  330. {
  331. CleanUpForError();
  332. return serverResult;
  333. }
  334. descriptor.BufferAddress = recvListBufferAddress;
  335. }
  336. else
  337. {
  338. descriptor.BufferAddress = 0;
  339. }
  340. serverProcess.CpuMemory.Write(serverMsg.Address + offset * 4, descriptor.Pack());
  341. offset += 2;
  342. }
  343. // Copy send, receive and exchange buffers.
  344. uint totalBuffersCount =
  345. clientHeader.SendBuffersCount +
  346. clientHeader.ReceiveBuffersCount +
  347. clientHeader.ExchangeBuffersCount;
  348. for (int index = 0; index < totalBuffersCount; index++)
  349. {
  350. ulong clientDescAddress = clientMsg.DramAddress + offset * 4;
  351. uint descWord0 = KernelContext.Memory.Read<uint>(clientDescAddress + 0);
  352. uint descWord1 = KernelContext.Memory.Read<uint>(clientDescAddress + 4);
  353. uint descWord2 = KernelContext.Memory.Read<uint>(clientDescAddress + 8);
  354. bool isSendDesc = index < clientHeader.SendBuffersCount;
  355. bool isExchangeDesc = index >= clientHeader.SendBuffersCount + clientHeader.ReceiveBuffersCount;
  356. bool notReceiveDesc = isSendDesc || isExchangeDesc;
  357. bool isReceiveDesc = !notReceiveDesc;
  358. MemoryPermission permission = index >= clientHeader.SendBuffersCount
  359. ? MemoryPermission.ReadAndWrite
  360. : MemoryPermission.Read;
  361. uint sizeHigh4 = (descWord2 >> 24) & 0xf;
  362. ulong bufferSize = descWord0 | (ulong)sizeHigh4 << 32;
  363. ulong dstAddress = 0;
  364. if (bufferSize != 0)
  365. {
  366. ulong bufferAddress;
  367. bufferAddress = descWord2 >> 28;
  368. bufferAddress |= ((descWord2 >> 2) & 7) << 4;
  369. bufferAddress = (bufferAddress << 32) | descWord1;
  370. MemoryState state = IpcMemoryStates[(descWord2 + 1) & 3];
  371. clientResult = serverProcess.MemoryManager.MapBufferFromClientProcess(
  372. bufferSize,
  373. bufferAddress,
  374. clientProcess.MemoryManager,
  375. permission,
  376. state,
  377. notReceiveDesc,
  378. out dstAddress);
  379. if (clientResult != KernelResult.Success)
  380. {
  381. CleanUpForError();
  382. return serverResult;
  383. }
  384. if (isSendDesc)
  385. {
  386. clientResult = request.BufferDescriptorTable.AddSendBuffer(bufferAddress, dstAddress, bufferSize, state);
  387. }
  388. else if (isReceiveDesc)
  389. {
  390. clientResult = request.BufferDescriptorTable.AddReceiveBuffer(bufferAddress, dstAddress, bufferSize, state);
  391. }
  392. else /* if (isExchangeDesc) */
  393. {
  394. clientResult = request.BufferDescriptorTable.AddExchangeBuffer(bufferAddress, dstAddress, bufferSize, state);
  395. }
  396. if (clientResult != KernelResult.Success)
  397. {
  398. CleanUpForError();
  399. return serverResult;
  400. }
  401. }
  402. descWord1 = (uint)dstAddress;
  403. descWord2 &= 3;
  404. descWord2 |= sizeHigh4 << 24;
  405. descWord2 |= (uint)(dstAddress >> 34) & 0x3ffffffc;
  406. descWord2 |= (uint)(dstAddress >> 4) & 0xf0000000;
  407. ulong serverDescAddress = serverMsg.Address + offset * 4;
  408. serverProcess.CpuMemory.Write(serverDescAddress + 0, descWord0);
  409. serverProcess.CpuMemory.Write(serverDescAddress + 4, descWord1);
  410. serverProcess.CpuMemory.Write(serverDescAddress + 8, descWord2);
  411. offset += 3;
  412. }
  413. // Copy raw data.
  414. if (clientHeader.RawDataSizeInWords != 0)
  415. {
  416. ulong copySrc = clientMsg.Address + offset * 4;
  417. ulong copyDst = serverMsg.Address + offset * 4;
  418. ulong copySize = clientHeader.RawDataSizeInWords * 4;
  419. if (serverMsg.IsCustom || clientMsg.IsCustom)
  420. {
  421. MemoryPermission permission = clientMsg.IsCustom
  422. ? MemoryPermission.None
  423. : MemoryPermission.Read;
  424. clientResult = clientProcess.MemoryManager.CopyDataToCurrentProcess(
  425. copyDst,
  426. copySize,
  427. copySrc,
  428. MemoryState.IsPoolAllocated,
  429. MemoryState.IsPoolAllocated,
  430. permission,
  431. MemoryAttribute.Uncached,
  432. MemoryAttribute.None);
  433. }
  434. else
  435. {
  436. copySrc = clientProcess.MemoryManager.GetDramAddressFromVa(copySrc);
  437. copyDst = serverProcess.MemoryManager.GetDramAddressFromVa(copyDst);
  438. KernelContext.Memory.Copy(copyDst, copySrc, copySize);
  439. }
  440. if (clientResult != KernelResult.Success)
  441. {
  442. CleanUpForError();
  443. return serverResult;
  444. }
  445. }
  446. return KernelResult.Success;
  447. }
  448. public KernelResult Reply(ulong customCmdBuffAddr = 0, ulong customCmdBuffSize = 0)
  449. {
  450. KThread serverThread = KernelContext.Scheduler.GetCurrentThread();
  451. KProcess serverProcess = serverThread.Owner;
  452. KernelContext.CriticalSection.Enter();
  453. if (_activeRequest == null)
  454. {
  455. KernelContext.CriticalSection.Leave();
  456. return KernelResult.InvalidState;
  457. }
  458. KSessionRequest request = _activeRequest;
  459. _activeRequest = null;
  460. if (_requests.Count != 0)
  461. {
  462. Signal();
  463. }
  464. KernelContext.CriticalSection.Leave();
  465. KThread clientThread = request.ClientThread;
  466. KProcess clientProcess = clientThread.Owner;
  467. Message clientMsg = new Message(request);
  468. Message serverMsg = new Message(serverThread, customCmdBuffAddr, customCmdBuffSize);
  469. MessageHeader clientHeader = GetClientMessageHeader(clientMsg);
  470. MessageHeader serverHeader = GetServerMessageHeader(serverMsg);
  471. KernelResult clientResult = KernelResult.Success;
  472. KernelResult serverResult = KernelResult.Success;
  473. void CleanUpForError()
  474. {
  475. CloseAllHandles(clientMsg, serverHeader, clientProcess);
  476. FinishRequest(request, clientResult);
  477. }
  478. if (clientHeader.ReceiveListType < 2 &&
  479. clientHeader.ReceiveListOffset > clientMsg.Size)
  480. {
  481. CleanUpForError();
  482. return KernelResult.InvalidCombination;
  483. }
  484. else if (clientHeader.ReceiveListType == 2 &&
  485. clientHeader.ReceiveListOffset + 8 > clientMsg.Size)
  486. {
  487. CleanUpForError();
  488. return KernelResult.InvalidCombination;
  489. }
  490. else if (clientHeader.ReceiveListType > 2 &&
  491. clientHeader.ReceiveListType * 8 - 0x10 + clientHeader.ReceiveListOffset > clientMsg.Size)
  492. {
  493. CleanUpForError();
  494. return KernelResult.InvalidCombination;
  495. }
  496. if (clientHeader.ReceiveListOffsetInWords < clientHeader.MessageSizeInWords)
  497. {
  498. CleanUpForError();
  499. return KernelResult.InvalidCombination;
  500. }
  501. if (serverHeader.MessageSizeInWords * 4 > clientMsg.Size)
  502. {
  503. CleanUpForError();
  504. return KernelResult.CmdBufferTooSmall;
  505. }
  506. if (serverHeader.SendBuffersCount != 0 ||
  507. serverHeader.ReceiveBuffersCount != 0 ||
  508. serverHeader.ExchangeBuffersCount != 0)
  509. {
  510. CleanUpForError();
  511. return KernelResult.InvalidCombination;
  512. }
  513. // Read receive list.
  514. ulong[] receiveList = GetReceiveList(
  515. clientMsg,
  516. clientHeader.ReceiveListType,
  517. clientHeader.ReceiveListOffset);
  518. // Copy receive and exchange buffers.
  519. clientResult = request.BufferDescriptorTable.CopyBuffersToClient(clientProcess.MemoryManager);
  520. if (clientResult != KernelResult.Success)
  521. {
  522. CleanUpForError();
  523. return serverResult;
  524. }
  525. // Copy header.
  526. KernelContext.Memory.Write(clientMsg.DramAddress + 0, serverHeader.Word0);
  527. KernelContext.Memory.Write(clientMsg.DramAddress + 4, serverHeader.Word1);
  528. // Copy handles.
  529. uint offset;
  530. if (serverHeader.HasHandles)
  531. {
  532. offset = 3;
  533. KernelContext.Memory.Write(clientMsg.DramAddress + 8, serverHeader.Word2);
  534. if (serverHeader.HasPid)
  535. {
  536. KernelContext.Memory.Write(clientMsg.DramAddress + offset * 4, serverProcess.Pid);
  537. offset += 2;
  538. }
  539. for (int index = 0; index < serverHeader.CopyHandlesCount; index++)
  540. {
  541. int newHandle = 0;
  542. int handle = serverProcess.CpuMemory.Read<int>(serverMsg.Address + offset * 4);
  543. if (handle != 0)
  544. {
  545. GetCopyObjectHandle(serverThread, clientProcess, handle, out newHandle);
  546. }
  547. KernelContext.Memory.Write(clientMsg.DramAddress + offset * 4, newHandle);
  548. offset++;
  549. }
  550. for (int index = 0; index < serverHeader.MoveHandlesCount; index++)
  551. {
  552. int newHandle = 0;
  553. int handle = serverProcess.CpuMemory.Read<int>(serverMsg.Address + offset * 4);
  554. if (handle != 0)
  555. {
  556. if (clientResult == KernelResult.Success)
  557. {
  558. clientResult = GetMoveObjectHandle(serverProcess, clientProcess, handle, out newHandle);
  559. }
  560. else
  561. {
  562. serverProcess.HandleTable.CloseHandle(handle);
  563. }
  564. }
  565. KernelContext.Memory.Write(clientMsg.DramAddress + offset * 4, newHandle);
  566. offset++;
  567. }
  568. }
  569. else
  570. {
  571. offset = 2;
  572. }
  573. // Copy pointer/receive list buffers.
  574. uint recvListDstOffset = 0;
  575. for (int index = 0; index < serverHeader.PointerBuffersCount; index++)
  576. {
  577. ulong pointerDesc = serverProcess.CpuMemory.Read<ulong>(serverMsg.Address + offset * 4);
  578. PointerBufferDesc descriptor = new PointerBufferDesc(pointerDesc);
  579. ulong recvListBufferAddress = 0;
  580. if (descriptor.BufferSize != 0)
  581. {
  582. clientResult = GetReceiveListAddress(
  583. descriptor,
  584. clientMsg,
  585. clientHeader.ReceiveListType,
  586. serverHeader.MessageSizeInWords,
  587. receiveList,
  588. ref recvListDstOffset,
  589. out recvListBufferAddress);
  590. if (clientResult != KernelResult.Success)
  591. {
  592. CleanUpForError();
  593. return serverResult;
  594. }
  595. clientResult = clientProcess.MemoryManager.CopyDataFromCurrentProcess(
  596. recvListBufferAddress,
  597. descriptor.BufferSize,
  598. MemoryState.IsPoolAllocated,
  599. MemoryState.IsPoolAllocated,
  600. MemoryPermission.Read,
  601. MemoryAttribute.Uncached,
  602. MemoryAttribute.None,
  603. descriptor.BufferAddress);
  604. if (clientResult != KernelResult.Success)
  605. {
  606. CleanUpForError();
  607. return serverResult;
  608. }
  609. }
  610. ulong dstDescAddress = clientMsg.DramAddress + offset * 4;
  611. ulong clientPointerDesc =
  612. (recvListBufferAddress << 32) |
  613. ((recvListBufferAddress >> 20) & 0xf000) |
  614. ((recvListBufferAddress >> 30) & 0xffc0);
  615. clientPointerDesc |= pointerDesc & 0xffff000f;
  616. KernelContext.Memory.Write(dstDescAddress + 0, clientPointerDesc);
  617. offset += 2;
  618. }
  619. // Set send, receive and exchange buffer descriptors to zero.
  620. uint totalBuffersCount =
  621. serverHeader.SendBuffersCount +
  622. serverHeader.ReceiveBuffersCount +
  623. serverHeader.ExchangeBuffersCount;
  624. for (int index = 0; index < totalBuffersCount; index++)
  625. {
  626. ulong dstDescAddress = clientMsg.DramAddress + offset * 4;
  627. KernelContext.Memory.Write(dstDescAddress + 0, 0);
  628. KernelContext.Memory.Write(dstDescAddress + 4, 0);
  629. KernelContext.Memory.Write(dstDescAddress + 8, 0);
  630. offset += 3;
  631. }
  632. // Copy raw data.
  633. if (serverHeader.RawDataSizeInWords != 0)
  634. {
  635. ulong copyDst = clientMsg.Address + offset * 4;
  636. ulong copySrc = serverMsg.Address + offset * 4;
  637. ulong copySize = serverHeader.RawDataSizeInWords * 4;
  638. if (serverMsg.IsCustom || clientMsg.IsCustom)
  639. {
  640. MemoryPermission permission = clientMsg.IsCustom
  641. ? MemoryPermission.None
  642. : MemoryPermission.Read;
  643. clientResult = clientProcess.MemoryManager.CopyDataFromCurrentProcess(
  644. copyDst,
  645. copySize,
  646. MemoryState.IsPoolAllocated,
  647. MemoryState.IsPoolAllocated,
  648. permission,
  649. MemoryAttribute.Uncached,
  650. MemoryAttribute.None,
  651. copySrc);
  652. }
  653. else
  654. {
  655. copyDst = clientProcess.MemoryManager.GetDramAddressFromVa(copyDst);
  656. copySrc = serverProcess.MemoryManager.GetDramAddressFromVa(copySrc);
  657. KernelContext.Memory.Copy(copyDst, copySrc, copySize);
  658. }
  659. }
  660. // Unmap buffers from server.
  661. FinishRequest(request, clientResult);
  662. return serverResult;
  663. }
  664. private MessageHeader GetClientMessageHeader(Message clientMsg)
  665. {
  666. uint word0 = KernelContext.Memory.Read<uint>(clientMsg.DramAddress + 0);
  667. uint word1 = KernelContext.Memory.Read<uint>(clientMsg.DramAddress + 4);
  668. uint word2 = KernelContext.Memory.Read<uint>(clientMsg.DramAddress + 8);
  669. return new MessageHeader(word0, word1, word2);
  670. }
  671. private MessageHeader GetServerMessageHeader(Message serverMsg)
  672. {
  673. KProcess currentProcess = KernelContext.Scheduler.GetCurrentProcess();
  674. uint word0 = currentProcess.CpuMemory.Read<uint>(serverMsg.Address + 0);
  675. uint word1 = currentProcess.CpuMemory.Read<uint>(serverMsg.Address + 4);
  676. uint word2 = currentProcess.CpuMemory.Read<uint>(serverMsg.Address + 8);
  677. return new MessageHeader(word0, word1, word2);
  678. }
  679. private KernelResult GetCopyObjectHandle(
  680. KThread srcThread,
  681. KProcess dstProcess,
  682. int srcHandle,
  683. out int dstHandle)
  684. {
  685. dstHandle = 0;
  686. KProcess srcProcess = srcThread.Owner;
  687. KAutoObject obj;
  688. if (srcHandle == KHandleTable.SelfProcessHandle)
  689. {
  690. obj = srcProcess;
  691. }
  692. else if (srcHandle == KHandleTable.SelfThreadHandle)
  693. {
  694. obj = srcThread;
  695. }
  696. else
  697. {
  698. obj = srcProcess.HandleTable.GetObject<KAutoObject>(srcHandle);
  699. }
  700. if (obj != null)
  701. {
  702. return dstProcess.HandleTable.GenerateHandle(obj, out dstHandle);
  703. }
  704. else
  705. {
  706. return KernelResult.InvalidHandle;
  707. }
  708. }
  709. private KernelResult GetMoveObjectHandle(
  710. KProcess srcProcess,
  711. KProcess dstProcess,
  712. int srcHandle,
  713. out int dstHandle)
  714. {
  715. dstHandle = 0;
  716. KAutoObject obj = srcProcess.HandleTable.GetObject<KAutoObject>(srcHandle);
  717. if (obj != null)
  718. {
  719. KernelResult result = dstProcess.HandleTable.GenerateHandle(obj, out dstHandle);
  720. srcProcess.HandleTable.CloseHandle(srcHandle);
  721. return result;
  722. }
  723. else
  724. {
  725. return KernelResult.InvalidHandle;
  726. }
  727. }
  728. private ulong[] GetReceiveList(Message message, uint recvListType, uint recvListOffset)
  729. {
  730. int recvListSize = 0;
  731. if (recvListType >= 3)
  732. {
  733. recvListSize = (int)recvListType - 2;
  734. }
  735. else if (recvListType == 2)
  736. {
  737. recvListSize = 1;
  738. }
  739. ulong[] receiveList = new ulong[recvListSize];
  740. ulong recvListAddress = message.DramAddress + recvListOffset;
  741. for (int index = 0; index < recvListSize; index++)
  742. {
  743. receiveList[index] = KernelContext.Memory.Read<ulong>(recvListAddress + (ulong)index * 8);
  744. }
  745. return receiveList;
  746. }
  747. private KernelResult GetReceiveListAddress(
  748. PointerBufferDesc descriptor,
  749. Message message,
  750. uint recvListType,
  751. uint messageSizeInWords,
  752. ulong[] receiveList,
  753. ref uint dstOffset,
  754. out ulong address)
  755. {
  756. ulong recvListBufferAddress = address = 0;
  757. if (recvListType == 0)
  758. {
  759. return KernelResult.OutOfResource;
  760. }
  761. else if (recvListType == 1 || recvListType == 2)
  762. {
  763. ulong recvListBaseAddr;
  764. ulong recvListEndAddr;
  765. if (recvListType == 1)
  766. {
  767. recvListBaseAddr = message.Address + messageSizeInWords * 4;
  768. recvListEndAddr = message.Address + message.Size;
  769. }
  770. else /* if (recvListType == 2) */
  771. {
  772. ulong packed = receiveList[0];
  773. recvListBaseAddr = packed & 0x7fffffffff;
  774. uint size = (uint)(packed >> 48);
  775. if (size == 0)
  776. {
  777. return KernelResult.OutOfResource;
  778. }
  779. recvListEndAddr = recvListBaseAddr + size;
  780. }
  781. recvListBufferAddress = BitUtils.AlignUp(recvListBaseAddr + dstOffset, 0x10);
  782. ulong endAddress = recvListBufferAddress + descriptor.BufferSize;
  783. dstOffset = (uint)endAddress - (uint)recvListBaseAddr;
  784. if (recvListBufferAddress + descriptor.BufferSize <= recvListBufferAddress ||
  785. recvListBufferAddress + descriptor.BufferSize > recvListEndAddr)
  786. {
  787. return KernelResult.OutOfResource;
  788. }
  789. }
  790. else /* if (recvListType > 2) */
  791. {
  792. if (descriptor.ReceiveIndex >= receiveList.Length)
  793. {
  794. return KernelResult.OutOfResource;
  795. }
  796. ulong packed = receiveList[descriptor.ReceiveIndex];
  797. recvListBufferAddress = packed & 0x7fffffffff;
  798. uint size = (uint)(packed >> 48);
  799. if (recvListBufferAddress == 0 || size == 0 || size < descriptor.BufferSize)
  800. {
  801. return KernelResult.OutOfResource;
  802. }
  803. }
  804. address = recvListBufferAddress;
  805. return KernelResult.Success;
  806. }
  807. private void CloseAllHandles(Message message, MessageHeader header, KProcess process)
  808. {
  809. if (header.HasHandles)
  810. {
  811. uint totalHandeslCount = header.CopyHandlesCount + header.MoveHandlesCount;
  812. uint offset = 3;
  813. if (header.HasPid)
  814. {
  815. process.CpuMemory.Write(message.Address + offset * 4, 0L);
  816. offset += 2;
  817. }
  818. for (int index = 0; index < totalHandeslCount; index++)
  819. {
  820. int handle = process.CpuMemory.Read<int>(message.Address + offset * 4);
  821. if (handle != 0)
  822. {
  823. process.HandleTable.CloseHandle(handle);
  824. process.CpuMemory.Write(message.Address + offset * 4, 0);
  825. }
  826. offset++;
  827. }
  828. }
  829. }
  830. public override bool IsSignaled()
  831. {
  832. if (_parent.ClientSession.State != ChannelState.Open)
  833. {
  834. return true;
  835. }
  836. return _requests.Count != 0 && _activeRequest == null;
  837. }
  838. protected override void Destroy()
  839. {
  840. _parent.DisconnectServer();
  841. CancelAllRequestsServerDisconnected();
  842. _parent.DecrementReferenceCount();
  843. }
  844. private void CancelAllRequestsServerDisconnected()
  845. {
  846. foreach (KSessionRequest request in IterateWithRemovalOfAllRequests())
  847. {
  848. FinishRequest(request, KernelResult.PortRemoteClosed);
  849. }
  850. }
  851. public void CancelAllRequestsClientDisconnected()
  852. {
  853. foreach (KSessionRequest request in IterateWithRemovalOfAllRequests())
  854. {
  855. if (request.ClientThread.ShallBeTerminated ||
  856. request.ClientThread.SchedFlags == ThreadSchedState.TerminationPending)
  857. {
  858. continue;
  859. }
  860. // Client sessions can only be disconnected on async requests (because
  861. // the client would be otherwise blocked waiting for the response), so
  862. // we only need to handle the async case here.
  863. if (request.AsyncEvent != null)
  864. {
  865. SendResultToAsyncRequestClient(request, KernelResult.PortRemoteClosed);
  866. }
  867. }
  868. WakeServerThreads(KernelResult.PortRemoteClosed);
  869. }
  870. private IEnumerable<KSessionRequest> IterateWithRemovalOfAllRequests()
  871. {
  872. KernelContext.CriticalSection.Enter();
  873. if (_activeRequest != null)
  874. {
  875. KSessionRequest request = _activeRequest;
  876. _activeRequest = null;
  877. KernelContext.CriticalSection.Leave();
  878. yield return request;
  879. }
  880. else
  881. {
  882. KernelContext.CriticalSection.Leave();
  883. }
  884. while (DequeueRequest(out KSessionRequest request))
  885. {
  886. yield return request;
  887. }
  888. }
  889. private bool DequeueRequest(out KSessionRequest request)
  890. {
  891. request = null;
  892. KernelContext.CriticalSection.Enter();
  893. bool hasRequest = _requests.First != null;
  894. if (hasRequest)
  895. {
  896. request = _requests.First.Value;
  897. _requests.RemoveFirst();
  898. }
  899. KernelContext.CriticalSection.Leave();
  900. return hasRequest;
  901. }
  902. private void FinishRequest(KSessionRequest request, KernelResult result)
  903. {
  904. KProcess clientProcess = request.ClientThread.Owner;
  905. KProcess serverProcess = request.ServerProcess;
  906. KernelResult unmapResult = KernelResult.Success;
  907. if (serverProcess != null)
  908. {
  909. unmapResult = request.BufferDescriptorTable.UnmapServerBuffers(serverProcess.MemoryManager);
  910. }
  911. if (unmapResult == KernelResult.Success)
  912. {
  913. request.BufferDescriptorTable.RestoreClientBuffers(clientProcess.MemoryManager);
  914. }
  915. WakeClientThread(request, result);
  916. }
  917. private void WakeClientThread(KSessionRequest request, KernelResult result)
  918. {
  919. // Wait client thread waiting for a response for the given request.
  920. if (request.AsyncEvent != null)
  921. {
  922. SendResultToAsyncRequestClient(request, result);
  923. }
  924. else
  925. {
  926. KernelContext.CriticalSection.Enter();
  927. WakeAndSetResult(request.ClientThread, result);
  928. KernelContext.CriticalSection.Leave();
  929. }
  930. }
  931. private void SendResultToAsyncRequestClient(KSessionRequest request, KernelResult result)
  932. {
  933. KProcess clientProcess = request.ClientThread.Owner;
  934. if (result != KernelResult.Success)
  935. {
  936. ulong address = clientProcess.MemoryManager.GetDramAddressFromVa(request.CustomCmdBuffAddr);
  937. KernelContext.Memory.Write<ulong>(address, 0);
  938. KernelContext.Memory.Write(address + 8, (int)result);
  939. }
  940. clientProcess.MemoryManager.UnborrowIpcBuffer(request.CustomCmdBuffAddr, request.CustomCmdBuffSize);
  941. request.AsyncEvent.Signal();
  942. }
  943. private void WakeServerThreads(KernelResult result)
  944. {
  945. // Wake all server threads waiting for requests.
  946. KernelContext.CriticalSection.Enter();
  947. foreach (KThread thread in WaitingThreads)
  948. {
  949. WakeAndSetResult(thread, result);
  950. }
  951. KernelContext.CriticalSection.Leave();
  952. }
  953. private void WakeAndSetResult(KThread thread, KernelResult result)
  954. {
  955. if ((thread.SchedFlags & ThreadSchedState.LowMask) == ThreadSchedState.Paused)
  956. {
  957. thread.SignaledObj = null;
  958. thread.ObjSyncResult = result;
  959. thread.Reschedule(ThreadSchedState.Running);
  960. }
  961. }
  962. }
  963. }