asm volatile("ltr %%ax" : : "a" (GDT_DESC_TSS * 8));
cpu_data->linux_cr0 = read_cr0();
+ cpu_data->linux_cr4 = read_cr4();
/* swap CR3 */
cpu_data->linux_cr3 = read_cr3();
write_msr(MSR_EFER, cpu_data->linux_efer);
write_cr0(cpu_data->linux_cr0);
write_cr3(cpu_data->linux_cr3);
+ write_cr4(cpu_data->linux_cr4);
asm volatile("lgdtq %0" : : "m" (cpu_data->linux_gdtr));
asm volatile("lidtq %0" : : "m" (cpu_data->linux_idtr));
vmcb->cr0 = cpu_data->linux_cr0 & SVM_CR0_ALLOWED_BITS;
vmcb->cr3 = cpu_data->linux_cr3;
- vmcb->cr4 = read_cr4();
+ vmcb->cr4 = cpu_data->linux_cr4;
set_svm_segment_from_segment(&vmcb->cs, &cpu_data->linux_cs);
set_svm_segment_from_segment(&vmcb->ds, &cpu_data->linux_ds);
* But we want to avoid surprises with new features unknown to us but
* set by Linux. So check if any assumed revered bit was set and bail
* out if so.
+ * Note that the APM defines all reserved CR4 bits as must-be-zero.
*/
if (cpu_data->linux_cr0 & X86_CR0_RESERVED)
return -EIO;
- /* bring CR0 into well-defined state */
+ /* bring CR0 and CR4 into well-defined states */
write_cr0(X86_CR0_HOST_STATE);
+ write_cr4(X86_CR4_HOST_STATE);
write_msr(MSR_VM_HSAVE_PA, paging_hvirt2phys(cpu_data->host_state));
ok &= vmcs_write64(HOST_RIP, (unsigned long)vmx_vmexit);
ok &= vmx_set_guest_cr(CR0_IDX, cpu_data->linux_cr0);
- ok &= vmx_set_guest_cr(CR4_IDX, read_cr4());
+ ok &= vmx_set_guest_cr(CR4_IDX, cpu_data->linux_cr4);
ok &= vmcs_write64(GUEST_CR3, cpu_data->linux_cr3);
int vcpu_init(struct per_cpu *cpu_data)
{
- unsigned long cr4, feature_ctrl, mask;
+ unsigned long feature_ctrl, mask;
u32 revision_id;
int err;
- cr4 = read_cr4();
- if (cr4 & X86_CR4_VMXE)
+ if (cpu_data->linux_cr4 & X86_CR4_VMXE)
return -EBUSY;
err = vmx_check_features();
* set by Linux. So check if any assumed revered bit was set or should
* be set for VMX operation and bail out if so.
*/
- if ((cpu_data->linux_cr0 | cr_required1[CR0_IDX]) & X86_CR0_RESERVED)
+ if ((cpu_data->linux_cr0 | cr_required1[CR0_IDX]) & X86_CR0_RESERVED ||
+ (cpu_data->linux_cr4 | cr_required1[CR4_IDX]) & X86_CR4_RESERVED)
return -EIO;
/*
- * Bring CR0 into well-defined state. If it doesn't match with VMX
- * requirements, vmxon will fail.
+ * Bring CR0 and CR4 into well-defined states. If they do not match
+ * with VMX requirements, vmxon will fail.
+ * X86_CR4_OSXSAVE is enabled if available so that xsetbv can be
+ * executed on behalf of a cell.
*/
write_cr0(X86_CR0_HOST_STATE);
-
- write_cr4(cr4 | X86_CR4_VMXE);
- // TODO: validate CR4
+ write_cr4(X86_CR4_HOST_STATE | X86_CR4_VMXE |
+ ((cpuid_ecx(1) & X86_FEATURE_XSAVE) ? X86_CR4_OSXSAVE : 0));
if (!vmxon(cpu_data)) {
- write_cr4(cr4);
+ write_cr4(cpu_data->linux_cr4);
return -EIO;
}
vmcs_clear(cpu_data);
asm volatile("vmxoff" : : : "cc");
- write_cr4(read_cr4() & ~X86_CR4_VMXE);
+ cpu_data->linux_cr4 &= ~X86_CR4_VMXE;
}
void __attribute__((noreturn)) vcpu_activate_vmm(struct per_cpu *cpu_data)
cpu_data->linux_cr0 = vmcs_read64(GUEST_CR0);
cpu_data->linux_cr3 = vmcs_read64(GUEST_CR3);
+ cpu_data->linux_cr4 = vmcs_read64(GUEST_CR4);
cpu_data->linux_gdtr.base = vmcs_read64(GUEST_GDTR_BASE);
cpu_data->linux_gdtr.limit = vmcs_read64(GUEST_GDTR_LIMIT);