@@ -61,15 +61,26 @@ module_param_named(unrestricted_guest,
static int __read_mostly emulate_invalid_guest_state = 0;
module_param(emulate_invalid_guest_state, bool, S_IRUGO);
-struct vmcs {
- u32 revision_id;
- u32 abort;
- char data[0];
+struct __attribute__ ((__packed__)) level_state {
+ /* Has the level1 guest done vmclear? */
+ bool vmclear;
};
struct nested_vmx {
/* Has the level1 guest done vmxon? */
bool vmxon;
+
+ /*
+ * Level 2 state : includes vmcs,registers and
+ * a copy of vmcs12 for vmread/vmwrite
+ */
+ struct level_state *l2_state;
+};
+
+struct vmcs {
+ u32 revision_id;
+ u32 abort;
+ char data[0];
};
struct vcpu_vmx {
@@ -186,6 +197,8 @@ static struct kvm_vmx_segment_field {
static void ept_save_pdptrs(struct kvm_vcpu *vcpu);
+static int create_l2_state(struct kvm_vcpu *vcpu);
+
/*
* Keep MSR_K6_STAR at the end, as setup_msrs() will try to optimize it
* away by decrementing the array size.
@@ -1293,6 +1306,30 @@ static void vmclear_local_vcpus(void)
__vcpu_clear(vmx);
}
+struct level_state *create_state(void)
+{
+ struct level_state *state = NULL;
+
+ state = kzalloc(sizeof(struct level_state), GFP_KERNEL);
+ if (!state) {
+ printk(KERN_INFO "Error create level state\n");
+ return NULL;
+ }
+ return state;
+}
+
+int create_l2_state(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+ if (!vmx->nested.l2_state) {
+ vmx->nested.l2_state = create_state();
+ if (!vmx->nested.l2_state)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
/* Just like cpu_vmxoff(), but with the __kvm_handle_fault_on_reboot()
* tricks.
@@ -3261,6 +3298,27 @@ static int handle_vmx_insn(struct kvm_vcpu *vcpu)
return 1;
}
+static void clear_rflags_cf_zf(struct kvm_vcpu *vcpu)
+{
+ unsigned long rflags;
+ rflags = vmx_get_rflags(vcpu);
+ rflags &= ~(X86_EFLAGS_CF | X86_EFLAGS_ZF);
+ vmx_set_rflags(vcpu, rflags);
+}
+
+static int handle_vmclear(struct kvm_vcpu *vcpu)
+{
+ if (!nested_vmx_check_permission(vcpu))
+ return 1;
+
+ to_vmx(vcpu)->nested.l2_state->vmclear = 1;
+
+ skip_emulated_instruction(vcpu);
+ clear_rflags_cf_zf(vcpu);
+
+ return 1;
+}
+
static int handle_vmoff(struct kvm_vcpu *vcpu)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -3310,6 +3368,8 @@ static int handle_vmon(struct kvm_vcpu *vcpu)
vmx->nested.vmxon = 1;
+ create_l2_state(vcpu);
+
skip_emulated_instruction(vcpu);
return 1;
}
@@ -3582,7 +3642,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = {
[EXIT_REASON_HLT] = handle_halt,
[EXIT_REASON_INVLPG] = handle_invlpg,
[EXIT_REASON_VMCALL] = handle_vmcall,
- [EXIT_REASON_VMCLEAR] = handle_vmx_insn,
+ [EXIT_REASON_VMCLEAR] = handle_vmclear,
[EXIT_REASON_VMLAUNCH] = handle_vmx_insn,
[EXIT_REASON_VMPTRLD] = handle_vmx_insn,
[EXIT_REASON_VMPTRST] = handle_vmx_insn,