Browse Source

hv_vcpu_create/hv_vcpu_run, extract structs from kernel

Zhuowei Zhang 3 năm trước cách đây
mục cha
commit
74cdb2d02b
4 tập tin đã thay đổi với 528 bổ sung14 xóa
  1. 4 1
      build.sh
  2. 9 0
      hv.entitlements
  3. 157 13
      hv.m
  4. 358 0
      hv_kernel_structs.h

+ 4 - 1
build.sh

@@ -1 +1,4 @@
-exec clang -fmodules -target arm64e-apple-macos12 -o hv hv.m
+#!/bin/sh
+set -e
+clang -fmodules -Os -g -target arm64-apple-macos12 -o hv hv.m
+codesign --sign - --force --entitlements hv.entitlements hv

+ 9 - 0
hv.entitlements

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/
+PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+<key>com.apple.security.hypervisor</key>
+<true/>
+</dict>
+</plist>

+ 157 - 13
hv.m

@@ -1,11 +1,48 @@
 // Decompiled by hand (based-ish on a Ghidra decompile) from Hypervisor.framework on macOS 12.0b1
 @import Darwin;
+#include <Hypervisor/Hypervisor.h>
 #include <assert.h>
+#include "hv_kernel_structs.h"
 
-typedef uint64_t hv_return_t;
+#if NO_HVF_HEADER
+@protocol OS_hv_vcpu_config;
+@class NSObject;
+
+typedef kern_return_t hv_return_t;
 typedef void* hv_vm_config_t;
+typedef uint64_t hv_ipa_t;
+typedef uint64_t hv_vcpu_t;
+typedef uint64_t hv_exception_syndrome_t;
+typedef uint64_t hv_exception_address_t;
+typedef uint64_t hv_exit_reason_t;
+typedef NSObject<OS_hv_vcpu_config>* hv_vcpu_config_t;
+typedef uint64_t hv_memory_flags_t;
+#define HV_BAD_ARGUMENT 0xfae94003;
+#define HV_UNSUPPORTED 0xfae9400f;
+
+// from hv_vcpu_types.h
+
+typedef struct hv_vcpu_exit_exception {
+  hv_exception_syndrome_t syndrome;
+  hv_exception_address_t virtual_address;
+  hv_ipa_t physical_address;
+} hv_vcpu_exit_exception_t;
+
+typedef struct hv_vcpu_exit {
+  hv_exit_reason_t reason;
+  hv_vcpu_exit_exception_t exception;
+} hv_vcpu_exit_t;
+#endif  // NO_HVF_HEADER
 
+static_assert(sizeof(hv_vcpu_exit_t) == 0x20, "hv_vcpu_exit");
+
+#define HV_CALL_VM_GET_CAPABILITIES 0
 #define HV_CALL_VM_CREATE 1
+#define HV_CALL_VM_MAP 3
+#define HV_CALL_VCPU_CREATE 6
+#define HV_CALL_VCPU_DESTROY 7
+#define HV_CALL_VCPU_DIRTY_BANKED_STATE 8
+#define HV_CALL_VCPU_RUN 9
 
 __attribute__((naked)) uint64_t hv_trap(unsigned int hv_call, void* hv_arg) {
   asm volatile("mov x16, #-0x5\n"
@@ -13,21 +50,22 @@ __attribute__((naked)) uint64_t hv_trap(unsigned int hv_call, void* hv_arg) {
                "ret\n");
 }
 
+// type lookup hv_vm_create_t
 struct hv_vm_create_kernel_args {
-  uint64_t field_0;    // 0x0
-  uint64_t field_8;    // 0x8
-  int32_t field_10;    // 0x10
-  uint32_t unused_14;  // 0x14
-  int32_t field_18;    // 0x18
+  uint64_t min_ipa;
+  uint64_t ipa_size;
+  uint32_t granule;
+  uint32_t flags;
+  uint32_t isa;
 };
 static_assert(sizeof(struct hv_vm_create_kernel_args) == 0x20, "hv_vm_create_kernel_args size");
 
 const struct hv_vm_create_kernel_args kDefaultVmCreateKernelArgs = {
-    .field_0 = 0,
-    .field_8 = 0,
-    .field_10 = 0,
-    .unused_14 = 0,
-    .field_18 = 1,
+    .min_ipa = 0,
+    .ipa_size = 0,
+    .granule = 0,
+    .flags = 0,
+    .isa = 1,
 };
 
 hv_return_t hv_vm_create(hv_vm_config_t config) {
@@ -38,7 +76,113 @@ hv_return_t hv_vm_create(hv_vm_config_t config) {
   return hv_trap(HV_CALL_VM_CREATE, &args);
 }
 
+struct hv_vm_map_kernel_args {
+  void* addr;               // 0x0
+  hv_ipa_t ipa;             // 0x8
+  size_t size;              // 0x10
+  hv_memory_flags_t flags;  // 0x18
+  uint64_t padding;         // 0x20
+};
+
+hv_return_t hv_vm_map(void* addr, hv_ipa_t ipa, size_t size, hv_memory_flags_t flags) {
+  struct hv_vm_map_kernel_args args = {
+      .addr = addr, .ipa = ipa, .size = size, .flags = flags, .padding = 0};
+  return hv_trap(HV_CALL_VM_MAP, &args);
+}
+
+static pthread_mutex_t vcpus_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+struct hv_vcpu_zone {
+  arm_guest_rw_context_t rw;
+  arm_guest_ro_context_t ro;
+};
+
+static_assert(sizeof(struct hv_vcpu_zone) == 0x8000, "hv_vcpu_zone");
+
+struct hv_vcpu_data {
+  struct hv_vcpu_zone* vcpu_zone;  // 0x0
+  // TODO(zhuowei)
+  char filler[0xf0 - 0x8];  // 0x8
+  hv_vcpu_exit_t exit;      // 0xf0
+  char filler2[0x8];        // 0x110
+};
+
+static_assert(sizeof(struct hv_vcpu_data) == 0x118, "hv_vcpu_data");
+
+static const size_t kHvMaxVcpus = 0x40;
+static struct hv_vcpu_data vcpus[kHvMaxVcpus];
+
+struct hv_vcpu_create_kernel_args {
+  uint64_t always_zero;                   // 0x0
+  struct hv_vcpu_zone* output_vcpu_zone;  // 0x8
+};
+
+// ' hyp', 0xe
+static const uint64_t kHvVcpuMagic = 0x206879700000000eull;
+
+hv_return_t hv_vcpu_create(hv_vcpu_t* vcpu, hv_vcpu_exit_t** exit, hv_vcpu_config_t config) {
+  pthread_mutex_lock(&vcpus_mutex);
+  // TODO(zhuowei): support more than one
+  struct hv_vcpu_data* vcpu_data = &vcpus[0];
+  struct hv_vcpu_create_kernel_args args = {
+      .always_zero = 0,
+      .output_vcpu_zone = 0,
+  };
+  kern_return_t err = hv_trap(HV_CALL_VCPU_CREATE, &args);
+  if (err) {
+    pthread_mutex_unlock(&vcpus_mutex);
+    return err;
+  }
+  printf("vcpu_zone = %p\n", args.output_vcpu_zone);
+  if (args.output_vcpu_zone->ro.ver != kHvVcpuMagic) {
+    hv_trap(HV_CALL_VCPU_DESTROY, nil);
+    pthread_mutex_unlock(&vcpus_mutex);
+    return HV_UNSUPPORTED;
+  }
+  vcpu_data->vcpu_zone = args.output_vcpu_zone;
+  *vcpu = 0;  // TODO(zhuowei)
+  *exit = &vcpu_data->exit;
+  pthread_mutex_unlock(&vcpus_mutex);
+  // TODO(zhuowei): configure regs
+  return 0;
+}
+
+hv_return_t hv_vcpu_run(hv_vcpu_t vcpu) {
+  // TODO(zhuowei): update registers
+  struct hv_vcpu_data* vcpu_data = &vcpus[0];
+  hv_return_t err = hv_trap(HV_CALL_VCPU_RUN, nil);
+  if (err) {
+    return err;
+  }
+  printf("exit = %d\n", vcpu_data->vcpu_zone->ro.exit.vmexit_reason);
+  return 0;
+}
+
+hv_return_t hv_vcpu_get_reg(hv_vcpu_t vcpu, hv_reg_t reg, uint64_t* value) {
+  if (reg > HV_REG_CPSR) {
+    return HV_BAD_ARGUMENT;
+  }
+  struct hv_vcpu_zone* vcpu_zone = vcpus[vcpu].vcpu_zone;
+  // TODO(zhuowei): lr, pc
+  if (reg <= HV_REG_X30) {
+    *value = vcpu_zone->rw.regs.x[reg];
+  } else if (reg == HV_REG_FPCR) {
+    *value = vcpu_zone->rw.neon.fpcr;
+  } else if (reg == HV_REG_FPSR) {
+    *value = vcpu_zone->rw.neon.fpsr;
+  } else if (reg == HV_REG_CPSR) {
+    *value = vcpu_zone->rw.regs.cpsr;
+  }
+  return 0;
+}
+
 int main() {
   hv_return_t err = hv_vm_create(nil);
-  printf("%llu\n", err);
-}
+  printf("%x\n", err);
+  hv_vcpu_t cpu = 0;
+  hv_vcpu_exit_t* exit = nil;
+  err = hv_vcpu_create(&cpu, &exit, nil);
+  printf("%x\n", err);
+  err = hv_vcpu_run(cpu);
+  printf("%x\n", err);
+}

+ 358 - 0
hv_kernel_structs.h

@@ -0,0 +1,358 @@
+#pragma once
+#include <Hypervisor/Hypervisor.h>
+
+// Headers extracted from
+// Kernel_Debug_Kit_12.5_build_21G5027d.dmg/kernel.release.t8101
+
+// type lookup hv_vcpu_t
+// type lookup arm_guest_context_t
+
+typedef struct {
+  uint64_t mdscr_el1;
+  uint64_t tpidr_el1;
+  uint64_t tpidr_el0;
+  uint64_t tpidrro_el0;
+  uint64_t sp_el0;
+  uint64_t sp_el1;
+  uint64_t par_el1;
+  uint64_t csselr_el1;
+  uint64_t apstate;
+  uint64_t afpcr_el0;
+} arm_guest_shared_sysregs_t;
+
+typedef struct {
+  uint64_t ttbr0_el1;
+  uint64_t ttbr1_el1;
+  uint64_t tcr_el1;
+  uint64_t elr_el1;
+  uint64_t far_el1;
+  uint64_t esr_el1;
+  uint64_t mair_el1;
+  uint64_t amair_el1;
+  uint64_t vbar_el1;
+  uint64_t cntv_cval_el0;
+  uint64_t cntp_cval_el0;
+  uint64_t actlr_el1;
+  uint64_t sctlr_el1;
+  uint64_t cpacr_el1;
+  uint64_t spsr_el1;
+  uint64_t afsr0_el1;
+  uint64_t afsr1_el1;
+  uint64_t contextidr_el1;
+  uint64_t cntv_ctl_el0;
+  uint64_t cntp_ctl_el0;
+  uint64_t cntkctl_el1;
+  uint64_t ich_vmcr_el2;
+} arm_guest_banked_sysregs_t;
+
+typedef struct {
+  uint64_t hcr_el2;
+  uint64_t hacr_el2;
+  uint64_t cptr_el2;
+  uint64_t mdcr_el2;
+  uint64_t vmpidr_el2;
+  uint64_t vpidr_el2;
+  uint64_t virtual_timer_offset;
+  uint64_t hfgrtr_el2;
+  uint64_t hfgwtr_el2;
+  uint64_t hfgitr_el2;
+  uint64_t hdfgrtr_el2;
+  uint64_t hdfgwtr_el2;
+  uint64_t cnthctl_el2;
+  uint64_t timer;
+  uint64_t vmkeyhi_el2;
+  uint64_t vmkeylo_el2;
+  uint64_t apsts_el1;
+  uint64_t ich_hcr_el2;
+  uint64_t ich_lr_el2[8];
+  uint64_t host_debug;
+} arm_guest_controls_t;
+
+typedef struct {
+  struct {
+    uint64_t bvr;
+    uint64_t bcr;
+  } bp[16];
+  struct {
+    uint64_t wvr;
+    uint64_t wcr;
+  } wp[16];
+  uint64_t mdccint_el1;
+  uint64_t osdtrrx_el1;
+  uint64_t osdtrtx_el1;
+  uint8_t dbgclaim_el1;
+} arm_guest_dbgregs_t;
+
+typedef struct {
+  uint64_t amx_state_t_el1;
+  uint64_t amx_config_el1;
+  uint64_t aspsr_el1;
+  uint64_t ctrr_ctl_el1;
+  uint64_t ctrr_a_lwr_el1;
+  uint64_t ctrr_a_upr_el1;
+  uint64_t ctrr_b_lwr_el1;
+  uint64_t ctrr_b_upr_el1;
+  uint64_t ctrr_lock_el1;
+  uint64_t vmsa_lock_el1;
+  uint64_t pmcr1_el1;
+  uint64_t apctl_el1;
+  uint64_t apgakeyhi_el1;
+  uint64_t apgakeylo_el1;
+  uint64_t apiakeyhi_el1;
+  uint64_t apiakeylo_el1;
+  uint64_t apibkeyhi_el1;
+  uint64_t apibkeylo_el1;
+  uint64_t apdakeyhi_el1;
+  uint64_t apdakeylo_el1;
+  uint64_t apdbkeyhi_el1;
+  uint64_t apdbkeylo_el1;
+  uint64_t kernkeyhi_el1;
+  uint64_t kernkeylo_el1;
+  uint64_t gxf_config_el1;
+  uint64_t gxf_entry_el1;
+  uint64_t gxf_pabentry_el1;
+  uint64_t sp_gl1;
+  uint64_t tpidr_gl1;
+  uint64_t aspsr_gl1;
+  uint64_t vbar_gl1;
+  uint64_t far_gl1;
+  uint64_t esr_gl1;
+  uint64_t elr_gl1;
+  uint64_t spsr_gl1;
+  uint64_t pmcr1_gl1;
+  uint64_t afsr1_gl1;
+  uint64_t sprr_config_el1;
+  uint64_t sprr_amrange_el1;
+  uint64_t sprr_pperm_el1;
+  uint64_t sprr_uperm_el0;
+  uint64_t sprr_pmprr_el1;
+  uint64_t sprr_umprr_el1;
+  uint64_t sprr_pperm_sh1_el1;
+  uint64_t sprr_pperm_sh2_el1;
+  uint64_t sprr_pperm_sh3_el1;
+  uint64_t sprr_pperm_sh4_el1;
+  uint64_t sprr_pperm_sh5_el1;
+  uint64_t sprr_pperm_sh6_el1;
+  uint64_t sprr_pperm_sh7_el1;
+  uint64_t sprr_uperm_sh1_el1;
+  uint64_t sprr_uperm_sh2_el1;
+  uint64_t sprr_uperm_sh3_el1;
+  uint64_t sprr_uperm_sh4_el1;
+  uint64_t sprr_uperm_sh5_el1;
+  uint64_t sprr_uperm_sh6_el1;
+  uint64_t sprr_uperm_sh7_el1;
+  uint64_t acfg_el1;
+  uint64_t jrange_el1;
+  uint64_t jctl_el1;
+  uint64_t japiakeyhi_el1;
+  uint64_t japiakeylo_el1;
+  uint64_t japibkeyhi_el1;
+  uint64_t japibkeylo_el1;
+} arm_guest_extregs_t;
+
+typedef struct {
+  uint8_t __res_00_20[32];
+  uint64_t vttbr_el2;
+  uint64_t __res_28;
+  uint64_t vsttbr_el2;
+  uint64_t __res_38;
+  uint64_t vtcr_el2;
+  uint64_t vstcr_el2;
+  uint64_t vmpidr_el2;
+  uint64_t __res_58;
+  uint64_t cntvoff_el2;
+  uint8_t __res_68_78[16];
+  uint64_t hcr_el2;
+  uint64_t hstr_el2;
+  uint64_t vpidr_el2;
+  uint64_t tpidr_el2;
+  uint8_t __res_98_b0[24];
+  uint64_t vncr_el2;
+  uint8_t __res_b8_100[72];
+  uint64_t cpacr_el1;
+  uint64_t contextidr_el1;
+  uint64_t sctlr_el1;
+  uint64_t actlr_el1;
+  uint64_t tcr_el1;
+  uint64_t afsr0_el1;
+  uint64_t afsr1_el1;
+  uint64_t esr_el1;
+  uint64_t mair_el1;
+  uint64_t amair_el1;
+  uint8_t __res_158_150[8];
+  uint64_t mdscr_el1;
+  uint64_t spsr_el1;
+  uint64_t cntv_cval_el0;
+  uint64_t cntv_ctl_el0;
+  uint64_t cntp_cval_el0;
+  uint64_t cntp_ctl_el0;
+  uint64_t scxtnum_el1;
+  uint64_t tfsr_el1;
+  uint8_t __res_198_1a8[16];
+  uint64_t cntpoff_el2;
+  uint8_t __res_1b0_1b8[8];
+  uint64_t hfgrtr_el2;
+  uint64_t hfgwtr_el2;
+  uint64_t hfgitr_el2;
+  uint64_t hdfgrtr_el2;
+  uint64_t hdfgwtr_el2;
+  uint64_t zcr_el1;
+  uint8_t __res_1e8_200[24];
+  uint64_t ttbr0_el1;
+  uint8_t __res_208_210[8];
+  uint64_t ttbr1_el1;
+  uint8_t __res_218_220[8];
+  uint64_t far_el1;
+  uint8_t __res_228_230[8];
+  uint64_t elr_el1;
+  uint8_t __res_238_240[8];
+  uint64_t sp_el1;
+  uint8_t __res_248_250[8];
+  uint64_t vbar_el1;
+  uint8_t __res_400_258[424];
+  uint64_t ich_lr_el2[16];
+  uint64_t ich_ap0r_el2[4];
+  uint64_t ich_ap1r_el2[4];
+  uint64_t ich_hcr_el2;
+  uint64_t ich_vmcr_el2;
+  uint8_t __res_4d0_500[48];
+  uint64_t vdisr_el2;
+  uint64_t vsesr_el2;
+  uint8_t __res_510_800[752];
+  uint64_t pmblimitr_el1;
+  uint8_t __res_808_810[8];
+  uint64_t pmbptr_el1;
+  uint8_t __res_818_820[8];
+  uint64_t pmbsr_el1;
+  uint64_t pmscr_el1;
+  uint64_t pmsevfr_el1;
+  uint64_t pmsicr_el1;
+  uint64_t pmsirr_el1;
+  uint64_t pmslatfr_el1;
+  uint8_t __res_850_880[48];
+  uint64_t trfcr_el1;
+  uint8_t __res_888_1000[1912];
+} arm_vncr_context_t;
+
+typedef struct {
+  uint8_t __res_000_008[8];
+  uint64_t avncr_el2;
+  uint64_t aspsr_el1;
+  uint8_t __res_018_100[232];
+  uint64_t apctl_el1;
+  uint64_t apsts_el1;
+  uint64_t vmkey_lo_el2;
+  uint64_t vmkey_hi_el2;
+  uint64_t apgakeylo_el1;
+  uint64_t apgakeyhi_el1;
+  uint64_t apiakeylo_el1;
+  uint64_t apiakeyhi_el1;
+  uint64_t apibkeylo_el1;
+  uint64_t apibkeyhi_el1;
+  uint64_t apdakeylo_el1;
+  uint64_t apdakeyhi_el1;
+  uint64_t apdbkeylo_el1;
+  uint64_t apdbkeyhi_el1;
+  uint64_t kernkeylo_el1;
+  uint64_t kernkeyhi_el1;
+  uint8_t __res_180_2d0[336];
+  uint64_t jctl_el1;
+  uint64_t jrange_el1;
+  uint64_t japiakeylo_el1;
+  uint64_t japiakeyhi_el1;
+  uint64_t japibkeylo_el1;
+  uint64_t japibkeyhi_el1;
+  uint64_t amx_config_el1;
+  uint8_t __res_308_360[88];
+  uint64_t vmsa_lock_el1;
+  uint8_t __res_368_3c0[88];
+  uint64_t pmcr1_el1;
+  uint8_t __res_3c8_400[56];
+  uint64_t apl_lrtmr_el2;
+  uint64_t apl_intenable_el2;
+  uint8_t __res_410_1000[3056];
+} apple_vncr_context_t;
+
+typedef union {
+  struct {
+    union {
+      // arm_context_t guest_context;
+      struct {
+        uint64_t res1[1];
+        struct {
+          uint64_t x[29];
+          uint64_t fp;
+          uint64_t lr;
+          uint64_t sp;
+          uint64_t pc;
+          uint32_t cpsr;
+          uint32_t pad;
+        } regs;
+        uint64_t res2[4];
+        struct {
+          __uint128_t q[32];
+          uint32_t fpsr;
+          uint32_t fpcr;
+        } neon;
+      };
+    };
+    arm_guest_shared_sysregs_t shared_sysregs;
+    arm_guest_banked_sysregs_t banked_sysregs;
+    arm_guest_dbgregs_t dbgregs;
+    volatile arm_guest_controls_t controls;
+    volatile uint64_t state_dirty;
+    uint64_t guest_tick_count;
+    arm_guest_extregs_t extregs;
+    arm_vncr_context_t vncr;
+    apple_vncr_context_t avncr;
+  };
+  uint8_t page[16384];
+} arm_guest_rw_context_t;
+
+typedef struct {
+  uint32_t vmexit_reason;
+  uint32_t vmexit_esr;
+  uint32_t vmexit_instr;
+  uint64_t vmexit_far;
+  uint64_t vmexit_hpfar;
+} arm_guest_vmexit_t;
+
+typedef union {
+  struct {
+    uint64_t ver;
+    arm_guest_vmexit_t exit;
+    arm_guest_controls_t controls;
+    uint64_t state_valid;
+    uint64_t state_dirty;
+    uint64_t state_used;
+    uint32_t ich_vtr_el2;
+    uint32_t ich_misr_el2;
+    uint32_t ich_elrsr_el2;
+  };
+  uint8_t page[16384];
+} arm_guest_ro_context_t;
+
+typedef struct {
+  uint64_t cptr_el2;
+  uint64_t mdscr_el1;
+  uint64_t tpidr_el1;
+  uint64_t tpidr_el0;
+  uint64_t tpidrro_el0;
+  uint64_t sp_el0;
+  uint64_t jop_hash;
+  uint64_t vmenter_ticks;
+  uint64_t vmexit_ticks;
+  uint64_t vncr_el2;
+  uint64_t avncr_el2;
+  uint64_t ich_ap0r0_el2;
+  uint64_t ich_ap1r0_el2;
+  vm_map_t guest_map;
+  bool flush_local_tlb;
+  uint64_t actlr_en_mdsb;
+} arm_host_context_t;
+
+typedef struct {
+  arm_guest_rw_context_t rw;
+  arm_guest_ro_context_t ro;
+  arm_host_context_t priv;
+} arm_guest_context_t;