|
|
@@ -2390,9 +2390,21 @@ static int rsm_load_seg_64(struct x86_emulate_ctxt *ctxt, u64 smbase, int n)
|
|
|
}
|
|
|
|
|
|
static int rsm_enter_protected_mode(struct x86_emulate_ctxt *ctxt,
|
|
|
- u64 cr0, u64 cr4)
|
|
|
+ u64 cr0, u64 cr3, u64 cr4)
|
|
|
{
|
|
|
int bad;
|
|
|
+ u64 pcid;
|
|
|
+
|
|
|
+ /* In order to later set CR4.PCIDE, CR3[11:0] must be zero. */
|
|
|
+ pcid = 0;
|
|
|
+ if (cr4 & X86_CR4_PCIDE) {
|
|
|
+ pcid = cr3 & 0xfff;
|
|
|
+ cr3 &= ~0xfff;
|
|
|
+ }
|
|
|
+
|
|
|
+ bad = ctxt->ops->set_cr(ctxt, 3, cr3);
|
|
|
+ if (bad)
|
|
|
+ return X86EMUL_UNHANDLEABLE;
|
|
|
|
|
|
/*
|
|
|
* First enable PAE, long mode needs it before CR0.PG = 1 is set.
|
|
|
@@ -2411,6 +2423,12 @@ static int rsm_enter_protected_mode(struct x86_emulate_ctxt *ctxt,
|
|
|
bad = ctxt->ops->set_cr(ctxt, 4, cr4);
|
|
|
if (bad)
|
|
|
return X86EMUL_UNHANDLEABLE;
|
|
|
+ if (pcid) {
|
|
|
+ bad = ctxt->ops->set_cr(ctxt, 3, cr3 | pcid);
|
|
|
+ if (bad)
|
|
|
+ return X86EMUL_UNHANDLEABLE;
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
return X86EMUL_CONTINUE;
|
|
|
@@ -2421,11 +2439,11 @@ static int rsm_load_state_32(struct x86_emulate_ctxt *ctxt, u64 smbase)
|
|
|
struct desc_struct desc;
|
|
|
struct desc_ptr dt;
|
|
|
u16 selector;
|
|
|
- u32 val, cr0, cr4;
|
|
|
+ u32 val, cr0, cr3, cr4;
|
|
|
int i;
|
|
|
|
|
|
cr0 = GET_SMSTATE(u32, smbase, 0x7ffc);
|
|
|
- ctxt->ops->set_cr(ctxt, 3, GET_SMSTATE(u32, smbase, 0x7ff8));
|
|
|
+ cr3 = GET_SMSTATE(u32, smbase, 0x7ff8);
|
|
|
ctxt->eflags = GET_SMSTATE(u32, smbase, 0x7ff4) | X86_EFLAGS_FIXED;
|
|
|
ctxt->_eip = GET_SMSTATE(u32, smbase, 0x7ff0);
|
|
|
|
|
|
@@ -2467,14 +2485,14 @@ static int rsm_load_state_32(struct x86_emulate_ctxt *ctxt, u64 smbase)
|
|
|
|
|
|
ctxt->ops->set_smbase(ctxt, GET_SMSTATE(u32, smbase, 0x7ef8));
|
|
|
|
|
|
- return rsm_enter_protected_mode(ctxt, cr0, cr4);
|
|
|
+ return rsm_enter_protected_mode(ctxt, cr0, cr3, cr4);
|
|
|
}
|
|
|
|
|
|
static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase)
|
|
|
{
|
|
|
struct desc_struct desc;
|
|
|
struct desc_ptr dt;
|
|
|
- u64 val, cr0, cr4;
|
|
|
+ u64 val, cr0, cr3, cr4;
|
|
|
u32 base3;
|
|
|
u16 selector;
|
|
|
int i, r;
|
|
|
@@ -2491,7 +2509,7 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase)
|
|
|
ctxt->ops->set_dr(ctxt, 7, (val & DR7_VOLATILE) | DR7_FIXED_1);
|
|
|
|
|
|
cr0 = GET_SMSTATE(u64, smbase, 0x7f58);
|
|
|
- ctxt->ops->set_cr(ctxt, 3, GET_SMSTATE(u64, smbase, 0x7f50));
|
|
|
+ cr3 = GET_SMSTATE(u64, smbase, 0x7f50);
|
|
|
cr4 = GET_SMSTATE(u64, smbase, 0x7f48);
|
|
|
ctxt->ops->set_smbase(ctxt, GET_SMSTATE(u32, smbase, 0x7f00));
|
|
|
val = GET_SMSTATE(u64, smbase, 0x7ed0);
|
|
|
@@ -2519,7 +2537,7 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase)
|
|
|
dt.address = GET_SMSTATE(u64, smbase, 0x7e68);
|
|
|
ctxt->ops->set_gdt(ctxt, &dt);
|
|
|
|
|
|
- r = rsm_enter_protected_mode(ctxt, cr0, cr4);
|
|
|
+ r = rsm_enter_protected_mode(ctxt, cr0, cr3, cr4);
|
|
|
if (r != X86EMUL_CONTINUE)
|
|
|
return r;
|
|
|
|