c - Hypervisor.framework 16位实模式

标签 c x86 intel hypervisor

如何在 macOS 上使用 Hypervisor.framework 在 16 位实模式下模拟 CPU?具体来说,我需要做什么才能使 CPU 处于实模式而不是保护模式?我认为简单地取消设置 CR0 的位 0 就足够了,但事实并非如此。

这是代码。由于虚拟机在保护模式下运行,因此它错误地将 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;
}

最佳答案

下面的代码在我的环境(MacOS Majove 10.14.3)上运行良好。因为我不是这方面的专业水平程序员,所以我不确定下面的所有参数是否正确或最好。

#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;
}

关于c - Hypervisor.framework 16位实模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54172141/

相关文章:

multithreading - “XORL AX, AX”如何用作内存屏障? [复制]

c - 内联 asm 代码组织

assembly - 与汇编代码的 .L2 标签关联的代码是否在此段中按程序调用?

java - 为什么我的 Java 应用程序在 AMD 处理器上运行速度更快?

x86 - amd和intel程序员模型兼容性

c - 为指向结构内结构的指针分配内存

在另一个中断 vector 中调用一个中断 vector

c++ - 确定库的地址内存

c++ - C 和 C++ 是客户端吗?或服务器端?

operating-system - 直接连接到 CPU 的 PCIe 插槽的中断路由