From: Like Xu <like.xu.linux@gmail.com>
To: Yang Weijiang <weijiang.yang@intel.com>
Cc: kvm@vger.kernel.org,
"Wang Wei (Intel VMM)" <wei.w.wang@intel.com>,
Paolo Bonzini <pbonzini@redhat.com>,
Jim Mattson <jmattson@google.com>,
Vitaly Kuznetsov <vkuznets@redhat.com>,
Sean Christopherson <seanjc@google.com>
Subject: Re: [kvm-unit-tests PATCH] x86: Add Arch LBR unit-test application
Date: Mon, 9 Aug 2021 12:55:28 +0800 [thread overview]
Message-ID: <c5ffb720-48ea-b4e8-6a47-dca78a726a7c@gmail.com> (raw)
In-Reply-To: <1628235832-26608-1-git-send-email-weijiang.yang@intel.com>
On 6/8/2021 3:43 pm, Yang Weijiang wrote:
> This unit-test app targets to check whehter Arch LBR is enabled
s/whehter/whether/
> for guest. XSAVES/XRSTORS are used to accelerate LBR MSR save/restore.
This test just verifies that LBR records are not changed or lost before and after
the XSAVES/XRSTORS operations instead of measuring the acceleration.
Please add more sub-testcases:
- Sanity checks about valid MSR_ARCH_LBR_CTL_bitmask;
- On a software write to IA32_LBR_DEPTH, all LBR entries are reset to 0;
- LBR from the nested VM since you added the nested support (not in immediate need);
- Check the #DB/#SMI behavior about both leagcy and Arch LBR logging;
>
> Signed-off-by: Yang Weijiang <weijiang.yang@intel.com>
> ---
> x86/Makefile.x86_64 | 1 +
> x86/pmu_arch_lbr.c | 221 ++++++++++++++++++++++++++++++++++++++++++++
> x86/unittests.cfg | 6 ++
> 3 files changed, 228 insertions(+)
> create mode 100644 x86/pmu_arch_lbr.c
>
> diff --git a/x86/Makefile.x86_64 b/x86/Makefile.x86_64
> index 8134952..0727830 100644
> --- a/x86/Makefile.x86_64
> +++ b/x86/Makefile.x86_64
> @@ -24,6 +24,7 @@ tests += $(TEST_DIR)/vmware_backdoors.flat
> tests += $(TEST_DIR)/rdpru.flat
> tests += $(TEST_DIR)/pks.flat
> tests += $(TEST_DIR)/pmu_lbr.flat
> +tests += $(TEST_DIR)/pmu_arch_lbr.flat
Why separate into two files considering some basic test codes can be reused ?
>
> ifneq ($(fcf_protection_full),)
> tests += $(TEST_DIR)/cet.flat
> diff --git a/x86/pmu_arch_lbr.c b/x86/pmu_arch_lbr.c
> new file mode 100644
> index 0000000..9a1e562
> --- /dev/null
> +++ b/x86/pmu_arch_lbr.c
> @@ -0,0 +1,221 @@
> +#include "asm-generic/page.h"
> +#include "x86/processor.h"
> +#include "x86/msr.h"
> +#include "x86/desc.h"
> +#include "bitops.h"
> +
> +#define MSR_ARCH_LBR_CTL 0x000014ce
> +#define MSR_ARCH_LBR_DEPTH 0x000014cf
> +#define MSR_ARCH_LBR_FROM_0 0x00001500
> +#define MSR_ARCH_LBR_TO_0 0x00001600
> +#define MSR_ARCH_LBR_INFO_0 0x00001200
> +
> +#define MSR_IA32_XSS 0x00000da0
> +
> +#define IA32_XSS_ARCH_LBR (1UL << 15)
> +#define CR4_OSXSAVE_BIT (1UL << 18)
> +#define CPUID_EDX_ARCH_LBR (1UL << 19)
> +
> +#define ARCH_LBR_CTL_BITS 0x3f0003
> +#define MAX_LBR_DEPTH 32
> +
> +#define XSAVES ".byte 0x48,0x0f,0xc7,0x2f\n\t"
> +#define XRSTORS ".byte 0x48,0x0f,0xc7,0x1f\n\t"
> +
> +struct xstate_header {
> + u64 xfeatures;
> + u64 xcomp_bv;
> + u64 reserved[6];
> +} __attribute__((packed));
> +
> +struct arch_lbr_entry {
> + u64 lbr_from;
> + u64 lbr_to;
> + u64 lbr_info;
> +}__attribute__((packed));
> +
> +struct arch_lbr_struct {
> + u64 lbr_ctl;
> + u64 lbr_depth;
> + u64 ler_from;
> + u64 ler_to;
> + u64 ler_info;
> + struct arch_lbr_entry lbr_records[MAX_LBR_DEPTH];
> +}__attribute__((packed));
> +
> +struct xsave_struct {
> + u8 fpu_sse[512];
> + struct xstate_header xstate_hdr;
> + struct arch_lbr_struct records;
> +} __attribute__((packed));
> +
> +u8 __attribute__((__aligned__(64))) xsave_buffer[PAGE_SIZE];
> +
> +struct xsave_struct *test_buf = (struct xsave_struct *)xsave_buffer;
> +
> +u64 lbr_from[MAX_LBR_DEPTH], lbr_to[MAX_LBR_DEPTH], lbr_info[MAX_LBR_DEPTH];
> +
> +u64 lbr_ctl, lbr_depth;
> +
> +volatile int count;
> +
> +static __attribute__((noinline)) int compute_flag(int i)
> +{
> + if (i % 10 < 4)
> + return i + 1;
> + return 0;
> +}
> +
> +static __attribute__((noinline)) int lbr_test(void)
> +{
> + int i;
> + int flag;
> + volatile double x = 1212121212, y = 121212;
> +
> + for (i = 0; i < 200000000; i++) {
> + flag = compute_flag(i);
> + count++;
> + if (flag)
> + x += x / y + y / x;
> + }
> + return 0;
> +}
> +
> +static inline void xrstors(struct xsave_struct *fx, unsigned long mask)
> +{
> + u32 lmask = mask;
> + u32 hmask = mask >> 32;
> +
> + asm volatile(XRSTORS
> + : : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
> + : "memory");
> +}
> +
> +static inline int xsaves(struct xsave_struct *fx, unsigned long mask)
> +{
> + u32 lmask = mask;
> + u32 hmask = mask >> 32;
> + int err = 0;
> +
> + asm volatile(XSAVES
> + : [err] "=r" (err) : "D" (fx), "m" (*fx), "a" (lmask), "d" (hmask)
> + : "memory");
> + return err;
> +}
> +
> +static void clear_lbr_records(void)
> +{
> + int i;
> +
> + for (i = 0; i < lbr_depth; ++i) {
> + wrmsr(MSR_ARCH_LBR_FROM_0 + i, 0);
> + wrmsr(MSR_ARCH_LBR_TO_0 + i, 0);
> + wrmsr(MSR_ARCH_LBR_INFO_0 + i, 0);
> + }
> +}
"On a software write to IA32_LBR_DEPTH, all LBR entries are reset to 0."
> +
> +static bool check_xsaves_records(void)
> +{
> + int i;
> + struct arch_lbr_entry *records = test_buf->records.lbr_records;
> +
> + for (i = 0; i < lbr_depth; ++i) {
> + if (lbr_from[i] != (*(records + i)).lbr_from ||
> + lbr_to[i] != (*(records + i)).lbr_to ||
> + lbr_info[i] != (*(records + i)).lbr_info)
> + break;
> + }
> +
> + return i == lbr_depth;
> +}
> +
> +static bool check_msrs_records(void)
> +{
> + int i;
> +
> + for (i = 0; i < lbr_depth; ++i) {
> + if (lbr_from[i] != rdmsr(MSR_ARCH_LBR_FROM_0 + i) ||
> + lbr_to[i] != rdmsr(MSR_ARCH_LBR_TO_0 + i) ||
> + lbr_info[i] != rdmsr(MSR_ARCH_LBR_INFO_0 + i))
> + break;
> + }
> +
> + return i == lbr_depth;
> +}
> +
> +static void test_with_xsaves(void)
> +{
> + u32 cr4;
> +
> + /* Only test Arch LBR save/restore, ignore other features.*/
> + wrmsr(MSR_IA32_XSS, IA32_XSS_ARCH_LBR);
> +
> + cr4 = read_cr4();
> + write_cr4(cr4 | CR4_OSXSAVE_BIT);
> +
> + xsaves(test_buf, IA32_XSS_ARCH_LBR | 0x3);
> +
> + report(check_xsaves_records(),
> + "The LBR records in XSAVES area match the MSR values!");
> +
> + clear_lbr_records();
> +
> + xrstors(test_buf, IA32_XSS_ARCH_LBR | 0x3);
> +
> + report(check_msrs_records(),
> + "The restored LBR MSR values match the original ones!");
> +}
> +
> +int main(int ac, char **av)
> +{
> + struct cpuid id;
> + int i;
> +
> + id = cpuid(0x7);
> + if (!(id.d & CPUID_EDX_ARCH_LBR)) {
> + printf("No Arch LBR is detected!\n");
> + return report_summary();
> + }
> +
> + id = raw_cpuid(0xd, 1);
> + if (!(id.a & 0x8)) {
> + printf("XSAVES is not supported!.\n");
> + return report_summary();
> + }
> +
> + setup_vm();
> +
> + id = cpuid(0x1c);
> + lbr_depth = (fls(id.a & 0xff) + 1)*8;
> +
> + wrmsr(MSR_ARCH_LBR_DEPTH, lbr_depth);
Need to check if all LBR entries are reset to 0 to avoid contamination.
> +
> + lbr_ctl = ARCH_LBR_CTL_BITS;
> + wrmsr(MSR_ARCH_LBR_CTL, lbr_ctl);
> +
> + lbr_test();
> +
> + /* Disable Arch LBR sampling before run sanity checks. */
> + lbr_ctl &= ~0x1;
> + wrmsr(MSR_ARCH_LBR_CTL, lbr_ctl);
> +
> + /*
> + * LBR records are kept at this point, need to save them
> + * ASAP, otherwise they could be reset to 0s.
How ? LBR has just been disabled, so why is it possible to reset it to 0s.
> + */
> + for (i = 0; i < lbr_depth; ++i) {
> + if (!(lbr_from[i] = rdmsr(MSR_ARCH_LBR_FROM_0 + i)) ||
> + !(lbr_to[i] = rdmsr(MSR_ARCH_LBR_TO_0 + i)) ||
> + !(lbr_info[i] = rdmsr(MSR_ARCH_LBR_INFO_0 + i)))
> + break;
> + }
> +
> + if (i != lbr_depth) {
> + printf("Invalid Arch LBR records.\n");
> + return report_summary();
> + }
> +
> + test_with_xsaves();
> +
> + return report_summary();
> +}
> diff --git a/x86/unittests.cfg b/x86/unittests.cfg
> index d5efab0..88b2203 100644
> --- a/x86/unittests.cfg
> +++ b/x86/unittests.cfg
> @@ -185,6 +185,12 @@ extra_params = -cpu host,migratable=no
> check = /sys/module/kvm/parameters/ignore_msrs=N
> check = /proc/sys/kernel/nmi_watchdog=0
>
> +[pmu_arch_lbr]
> +file = pmu_arch_lbr.flat
> +extra_params = -cpu host,lbr-fmt=0x3f
Ugh, please keep using "migratable=no"
> +check = /sys/module/kvm/parameters/ignore_msrs=N
> +check = /proc/sys/kernel/nmi_watchdog=0
For nmi_watchdog=1, the Arch LBR test should pass as well.
> +
> [vmware_backdoors]
> file = vmware_backdoors.flat
> extra_params = -machine vmport=on -cpu max
>
prev parent reply other threads:[~2021-08-09 4:55 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-08-06 7:43 [kvm-unit-tests PATCH] x86: Add Arch LBR unit-test application Yang Weijiang
2021-08-09 4:55 ` Like Xu [this message]
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=c5ffb720-48ea-b4e8-6a47-dca78a726a7c@gmail.com \
--to=like.xu.linux@gmail.com \
--cc=jmattson@google.com \
--cc=kvm@vger.kernel.org \
--cc=pbonzini@redhat.com \
--cc=seanjc@google.com \
--cc=vkuznets@redhat.com \
--cc=wei.w.wang@intel.com \
--cc=weijiang.yang@intel.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.