From patchwork Tue Oct 27 17:19:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandru Elisei X-Patchwork-Id: 11861127 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 07F23C56201 for ; Tue, 27 Oct 2020 17:20:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A8963222E9 for ; Tue, 27 Oct 2020 17:20:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1818317AbgJ0RS6 (ORCPT ); Tue, 27 Oct 2020 13:18:58 -0400 Received: from foss.arm.com ([217.140.110.172]:47648 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1818301AbgJ0RSz (ORCPT ); Tue, 27 Oct 2020 13:18:55 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 3A49B139F; Tue, 27 Oct 2020 10:18:54 -0700 (PDT) Received: from monolith.localdoman (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id D640B3F719; Tue, 27 Oct 2020 10:18:50 -0700 (PDT) From: Alexandru Elisei To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Cc: drjones@redhat.com, pbonzini@redhat.com, Eric Auger Subject: [kvm-unit-tests RFC PATCH v2 1/5] arm64: Move get_id_aa64dfr0() in processor.h Date: Tue, 27 Oct 2020 17:19:40 +0000 Message-Id: <20201027171944.13933-2-alexandru.elisei@arm.com> X-Mailer: git-send-email 2.29.1 In-Reply-To: <20201027171944.13933-1-alexandru.elisei@arm.com> References: <20201027171944.13933-1-alexandru.elisei@arm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org From: Eric Auger SPE support is reported in the ID_AA64DFR0_EL1 register. Move the function get_id_aa64dfr0() from the pmu test to processor.h so it can be reused by the SPE tests. [ Alexandru E: Reworded commit ] Signed-off-by: Eric Auger Signed-off-by: Alexandru Elisei --- lib/arm64/asm/processor.h | 5 +++++ arm/pmu.c | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h index 02665b84cc7e..11b756475494 100644 --- a/lib/arm64/asm/processor.h +++ b/lib/arm64/asm/processor.h @@ -88,6 +88,11 @@ static inline uint64_t get_mpidr(void) return read_sysreg(mpidr_el1); } +static inline uint64_t get_id_aa64dfr0(void) +{ + return read_sysreg(id_aa64dfr0_el1); +} + #define MPIDR_HWID_BITMASK 0xff00ffffff extern int mpidr_to_cpu(uint64_t mpidr); diff --git a/arm/pmu.c b/arm/pmu.c index 831fb6618279..5406ca3b31ed 100644 --- a/arm/pmu.c +++ b/arm/pmu.c @@ -167,7 +167,6 @@ static void test_overflow_interrupt(void) {} #define ID_DFR0_PMU_V3_8_5 0b0110 #define ID_DFR0_PMU_IMPDEF 0b1111 -static inline uint32_t get_id_aa64dfr0(void) { return read_sysreg(id_aa64dfr0_el1); } static inline uint32_t get_pmcr(void) { return read_sysreg(pmcr_el0); } static inline void set_pmcr(uint32_t v) { write_sysreg(v, pmcr_el0); } static inline uint64_t get_pmccntr(void) { return read_sysreg(pmccntr_el0); } From patchwork Tue Oct 27 17:19:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandru Elisei X-Patchwork-Id: 11861133 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E6319C388F9 for ; Tue, 27 Oct 2020 17:21:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9D9E021D24 for ; Tue, 27 Oct 2020 17:21:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1818455AbgJ0RUx (ORCPT ); Tue, 27 Oct 2020 13:20:53 -0400 Received: from foss.arm.com ([217.140.110.172]:47664 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1818310AbgJ0RS6 (ORCPT ); Tue, 27 Oct 2020 13:18:58 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 2A80C150C; Tue, 27 Oct 2020 10:18:57 -0700 (PDT) Received: from monolith.localdoman (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id C3D4A3F719; Tue, 27 Oct 2020 10:18:54 -0700 (PDT) From: Alexandru Elisei To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Cc: drjones@redhat.com, pbonzini@redhat.com Subject: [kvm-unit-tests RFC PATCH v2 2/5] lib/{bitops,alloc_page}.h: Add missing headers Date: Tue, 27 Oct 2020 17:19:41 +0000 Message-Id: <20201027171944.13933-3-alexandru.elisei@arm.com> X-Mailer: git-send-email 2.29.1 In-Reply-To: <20201027171944.13933-1-alexandru.elisei@arm.com> References: <20201027171944.13933-1-alexandru.elisei@arm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org bitops.h uses the 'bool' and 'size_t' types, but doesn't include the stddef.h and stdbool.h headers, where the types are defined. This can cause the following error when compiling: In file included from arm/new-test.c:9: /path/to/kvm-unit-tests/lib/bitops.h:77:15: error: unknown type name 'bool' 77 | static inline bool is_power_of_2(unsigned long n) | ^~~~ /path/to/kvm-unit-tests/lib/bitops.h:82:38: error: unknown type name 'size_t' 82 | static inline unsigned int get_order(size_t size) | ^~~~~~ /path/to/kvm-unit-tests/lib/bitops.h:24:1: note: 'size_t' is defined in header ''; did you forget to '#include '? 23 | #include +++ |+#include 24 | make: *** [: arm/new-test.o] Error 1 The same errors were observed when including alloc_page.h. Fix both files by including stddef.h and stdbool.h. Signed-off-by: Alexandru Elisei Reviewed-by: Eric Auger --- lib/alloc_page.h | 2 ++ lib/bitops.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/lib/alloc_page.h b/lib/alloc_page.h index 88540d1def06..182862c43363 100644 --- a/lib/alloc_page.h +++ b/lib/alloc_page.h @@ -4,6 +4,8 @@ * This is a simple allocator that provides contiguous physical addresses * with byte granularity. */ +#include +#include #ifndef ALLOC_PAGE_H #define ALLOC_PAGE_H 1 diff --git a/lib/bitops.h b/lib/bitops.h index 308aa86514a8..5aeea0b998b1 100644 --- a/lib/bitops.h +++ b/lib/bitops.h @@ -1,5 +1,7 @@ #ifndef _BITOPS_H_ #define _BITOPS_H_ +#include +#include /* * Adapted from From patchwork Tue Oct 27 17:19:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandru Elisei X-Patchwork-Id: 11861129 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 898BBC55179 for ; Tue, 27 Oct 2020 17:20:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4F9CB21D42 for ; Tue, 27 Oct 2020 17:20:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1818330AbgJ0RTD (ORCPT ); Tue, 27 Oct 2020 13:19:03 -0400 Received: from foss.arm.com ([217.140.110.172]:47672 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1818324AbgJ0RTC (ORCPT ); Tue, 27 Oct 2020 13:19:02 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id DE6C8139F; Tue, 27 Oct 2020 10:19:00 -0700 (PDT) Received: from monolith.localdoman (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 9DB1C3F719; Tue, 27 Oct 2020 10:18:57 -0700 (PDT) From: Alexandru Elisei To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Cc: drjones@redhat.com, pbonzini@redhat.com, Eric Auger Subject: [kvm-unit-tests RFC PATCH v2 3/5] arm64: spe: Add introspection test Date: Tue, 27 Oct 2020 17:19:42 +0000 Message-Id: <20201027171944.13933-4-alexandru.elisei@arm.com> X-Mailer: git-send-email 2.29.1 In-Reply-To: <20201027171944.13933-1-alexandru.elisei@arm.com> References: <20201027171944.13933-1-alexandru.elisei@arm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org From: Eric Auger Probe the DTB and the ID registers to get information about SPE, then compare the register fields with the valid values as defined by ARM DDI 0487F.b. SPE is supported only on AArch64, so make the test exclusive to the arm64 architecture. [ Alexandru E: Removed aarch32 compilation support, added DTB probing, reworded commit, mostly cosmetic changes to the code ] Signed-off-by: Eric Auger Signed-off-by: Alexandru Elisei --- arm/Makefile.arm64 | 1 + lib/libcflat.h | 1 + arm/spe.c | 172 +++++++++++++++++++++++++++++++++++++++++++++ arm/unittests.cfg | 7 ++ 4 files changed, 181 insertions(+) create mode 100644 arm/spe.c diff --git a/arm/Makefile.arm64 b/arm/Makefile.arm64 index dbc7524d3070..94b9c63f0b05 100644 --- a/arm/Makefile.arm64 +++ b/arm/Makefile.arm64 @@ -30,6 +30,7 @@ OBJDIRS += lib/arm64 tests = $(TEST_DIR)/timer.flat tests += $(TEST_DIR)/micro-bench.flat tests += $(TEST_DIR)/cache.flat +tests += $(TEST_DIR)/spe.flat include $(SRCDIR)/$(TEST_DIR)/Makefile.common diff --git a/lib/libcflat.h b/lib/libcflat.h index ec0f58b05701..37550c99ffb6 100644 --- a/lib/libcflat.h +++ b/lib/libcflat.h @@ -37,6 +37,7 @@ #define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) #define SZ_256 (1 << 8) +#define SZ_2K (1 << 11) #define SZ_4K (1 << 12) #define SZ_8K (1 << 13) #define SZ_16K (1 << 14) diff --git a/arm/spe.c b/arm/spe.c new file mode 100644 index 000000000000..c199cd239194 --- /dev/null +++ b/arm/spe.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2020, Red Hat Inc, Eric Auger + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 2.1 and + * only version 2.1 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + */ +#include + +#include +#include +#include + +#include +#include +#include + +#define ID_AA64DFR0_PMSVER_SHIFT 32 +#define ID_AA64DFR0_PMSVER_MASK 0xf + +#define SYS_PMBIDR_EL1 sys_reg(3, 0, 9, 10, 7) +#define SYS_PMBIDR_EL1_F_SHIFT 5 +#define SYS_PMBIDR_EL1_P_SHIFT 4 +#define SYS_PMBIDR_EL1_ALIGN_MASK 0xfUL +#define SYS_PMBIDR_EL1_ALIGN_SHIFT 0 + +#define SYS_PMSIDR_EL1 sys_reg(3, 0, 9, 9, 7) +#define SYS_PMSIDR_EL1_FE_SHIFT 0 +#define SYS_PMSIDR_EL1_FT_SHIFT 1 +#define SYS_PMSIDR_EL1_FL_SHIFT 2 +#define SYS_PMSIDR_EL1_INTERVAL_SHIFT 8 +#define SYS_PMSIDR_EL1_INTERVAL_MASK 0xfUL +#define SYS_PMSIDR_EL1_MAXSIZE_SHIFT 12 +#define SYS_PMSIDR_EL1_MAXSIZE_MASK 0xfUL +#define SYS_PMSIDR_EL1_MAXSIZE_MASK 0xfUL +#define SYS_PMSIDR_EL1_COUNTSIZE_SHIFT 16 +#define SYS_PMSIDR_EL1_COUNTSIZE_MASK 0xfUL + +struct spe { + uint32_t intid; + int min_interval; + int max_record_size; + int countsize; + bool fl_cap; + bool ft_cap; + bool fe_cap; + int align; +}; +static struct spe spe; + +static int spe_min_interval(uint8_t interval) +{ + switch (interval) { + case 0x0: + return 256; + case 0x2: + return 512; + case 0x3: + return 768; + case 0x4: + return 1024; + case 0x5: + return 1536; + case 0x6: + return 2048; + case 0x7: + return 3072; + case 0x8: + return 4096; + default: + return 0; + } +} + +static bool spe_probe(void) +{ + const struct fdt_property *prop; + const void *fdt = dt_fdt(); + int node, len; + uint32_t *data; + uint64_t pmbidr, pmsidr; + uint64_t aa64dfr0 = get_id_aa64dfr0(); + uint8_t pmsver, interval; + + node = fdt_node_offset_by_compatible(fdt, -1, "arm,statistical-profiling-extension-v1"); + assert(node >= 0); + prop = fdt_get_property(fdt, node, "interrupts", &len); + assert(prop && len == 3 * sizeof(u32)); + + data = (u32 *)prop->data; + /* SPE interrupt is required to be a PPI. */ + assert(fdt32_to_cpu(data[0]) == 1); + spe.intid = fdt32_to_cpu(data[1]); + + pmsver = (aa64dfr0 >> ID_AA64DFR0_PMSVER_SHIFT) & ID_AA64DFR0_PMSVER_MASK; + if (!pmsver || pmsver > 2) { + report_info("Unknown SPE version: 0x%x", pmsver); + return false; + } + + pmbidr = read_sysreg_s(SYS_PMBIDR_EL1); + if (pmbidr & BIT(SYS_PMBIDR_EL1_P_SHIFT)) { + report_info("Profiling buffer owned by higher exception level"); + return false; + } + + spe.align = (pmbidr >> SYS_PMBIDR_EL1_ALIGN_SHIFT) & SYS_PMBIDR_EL1_ALIGN_MASK; + spe.align = 1 << spe.align; + + pmsidr = read_sysreg_s(SYS_PMSIDR_EL1); + + interval = (pmsidr >> SYS_PMSIDR_EL1_INTERVAL_SHIFT) & SYS_PMSIDR_EL1_INTERVAL_MASK; + spe.min_interval = spe_min_interval(interval); + + spe.max_record_size = (pmsidr >> SYS_PMSIDR_EL1_MAXSIZE_SHIFT) & \ + SYS_PMSIDR_EL1_MAXSIZE_MASK; + spe.max_record_size = 1 << spe.max_record_size; + + spe.countsize = (pmsidr >> SYS_PMSIDR_EL1_COUNTSIZE_SHIFT) & \ + SYS_PMSIDR_EL1_COUNTSIZE_MASK; + + spe.fl_cap = pmsidr & BIT(SYS_PMSIDR_EL1_FL_SHIFT); + spe.ft_cap = pmsidr & BIT(SYS_PMSIDR_EL1_FT_SHIFT); + spe.fe_cap = pmsidr & BIT(SYS_PMSIDR_EL1_FE_SHIFT); + + return true; +} + +static void spe_test_introspection(void) +{ + report_prefix_push("spe-introspection"); + + report(spe.align <= SZ_2K, "PMBIDR_E1.Align"); + report(spe.countsize == 0x2, "PMSIDR_EL1.CountSize"); + report(spe.max_record_size >= 16 && spe.max_record_size <= 2048, + "PMSIDR_EL1 maximum record size"); + report(spe.min_interval >= 256 && spe.min_interval <= 4096, + "PMSIDR_EL1 minimum sampling interval"); + report(spe.fl_cap && spe.ft_cap && spe.fe_cap, "PMSIDR_EL1 sampling filters"); + + report_prefix_pop(); +} + +int main(int argc, char *argv[]) +{ + if (!spe_probe()) { + report_skip("SPE not supported"); + return report_summary(); + } + + printf("intid: %u\n", PPI(spe.intid)); + printf("align: %d\n", spe.align); + printf("min_interval: %d\n", spe.min_interval); + printf("max_record_size: %d\n", spe.max_record_size); + + if (argc < 2) + report_abort("no test specified"); + + report_prefix_push("spe"); + + if (strcmp(argv[1], "spe-introspection") == 0) + spe_test_introspection(); + else + report_abort("Unknown subtest '%s'", argv[1]); + + return report_summary(); +} diff --git a/arm/unittests.cfg b/arm/unittests.cfg index f776b66ef96d..ad10be123774 100644 --- a/arm/unittests.cfg +++ b/arm/unittests.cfg @@ -134,6 +134,13 @@ extra_params = -append 'pmu-overflow-interrupt' #groups = pmu #accel = tcg +[spe-introspection] +file = spe.flat +groups = spe +arch = arm64 +accel = kvm +extra_params = -append 'spe-introspection' + # Test GIC emulation [gicv2-ipi] file = gic.flat From patchwork Tue Oct 27 17:19:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandru Elisei X-Patchwork-Id: 11861135 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id BCD04C4363A for ; Tue, 27 Oct 2020 17:21:28 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 77A7121D24 for ; Tue, 27 Oct 2020 17:21:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1818063AbgJ0RUt (ORCPT ); Tue, 27 Oct 2020 13:20:49 -0400 Received: from foss.arm.com ([217.140.110.172]:47680 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1818332AbgJ0RTF (ORCPT ); Tue, 27 Oct 2020 13:19:05 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 2FEF1150C; Tue, 27 Oct 2020 10:19:04 -0700 (PDT) Received: from monolith.localdoman (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 5953B3F719; Tue, 27 Oct 2020 10:19:00 -0700 (PDT) From: Alexandru Elisei To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Cc: drjones@redhat.com, pbonzini@redhat.com Subject: [kvm-unit-tests RFC PATCH v2 4/5] lib: arm/arm64: Add function to unmap a page Date: Tue, 27 Oct 2020 17:19:43 +0000 Message-Id: <20201027171944.13933-5-alexandru.elisei@arm.com> X-Mailer: git-send-email 2.29.1 In-Reply-To: <20201027171944.13933-1-alexandru.elisei@arm.com> References: <20201027171944.13933-1-alexandru.elisei@arm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Being able to cause a stage 1 data abort might be useful for future tests. Add a function that unmaps a page from the translation tables. Signed-off-by: Alexandru Elisei Reviewed-by: Eric Auger --- lib/arm/asm/mmu-api.h | 1 + lib/arm/mmu.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/lib/arm/asm/mmu-api.h b/lib/arm/asm/mmu-api.h index 2bbe1faea900..305f77c6501f 100644 --- a/lib/arm/asm/mmu-api.h +++ b/lib/arm/asm/mmu-api.h @@ -23,4 +23,5 @@ extern void mmu_set_range_ptes(pgd_t *pgtable, uintptr_t virt_offset, phys_addr_t phys_start, phys_addr_t phys_end, pgprot_t prot); extern void mmu_clear_user(pgd_t *pgtable, unsigned long vaddr); +extern void mmu_unmap_page(pgd_t *pgtable, unsigned long vaddr); #endif diff --git a/lib/arm/mmu.c b/lib/arm/mmu.c index 540a1e842d5b..72ac0be8d146 100644 --- a/lib/arm/mmu.c +++ b/lib/arm/mmu.c @@ -232,3 +232,35 @@ void mmu_clear_user(pgd_t *pgtable, unsigned long vaddr) out_flush_tlb: flush_tlb_page(vaddr); } + +void mmu_unmap_page(pgd_t *pgtable, unsigned long vaddr) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + + if (!mmu_enabled()) + return; + + pgd = pgd_offset(pgtable, vaddr); + if (!pgd_valid(*pgd)) + return; + + pmd = pmd_offset(pgd, vaddr); + if (!pmd_valid(*pmd)) + return; + + if (pmd_huge(*pmd)) { + WRITE_ONCE(*pmd, 0); + goto out_flush_tlb; + } else { + pte = pte_offset(pmd, vaddr); + if (!pte_valid(*pte)) + return; + WRITE_ONCE(*pte, 0); + goto out_flush_tlb; + } + +out_flush_tlb: + flush_tlb_page(vaddr); +} From patchwork Tue Oct 27 17:19:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexandru Elisei X-Patchwork-Id: 11861125 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI,SIGNED_OFF_BY, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4054BC4363A for ; Tue, 27 Oct 2020 17:19:13 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E36F220780 for ; Tue, 27 Oct 2020 17:19:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1818347AbgJ0RTK (ORCPT ); Tue, 27 Oct 2020 13:19:10 -0400 Received: from foss.arm.com ([217.140.110.172]:47688 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1818337AbgJ0RTJ (ORCPT ); Tue, 27 Oct 2020 13:19:09 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 5199715AB; Tue, 27 Oct 2020 10:19:07 -0700 (PDT) Received: from monolith.localdoman (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id A72AA3F719; Tue, 27 Oct 2020 10:19:04 -0700 (PDT) From: Alexandru Elisei To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu Cc: drjones@redhat.com, pbonzini@redhat.com Subject: [kvm-unit-tests RFC PATCH v2 5/5] am64: spe: Add buffer test Date: Tue, 27 Oct 2020 17:19:44 +0000 Message-Id: <20201027171944.13933-6-alexandru.elisei@arm.com> X-Mailer: git-send-email 2.29.1 In-Reply-To: <20201027171944.13933-1-alexandru.elisei@arm.com> References: <20201027171944.13933-1-alexandru.elisei@arm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org According to ARM DDI 0487F.b, a profiling buffer management event occurs: * On a fault. * On an external abort. * When the buffer fills. * When software sets the service bit, PMBSR_EL1.S. Set up the buffer to trigger the events and check that they are reported correctly. Signed-off-by: Alexandru Elisei --- arm/spe.c | 342 +++++++++++++++++++++++++++++++++++++++++++++- arm/unittests.cfg | 8 ++ 2 files changed, 346 insertions(+), 4 deletions(-) diff --git a/arm/spe.c b/arm/spe.c index c199cd239194..c185883d079a 100644 --- a/arm/spe.c +++ b/arm/spe.c @@ -15,8 +15,10 @@ #include #include #include +#include #include +#include #include #include @@ -41,6 +43,44 @@ #define SYS_PMSIDR_EL1_COUNTSIZE_SHIFT 16 #define SYS_PMSIDR_EL1_COUNTSIZE_MASK 0xfUL +#define SYS_PMSCR_EL1 sys_reg(3, 0, 9, 9, 0) +#define SYS_PMSCR_EL1_E1SPE_SHIFT 1 +#define SYS_PMSCR_EL1_PA_SHIFT 4 +#define SYS_PMSCR_EL1_TS_SHIFT 5 + +#define SYS_PMSICR_EL1 sys_reg(3, 0, 9, 9, 2) + +#define SYS_PMSIRR_EL1 sys_reg(3, 0, 9, 9, 3) +#define SYS_PMSIRR_EL1_INTERVAL_SHIFT 8 +#define SYS_PMSIRR_EL1_INTERVAL_MASK 0xffffffUL + +#define SYS_PMSFCR_EL1 sys_reg(3, 0, 9, 9, 4) +#define SYS_PMSFCR_EL1_FE_SHIFT 0 +#define SYS_PMSFCR_EL1_FT_SHIFT 1 +#define SYS_PMSFCR_EL1_FL_SHIFT 2 +#define SYS_PMSFCR_EL1_B_SHIFT 16 +#define SYS_PMSFCR_EL1_LD_SHIFT 17 +#define SYS_PMSFCR_EL1_ST_SHIFT 18 + +#define SYS_PMSEVFR_EL1 sys_reg(3, 0, 9, 9, 5) +#define SYS_PMSLATFR_EL1 sys_reg(3, 0, 9, 9, 6) + +#define SYS_PMBLIMITR_EL1 sys_reg(3, 0, 9, 10, 0) +#define SYS_PMBLIMITR_EL1_E_SHIFT 0 + +#define SYS_PMBPTR_EL1 sys_reg(3, 0, 9, 10, 1) + +#define SYS_PMBSR_EL1 sys_reg(3, 0, 9, 10, 3) +#define SYS_PMBSR_EL1_S_SHIFT 17 +#define SYS_PMBSR_EL1_EA_SHIFT 18 +#define SYS_PMBSR_EL1_BSC_BUF_FULL 1 +#define SYS_PMBSR_EL1_EC_SHIFT 26 +#define SYS_PMBSR_EL1_EC_MASK 0x3fUL +#define SYS_PMBSR_EL1_EC_FAULT_S1 0x24 +#define SYS_PMBSR_EL1_RES0 0x00000000fc0fffffUL + +#define psb_csync() asm volatile("hint #17" : : : "memory") + struct spe { uint32_t intid; int min_interval; @@ -53,6 +93,15 @@ struct spe { }; static struct spe spe; +struct spe_buffer { + uint64_t base; + uint64_t limit; +}; +static struct spe_buffer buffer; + +static volatile bool pmbirq_asserted, reassert_irq; +static volatile uint64_t irq_pmbsr; + static int spe_min_interval(uint8_t interval) { switch (interval) { @@ -131,6 +180,273 @@ static bool spe_probe(void) return true; } +/* + * Resets and starts a profiling session. Must be called with sampling and + * buffer disabled. + */ +static void spe_reset_and_start(struct spe_buffer *spe_buffer) +{ + uint64_t pmscr; + + assert(spe_buffer->base); + assert(spe_buffer->limit > spe_buffer->base); + + write_sysreg_s(spe_buffer->base, SYS_PMBPTR_EL1); + /* Change the buffer pointer before PMBLIMITR_EL1. */ + isb(); + + write_sysreg_s(spe_buffer->limit | BIT(SYS_PMBLIMITR_EL1_E_SHIFT), + SYS_PMBLIMITR_EL1); + write_sysreg_s(0, SYS_PMBSR_EL1); + write_sysreg_s(0, SYS_PMSICR_EL1); + /* PMSICR_EL1 must be written to zero before a new sampling session. */ + isb(); + + pmscr = BIT(SYS_PMSCR_EL1_E1SPE_SHIFT) | + BIT(SYS_PMSCR_EL1_PA_SHIFT) | + BIT(SYS_PMSCR_EL1_TS_SHIFT); + write_sysreg_s(pmscr, SYS_PMSCR_EL1); + isb(); +} + +static void spe_stop_and_drain(void) +{ + write_sysreg_s(0, SYS_PMSCR_EL1); + isb(); + + psb_csync(); + dsb(nsh); + write_sysreg_s(0, SYS_PMBLIMITR_EL1); + isb(); +} + +static void spe_irq_handler(struct pt_regs *regs) +{ + uint32_t intid = gic_read_iar(); + + spe_stop_and_drain(); + + irq_pmbsr = read_sysreg_s(SYS_PMBSR_EL1); + + if (intid != PPI(spe.intid)) { + report_info("Unexpected interrupt: %u", intid); + /* + * When we get the interrupt, at least one bit, PMBSR_EL1.S, + * will be set. We can the value zero for an error. + */ + irq_pmbsr = 0; + goto out; + } + + if (irq_pmbsr && reassert_irq) { + /* + * Don't clear the service bit now, but ack the interrupt so it + * can be handled again. + */ + gic_write_eoir(intid); + reassert_irq = false; + irq_pmbsr = 0; + return; + } + +out: + write_sysreg_s(0, SYS_PMBSR_EL1); + /* Clear PMBSR_EL1 before EOI'ing the interrupt */ + isb(); + gic_write_eoir(intid); + + pmbirq_asserted = true; +} + +static void spe_enable_interrupt(void) +{ + void *gic_isenabler; + + switch (gic_version()) { + case 2: + gic_isenabler = gicv2_dist_base() + GICD_ISENABLER; + break; + case 3: + gic_isenabler = gicv3_sgi_base() + GICR_ISENABLER0; + break; + default: + report_abort("Unknown GIC version %d", gic_version()); + } + + writel(1 << PPI(spe.intid), gic_isenabler); +} + +static void spe_init(void) +{ + uint64_t pmsfcr, pmsirr; + + /* + * PMSCR_EL1.E1SPE resets to UNKNOWN value, make sure sampling is + * disabled. + */ + write_sysreg_s(0, SYS_PMSCR_EL1); + isb(); + + install_irq_handler(EL1H_IRQ, spe_irq_handler); + + gic_enable_defaults(); + spe_enable_interrupt(); + local_irq_enable(); + + buffer.base = (u64)memalign(PAGE_SIZE, PAGE_SIZE); + assert_msg(buffer.base, "Cannot allocate profiling buffer"); + buffer.limit = buffer.base + PAGE_SIZE; + + /* Select all operations for sampling */ + pmsfcr = BIT(SYS_PMSFCR_EL1_FT_SHIFT) | + BIT(SYS_PMSFCR_EL1_B_SHIFT) | + BIT(SYS_PMSFCR_EL1_LD_SHIFT) | + BIT(SYS_PMSFCR_EL1_ST_SHIFT); + write_sysreg_s(pmsfcr, SYS_PMSFCR_EL1); + + /* + * From ARM DDI 0487F.b: "[..] Software should set this to a value + * greater than the minimum indicated by PMSIDR_EL1.Interval" + */ + pmsirr = (spe.min_interval + 1) & SYS_PMSIRR_EL1_INTERVAL_MASK; + pmsirr <<= SYS_PMSIRR_EL1_INTERVAL_SHIFT; + write_sysreg_s(pmsirr, SYS_PMSIRR_EL1); + isb(); +} + +static bool spe_test_buffer_service(void) +{ + uint64_t expected_pmbsr; + int i; + + spe_stop_and_drain(); + + reassert_irq = true; + pmbirq_asserted = false; + + expected_pmbsr = 0x12345678 | BIT(SYS_PMBSR_EL1_S_SHIFT); + expected_pmbsr &= SYS_PMBSR_EL1_RES0; + + /* + * ARM DDI 0487F.b, page D9-2803: + * + * "PMBIRQ is a level-sensitive interrupt request driven by PMBSR_EL1.S. + * This means that a direct write that sets PMBSR_EL1.S to 1 causes the + * interrupt to be asserted, and PMBIRQ remains asserted until software + * clears PMBSR_EL1.S to 0." + */ + write_sysreg_s(expected_pmbsr, SYS_PMBSR_EL1); + isb(); + + /* Wait for up to 1 second for the GIC to assert the interrupt. */ + for (i = 0; i < 10; i++) { + if (pmbirq_asserted) + break; + mdelay(100); + } + reassert_irq = false; + + return irq_pmbsr == expected_pmbsr; +} + +static bool spe_test_buffer_full(void) +{ + volatile uint64_t cnt = 0; + uint64_t expected_pmbsr, pmbptr; + + spe_stop_and_drain(); + + pmbirq_asserted = false; + expected_pmbsr = BIT(SYS_PMBSR_EL1_S_SHIFT) | SYS_PMBSR_EL1_BSC_BUF_FULL; + + spe_reset_and_start(&buffer); + for (;;) { + cnt++; + if (pmbirq_asserted) + break; + } + + pmbptr = read_sysreg_s(SYS_PMBPTR_EL1); + /* + * ARM DDI 0487F.b, page D9-2804: + * + * "[..] the Profiling Buffer management event is generated when the PE + * writes past the write limit pointer minus 2^(PMSIDR_EL1.MaxSize)." + */ + return (pmbptr >= buffer.limit - spe.max_record_size) && + (irq_pmbsr == expected_pmbsr); +} + +static bool spe_test_buffer_stage1_dabt(void) +{ + volatile uint64_t cnt = 0; + struct spe_buffer dabt_buffer; + uint8_t pmbsr_ec; + + spe_stop_and_drain(); + + dabt_buffer.base = (u64)memalign(PAGE_SIZE, PAGE_SIZE); + assert_msg(dabt_buffer.base, "Cannot allocate profiling buffer"); + dabt_buffer.limit = dabt_buffer.base + PAGE_SIZE; + mmu_unmap_page(current_thread_info()->pgtable, dabt_buffer.base); + + pmbirq_asserted = false; + + spe_reset_and_start(&dabt_buffer); + for (;;) { + cnt++; + if (pmbirq_asserted) + break; + } + + pmbsr_ec = (irq_pmbsr >> SYS_PMBSR_EL1_EC_SHIFT) & SYS_PMBSR_EL1_EC_MASK; + return (irq_pmbsr & BIT(SYS_PMBSR_EL1_S_SHIFT)) && + (pmbsr_ec == SYS_PMBSR_EL1_EC_FAULT_S1); +} + +static bool spe_test_buffer_extabt(void) +{ + struct spe_buffer extabt_buffer; + volatile uint64_t cnt = 0; + phys_addr_t highest_end = 0; + struct mem_region *r; + + spe_stop_and_drain(); + + /* + * Find a physical address most likely to be absent from the stage 2 + * tables. Full explanation in arm/selftest.c, in check_pabt_init(). + */ + for (r = mem_regions; r->end; r++) { + if (r->flags & MR_F_IO) + continue; + if (r->end > highest_end) + highest_end = PAGE_ALIGN(r->end); + } + + if (mem_region_get_flags(highest_end) != MR_F_UNKNOWN) + return false; + + extabt_buffer.base = (u64)vmap(highest_end, PAGE_SIZE); + extabt_buffer.limit = extabt_buffer.base + PAGE_SIZE; + + pmbirq_asserted = false; + + report_info("Expecting KVM Stage 2 Data Abort at pmbptr=0x%lx", + extabt_buffer.base); + + spe_reset_and_start(&extabt_buffer); + for (;;) { + cnt++; + if (pmbirq_asserted) + break; + } + + return (irq_pmbsr & BIT(SYS_PMBSR_EL1_S_SHIFT)) && + (irq_pmbsr & BIT(SYS_PMBSR_EL1_EA_SHIFT)); + +} + static void spe_test_introspection(void) { report_prefix_push("spe-introspection"); @@ -146,8 +462,22 @@ static void spe_test_introspection(void) report_prefix_pop(); } +static void spe_test_buffer(void) +{ + report_prefix_push("spe-buffer"); + + report(spe_test_buffer_service(), "Service management event"); + report(spe_test_buffer_full(), "Buffer full management event"); + report(spe_test_buffer_stage1_dabt(), "Stage 1 data abort management event"); + report(spe_test_buffer_extabt(), "Buffer external abort management event"); + + report_prefix_pop(); +} + int main(int argc, char *argv[]) { + int i; + if (!spe_probe()) { report_skip("SPE not supported"); return report_summary(); @@ -161,12 +491,16 @@ int main(int argc, char *argv[]) if (argc < 2) report_abort("no test specified"); + spe_init(); + report_prefix_push("spe"); - if (strcmp(argv[1], "spe-introspection") == 0) - spe_test_introspection(); - else - report_abort("Unknown subtest '%s'", argv[1]); + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "spe-introspection") == 0) + spe_test_introspection(); + if (strcmp(argv[i], "spe-buffer") == 0) + spe_test_buffer(); + } return report_summary(); } diff --git a/arm/unittests.cfg b/arm/unittests.cfg index ad10be123774..ba21421e81aa 100644 --- a/arm/unittests.cfg +++ b/arm/unittests.cfg @@ -141,6 +141,14 @@ arch = arm64 accel = kvm extra_params = -append 'spe-introspection' +[spe-buffer] +file = spe.flat +groups = spe +arch = arm64 +timeout = 10s +accel = kvm +extra_params = -append 'spe-buffer' + # Test GIC emulation [gicv2-ipi] file = gic.flat