不能在超过 1 个处理器上调用 VMXON

can't call VMXON on more than 1 processor

我正在尝试在 Intel 芯片上为 Linux(5.0.x 内核)构建我自己的管理程序,但我 运行 遇到了一个奇怪的问题。 每当我尝试在多个处理器上执行 VMXON 时,它都会失败。 我确保启用了 VMX,我分配了一个对齐的页面并将 VMCS REV ID 写入 VMXON 区域,但我不确定问题出在哪里。

这是我的代码:

vmx.c:

#include "vmx.h"

typedef struct vmstate {
    bool vmx_enabled;
    void *vmxon_region;
    phys_addr_t vmxon_physical;
    void *vmcs_region;
    phys_addr_t vmcs_physical;
} vmstate;

static DEFINE_PER_CPU(vmstate*, cpu_vms);

static inline int VMXON(phys_addr_t phys){
    uint8_t ret;
    // TODO: Signal VMX to PT, to avoid PT crashes (Processor Trace)
    __asm__ __volatile__ (
        "vmxon %[pa]; setna %[ret]"
        : [ret]"=rm"(ret)
        : [pa]"m"(phys)
        : "cc", "memory"
    );
    return ret;
}

static inline void VMXOFF(void){
    __asm__ __volatile__("vmxoff" : : : "cc");
}

static void enable_vmx_operation_cr(void){
    // Enable 14th bit in CR4
    __write_cr4(__read_cr4() | 0x2000);
}

static void disable_vmx_operation_cr(void){
    __write_cr4(__read_cr4() & ~(0x2000));
}

static vmstate *create_vmstate(void){
    vmstate *vms = kzalloc(sizeof(vmstate), GFP_KERNEL);
    vms->vmx_enabled = false;
    return vms;
}

static void alloc_vmxon_region(vmstate *vms){
    // TODO: respect physical width as set by the IA32_VMX_BASIC[48] bit for 32bit support
    uint32_t vmcs_revid = 0;
    uint32_t hi = 0;

    void *vmxon_region = kmalloc(4096, GFP_KERNEL);

    rdmsr_safe(MSR_IA32_VMX_BASIC, &vmcs_revid, &hi);
    memcpy(vmxon_region, &vmcs_revid, 4);

    vms->vmxon_region = vmxon_region;
    vms->vmxon_physical = virt_to_phys(vmxon_region);
}

static void teardown_vmstate(vmstate *vms){
    if(vms->vmxon_region)
        kfree(vms->vmxon_region);

}

void vmx_teardown(void){
    int i;
    vmstate* vms;
    for_each_possible_cpu(i){
        vms = per_cpu(cpu_vms, i);

        if(vms->vmx_enabled == true) {
            VMXOFF();
            vms->vmx_enabled = false;
        }
        disable_vmx_operation_cr();
        teardown_vmstate(vms);
        kfree(vms);
    }
}

int vmx_setup(void){
    int i;
    vmstate* vms;
    printk(KERN_INFO "NUM CPUS: %d", num_possible_cpus());

    for_each_possible_cpu(i) {
        // Allocate vmstate for every processor
        per_cpu(cpu_vms, i) = create_vmstate();
        vms = per_cpu(cpu_vms, i);

        alloc_vmxon_region(vms);

        enable_vmx_operation_cr();
        if(VMXON(vms->vmxon_physical)){
            printk(KERN_ALERT "VMXON operation failed!");
            vms->vmx_enabled = false;   
        }
        else
            vms->vmx_enabled = true;
    }
    for_each_possible_cpu(i){
        vms = per_cpu(cpu_vms, i);
        if(vms->vmx_enabled == false) {
            printk(KERN_ALERT "Tearing down after VMXON fail!");
            vmx_teardown();
            return -1;
        }
    }
    return 0;
}

vmx_setup 由设备打开文件操作调用:

static int hyper_dev_open(struct inode* inode, struct file *filep){
        int err;
        printk(KERN_INFO "Enabling VMX operation!\n");
        if((err = vmx_setup()))
                return err;
        return 0;
}

当我在另一个处理器上执行VMXON时,进位标志设置为1,零标志为0。 但是,如果我在 VMXON() 之后添加一个 VMXOFF(),则驱动程序可以工作,因此不会并行启用两个 VMX 操作。

任何建议都会有所帮助:)

for_each_possible_cpu 简单地迭代可用的 CPU;它不会依次在每个 CPU 上将执行更改为 运行。单个 CPU.

上的整个循环 运行s

因此,您试图在同一个 CPU 上重复执行 vmxon,这就是它失败的原因。