HvAddressSpace.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. using Ryujinx.Cpu.AppleHv.Arm;
  2. using Ryujinx.Memory;
  3. using System;
  4. namespace Ryujinx.Cpu.AppleHv
  5. {
  6. class HvAddressSpace : IDisposable
  7. {
  8. private const ulong KernelRegionBase = unchecked((ulong)-(1L << 39));
  9. private const ulong KernelRegionCodeOffset = 0UL;
  10. private const ulong KernelRegionCodeSize = 0x2000UL;
  11. private const ulong KernelRegionTlbiEretOffset = KernelRegionCodeOffset + 0x1000UL;
  12. private const ulong KernelRegionEretOffset = KernelRegionTlbiEretOffset + 4UL;
  13. public const ulong KernelRegionEretAddress = KernelRegionBase + KernelRegionEretOffset;
  14. public const ulong KernelRegionTlbiEretAddress = KernelRegionBase + KernelRegionTlbiEretOffset;
  15. private const ulong AllocationGranule = 1UL << 14;
  16. private readonly ulong _asBase;
  17. private readonly ulong _asSize;
  18. private readonly ulong _backingSize;
  19. private readonly HvAddressSpaceRange _userRange;
  20. private readonly HvAddressSpaceRange _kernelRange;
  21. private MemoryBlock _kernelCodeBlock;
  22. public HvAddressSpace(MemoryBlock backingMemory, ulong asSize)
  23. {
  24. (_asBase, var ipaAllocator) = HvVm.CreateAddressSpace(backingMemory);
  25. _asSize = asSize;
  26. _backingSize = backingMemory.Size;
  27. _userRange = new HvAddressSpaceRange(ipaAllocator);
  28. _kernelRange = new HvAddressSpaceRange(ipaAllocator);
  29. _kernelCodeBlock = new MemoryBlock(AllocationGranule);
  30. InitializeKernelCode(ipaAllocator);
  31. }
  32. private void InitializeKernelCode(HvIpaAllocator ipaAllocator)
  33. {
  34. // Write exception handlers.
  35. for (ulong offset = 0; offset < 0x800; offset += 0x80)
  36. {
  37. // Offsets:
  38. // 0x0: Synchronous
  39. // 0x80: IRQ
  40. // 0x100: FIQ
  41. // 0x180: SError
  42. _kernelCodeBlock.Write(KernelRegionCodeOffset + offset, 0xD41FFFE2u); // HVC #0xFFFF
  43. _kernelCodeBlock.Write(KernelRegionCodeOffset + offset + 4, 0xD69F03E0u); // ERET
  44. }
  45. _kernelCodeBlock.Write(KernelRegionTlbiEretOffset, 0xD508831Fu); // TLBI VMALLE1IS
  46. _kernelCodeBlock.Write(KernelRegionEretOffset, 0xD69F03E0u); // ERET
  47. ulong kernelCodePa = ipaAllocator.Allocate(AllocationGranule);
  48. HvApi.hv_vm_map((ulong)_kernelCodeBlock.Pointer, kernelCodePa, AllocationGranule, hv_memory_flags_t.HV_MEMORY_READ | hv_memory_flags_t.HV_MEMORY_EXEC).ThrowOnError();
  49. _kernelRange.Map(KernelRegionCodeOffset, kernelCodePa, KernelRegionCodeSize, ApFlags.UserNoneKernelReadExecute);
  50. }
  51. public void InitializeMmu(ulong vcpu)
  52. {
  53. HvApi.hv_vcpu_set_sys_reg(vcpu, hv_sys_reg_t.HV_SYS_REG_VBAR_EL1, KernelRegionBase + KernelRegionCodeOffset);
  54. HvApi.hv_vcpu_set_sys_reg(vcpu, hv_sys_reg_t.HV_SYS_REG_TTBR0_EL1, _userRange.GetIpaBase());
  55. HvApi.hv_vcpu_set_sys_reg(vcpu, hv_sys_reg_t.HV_SYS_REG_TTBR1_EL1, _kernelRange.GetIpaBase());
  56. HvApi.hv_vcpu_set_sys_reg(vcpu, hv_sys_reg_t.HV_SYS_REG_MAIR_EL1, 0xffUL);
  57. HvApi.hv_vcpu_set_sys_reg(vcpu, hv_sys_reg_t.HV_SYS_REG_TCR_EL1, 0x00000011B5193519UL);
  58. HvApi.hv_vcpu_set_sys_reg(vcpu, hv_sys_reg_t.HV_SYS_REG_SCTLR_EL1, 0x0000000034D5D925UL);
  59. }
  60. public bool GetAndClearUserTlbInvalidationPending()
  61. {
  62. return _userRange.GetAndClearTlbInvalidationPending();
  63. }
  64. public void MapUser(ulong va, ulong pa, ulong size, MemoryPermission permission)
  65. {
  66. pa += _asBase;
  67. lock (_userRange)
  68. {
  69. _userRange.Map(va, pa, size, GetApFlags(permission));
  70. }
  71. }
  72. public void UnmapUser(ulong va, ulong size)
  73. {
  74. lock (_userRange)
  75. {
  76. _userRange.Unmap(va, size);
  77. }
  78. }
  79. public void ReprotectUser(ulong va, ulong size, MemoryPermission permission)
  80. {
  81. lock (_userRange)
  82. {
  83. _userRange.Reprotect(va, size, GetApFlags(permission));
  84. }
  85. }
  86. private static ApFlags GetApFlags(MemoryPermission permission)
  87. {
  88. return permission switch
  89. {
  90. MemoryPermission.None => ApFlags.UserNoneKernelRead,
  91. MemoryPermission.Execute => ApFlags.UserExecuteKernelRead,
  92. MemoryPermission.Read => ApFlags.UserReadKernelRead,
  93. MemoryPermission.ReadAndWrite => ApFlags.UserReadWriteKernelReadWrite,
  94. MemoryPermission.ReadAndExecute => ApFlags.UserReadExecuteKernelRead,
  95. MemoryPermission.ReadWriteExecute => ApFlags.UserReadWriteExecuteKernelReadWrite,
  96. _ => throw new ArgumentException($"Permission \"{permission}\" is invalid.")
  97. };
  98. }
  99. public void Dispose()
  100. {
  101. _userRange.Dispose();
  102. _kernelRange.Dispose();
  103. HvVm.DestroyAddressSpace(_asBase, _backingSize);
  104. }
  105. }
  106. }