KServerSession.cs 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260
  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. CancelRequest(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. if (descriptor.BufferSize != 0)
  580. {
  581. clientResult = GetReceiveListAddress(
  582. descriptor,
  583. clientMsg,
  584. clientHeader.ReceiveListType,
  585. serverHeader.MessageSizeInWords,
  586. receiveList,
  587. ref recvListDstOffset,
  588. out ulong recvListBufferAddress);
  589. if (clientResult != KernelResult.Success)
  590. {
  591. CleanUpForError();
  592. return serverResult;
  593. }
  594. clientResult = clientProcess.MemoryManager.CopyDataFromCurrentProcess(
  595. recvListBufferAddress,
  596. descriptor.BufferSize,
  597. MemoryState.IsPoolAllocated,
  598. MemoryState.IsPoolAllocated,
  599. MemoryPermission.Read,
  600. MemoryAttribute.Uncached,
  601. MemoryAttribute.None,
  602. descriptor.BufferAddress);
  603. if (clientResult != KernelResult.Success)
  604. {
  605. CleanUpForError();
  606. return serverResult;
  607. }
  608. }
  609. offset += 2;
  610. }
  611. // Set send, receive and exchange buffer descriptors to zero.
  612. uint totalBuffersCount =
  613. serverHeader.SendBuffersCount +
  614. serverHeader.ReceiveBuffersCount +
  615. serverHeader.ExchangeBuffersCount;
  616. for (int index = 0; index < totalBuffersCount; index++)
  617. {
  618. ulong dstDescAddress = clientMsg.DramAddress + offset * 4;
  619. KernelContext.Memory.Write(dstDescAddress + 0, 0);
  620. KernelContext.Memory.Write(dstDescAddress + 4, 0);
  621. KernelContext.Memory.Write(dstDescAddress + 8, 0);
  622. offset += 3;
  623. }
  624. // Copy raw data.
  625. if (serverHeader.RawDataSizeInWords != 0)
  626. {
  627. ulong copyDst = clientMsg.Address + offset * 4;
  628. ulong copySrc = serverMsg.Address + offset * 4;
  629. ulong copySize = serverHeader.RawDataSizeInWords * 4;
  630. if (serverMsg.IsCustom || clientMsg.IsCustom)
  631. {
  632. MemoryPermission permission = clientMsg.IsCustom
  633. ? MemoryPermission.None
  634. : MemoryPermission.Read;
  635. clientResult = clientProcess.MemoryManager.CopyDataFromCurrentProcess(
  636. copyDst,
  637. copySize,
  638. MemoryState.IsPoolAllocated,
  639. MemoryState.IsPoolAllocated,
  640. permission,
  641. MemoryAttribute.Uncached,
  642. MemoryAttribute.None,
  643. copySrc);
  644. }
  645. else
  646. {
  647. copyDst = clientProcess.MemoryManager.GetDramAddressFromVa(copyDst);
  648. copySrc = serverProcess.MemoryManager.GetDramAddressFromVa(copySrc);
  649. KernelContext.Memory.Copy(copyDst, copySrc, copySize);
  650. }
  651. }
  652. // Unmap buffers from server.
  653. clientResult = request.BufferDescriptorTable.UnmapServerBuffers(serverProcess.MemoryManager);
  654. if (clientResult != KernelResult.Success)
  655. {
  656. CleanUpForError();
  657. return serverResult;
  658. }
  659. WakeClientThread(request, clientResult);
  660. return serverResult;
  661. }
  662. private MessageHeader GetClientMessageHeader(Message clientMsg)
  663. {
  664. uint word0 = KernelContext.Memory.Read<uint>(clientMsg.DramAddress + 0);
  665. uint word1 = KernelContext.Memory.Read<uint>(clientMsg.DramAddress + 4);
  666. uint word2 = KernelContext.Memory.Read<uint>(clientMsg.DramAddress + 8);
  667. return new MessageHeader(word0, word1, word2);
  668. }
  669. private MessageHeader GetServerMessageHeader(Message serverMsg)
  670. {
  671. KProcess currentProcess = KernelContext.Scheduler.GetCurrentProcess();
  672. uint word0 = currentProcess.CpuMemory.Read<uint>(serverMsg.Address + 0);
  673. uint word1 = currentProcess.CpuMemory.Read<uint>(serverMsg.Address + 4);
  674. uint word2 = currentProcess.CpuMemory.Read<uint>(serverMsg.Address + 8);
  675. return new MessageHeader(word0, word1, word2);
  676. }
  677. private KernelResult GetCopyObjectHandle(
  678. KThread srcThread,
  679. KProcess dstProcess,
  680. int srcHandle,
  681. out int dstHandle)
  682. {
  683. dstHandle = 0;
  684. KProcess srcProcess = srcThread.Owner;
  685. KAutoObject obj;
  686. if (srcHandle == KHandleTable.SelfProcessHandle)
  687. {
  688. obj = srcProcess;
  689. }
  690. else if (srcHandle == KHandleTable.SelfThreadHandle)
  691. {
  692. obj = srcThread;
  693. }
  694. else
  695. {
  696. obj = srcProcess.HandleTable.GetObject<KAutoObject>(srcHandle);
  697. }
  698. if (obj != null)
  699. {
  700. return dstProcess.HandleTable.GenerateHandle(obj, out dstHandle);
  701. }
  702. else
  703. {
  704. return KernelResult.InvalidHandle;
  705. }
  706. }
  707. private KernelResult GetMoveObjectHandle(
  708. KProcess srcProcess,
  709. KProcess dstProcess,
  710. int srcHandle,
  711. out int dstHandle)
  712. {
  713. dstHandle = 0;
  714. KAutoObject obj = srcProcess.HandleTable.GetObject<KAutoObject>(srcHandle);
  715. if (obj != null)
  716. {
  717. KernelResult result = dstProcess.HandleTable.GenerateHandle(obj, out dstHandle);
  718. srcProcess.HandleTable.CloseHandle(srcHandle);
  719. return result;
  720. }
  721. else
  722. {
  723. return KernelResult.InvalidHandle;
  724. }
  725. }
  726. private ulong[] GetReceiveList(Message message, uint recvListType, uint recvListOffset)
  727. {
  728. int recvListSize = 0;
  729. if (recvListType >= 3)
  730. {
  731. recvListSize = (int)recvListType - 2;
  732. }
  733. else if (recvListType == 2)
  734. {
  735. recvListSize = 1;
  736. }
  737. ulong[] receiveList = new ulong[recvListSize];
  738. ulong recvListAddress = message.DramAddress + recvListOffset;
  739. for (int index = 0; index < recvListSize; index++)
  740. {
  741. receiveList[index] = KernelContext.Memory.Read<ulong>(recvListAddress + (ulong)index * 8);
  742. }
  743. return receiveList;
  744. }
  745. private KernelResult GetReceiveListAddress(
  746. PointerBufferDesc descriptor,
  747. Message message,
  748. uint recvListType,
  749. uint messageSizeInWords,
  750. ulong[] receiveList,
  751. ref uint dstOffset,
  752. out ulong address)
  753. {
  754. ulong recvListBufferAddress = address = 0;
  755. if (recvListType == 0)
  756. {
  757. return KernelResult.OutOfResource;
  758. }
  759. else if (recvListType == 1 || recvListType == 2)
  760. {
  761. ulong recvListBaseAddr;
  762. ulong recvListEndAddr;
  763. if (recvListType == 1)
  764. {
  765. recvListBaseAddr = message.Address + messageSizeInWords * 4;
  766. recvListEndAddr = message.Address + message.Size;
  767. }
  768. else /* if (recvListType == 2) */
  769. {
  770. ulong packed = receiveList[0];
  771. recvListBaseAddr = packed & 0x7fffffffff;
  772. uint size = (uint)(packed >> 48);
  773. if (size == 0)
  774. {
  775. return KernelResult.OutOfResource;
  776. }
  777. recvListEndAddr = recvListBaseAddr + size;
  778. }
  779. recvListBufferAddress = BitUtils.AlignUp(recvListBaseAddr + dstOffset, 0x10);
  780. ulong endAddress = recvListBufferAddress + descriptor.BufferSize;
  781. dstOffset = (uint)endAddress - (uint)recvListBaseAddr;
  782. if (recvListBufferAddress + descriptor.BufferSize <= recvListBufferAddress ||
  783. recvListBufferAddress + descriptor.BufferSize > recvListEndAddr)
  784. {
  785. return KernelResult.OutOfResource;
  786. }
  787. }
  788. else /* if (recvListType > 2) */
  789. {
  790. if (descriptor.ReceiveIndex >= receiveList.Length)
  791. {
  792. return KernelResult.OutOfResource;
  793. }
  794. ulong packed = receiveList[descriptor.ReceiveIndex];
  795. recvListBufferAddress = packed & 0x7fffffffff;
  796. uint size = (uint)(packed >> 48);
  797. if (recvListBufferAddress == 0 || size == 0 || size < descriptor.BufferSize)
  798. {
  799. return KernelResult.OutOfResource;
  800. }
  801. }
  802. address = recvListBufferAddress;
  803. return KernelResult.Success;
  804. }
  805. private void CloseAllHandles(Message message, MessageHeader header, KProcess process)
  806. {
  807. if (header.HasHandles)
  808. {
  809. uint totalHandeslCount = header.CopyHandlesCount + header.MoveHandlesCount;
  810. uint offset = 3;
  811. if (header.HasPid)
  812. {
  813. process.CpuMemory.Write(message.Address + offset * 4, 0L);
  814. offset += 2;
  815. }
  816. for (int index = 0; index < totalHandeslCount; index++)
  817. {
  818. int handle = process.CpuMemory.Read<int>(message.Address + offset * 4);
  819. if (handle != 0)
  820. {
  821. process.HandleTable.CloseHandle(handle);
  822. process.CpuMemory.Write(message.Address + offset * 4, 0);
  823. }
  824. offset++;
  825. }
  826. }
  827. }
  828. public override bool IsSignaled()
  829. {
  830. if (_parent.ClientSession.State != ChannelState.Open)
  831. {
  832. return true;
  833. }
  834. return _requests.Count != 0 && _activeRequest == null;
  835. }
  836. protected override void Destroy()
  837. {
  838. _parent.DisconnectServer();
  839. CancelAllRequestsServerDisconnected();
  840. _parent.DecrementReferenceCount();
  841. }
  842. private void CancelAllRequestsServerDisconnected()
  843. {
  844. foreach (KSessionRequest request in IterateWithRemovalOfAllRequests())
  845. {
  846. CancelRequest(request, KernelResult.PortRemoteClosed);
  847. }
  848. }
  849. public void CancelAllRequestsClientDisconnected()
  850. {
  851. foreach (KSessionRequest request in IterateWithRemovalOfAllRequests())
  852. {
  853. if (request.ClientThread.ShallBeTerminated ||
  854. request.ClientThread.SchedFlags == ThreadSchedState.TerminationPending)
  855. {
  856. continue;
  857. }
  858. // Client sessions can only be disconnected on async requests (because
  859. // the client would be otherwise blocked waiting for the response), so
  860. // we only need to handle the async case here.
  861. if (request.AsyncEvent != null)
  862. {
  863. SendResultToAsyncRequestClient(request, KernelResult.PortRemoteClosed);
  864. }
  865. }
  866. WakeServerThreads(KernelResult.PortRemoteClosed);
  867. }
  868. private IEnumerable<KSessionRequest> IterateWithRemovalOfAllRequests()
  869. {
  870. KernelContext.CriticalSection.Enter();
  871. if (_activeRequest != null)
  872. {
  873. KSessionRequest request = _activeRequest;
  874. _activeRequest = null;
  875. KernelContext.CriticalSection.Leave();
  876. yield return request;
  877. }
  878. else
  879. {
  880. KernelContext.CriticalSection.Leave();
  881. }
  882. while (DequeueRequest(out KSessionRequest request))
  883. {
  884. yield return request;
  885. }
  886. }
  887. private bool DequeueRequest(out KSessionRequest request)
  888. {
  889. request = null;
  890. KernelContext.CriticalSection.Enter();
  891. bool hasRequest = _requests.First != null;
  892. if (hasRequest)
  893. {
  894. request = _requests.First.Value;
  895. _requests.RemoveFirst();
  896. }
  897. KernelContext.CriticalSection.Leave();
  898. return hasRequest;
  899. }
  900. private void CancelRequest(KSessionRequest request, KernelResult result)
  901. {
  902. KProcess clientProcess = request.ClientThread.Owner;
  903. KProcess serverProcess = request.ServerProcess;
  904. KernelResult unmapResult = KernelResult.Success;
  905. if (serverProcess != null)
  906. {
  907. unmapResult = request.BufferDescriptorTable.UnmapServerBuffers(serverProcess.MemoryManager);
  908. }
  909. if (unmapResult == KernelResult.Success)
  910. {
  911. request.BufferDescriptorTable.RestoreClientBuffers(clientProcess.MemoryManager);
  912. }
  913. WakeClientThread(request, result);
  914. }
  915. private void WakeClientThread(KSessionRequest request, KernelResult result)
  916. {
  917. // Wait client thread waiting for a response for the given request.
  918. if (request.AsyncEvent != null)
  919. {
  920. SendResultToAsyncRequestClient(request, result);
  921. }
  922. else
  923. {
  924. KernelContext.CriticalSection.Enter();
  925. WakeAndSetResult(request.ClientThread, result);
  926. KernelContext.CriticalSection.Leave();
  927. }
  928. }
  929. private void SendResultToAsyncRequestClient(KSessionRequest request, KernelResult result)
  930. {
  931. KProcess clientProcess = request.ClientThread.Owner;
  932. ulong address = clientProcess.MemoryManager.GetDramAddressFromVa(request.CustomCmdBuffAddr);
  933. KernelContext.Memory.Write<ulong>(address, 0);
  934. KernelContext.Memory.Write(address + 8, (int)result);
  935. clientProcess.MemoryManager.UnborrowIpcBuffer(
  936. request.CustomCmdBuffAddr,
  937. request.CustomCmdBuffSize);
  938. request.AsyncEvent.Signal();
  939. }
  940. private void WakeServerThreads(KernelResult result)
  941. {
  942. // Wake all server threads waiting for requests.
  943. KernelContext.CriticalSection.Enter();
  944. foreach (KThread thread in WaitingThreads)
  945. {
  946. WakeAndSetResult(thread, result);
  947. }
  948. KernelContext.CriticalSection.Leave();
  949. }
  950. private void WakeAndSetResult(KThread thread, KernelResult result)
  951. {
  952. if ((thread.SchedFlags & ThreadSchedState.LowMask) == ThreadSchedState.Paused)
  953. {
  954. thread.SignaledObj = null;
  955. thread.ObjSyncResult = result;
  956. thread.Reschedule(ThreadSchedState.Running);
  957. }
  958. }
  959. }
  960. }