我正在尝试在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操作。
任何建议都会有所帮助:)
答案 0 :(得分:1)
for_each_possible_cpu
仅在可用的CPU上进行迭代;它不会改变执行顺序并依次在每个CPU上运行。整个循环在单个CPU上运行。
因此,您试图在同一CPU上重复执行vmxon
,这就是失败的原因。