@@ -128,6 +128,7 @@
#define Priv (1<<27) /* instruction generates #GP if current CPL != 0 */
#define No64 (1<<28)
#define PageTable (1 << 29) /* instruction used to write page table */
+#define LockReg (1<<30) /* lock prefix is allowed for the instruction even for reg destination */
/* Source 2 operand type */
#define Src2Shift (30)
#define Src2None (OpNone << Src2Shift)
@@ -420,6 +421,7 @@ static int emulator_check_intercept(struct x86_emulate_ctxt *ctxt,
struct x86_instruction_info info = {
.intercept = intercept,
.rep_prefix = ctxt->rep_prefix,
+ .lock_prefix = ctxt->lock_prefix,
.modrm_mod = ctxt->modrm_mod,
.modrm_reg = ctxt->modrm_reg,
.modrm_rm = ctxt->modrm_rm,
@@ -2874,7 +2876,10 @@ static int em_mov(struct x86_emulate_ctxt *ctxt)
static int em_cr_write(struct x86_emulate_ctxt *ctxt)
{
- if (ctxt->ops->set_cr(ctxt, ctxt->modrm_reg, ctxt->src.val))
+ int cr = ctxt->modrm_reg;
+ if (ctxt->lock_prefix && cr == 0)
+ cr = 8;
+ if (ctxt->ops->set_cr(ctxt, cr, ctxt->src.val))
return emulate_gp(ctxt, 0);
/* Disable writeback. */
@@ -3177,6 +3182,8 @@ static int check_cr_write(struct x86_emulate_ctxt *ctxt)
CR8_RESERVED_BITS,
};
+ if (ctxt->lock_prefix && cr == 0)
+ cr = 8;
if (!valid_cr(cr))
return emulate_ud(ctxt);
@@ -3599,9 +3606,9 @@ static struct opcode twobyte_table[256] = {
/* 0x10 - 0x1F */
N, N, N, N, N, N, N, N, D(ImplicitOps | ModRM), N, N, N, N, N, N, N,
/* 0x20 - 0x2F */
- DIP(ModRM | DstMem | Priv | Op3264, cr_read, check_cr_read),
+ DIP(Lock | LockReg | ModRM | DstMem | Priv | Op3264, cr_read, check_cr_read),
DIP(ModRM | DstMem | Priv | Op3264, dr_read, check_dr_read),
- IIP(ModRM | SrcMem | Priv | Op3264, em_cr_write, cr_write, check_cr_write),
+ IIP(Lock | LockReg | ModRM | SrcMem | Priv | Op3264, em_cr_write, cr_write, check_cr_write),
IIP(ModRM | SrcMem | Priv | Op3264, em_dr_write, dr_write, check_dr_write),
N, N, N, N,
N, N, N, GP(ModRM | DstMem | SrcReg | Sse | Mov | Aligned, &pfx_vmovntpx),
@@ -4130,7 +4137,8 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
}
/* LOCK prefix is allowed only with some instructions */
- if (ctxt->lock_prefix && (!(ctxt->d & Lock) || ctxt->dst.type != OP_MEM)) {
+ if (ctxt->lock_prefix && (!(ctxt->d & Lock)
+ || (ctxt->dst.type != OP_MEM && !(ctxt->d & LockReg)))) {
rc = emulate_ud(ctxt);
goto done;
}
@@ -4146,8 +4146,13 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
unsigned long cr0, val;
u64 intercept;
- if (info->intercept == x86_intercept_cr_write)
- icpt_info.exit_code += info->modrm_reg;
+ if (info->intercept == x86_intercept_cr_write) {
+ int cr = info->modrm_reg;
+ if (cr == 0 && info->lock_prefix) {
+ cr = 8;
+ }
+ icpt_info.exit_code += cr;
+ }
if (icpt_info.exit_code != SVM_EXIT_WRITE_CR0)
break;
@@ -33,6 +33,7 @@ struct x86_exception {
struct x86_instruction_info {
u8 intercept; /* which intercept */
u8 rep_prefix; /* rep prefix? */
+ u8 lock_prefix; /* lock prefix? */
u8 modrm_mod; /* mod part of modrm */
u8 modrm_reg; /* index of register used */
u8 modrm_rm; /* rm part of modrm */