hv.m 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. // Decompiled by hand (based-ish on a Ghidra decompile) from Hypervisor.framework on macOS 12.0b1
  2. @import Darwin;
  3. #include <Hypervisor/Hypervisor.h>
  4. #include <assert.h>
  5. #include "hv_kernel_structs.h"
  6. #if NO_HVF_HEADER
  7. @protocol OS_hv_vcpu_config;
  8. @class NSObject;
  9. typedef kern_return_t hv_return_t;
  10. typedef void* hv_vm_config_t;
  11. typedef uint64_t hv_ipa_t;
  12. typedef uint64_t hv_vcpu_t;
  13. typedef uint64_t hv_exception_syndrome_t;
  14. typedef uint64_t hv_exception_address_t;
  15. typedef uint64_t hv_exit_reason_t;
  16. typedef NSObject<OS_hv_vcpu_config>* hv_vcpu_config_t;
  17. typedef uint64_t hv_memory_flags_t;
  18. #define HV_BAD_ARGUMENT 0xfae94003;
  19. #define HV_UNSUPPORTED 0xfae9400f;
  20. // from hv_vcpu_types.h
  21. typedef struct hv_vcpu_exit_exception {
  22. hv_exception_syndrome_t syndrome;
  23. hv_exception_address_t virtual_address;
  24. hv_ipa_t physical_address;
  25. } hv_vcpu_exit_exception_t;
  26. typedef struct hv_vcpu_exit {
  27. hv_exit_reason_t reason;
  28. hv_vcpu_exit_exception_t exception;
  29. } hv_vcpu_exit_t;
  30. #endif // NO_HVF_HEADER
  31. static_assert(sizeof(hv_vcpu_exit_t) == 0x20, "hv_vcpu_exit");
  32. #define HV_CALL_VM_GET_CAPABILITIES 0
  33. #define HV_CALL_VM_CREATE 1
  34. #define HV_CALL_VM_MAP 3
  35. #define HV_CALL_VCPU_CREATE 6
  36. #define HV_CALL_VCPU_DESTROY 7
  37. #define HV_CALL_VCPU_DIRTY_BANKED_STATE 8
  38. #define HV_CALL_VCPU_RUN 9
  39. __attribute__((naked)) uint64_t hv_trap(unsigned int hv_call, void* hv_arg) {
  40. asm volatile("mov x16, #-0x5\n"
  41. "svc 0x80\n"
  42. "ret\n");
  43. }
  44. // type lookup hv_vm_create_t
  45. struct hv_vm_create_kernel_args {
  46. uint64_t min_ipa;
  47. uint64_t ipa_size;
  48. uint32_t granule;
  49. uint32_t flags;
  50. uint32_t isa;
  51. };
  52. static_assert(sizeof(struct hv_vm_create_kernel_args) == 0x20, "hv_vm_create_kernel_args size");
  53. const struct hv_vm_create_kernel_args kDefaultVmCreateKernelArgs = {
  54. .min_ipa = 0,
  55. .ipa_size = 0,
  56. .granule = 0,
  57. .flags = 0,
  58. .isa = 1,
  59. };
  60. hv_return_t hv_vm_create(hv_vm_config_t config) {
  61. struct hv_vm_create_kernel_args args = kDefaultVmCreateKernelArgs;
  62. if (config) {
  63. // TODO(zhuowei): figure this out?
  64. }
  65. return hv_trap(HV_CALL_VM_CREATE, &args);
  66. }
  67. struct hv_vm_map_kernel_args {
  68. void* addr; // 0x0
  69. hv_ipa_t ipa; // 0x8
  70. size_t size; // 0x10
  71. hv_memory_flags_t flags; // 0x18
  72. uint64_t padding; // 0x20
  73. };
  74. hv_return_t hv_vm_map(void* addr, hv_ipa_t ipa, size_t size, hv_memory_flags_t flags) {
  75. struct hv_vm_map_kernel_args args = {
  76. .addr = addr, .ipa = ipa, .size = size, .flags = flags, .padding = 0};
  77. return hv_trap(HV_CALL_VM_MAP, &args);
  78. }
  79. static pthread_mutex_t vcpus_mutex = PTHREAD_MUTEX_INITIALIZER;
  80. struct hv_vcpu_zone {
  81. arm_guest_rw_context_t rw;
  82. arm_guest_ro_context_t ro;
  83. };
  84. static_assert(sizeof(struct hv_vcpu_zone) == 0x8000, "hv_vcpu_zone");
  85. struct hv_vcpu_data {
  86. struct hv_vcpu_zone* vcpu_zone; // 0x0
  87. // TODO(zhuowei)
  88. char filler[0xf0 - 0x8]; // 0x8
  89. hv_vcpu_exit_t exit; // 0xf0
  90. char filler2[0x8]; // 0x110
  91. };
  92. static_assert(sizeof(struct hv_vcpu_data) == 0x118, "hv_vcpu_data");
  93. static const size_t kHvMaxVcpus = 0x40;
  94. static struct hv_vcpu_data vcpus[kHvMaxVcpus];
  95. struct hv_vcpu_create_kernel_args {
  96. uint64_t always_zero; // 0x0
  97. struct hv_vcpu_zone* output_vcpu_zone; // 0x8
  98. };
  99. // ' hyp', 0xe
  100. static const uint64_t kHvVcpuMagic = 0x206879700000000eull;
  101. hv_return_t hv_vcpu_create(hv_vcpu_t* vcpu, hv_vcpu_exit_t** exit, hv_vcpu_config_t config) {
  102. pthread_mutex_lock(&vcpus_mutex);
  103. // TODO(zhuowei): support more than one
  104. struct hv_vcpu_data* vcpu_data = &vcpus[0];
  105. struct hv_vcpu_create_kernel_args args = {
  106. .always_zero = 0,
  107. .output_vcpu_zone = 0,
  108. };
  109. kern_return_t err = hv_trap(HV_CALL_VCPU_CREATE, &args);
  110. if (err) {
  111. pthread_mutex_unlock(&vcpus_mutex);
  112. return err;
  113. }
  114. printf("vcpu_zone = %p\n", args.output_vcpu_zone);
  115. if (args.output_vcpu_zone->ro.ver != kHvVcpuMagic) {
  116. hv_trap(HV_CALL_VCPU_DESTROY, nil);
  117. pthread_mutex_unlock(&vcpus_mutex);
  118. return HV_UNSUPPORTED;
  119. }
  120. vcpu_data->vcpu_zone = args.output_vcpu_zone;
  121. *vcpu = 0; // TODO(zhuowei)
  122. *exit = &vcpu_data->exit;
  123. pthread_mutex_unlock(&vcpus_mutex);
  124. // TODO(zhuowei): configure regs
  125. return 0;
  126. }
  127. hv_return_t hv_vcpu_run(hv_vcpu_t vcpu) {
  128. // TODO(zhuowei): update registers
  129. struct hv_vcpu_data* vcpu_data = &vcpus[0];
  130. hv_return_t err = hv_trap(HV_CALL_VCPU_RUN, nil);
  131. if (err) {
  132. return err;
  133. }
  134. printf("exit = %d\n", vcpu_data->vcpu_zone->ro.exit.vmexit_reason);
  135. return 0;
  136. }
  137. hv_return_t hv_vcpu_get_reg(hv_vcpu_t vcpu, hv_reg_t reg, uint64_t* value) {
  138. if (reg > HV_REG_CPSR) {
  139. return HV_BAD_ARGUMENT;
  140. }
  141. struct hv_vcpu_zone* vcpu_zone = vcpus[vcpu].vcpu_zone;
  142. // TODO(zhuowei): lr, pc
  143. if (reg <= HV_REG_X30) {
  144. *value = vcpu_zone->rw.regs.x[reg];
  145. } else if (reg == HV_REG_FPCR) {
  146. *value = vcpu_zone->rw.neon.fpcr;
  147. } else if (reg == HV_REG_FPSR) {
  148. *value = vcpu_zone->rw.neon.fpsr;
  149. } else if (reg == HV_REG_CPSR) {
  150. *value = vcpu_zone->rw.regs.cpsr;
  151. }
  152. return 0;
  153. }
  154. int main() {
  155. hv_return_t err = hv_vm_create(nil);
  156. printf("%x\n", err);
  157. hv_vcpu_t cpu = 0;
  158. hv_vcpu_exit_t* exit = nil;
  159. err = hv_vcpu_create(&cpu, &exit, nil);
  160. printf("%x\n", err);
  161. err = hv_vcpu_run(cpu);
  162. printf("%x\n", err);
  163. }