From: Alexandre Chartre <alexandre.chartre@oracle.com>
To: tglx@linutronix.de, mingo@redhat.com, bp@alien8.de,
hpa@zytor.com, dave.hansen@linux.intel.com, luto@kernel.org,
peterz@infradead.org, x86@kernel.org, linux-mm@kvack.org,
linux-kernel@vger.kernel.org
Cc: pbonzini@redhat.com, konrad.wilk@oracle.com,
jan.setjeeilers@oracle.com, liran.alon@oracle.com,
junaids@google.com, graf@amazon.de, rppt@linux.vnet.ibm.com,
kuzuno@gmail.com, mgross@linux.intel.com,
alexandre.chartre@oracle.com
Subject: [RFC v4][PATCH part-3 03/14] asidrv: Introduce the ASIDRV_IOCTL_RUN_SEQUENCE ioctl
Date: Mon, 4 May 2020 17:02:24 +0200 [thread overview]
Message-ID: <20200504150235.12171-4-alexandre.chartre@oracle.com> (raw)
In-Reply-To: <20200504150235.12171-1-alexandre.chartre@oracle.com>
The ASIDRV_IOCTL_RUN_SEQUENCE ioctl runs a specified sequence with
the test ASI. The ioctl returns whether the run was successful or
not, and if the test ASI was active at the end of the run.
For now, two test sequences are implemented:
- ASIDRV_SEQ_NOP does nothing but enters and exits the test ASI;
- ASIDRV_SEQ_PRINTK calls printk while running with ASI.
Signed-off-by: Alexandre Chartre <alexandre.chartre@oracle.com>
---
drivers/staging/asi/asidrv.c | 248 +++++++++++++++++++++++++++++++++++
drivers/staging/asi/asidrv.h | 29 ++++
2 files changed, 277 insertions(+)
create mode 100644 drivers/staging/asi/asidrv.h
diff --git a/drivers/staging/asi/asidrv.c b/drivers/staging/asi/asidrv.c
index c06e4734e0e5..4f0548edb2f9 100644
--- a/drivers/staging/asi/asidrv.c
+++ b/drivers/staging/asi/asidrv.c
@@ -10,15 +10,28 @@
#include <asm/asi.h>
#include <asm/dpt.h>
+#include <asm/tlbflush.h>
+
+#include "asidrv.h"
struct asidrv_test {
struct asi *asi; /* ASI for testing */
struct dpt *dpt; /* ASI decorated page-table */
};
+struct asidrv_sequence {
+ const char *name;
+ enum asidrv_run_error (*setup)(struct asidrv_test *t);
+ enum asidrv_run_error (*run)(struct asidrv_test *t);
+ void (*cleanup)(struct asidrv_test *t);
+};
+
static struct asidrv_test *asidrv_test;
static void asidrv_test_destroy(struct asidrv_test *test);
+static void asidrv_run_fini(struct asidrv_test *test);
+static void asidrv_run_cleanup(struct asidrv_test *test,
+ struct asidrv_sequence *sequence);
static struct asidrv_test *asidrv_test_create(void)
{
@@ -86,8 +99,243 @@ static void asidrv_test_destroy(struct asidrv_test *test)
kfree(test);
}
+static int asidrv_asi_is_active(struct asi *asi)
+{
+ struct asi *current_asi;
+ unsigned long cr3;
+ bool is_active;
+ int idepth;
+
+ if (!asi)
+ return false;
+
+ current_asi = this_cpu_read(cpu_asi_session.asi);
+ if (current_asi == asi) {
+ idepth = this_cpu_read(cpu_asi_session.idepth);
+ is_active = (idepth == 0);
+ } else {
+ is_active = false;
+ if (current_asi) {
+ /* weird... another ASI is active! */
+ pr_debug("ASI %px is active (testing ASI = %px)\n",
+ current_asi, asi);
+ }
+ }
+
+ /*
+ * If the ASI is active check that the CR3 value is consistent with
+ * this ASI being active. Otherwise, check that CR3 value doesn't
+ * reference an ASI.
+ */
+ cr3 = __native_read_cr3();
+ if (is_active) {
+ if ((cr3 ^ asi->base_cr3) >> ASI_PCID_PREFIX_SHIFT == 0)
+ return true;
+
+ pr_warn("ASI %px: active ASI has inconsistent CR3 value (cr3=%lx, ASI base=%lx)\n",
+ asi, cr3, asi->base_cr3);
+
+ } else if (cr3 & ASI_PCID_PREFIX_MASK) {
+ pr_warn("ASI %px: inactive ASI has inconsistent CR3 value (cr3=%lx, ASI base=%lx)\n",
+ asi, cr3, asi->base_cr3);
+ }
+
+ return false;
+}
+
+/*
+ * Printk Test Sequence
+ */
+static enum asidrv_run_error asidrv_printk_run(struct asidrv_test *test)
+{
+ pr_notice("asidrv printk test...\n");
+ return ASIDRV_RUN_ERR_NONE;
+}
+
+struct asidrv_sequence asidrv_sequences[] = {
+ [ASIDRV_SEQ_NOP] = {
+ "nop",
+ NULL, NULL, NULL,
+ },
+ [ASIDRV_SEQ_PRINTK] = {
+ "printk",
+ NULL, asidrv_printk_run, NULL,
+ },
+};
+
+static enum asidrv_run_error asidrv_run_init(struct asidrv_test *test)
+{
+ int err;
+
+ /*
+ * Map the current stack, we need it to enter ASI.
+ */
+ err = dpt_map(test->dpt, current->stack,
+ PAGE_SIZE << THREAD_SIZE_ORDER);
+ if (err) {
+ asidrv_run_fini(test);
+ return ASIDRV_RUN_ERR_MAP_STACK;
+ }
+
+ /*
+ * Map the current task, schedule() needs it.
+ */
+ err = dpt_map(test->dpt, current, sizeof(struct task_struct));
+ if (err)
+ return ASIDRV_RUN_ERR_MAP_TASK;
+
+ /*
+ * The ASI page-table has been updated so bump the generation
+ * number to have the ASI TLB flushed.
+ */
+ atomic64_inc(&test->asi->pgtable_gen);
+
+ return ASIDRV_RUN_ERR_NONE;
+}
+
+static void asidrv_run_fini(struct asidrv_test *test)
+{
+ dpt_unmap(test->dpt, current);
+ dpt_unmap(test->dpt, current->stack);
+}
+
+static enum asidrv_run_error asidrv_run_setup(struct asidrv_test *test,
+ struct asidrv_sequence *sequence)
+{
+ int run_err = ASIDRV_RUN_ERR_NONE;
+
+ if (sequence->setup) {
+ run_err = sequence->setup(test);
+ if (run_err)
+ goto failed;
+ }
+
+ return ASIDRV_RUN_ERR_NONE;
+
+failed:
+ return run_err;
+}
+
+static void asidrv_run_cleanup(struct asidrv_test *test,
+ struct asidrv_sequence *sequence)
+{
+ if (sequence->cleanup)
+ sequence->cleanup(test);
+}
+
+/*
+ * Run the specified sequence with ASI. Report result back.
+ */
+static enum asidrv_run_error asidrv_run(struct asidrv_test *test,
+ enum asidrv_seqnum seqnum,
+ bool *asi_active)
+{
+ struct asidrv_sequence *sequence = &asidrv_sequences[seqnum];
+ int run_err = ASIDRV_RUN_ERR_NONE;
+ int err = 0;
+
+ if (seqnum >= ARRAY_SIZE(asidrv_sequences)) {
+ pr_debug("Undefined sequence %d\n", seqnum);
+ return ASIDRV_RUN_ERR_SEQUENCE;
+ }
+
+ pr_debug("ASI running sequence %s\n", sequence->name);
+
+ run_err = asidrv_run_setup(test, sequence);
+ if (run_err)
+ return run_err;
+
+ err = asi_enter(test->asi);
+ if (err) {
+ run_err = ASIDRV_RUN_ERR_ENTER;
+ goto failed_noexit;
+ }
+
+ if (!asidrv_asi_is_active(test->asi)) {
+ run_err = ASIDRV_RUN_ERR_ACTIVE;
+ goto failed;
+ }
+
+ if (sequence->run) {
+ run_err = sequence->run(test);
+ if (run_err != ASIDRV_RUN_ERR_NONE)
+ goto failed;
+ }
+
+ *asi_active = asidrv_asi_is_active(test->asi);
+
+failed:
+ asi_exit(test->asi);
+
+failed_noexit:
+ asidrv_run_cleanup(test, sequence);
+
+ return run_err;
+}
+
+static int asidrv_ioctl_run_sequence(struct asidrv_test *test,
+ unsigned long arg)
+{
+ struct asidrv_run_param __user *urparam;
+ struct asidrv_run_param rparam;
+ enum asidrv_run_error run_err;
+ enum asidrv_seqnum seqnum;
+ bool asi_active = false;
+
+ urparam = (struct asidrv_run_param *)arg;
+ if (copy_from_user(&rparam, urparam, sizeof(rparam)))
+ return -EFAULT;
+
+ seqnum = rparam.sequence;
+
+ pr_debug("ASI sequence %d\n", seqnum);
+
+ run_err = asidrv_run_init(test);
+ if (run_err) {
+ pr_debug("ASI run init error %d\n", run_err);
+ goto failed_nofini;
+ }
+
+ run_err = asidrv_run(test, seqnum, &asi_active);
+ if (run_err) {
+ pr_debug("ASI run error %d\n", run_err);
+ } else {
+ pr_debug("ASI run okay, ASI is %s\n",
+ asi_active ? "active" : "inactive");
+ }
+
+ asidrv_run_fini(test);
+
+failed_nofini:
+ rparam.run_error = run_err;
+ rparam.asi_active = asi_active;
+
+ if (copy_to_user(urparam, &rparam, sizeof(rparam)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static long asidrv_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ struct asidrv_test *test = asidrv_test;
+
+ switch (cmd) {
+
+ /* Test ioctls */
+
+ case ASIDRV_IOCTL_RUN_SEQUENCE:
+ return asidrv_ioctl_run_sequence(test, arg);
+
+ default:
+ return -ENOTTY;
+ };
+}
+
static const struct file_operations asidrv_fops = {
.owner = THIS_MODULE,
+ .unlocked_ioctl = asidrv_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
};
static struct miscdevice asidrv_miscdev = {
diff --git a/drivers/staging/asi/asidrv.h b/drivers/staging/asi/asidrv.h
new file mode 100644
index 000000000000..33acb058c443
--- /dev/null
+++ b/drivers/staging/asi/asidrv.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+
+#ifndef __ASIDRV_H__
+#define __ASIDRV_H__
+
+#include <linux/types.h>
+
+enum asidrv_seqnum {
+ ASIDRV_SEQ_NOP, /* empty sequence */
+ ASIDRV_SEQ_PRINTK, /* printk sequence */
+};
+
+enum asidrv_run_error {
+ ASIDRV_RUN_ERR_NONE, /* no error */
+ ASIDRV_RUN_ERR_SEQUENCE, /* unknown sequence */
+ ASIDRV_RUN_ERR_MAP_STACK, /* failed to map current stack */
+ ASIDRV_RUN_ERR_MAP_TASK, /* failed to map current task */
+ ASIDRV_RUN_ERR_ENTER, /* failed to enter ASI */
+ ASIDRV_RUN_ERR_ACTIVE, /* ASI is not active after entering ASI */
+};
+
+#define ASIDRV_IOCTL_RUN_SEQUENCE _IOWR('a', 1, struct asidrv_run_param)
+
+struct asidrv_run_param {
+ __u32 sequence; /* sequence to run */
+ __u32 run_error; /* result error after run */
+ __u32 asi_active; /* ASI is active after run? */
+};
+#endif
--
2.18.2
next prev parent reply other threads:[~2020-05-04 15:04 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-05-04 15:02 [RFC v4][PATCH part-3 00/14] ASI - Part III (ASI Test Driver and CLI) Alexandre Chartre
2020-05-04 15:02 ` [RFC v4][PATCH part-3 01/14] mm/asi: Define the test ASI type Alexandre Chartre
2020-05-04 15:02 ` [RFC v4][PATCH part-3 02/14] asidrv: Introduce the ASI driver Alexandre Chartre
2020-05-04 15:02 ` Alexandre Chartre [this message]
2020-05-04 15:02 ` [RFC v4][PATCH part-3 04/14] asidrv: Sequence to test ASI access to mapped/unmapped memory Alexandre Chartre
2020-05-04 15:02 ` [RFC v4][PATCH part-3 05/14] asidrv: Sequence to test interrupt on ASI Alexandre Chartre
2020-05-04 15:02 ` [RFC v4][PATCH part-3 06/14] asidrv: Sequence to test NMI " Alexandre Chartre
2020-05-04 15:02 ` [RFC v4][PATCH part-3 07/14] asidrv: Sequence to test interrupt+NMI " Alexandre Chartre
2020-05-04 15:02 ` [RFC v4][PATCH part-3 08/14] asidrv: Sequence to test scheduling in/out with ASI Alexandre Chartre
2020-05-04 15:02 ` [RFC v4][PATCH part-3 09/14] asidrv: Add ioctls to manage ASI page faults Alexandre Chartre
2020-05-04 15:02 ` [RFC v4][PATCH part-3 10/14] asidrv: Add ioctls to manage ASI mapped VA ranges Alexandre Chartre
2020-05-04 15:02 ` [RFC v4][PATCH part-3 11/14] asidrv/asicmd: Introduce the asicmd command Alexandre Chartre
2020-05-04 15:02 ` [RFC v4][PATCH part-3 12/14] asidrv/asicmd: Add more test sequences for testing ASI Alexandre Chartre
2020-05-04 15:02 ` [RFC v4][PATCH part-3 13/14] asidrv/asicmd: Add options to manage ASI page faults Alexandre Chartre
2020-05-04 15:02 ` [RFC v4][PATCH part-3 14/14] asidrv/asicmd: Add options to manage ASI mapped VA ranges Alexandre Chartre
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=20200504150235.12171-4-alexandre.chartre@oracle.com \
--to=alexandre.chartre@oracle.com \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=graf@amazon.de \
--cc=hpa@zytor.com \
--cc=jan.setjeeilers@oracle.com \
--cc=junaids@google.com \
--cc=konrad.wilk@oracle.com \
--cc=kuzuno@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=liran.alon@oracle.com \
--cc=luto@kernel.org \
--cc=mgross@linux.intel.com \
--cc=mingo@redhat.com \
--cc=pbonzini@redhat.com \
--cc=peterz@infradead.org \
--cc=rppt@linux.vnet.ibm.com \
--cc=tglx@linutronix.de \
--cc=x86@kernel.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox