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

Commit 6af6427a authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Greg Kroah-Hartman
Browse files

x86: xen: insn: Decode Xen and KVM emulate-prefix signature



commit 4d65adfcd1196818659d3bd9b42dccab291e1751 upstream.

Decode Xen and KVM's emulate-prefix signature by x86 insn decoder.
It is called "prefix" but actually not x86 instruction prefix, so
this adds insn.emulate_prefix_size field instead of reusing
insn.prefixes.

If x86 decoder finds a special sequence of instructions of
XEN_EMULATE_PREFIX and 'ud2a; .ascii "kvm"', it just counts the
length, set insn.emulate_prefix_size and fold it with the next
instruction. In other words, the signature and the next instruction
is treated as a single instruction.

Signed-off-by: default avatarMasami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: default avatarJosh Poimboeuf <jpoimboe@redhat.com>
Cc: Juergen Gross <jgross@suse.com>
Cc: x86@kernel.org
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: xen-devel@lists.xenproject.org
Cc: Randy Dunlap <rdunlap@infradead.org>
Link: https://lkml.kernel.org/r/156777564986.25081.4964537658500952557.stgit@devnote2


[mheyne: resolved contextual conflict in tools/objtools/sync-check.sh]
Signed-off-by: default avatarMaximilian Heyne <mheyne@amazon.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c67a4a91
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ struct insn {
		struct insn_field immediate2;	/* for 64bit imm or seg16 */
	};

	int	emulate_prefix_size;
	insn_attr_t attr;
	unsigned char opnd_bytes;
	unsigned char addr_bytes;
@@ -128,6 +129,11 @@ static inline int insn_is_evex(struct insn *insn)
	return (insn->vex_prefix.nbytes == 4);
}

static inline int insn_has_emulate_prefix(struct insn *insn)
{
	return !!insn->emulate_prefix_size;
}

/* Ensure this instruction is decoded completely */
static inline int insn_complete(struct insn *insn)
{
+34 −0
Original line number Diff line number Diff line
@@ -13,6 +13,8 @@
#include <asm/inat.h>
#include <asm/insn.h>

#include <asm/emulate_prefix.h>

/* Verify next sizeof(t) bytes can be on the same instruction */
#define validate_next(t, insn, n)	\
	((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr)
@@ -58,6 +60,36 @@ void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64)
		insn->addr_bytes = 4;
}

static const insn_byte_t xen_prefix[] = { __XEN_EMULATE_PREFIX };
static const insn_byte_t kvm_prefix[] = { __KVM_EMULATE_PREFIX };

static int __insn_get_emulate_prefix(struct insn *insn,
				     const insn_byte_t *prefix, size_t len)
{
	size_t i;

	for (i = 0; i < len; i++) {
		if (peek_nbyte_next(insn_byte_t, insn, i) != prefix[i])
			goto err_out;
	}

	insn->emulate_prefix_size = len;
	insn->next_byte += len;

	return 1;

err_out:
	return 0;
}

static void insn_get_emulate_prefix(struct insn *insn)
{
	if (__insn_get_emulate_prefix(insn, xen_prefix, sizeof(xen_prefix)))
		return;

	__insn_get_emulate_prefix(insn, kvm_prefix, sizeof(kvm_prefix));
}

/**
 * insn_get_prefixes - scan x86 instruction prefix bytes
 * @insn:	&struct insn containing instruction
@@ -76,6 +108,8 @@ void insn_get_prefixes(struct insn *insn)
	if (prefixes->got)
		return;

	insn_get_emulate_prefix(insn);

	nb = 0;
	lb = 0;
	b = peek_next(insn_byte_t, insn);
+14 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_X86_EMULATE_PREFIX_H
#define _ASM_X86_EMULATE_PREFIX_H

/*
 * Virt escape sequences to trigger instruction emulation;
 * ideally these would decode to 'whole' instruction and not destroy
 * the instruction stream; sadly this is not true for the 'kvm' one :/
 */

#define __XEN_EMULATE_PREFIX  0x0f,0x0b,0x78,0x65,0x6e  /* ud2 ; .ascii "xen" */
#define __KVM_EMULATE_PREFIX  0x0f,0x0b,0x6b,0x76,0x6d	/* ud2 ; .ascii "kvm" */

#endif
+6 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ struct insn {
		struct insn_field immediate2;	/* for 64bit imm or seg16 */
	};

	int	emulate_prefix_size;
	insn_attr_t attr;
	unsigned char opnd_bytes;
	unsigned char addr_bytes;
@@ -128,6 +129,11 @@ static inline int insn_is_evex(struct insn *insn)
	return (insn->vex_prefix.nbytes == 4);
}

static inline int insn_has_emulate_prefix(struct insn *insn)
{
	return !!insn->emulate_prefix_size;
}

/* Ensure this instruction is decoded completely */
static inline int insn_complete(struct insn *insn)
{
+34 −0
Original line number Diff line number Diff line
@@ -13,6 +13,8 @@
#include "../include/asm/inat.h"
#include "../include/asm/insn.h"

#include "../include/asm/emulate_prefix.h"

/* Verify next sizeof(t) bytes can be on the same instruction */
#define validate_next(t, insn, n)	\
	((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr)
@@ -58,6 +60,36 @@ void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64)
		insn->addr_bytes = 4;
}

static const insn_byte_t xen_prefix[] = { __XEN_EMULATE_PREFIX };
static const insn_byte_t kvm_prefix[] = { __KVM_EMULATE_PREFIX };

static int __insn_get_emulate_prefix(struct insn *insn,
				     const insn_byte_t *prefix, size_t len)
{
	size_t i;

	for (i = 0; i < len; i++) {
		if (peek_nbyte_next(insn_byte_t, insn, i) != prefix[i])
			goto err_out;
	}

	insn->emulate_prefix_size = len;
	insn->next_byte += len;

	return 1;

err_out:
	return 0;
}

static void insn_get_emulate_prefix(struct insn *insn)
{
	if (__insn_get_emulate_prefix(insn, xen_prefix, sizeof(xen_prefix)))
		return;

	__insn_get_emulate_prefix(insn, kvm_prefix, sizeof(kvm_prefix));
}

/**
 * insn_get_prefixes - scan x86 instruction prefix bytes
 * @insn:	&struct insn containing instruction
@@ -76,6 +108,8 @@ void insn_get_prefixes(struct insn *insn)
	if (prefixes->got)
		return;

	insn_get_emulate_prefix(insn);

	nb = 0;
	lb = 0;
	b = peek_next(insn_byte_t, insn);
Loading