TimeSharedMemory.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. using System;
  2. using System.Runtime.InteropServices;
  3. using System.Threading;
  4. using Ryujinx.HLE.HOS.Kernel.Memory;
  5. using Ryujinx.HLE.HOS.Kernel.Threading;
  6. using Ryujinx.HLE.HOS.Services.Time.Clock;
  7. using Ryujinx.HLE.HOS.Services.Time.Types;
  8. using Ryujinx.HLE.Utilities;
  9. namespace Ryujinx.HLE.HOS.Services.Time
  10. {
  11. class TimeSharedMemory
  12. {
  13. private Switch _device;
  14. private KSharedMemory _sharedMemory;
  15. private long _timeSharedMemoryAddress;
  16. private int _timeSharedMemorySize;
  17. private const uint SteadyClockContextOffset = 0x00;
  18. private const uint LocalSystemClockContextOffset = 0x38;
  19. private const uint NetworkSystemClockContextOffset = 0x80;
  20. private const uint AutomaticCorrectionEnabledOffset = 0xC8;
  21. public void Initialize(Switch device, KSharedMemory sharedMemory, long timeSharedMemoryAddress, int timeSharedMemorySize)
  22. {
  23. _device = device;
  24. _sharedMemory = sharedMemory;
  25. _timeSharedMemoryAddress = timeSharedMemoryAddress;
  26. _timeSharedMemorySize = timeSharedMemorySize;
  27. // Clean the shared memory
  28. _device.Memory.FillWithZeros(_timeSharedMemoryAddress, _timeSharedMemorySize);
  29. }
  30. public KSharedMemory GetSharedMemory()
  31. {
  32. return _sharedMemory;
  33. }
  34. public void SetupStandardSteadyClock(KThread thread, UInt128 clockSourceId, TimeSpanType currentTimePoint)
  35. {
  36. TimeSpanType ticksTimeSpan;
  37. // As this may be called before the guest code, we support passing a null thread to make this api usable.
  38. if (thread == null)
  39. {
  40. ticksTimeSpan = TimeSpanType.FromSeconds(0);
  41. }
  42. else
  43. {
  44. ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0);
  45. }
  46. SteadyClockContext context = new SteadyClockContext
  47. {
  48. InternalOffset = (ulong)(currentTimePoint.NanoSeconds - ticksTimeSpan.NanoSeconds),
  49. ClockSourceId = clockSourceId
  50. };
  51. WriteObjectToSharedMemory(SteadyClockContextOffset, 4, context);
  52. }
  53. public void SetAutomaticCorrectionEnabled(bool isAutomaticCorrectionEnabled)
  54. {
  55. // We convert the bool to byte here as a bool in C# takes 4 bytes...
  56. WriteObjectToSharedMemory(AutomaticCorrectionEnabledOffset, 0, Convert.ToByte(isAutomaticCorrectionEnabled));
  57. }
  58. public void SetSteadyClockRawTimePoint(KThread thread, TimeSpanType currentTimePoint)
  59. {
  60. SteadyClockContext context = ReadObjectFromSharedMemory<SteadyClockContext>(SteadyClockContextOffset, 4);
  61. TimeSpanType ticksTimeSpan = TimeSpanType.FromTicks(thread.Context.CntpctEl0, thread.Context.CntfrqEl0);
  62. context.InternalOffset = (ulong)(currentTimePoint.NanoSeconds - ticksTimeSpan.NanoSeconds);
  63. WriteObjectToSharedMemory(SteadyClockContextOffset, 4, context);
  64. }
  65. public void UpdateLocalSystemClockContext(SystemClockContext context)
  66. {
  67. WriteObjectToSharedMemory(LocalSystemClockContextOffset, 4, context);
  68. }
  69. public void UpdateNetworkSystemClockContext(SystemClockContext context)
  70. {
  71. WriteObjectToSharedMemory(NetworkSystemClockContextOffset, 4, context);
  72. }
  73. private T ReadObjectFromSharedMemory<T>(long offset, long padding)
  74. {
  75. long indexOffset = _timeSharedMemoryAddress + offset;
  76. T result;
  77. uint index;
  78. uint possiblyNewIndex;
  79. do
  80. {
  81. index = _device.Memory.ReadUInt32(indexOffset);
  82. long objectOffset = indexOffset + 4 + padding + (index & 1) * Marshal.SizeOf<T>();
  83. result = _device.Memory.ReadStruct<T>(objectOffset);
  84. Thread.MemoryBarrier();
  85. possiblyNewIndex = _device.Memory.ReadUInt32(indexOffset);
  86. } while (index != possiblyNewIndex);
  87. return result;
  88. }
  89. private void WriteObjectToSharedMemory<T>(long offset, long padding, T value)
  90. {
  91. long indexOffset = _timeSharedMemoryAddress + offset;
  92. uint newIndex = _device.Memory.ReadUInt32(indexOffset) + 1;
  93. long objectOffset = indexOffset + 4 + padding + (newIndex & 1) * Marshal.SizeOf<T>();
  94. _device.Memory.WriteStruct(objectOffset, value);
  95. Thread.MemoryBarrier();
  96. _device.Memory.WriteUInt32(indexOffset, newIndex);
  97. }
  98. }
  99. }