VMX,SVM编程指北——VMX ON

VMX,SVM编程指北——目录
https://www.cnblogs.com/FE-FR-SH/p/contents.html

先上一张图,简单认识一下涉及到的几种状态。
image
控制端称为Virtual-Machine Monitor(VMM);被控端称为Guest。
CPU根据你提供的 virtual-machine control structure (VMCS)进行相关的控制,一个VMM可以包括多个VMCS,从数据结构上看一个VMCS对应一个Virtual logical processor。

看图可知,你要先 VMXON 之后才能执行其它的各种VMX Operation,这是梦开始的地方,当然也有失眠的。

1,检查 CR0.PE 和 CR0.PG 是否等于 1 (Windows和Linux 默认就是等于1的,也许你不需要这一步)

点击查看代码
#define CR0_PE (1 << 0)
#define CR0_PG (1 << 31)
	
cr0 = __readcr0();
if (!(cr0 & CR0_PE))
{
	//...
}
if (!(cr0 & CR0_PG))
{
	//...
}

2,设置 CR4.VMXE 为 1;如果该值为 0,执行VMXON是会触发异常"invaild-opcode"

点击查看代码
#define CR4_VMXE ( 1 << 13)

cr4 = __readcr4();
cr4 |= CR4_VMXE;

__writecr4(cr4);

3,根据IA32_VMX_BASIC MSR确认VMXON region的长度以及标识(identifier);readmsr返回值为64bit,0-31 bits是标识符(Identifier),32-44 bits是所需的长度(size)。
这里分配的内存要4KB对齐,且为常驻non-pageable,即不可因分页机制而被换出;

点击查看代码
#define IA32_VMX_BASIC_MSR 0x480

msrBasicInfo = __readmsr(IA32_VMX_BASIC_MSR);
//...
low32 = msrBasicInfo & 0x00000000ffffffff;
high32 = (msrBasicInfo & 0xffffffff00000000) >> 32;

revisionIdentifier = low32;
size = high32 & 0x1fff; //44:32
//...
region = AllocMemory( 4_Kbyte_aligned(size));//non-pageable memory
if(NULL == region)
{
	//...
}
	
RtlZeroMemory(region, regionSize);
region->u32.revision_identifier = revisionIdentifier;

4,执行VMXON。注意需要使用vmcs对应的物理地址(Physical Address)。如果一切正确 这个CPU将进入 VMX root operation,此后可以使用其它的vmx_xx指令。

点击查看代码
physicalAddr = GetPhysicalAddress(region);

ret = __vmx_on(physicalAddr);
if(0 != ret)
{
	//vmxon failed.
}

5,关于编程方面的提示:
A,你应该注意到了,这些寄存器和指令都是对应 the logical processor的,即以上的所有代码 包括上一篇介绍的,都应该在同一个logical processor上运行。而当前的CPU都是多核,Windows和Linux都是多任务的,所以在写驱动代码时,需注意格外注意。
- 在processor 1上执行 __vm_on 然后在 processor 2上执行 __vmx_off,显然是错的
- 以上强调的内容与一个VMCS和一个logical processor是否绑定终身,是两回事。
B,对于多颗CPU的场景,注意NUMA影响内存访问快慢的问题。

posted @ 2021-11-04 21:54  FE&FR&SH  阅读(560)  评论(0编辑  收藏  举报