From: Paolo Bonzini <pbonzini@redhat.com>
To: Arthur Chunqi Li <yzt356@gmail.com>
Cc: kvm@vger.kernel.org, jan.kiszka@web.de, gleb@redhat.com
Subject: Re: [PATCH v2 4/4] kvm-unit-tests: VMX: Add test cases for instruction interception
Date: Mon, 09 Sep 2013 14:42:44 +0200 [thread overview]
Message-ID: <522DC244.4020405@redhat.com> (raw)
In-Reply-To: <1376567109-20834-5-git-send-email-yzt356@gmail.com>
Il 15/08/2013 13:45, Arthur Chunqi Li ha scritto:
> Add test cases for instruction interception, including four types:
> 1. Primary Processor-Based VM-Execution Controls (HLT/INVLPG/MWAIT/
> RDPMC/RDTSC/MONITOR/PAUSE)
> 2. Secondary Processor-Based VM-Execution Controls (WBINVD)
> 3. No control flag, always trap (CPUID/INVD)
> 4. Instructions always pass
>
> Signed-off-by: Arthur Chunqi Li <yzt356@gmail.com>
> ---
> x86/vmx.c | 3 +-
> x86/vmx.h | 7 +++
> x86/vmx_tests.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 160 insertions(+), 2 deletions(-)
>
> diff --git a/x86/vmx.c b/x86/vmx.c
> index ca36d35..c346070 100644
> --- a/x86/vmx.c
> +++ b/x86/vmx.c
> @@ -336,8 +336,7 @@ static void init_vmx(void)
> : MSR_IA32_VMX_ENTRY_CTLS);
> ctrl_cpu_rev[0].val = rdmsr(basic.ctrl ? MSR_IA32_VMX_TRUE_PROC
> : MSR_IA32_VMX_PROCBASED_CTLS);
> - if (ctrl_cpu_rev[0].set & CPU_SECONDARY)
> - ctrl_cpu_rev[1].val = rdmsr(MSR_IA32_VMX_PROCBASED_CTLS2);
> + ctrl_cpu_rev[1].val = rdmsr(MSR_IA32_VMX_PROCBASED_CTLS2);
> if (ctrl_cpu_rev[1].set & CPU_EPT || ctrl_cpu_rev[1].set & CPU_VPID)
> ept_vpid.val = rdmsr(MSR_IA32_VMX_EPT_VPID_CAP);
>
> diff --git a/x86/vmx.h b/x86/vmx.h
> index dba8b20..2784ac6 100644
> --- a/x86/vmx.h
> +++ b/x86/vmx.h
> @@ -354,12 +354,17 @@ enum Ctrl0 {
> CPU_INTR_WINDOW = 1ul << 2,
> CPU_HLT = 1ul << 7,
> CPU_INVLPG = 1ul << 9,
> + CPU_MWAIT = 1ul << 10,
> + CPU_RDPMC = 1ul << 11,
> + CPU_RDTSC = 1ul << 12,
> CPU_CR3_LOAD = 1ul << 15,
> CPU_CR3_STORE = 1ul << 16,
> CPU_TPR_SHADOW = 1ul << 21,
> CPU_NMI_WINDOW = 1ul << 22,
> CPU_IO = 1ul << 24,
> CPU_IO_BITMAP = 1ul << 25,
> + CPU_MONITOR = 1ul << 29,
> + CPU_PAUSE = 1ul << 30,
Please keep these sorted.
> CPU_MSR_BITMAP = 1ul << 28,
> CPU_SECONDARY = 1ul << 31,
> };
> @@ -368,6 +373,8 @@ enum Ctrl1 {
> CPU_EPT = 1ul << 1,
> CPU_VPID = 1ul << 5,
> CPU_URG = 1ul << 7,
> + CPU_WBINVD = 1ul << 6,
> + CPU_RDRAND = 1ul << 11,
> };
>
> #define SAVE_GPR \
> diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
> index cd4dd99..be3e3b4 100644
> --- a/x86/vmx_tests.c
> +++ b/x86/vmx_tests.c
> @@ -22,6 +22,16 @@ static inline void set_stage(u32 s)
> barrier();
> }
>
> +static inline u32 get_stage()
> +{
> + u32 s;
> +
> + barrier();
> + s = stage;
> + barrier();
> + return s;
> +}
> +
> void basic_init()
> {
> }
> @@ -630,6 +640,146 @@ static int iobmp_exit_handler()
> return VMX_TEST_VMEXIT;
> }
>
> +#define INSN_CPU0 0
> +#define INSN_CPU1 1
> +#define INSN_ALWAYS_TRAP 2
> +#define INSN_NEVER_TRAP 3
> +
> +#define FIELD_EXIT_QUAL 0
> +#define FIELD_INSN_INFO 1
> +
> +asm(
> + "insn_hlt: hlt;ret\n\t"
> + "insn_invlpg: invlpg 0x12345678;ret\n\t"
> + "insn_mwait: mwait;ret\n\t"
> + "insn_rdpmc: rdpmc;ret\n\t"
> + "insn_rdtsc: rdtsc;ret\n\t"
> + "insn_monitor: monitor;ret\n\t"
> + "insn_pause: pause;ret\n\t"
> + "insn_wbinvd: wbinvd;ret\n\t"
> + "insn_cpuid: cpuid;ret\n\t"
> + "insn_invd: invd;ret\n\t"
> +);
> +extern void insn_hlt();
> +extern void insn_invlpg();
> +extern void insn_mwait();
> +extern void insn_rdpmc();
> +extern void insn_rdtsc();
> +extern void insn_monitor();
> +extern void insn_pause();
> +extern void insn_wbinvd();
> +extern void insn_cpuid();
> +extern void insn_invd();
> +
> +u32 cur_insn;
> +
> +struct insn_table {
> + const char *name;
> + u32 flag;
> + void (*insn_func)();
> + u32 type;
> + u32 reason;
> + ulong exit_qual;
> + u32 insn_info;
> + // Use FIELD_EXIT_QUAL and FIELD_INSN_INFO to efines
> + // which field need to be tested, reason is always tested
> + u32 test_field;
> +};
> +
> +static struct insn_table insn_table[] = {
> + // Flags for Primary Processor-Based VM-Execution Controls
> + {"HLT", CPU_HLT, insn_hlt, INSN_CPU0, 12, 0, 0, 0},
> + {"INVLPG", CPU_INVLPG, insn_invlpg, INSN_CPU0, 14,
> + 0x12345678, 0, FIELD_EXIT_QUAL},
> + {"MWAIT", CPU_MWAIT, insn_mwait, INSN_CPU0, 36, 0, 0, 0},
> + {"RDPMC", CPU_RDPMC, insn_rdpmc, INSN_CPU0, 15, 0, 0, 0},
> + {"RDTSC", CPU_RDTSC, insn_rdtsc, INSN_CPU0, 16, 0, 0, 0},
> + {"MONITOR", CPU_MONITOR, insn_monitor, INSN_CPU0, 39, 0, 0, 0},
> + {"PAUSE", CPU_PAUSE, insn_pause, INSN_CPU0, 40, 0, 0, 0},
> + // Flags for Secondary Processor-Based VM-Execution Controls
> + {"WBINVD", CPU_WBINVD, insn_wbinvd, INSN_CPU1, 54, 0, 0, 0},
> + // Instructions always trap
> + {"CPUID", 0, insn_cpuid, INSN_ALWAYS_TRAP, 10, 0, 0, 0},
> + {"INVD", 0, insn_invd, INSN_ALWAYS_TRAP, 13, 0, 0, 0},
> + // Instructions never trap
> + {NULL},
> +};
> +
> +static void insn_intercept_init()
> +{
> + u32 ctrl_cpu[2];
> +
> + ctrl_cpu[0] = vmcs_read(CPU_EXEC_CTRL0);
> + ctrl_cpu[0] |= CPU_HLT | CPU_INVLPG | CPU_MWAIT | CPU_RDPMC | CPU_RDTSC |
> + CPU_MONITOR | CPU_PAUSE | CPU_SECONDARY;
> + ctrl_cpu[0] &= ctrl_cpu_rev[0].clr;
> + vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu[0]);
> + ctrl_cpu[1] = vmcs_read(CPU_EXEC_CTRL1);
> + ctrl_cpu[1] |= CPU_WBINVD | CPU_RDRAND;
> + ctrl_cpu[1] &= ctrl_cpu_rev[1].clr;
> + vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu[1]);
> +}
> +
> +static void insn_intercept_main()
> +{
> + cur_insn = 0;
> + while(insn_table[cur_insn].name != NULL) {
> + set_stage(cur_insn);
> + if ((insn_table[cur_insn].type == INSN_CPU0
> + && !(ctrl_cpu_rev[0].clr & insn_table[cur_insn].flag))
> + || (insn_table[cur_insn].type == INSN_CPU1
> + && !(ctrl_cpu_rev[1].clr & insn_table[cur_insn].flag))) {
> + printf("\tCPU_CTRL1.CPU_%s is not supported.\n",
> + insn_table[cur_insn].name);
> + continue;
> + }
> + insn_table[cur_insn].insn_func();
> + switch (insn_table[cur_insn].type) {
> + case INSN_CPU0:
> + case INSN_CPU1:
> + case INSN_ALWAYS_TRAP:
> + if (stage != cur_insn + 1)
> + report(insn_table[cur_insn].name, 0);
> + else
> + report(insn_table[cur_insn].name, 1);
> + break;
> + case INSN_NEVER_TRAP:
> + if (stage == cur_insn + 1)
> + report(insn_table[cur_insn].name, 0);
> + else
> + report(insn_table[cur_insn].name, 1);
> + break;
> + }
> + cur_insn ++;
No space before ++.
Otherwise looks good.
Paolo
> + }
> +}
> +
> +static int insn_intercept_exit_handler()
> +{
> + u64 guest_rip;
> + u32 reason;
> + ulong exit_qual;
> + u32 insn_len;
> + u32 insn_info;
> + bool pass;
> +
> + guest_rip = vmcs_read(GUEST_RIP);
> + reason = vmcs_read(EXI_REASON) & 0xff;
> + exit_qual = vmcs_read(EXI_QUALIFICATION);
> + insn_len = vmcs_read(EXI_INST_LEN);
> + insn_info = vmcs_read(EXI_INST_INFO);
> + pass = (cur_insn == get_stage()) &&
> + insn_table[cur_insn].reason == reason;
> + if (insn_table[cur_insn].test_field & FIELD_EXIT_QUAL)
> + pass = pass && insn_table[cur_insn].exit_qual == exit_qual;
> + if (insn_table[cur_insn].test_field & FIELD_INSN_INFO)
> + pass = pass && insn_table[cur_insn].insn_info == insn_info;
> + if (pass)
> + set_stage(stage + 1);
> + vmcs_write(GUEST_RIP, guest_rip + insn_len);
> + return VMX_TEST_RESUME;
> +}
> +
> /* name/init/guest_main/exit_handler/syscall_handler/guest_regs
> basic_* just implement some basic functions */
> struct vmx_test vmx_tests[] = {
> @@ -645,5 +795,7 @@ struct vmx_test vmx_tests[] = {
> cr_shadowing_exit_handler, basic_syscall_handler, {0} },
> { "I/O bitmap", iobmp_init, iobmp_main, iobmp_exit_handler,
> basic_syscall_handler, {0} },
> + { "instruction intercept", insn_intercept_init, insn_intercept_main,
> + insn_intercept_exit_handler, basic_syscall_handler, {0} },
> { NULL, NULL, NULL, NULL, NULL, {0} },
> };
>
next prev parent reply other threads:[~2013-09-09 12:42 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-08-15 11:45 [PATCH v2 0/4] kvm-unit-tests: Add a series of test cases Arthur Chunqi Li
2013-08-15 11:45 ` [PATCH v2 1/4] kvm-unit-tests: VMX: Add test cases for PAT and EFER Arthur Chunqi Li
2013-08-15 11:45 ` [PATCH v2 2/4] kvm-unit-tests: VMX: Add test cases for CR0/4 shadowing Arthur Chunqi Li
2013-09-09 12:36 ` Paolo Bonzini
2013-08-15 11:45 ` [PATCH v2 3/4] kvm-unit-tests: VMX: Add test cases for I/O bitmaps Arthur Chunqi Li
2013-09-09 12:39 ` Paolo Bonzini
2013-08-15 11:45 ` [PATCH v2 4/4] kvm-unit-tests: VMX: Add test cases for instruction interception Arthur Chunqi Li
2013-09-09 12:42 ` Paolo Bonzini [this message]
2013-09-02 9:06 ` [PATCH v2 0/4] kvm-unit-tests: Add a series of test cases Arthur Chunqi Li
2013-09-03 11:50 ` Gleb Natapov
2013-09-09 7:15 ` Jan Kiszka
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=522DC244.4020405@redhat.com \
--to=pbonzini@redhat.com \
--cc=gleb@redhat.com \
--cc=jan.kiszka@web.de \
--cc=kvm@vger.kernel.org \
--cc=yzt356@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.