简体   繁体   English

Hypervisor.framework 16位实模式

[英]Hypervisor.framework 16-bit real mode

How can I use Hypervisor.framework on macOS to emulate a CPU in 16-bit real mode? 如何在macOS上使用Hypervisor.framework在16位实模式下模拟CPU? Specifically, what do I need to do so that the CPU is in real mode as opposed to protected mode? 具体来说,我需要怎么做才能使CPU处于实模式而不是保护模式? I thought that simply having bit 0 of CR0 unset would be enough but it isn't. 我认为只需设置CR0的位0就足够了,但事实并非如此。

This is the code. 这是代码。 Since the VM is running in protected mode it incorrectly loads 0x90901234 into rax instead of 0x1234 . 由于VM在保护模式下运行,因此会将0x90901234错误地加载到rax而不是0x1234

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <Hypervisor/hv.h>
#include <Hypervisor/hv_arch_vmx.h>
#include <Hypervisor/hv_vmx.h>

#define req(x) { \
  hv_return_t ret = (x); \
  if (ret != HV_SUCCESS) { \
    printf("%s exited with code %d\n", #x, (int)ret); \
    exit(1); \
  } \
}

#define cap2ctrl(cap, ctrl) ((ctrl) | ((cap) & 0xffffffff)) & ((cap) >> 32)
#define VMCS_PRI_PROC_BASED_CTLS_HLT           (1 << 7)
#define VMCS_PRI_PROC_BASED_CTLS_CR8_LOAD      (1 << 19)
#define VMCS_PRI_PROC_BASED_CTLS_CR8_STORE     (1 << 20)

int main() {
  req(hv_vm_create(HV_VM_DEFAULT));

  hv_vcpuid_t vcpu;
  req(hv_vcpu_create(&vcpu, HV_VCPU_DEFAULT));

  uint64_t vmx_cap_pinbased, vmx_cap_procbased, vmx_cap_procbased2, vmx_cap_entry;
  req(hv_vmx_read_capability(HV_VMX_CAP_PINBASED, &vmx_cap_pinbased));
  req(hv_vmx_read_capability(HV_VMX_CAP_PROCBASED, &vmx_cap_procbased));
  req(hv_vmx_read_capability(HV_VMX_CAP_PROCBASED2, &vmx_cap_procbased2));
  req(hv_vmx_read_capability(HV_VMX_CAP_ENTRY, &vmx_cap_entry));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_CTRL_PIN_BASED, cap2ctrl(vmx_cap_pinbased, 0)));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_CTRL_CPU_BASED, cap2ctrl(
    vmx_cap_procbased,
    VMCS_PRI_PROC_BASED_CTLS_HLT |
    VMCS_PRI_PROC_BASED_CTLS_CR8_LOAD |
    VMCS_PRI_PROC_BASED_CTLS_CR8_STORE)));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_CTRL_CPU_BASED2, cap2ctrl(vmx_cap_procbased2, 0) | (1 << 7)));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_CTRL_VMENTRY_CONTROLS, cap2ctrl(vmx_cap_entry, 0)));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_CTRL_EXC_BITMAP, 0xffffffff));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_CTRL_CR0_MASK, 0xffffffff));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_CTRL_CR0_SHADOW, 0xffffffff));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_CTRL_CR4_MASK, 0xffffffff));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_CTRL_CR4_SHADOW, 0xffffffff));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CS, 1 << 3));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CS_AR, 0xc093));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CS_LIMIT, 0xffffffff));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CS_BASE, 0x0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_DS, 2 << 3));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_DS_AR, 0xc093));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_DS_LIMIT, 0xffffffff));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_DS_BASE, 0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_ES, 2 << 3));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_ES_AR, 0xc093));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_ES_LIMIT, 0xffffffff));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_ES_BASE, 0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_FS, 2 << 3));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_FS_AR, 0xc093));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_FS_LIMIT, 0xffffffff));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_FS_BASE, 0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_GS, 2 << 3));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_GS_AR, 0xc093));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_GS_LIMIT, 0xffffffff));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_GS_BASE, 0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_SS, 2 << 3));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_SS_AR, 0xc093));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_SS_LIMIT, 0xffffffff));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_SS_BASE, 0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_LDTR, 0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_LDTR_LIMIT, 0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_LDTR_AR, 0x10000));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_LDTR_BASE, 0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_TR, 0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_TR_LIMIT, 0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_TR_AR, 0x83));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_TR_BASE, 0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_GDTR_LIMIT, 0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_GDTR_BASE, 0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_IDTR_LIMIT, 0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_IDTR_BASE, 0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CR0, 0x20));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CR3, 0x0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CR4, 0x2000));

  // loads 0x1234 to ax if in 16-bit mode
  // loads 0x90901234 to eax if in 32-bit mode
  //     mov ax, 0x1234
  //     nop
  //     nop
  //     hlt
  unsigned char code[] = { 0xB8, 0x34, 0x12, 0x90, 0x90, 0xF4 };
  void *vm_mem = valloc(1 << 30);
  memcpy(vm_mem, code, sizeof code);
  req(hv_vm_map(vm_mem, 0, 1 << 30, HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC));

  req(hv_vcpu_write_register(vcpu, HV_X86_RIP, 0));
  req(hv_vcpu_write_register(vcpu, HV_X86_RFLAGS, 0x2));
  req(hv_vcpu_write_register(vcpu, HV_X86_RAX, 0));

  for (;;) {
    req(hv_vcpu_run(vcpu));

    uint64_t exit_reason;
    req(hv_vmx_vcpu_read_vmcs(vcpu, VMCS_RO_EXIT_REASON, &exit_reason));
    if (exit_reason == VMX_REASON_EPT_VIOLATION || exit_reason == VMX_REASON_IRQ)
      continue;
    break;
  }

  uint64_t x;
  req(hv_vcpu_read_register(vcpu, HV_X86_RAX, &x));
  printf("rax = 0x%llx\n", x);

  return 0;
}

The code below works fine on my environment (MacOS Majove 10.14.3). 以下代码在我的环境(MacOS Majove 10.14.3)上可以正常工作。 Because I'm not a professional level programmer in this area, I'm not sure all the parameters below are correct nor the best. 因为我不是该领域的专业级程序员,所以我不确定以下所有参数都是正确的还是最好的。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <Hypervisor/hv.h>
#include <Hypervisor/hv_arch_vmx.h>
#include <Hypervisor/hv_vmx.h>

#define req(x) { \
  hv_return_t ret = (x); \
  if (ret != HV_SUCCESS) { \
    printf("%s exited with code %d\n", #x, (int)ret); \
    exit(1); \
  } \
}

#define cap2ctrl(cap, ctrl) ((ctrl) | ((cap) & 0xffffffff)) & ((cap) >> 32)
#define VMCS_PRI_PROC_BASED_CTLS_HLT           (1 << 7)

int main() {
  req(hv_vm_create(HV_VM_DEFAULT));

  hv_vcpuid_t vcpu;
  req(hv_vcpu_create(&vcpu, HV_VCPU_DEFAULT));

  uint64_t ctrl_cpu_based;
  req(hv_vmx_vcpu_read_vmcs(vcpu, VMCS_CTRL_CPU_BASED, &ctrl_cpu_based));
  ctrl_cpu_based |= VMCS_PRI_PROC_BASED_CTLS_HLT;
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_CTRL_CPU_BASED, ctrl_cpu_based));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CS, 0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CS_AR, 0x009B));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CS_LIMIT, 0xfffff));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CS_BASE, 0x0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_DS, 0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_DS_AR, 0x0093));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_DS_LIMIT, 0xfffff));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_DS_BASE, 0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_ES, 0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_ES_AR, 0x0093));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_ES_LIMIT, 0xfffff));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_ES_BASE, 0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_FS, 0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_FS_AR, 0x0093));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_FS_LIMIT, 0xfffff));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_FS_BASE, 0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_GS, 0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_GS_AR, 0x0093));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_GS_LIMIT, 0xfffff));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_GS_BASE, 0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_SS, 0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_SS_AR, 0x0093));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_SS_LIMIT, 0xfffff));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_SS_BASE, 0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_LDTR, 0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_LDTR_LIMIT, 0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_LDTR_AR, 0x10000));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_LDTR_BASE, 0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_TR, 0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_TR_LIMIT, 0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_TR_AR, 0x8B));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_TR_BASE, 0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_GDTR_LIMIT, 0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_GDTR_BASE, 0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_IDTR_LIMIT, 0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_IDTR_BASE, 0));

  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CR0, 0x20));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CR3, 0x0));
  req(hv_vmx_vcpu_write_vmcs(vcpu, VMCS_GUEST_CR4, 0x2000));

  // loads 0x1234 to ax if in 16-bit mode
  // loads 0x90901234 to eax if in 32-bit mode
  //     mov ax, 0x1234
  //     nop
  //     nop
  //     hlt
  unsigned char code[] = { 0xB8, 0x34, 0x12, 0x90, 0x90, 0xF4 };
  void *vm_mem = valloc(1 << 30);
  memcpy(vm_mem, code, sizeof code);
  req(hv_vm_map(vm_mem, 0, 1 << 30, HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC));

  req(hv_vcpu_write_register(vcpu, HV_X86_RIP, 0));
  req(hv_vcpu_write_register(vcpu, HV_X86_RFLAGS, 0x2));
  req(hv_vcpu_write_register(vcpu, HV_X86_RAX, 0));

  for (;;) {
    req(hv_vcpu_run(vcpu));

    uint64_t exit_reason;
    req(hv_vmx_vcpu_read_vmcs(vcpu, VMCS_RO_EXIT_REASON, &exit_reason));
    if (exit_reason == VMX_REASON_EPT_VIOLATION || exit_reason == VMX_REASON_IRQ)
      continue;
    break;
  }

  uint64_t x;
  req(hv_vcpu_read_register(vcpu, HV_X86_RAX, &x));
  printf("rax = 0x%llx\n", x);

  return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM