Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 26d05cc7 authored by Avi Kivity's avatar Avi Kivity
Browse files

KVM: x86 emulator: move 0F 01 sub-opcodes into their own functions



Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent d4224449
Loading
Loading
Loading
Loading
+99 −47
Original line number Diff line number Diff line
@@ -2589,6 +2589,95 @@ static int em_clts(struct x86_emulate_ctxt *ctxt)
	return X86EMUL_CONTINUE;
}

static int em_vmcall(struct x86_emulate_ctxt *ctxt)
{
	struct decode_cache *c = &ctxt->decode;
	int rc;

	if (c->modrm_mod != 3 || c->modrm_rm != 1)
		return X86EMUL_UNHANDLEABLE;

	rc = ctxt->ops->fix_hypercall(ctxt);
	if (rc != X86EMUL_CONTINUE)
		return rc;

	/* Let the processor re-execute the fixed hypercall */
	c->eip = ctxt->eip;
	/* Disable writeback. */
	c->dst.type = OP_NONE;
	return X86EMUL_CONTINUE;
}

static int em_lgdt(struct x86_emulate_ctxt *ctxt)
{
	struct decode_cache *c = &ctxt->decode;
	struct desc_ptr desc_ptr;
	int rc;

	rc = read_descriptor(ctxt, ctxt->ops, c->src.addr.mem,
			     &desc_ptr.size, &desc_ptr.address,
			     c->op_bytes);
	if (rc != X86EMUL_CONTINUE)
		return rc;
	ctxt->ops->set_gdt(ctxt, &desc_ptr);
	/* Disable writeback. */
	c->dst.type = OP_NONE;
	return X86EMUL_CONTINUE;
}

static int em_svm(struct x86_emulate_ctxt *ctxt)
{
	struct decode_cache *c = &ctxt->decode;
	int rc;

	switch (c->modrm_rm) {
	case 1:
		rc = ctxt->ops->fix_hypercall(ctxt);
		break;
	default:
		return X86EMUL_UNHANDLEABLE;
	}
	/* Disable writeback. */
	c->dst.type = OP_NONE;
	return rc;
}

static int em_lidt(struct x86_emulate_ctxt *ctxt)
{
	struct decode_cache *c = &ctxt->decode;
	struct desc_ptr desc_ptr;
	int rc;

	rc = read_descriptor(ctxt, ctxt->ops, c->src.addr.mem,
			     &desc_ptr.size,
			     &desc_ptr.address,
			     c->op_bytes);
	if (rc != X86EMUL_CONTINUE)
		return rc;
	ctxt->ops->set_idt(ctxt, &desc_ptr);
	/* Disable writeback. */
	c->dst.type = OP_NONE;
	return X86EMUL_CONTINUE;
}

static int em_smsw(struct x86_emulate_ctxt *ctxt)
{
	struct decode_cache *c = &ctxt->decode;

	c->dst.bytes = 2;
	c->dst.val = ctxt->ops->get_cr(ctxt, 0);
	return X86EMUL_CONTINUE;
}

static int em_lmsw(struct x86_emulate_ctxt *ctxt)
{
	struct decode_cache *c = &ctxt->decode;
	ctxt->ops->set_cr(ctxt, 0, (ctxt->ops->get_cr(ctxt, 0) & ~0x0eul)
			  | (c->src.val & 0x0f));
	c->dst.type = OP_NONE;
	return X86EMUL_CONTINUE;
}

static bool valid_cr(int nr)
{
	switch (nr) {
@@ -3509,7 +3598,6 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
	int rc = X86EMUL_CONTINUE;
	int saved_dst_type = c->dst.type;
	int irq; /* Used for int 3, int, and into */
	struct desc_ptr desc_ptr;

	ctxt->decode.mem_read.pos = 0;

@@ -4022,62 +4110,26 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
	case 0x01: /* lgdt, lidt, lmsw */
		switch (c->modrm_reg) {
		case 0: /* vmcall */
			if (c->modrm_mod != 3 || c->modrm_rm != 1)
				goto cannot_emulate;

			rc = ctxt->ops->fix_hypercall(ctxt);
			if (rc != X86EMUL_CONTINUE)
				goto done;

			/* Let the processor re-execute the fixed hypercall */
			c->eip = ctxt->eip;
			/* Disable writeback. */
			c->dst.type = OP_NONE;
			rc = em_vmcall(ctxt);
			break;
		case 2: /* lgdt */
			rc = read_descriptor(ctxt, ops, c->src.addr.mem,
					     &desc_ptr.size, &desc_ptr.address,
					     c->op_bytes);
			if (rc != X86EMUL_CONTINUE)
				goto done;
			ctxt->ops->set_gdt(ctxt, &desc_ptr);
			/* Disable writeback. */
			c->dst.type = OP_NONE;
			rc = em_lgdt(ctxt);
			break;
		case 3: /* lidt/vmmcall */
			if (c->modrm_mod == 3) {
				switch (c->modrm_rm) {
				case 1:
					rc = ctxt->ops->fix_hypercall(ctxt);
					break;
				default:
					goto cannot_emulate;
				}
			} else {
				rc = read_descriptor(ctxt, ops, c->src.addr.mem,
						     &desc_ptr.size,
						     &desc_ptr.address,
						     c->op_bytes);
				if (rc != X86EMUL_CONTINUE)
					goto done;
				ctxt->ops->set_idt(ctxt, &desc_ptr);
			}
			/* Disable writeback. */
			c->dst.type = OP_NONE;
			if (c->modrm_mod == 3)
				return em_svm(ctxt);
			else
				return em_lidt(ctxt);
			break;
		case 4: /* smsw */
			c->dst.bytes = 2;
			c->dst.val = ops->get_cr(ctxt, 0);
			rc = em_smsw(ctxt);
			break;
		case 6: /* lmsw */
			ops->set_cr(ctxt, 0, (ops->get_cr(ctxt, 0) & ~0x0eul) |
				    (c->src.val & 0x0f));
			c->dst.type = OP_NONE;
			rc = em_lmsw(ctxt);
			break;
		case 5: /* not defined */
			emulate_ud(ctxt);
			rc = X86EMUL_PROPAGATE_FAULT;
			goto done;
			rc = emulate_ud(ctxt);
			break;
		case 7: /* invlpg*/
			rc = em_invlpg(ctxt);
			break;