From: Nicholas Piggin <npiggin@gmail.com>
To: Thomas Huth <thuth@redhat.com>
Cc: Laurent Vivier <lvivier@redhat.com>,
kvm@vger.kernel.org, Nicholas Piggin <npiggin@gmail.com>,
Andrew Jones <andrew.jones@linux.dev>,
Paolo Bonzini <pbonzini@redhat.com>,
linuxppc-dev@lists.ozlabs.org
Subject: [kvm-unit-tests PATCH v7 31/35] powerpc: add usermode support
Date: Tue, 19 Mar 2024 17:59:22 +1000 [thread overview]
Message-ID: <20240319075926.2422707-32-npiggin@gmail.com> (raw)
In-Reply-To: <20240319075926.2422707-1-npiggin@gmail.com>
The biggest difficulty for user mode is MMU support. Otherwise it is
a simple matter of setting and clearing MSR[PR] with rfid and sc
respectively.
Some common harness operations will fail in usermode, so some workarounds
are reqiured (e.g., puts() can't be used directly).
A usermode privileged instruction interrupt test is added.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
lib/powerpc/asm/processor.h | 9 +++++++++
lib/powerpc/asm/reg.h | 1 +
lib/powerpc/asm/smp.h | 1 +
lib/powerpc/io.c | 7 +++++++
lib/powerpc/processor.c | 38 +++++++++++++++++++++++++++++++++++++
lib/powerpc/rtas.c | 3 +++
lib/powerpc/setup.c | 8 ++++++--
lib/powerpc/spinlock.c | 4 ++++
lib/ppc64/mmu.c | 2 ++
powerpc/interrupts.c | 28 +++++++++++++++++++++++++++
10 files changed, 99 insertions(+), 2 deletions(-)
diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index d348239c5..749155696 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -19,6 +19,8 @@ extern bool cpu_has_prefix;
extern bool cpu_has_sc_lev;
extern bool cpu_has_pause_short;
+bool in_usermode(void);
+
static inline uint64_t mfspr(int nr)
{
uint64_t ret;
@@ -51,6 +53,8 @@ static inline void local_irq_enable(void)
{
unsigned long msr;
+ assert(!in_usermode());
+
asm volatile(
" mfmsr %0 \n \
ori %0,%0,%1 \n \
@@ -62,6 +66,8 @@ static inline void local_irq_disable(void)
{
unsigned long msr;
+ assert(!in_usermode());
+
asm volatile(
" mfmsr %0 \n \
andc %0,%0,%1 \n \
@@ -90,4 +96,7 @@ static inline bool machine_is_pseries(void)
void enable_mcheck(void);
void disable_mcheck(void);
+void enter_usermode(void);
+void exit_usermode(void);
+
#endif /* _ASMPOWERPC_PROCESSOR_H_ */
diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index b2fab4313..69ef21adb 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -58,5 +58,6 @@
#define MSR_SE UL(0x0400) /* Single Step Enable */
#define MSR_EE UL(0x8000)
#define MSR_ME UL(0x1000)
+#define MSR_PR UL(0x4000)
#endif
diff --git a/lib/powerpc/asm/smp.h b/lib/powerpc/asm/smp.h
index 820c05e9e..b96a55903 100644
--- a/lib/powerpc/asm/smp.h
+++ b/lib/powerpc/asm/smp.h
@@ -11,6 +11,7 @@ struct cpu {
unsigned long server_no;
unsigned long stack;
unsigned long exception_stack;
+ bool in_user;
secondary_entry_fn entry;
pgd_t *pgtable;
} __attribute__((packed)); /* used by asm */
diff --git a/lib/powerpc/io.c b/lib/powerpc/io.c
index cb7f2f050..5c2810884 100644
--- a/lib/powerpc/io.c
+++ b/lib/powerpc/io.c
@@ -11,6 +11,7 @@
#include <asm/setup.h>
#include <asm/processor.h>
#include <asm/atomic.h>
+#include <asm/smp.h>
#include "io.h"
static struct spinlock print_lock;
@@ -41,10 +42,16 @@ void io_init(void)
void puts(const char *s)
{
+ bool user = in_usermode();
+
+ if (user)
+ exit_usermode();
spin_lock(&print_lock);
while (*s)
putchar(*s++);
spin_unlock(&print_lock);
+ if (user)
+ enter_usermode();
}
/*
diff --git a/lib/powerpc/processor.c b/lib/powerpc/processor.c
index 09f6bb9d8..6c3000d5c 100644
--- a/lib/powerpc/processor.c
+++ b/lib/powerpc/processor.c
@@ -47,6 +47,8 @@ void do_handle_exception(struct pt_regs *regs)
unsigned char v;
__current_cpu = (struct cpu *)mfspr(SPR_SPRG0);
+ if (in_usermode())
+ current_cpu()->in_user = false;
/*
* We run with AIL=0, so interrupts taken with MMU disabled.
@@ -60,6 +62,8 @@ void do_handle_exception(struct pt_regs *regs)
if (v < 128 && handlers[v].func) {
handlers[v].func(regs, handlers[v].data);
+ if (regs->msr & MSR_PR)
+ current_cpu()->in_user = true;
return;
}
@@ -169,3 +173,37 @@ void disable_mcheck(void)
{
rfid_msr(mfmsr() & ~MSR_ME);
}
+
+bool in_usermode(void)
+{
+ return current_cpu()->in_user;
+}
+
+static void usermode_sc_handler(struct pt_regs *regs, void *data)
+{
+ regs->msr &= ~(MSR_PR|MSR_EE);
+ /* Interrupt return handler will keep in_user clear */
+}
+
+void enter_usermode(void)
+{
+ assert_msg(!in_usermode(), "enter_usermode called with in_usermode");
+ /* mfmsr would fault in usermode anyway */
+ assert_msg(!(mfmsr() & MSR_PR), "enter_usermode called from user mode");
+ assert_msg(!(mfmsr() & MSR_EE), "enter_usermode called with interrupts enabled");
+ assert_msg((mfmsr() & (MSR_IR|MSR_DR)) == (MSR_IR|MSR_DR),
+ "enter_usermode called with virtual memory disabled");
+
+ handle_exception(0xc00, usermode_sc_handler, NULL);
+ rfid_msr(mfmsr() | (MSR_PR|MSR_IR|MSR_DR|MSR_EE));
+ current_cpu()->in_user = true;
+}
+
+void exit_usermode(void)
+{
+ assert_msg(in_usermode(), "enter_usermode called with !in_usermode");
+ asm volatile("sc 0" ::: "memory");
+ handle_exception(0xc00, NULL, NULL);
+ assert(!in_usermode());
+ assert(!(mfmsr() & MSR_PR));
+}
diff --git a/lib/powerpc/rtas.c b/lib/powerpc/rtas.c
index b477a38e0..9c1e0affc 100644
--- a/lib/powerpc/rtas.c
+++ b/lib/powerpc/rtas.c
@@ -9,6 +9,7 @@
#include <libfdt/libfdt.h>
#include <devicetree.h>
#include <asm/spinlock.h>
+#include <asm/smp.h>
#include <asm/hcall.h>
#include <asm/io.h>
#include <asm/rtas.h>
@@ -137,6 +138,8 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...)
va_list list;
int ret;
+ assert_msg(!in_usermode(), "May not make RTAS call from user mode\n");
+
spin_lock(&rtas_lock);
va_start(list, outputs);
diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c
index ba659cc2b..30b988a5c 100644
--- a/lib/powerpc/setup.c
+++ b/lib/powerpc/setup.c
@@ -201,8 +201,11 @@ void cpu_init(struct cpu *cpu, int cpu_id)
cpu->exception_stack = (unsigned long)memalign(SZ_4K, SZ_64K);
cpu->exception_stack += SZ_64K - 64;
cpu->pgtable = NULL;
+ cpu->in_user = false;
}
+bool is_hvmode;
+
void setup(const void *fdt)
{
void *freemem = &stacktop;
@@ -211,8 +214,6 @@ void setup(const void *fdt)
u32 fdt_size;
int ret;
- cpu_has_hv = !!(mfmsr() & (1ULL << MSR_HV_BIT));
-
memset(cpus, 0xff, sizeof(cpus));
cpu = &cpus[0];
@@ -220,10 +221,13 @@ void setup(const void *fdt)
cpu->exception_stack = (unsigned long)boot_exception_stack;
cpu->exception_stack += SZ_64K - 64;
cpu->pgtable = NULL;
+ cpu->in_user = false;
mtspr(SPR_SPRG0, (unsigned long)cpu);
__current_cpu = cpu;
+ cpu_has_hv = !!(mfmsr() & (1ULL << MSR_HV_BIT));
+
enable_mcheck();
/*
diff --git a/lib/powerpc/spinlock.c b/lib/powerpc/spinlock.c
index 623a1f2c1..2c4904a33 100644
--- a/lib/powerpc/spinlock.c
+++ b/lib/powerpc/spinlock.c
@@ -9,6 +9,8 @@
*/
void spin_lock(struct spinlock *lock)
{
+ assert(!in_usermode());
+
if (!multithreaded) {
assert(lock->v == 0);
lock->v = 1;
@@ -20,7 +22,9 @@ void spin_lock(struct spinlock *lock)
void spin_unlock(struct spinlock *lock)
{
+ assert(!in_usermode());
assert(lock->v == 1);
+
if (!multithreaded) {
lock->v = 0;
} else {
diff --git a/lib/ppc64/mmu.c b/lib/ppc64/mmu.c
index ac9c0a285..4129f726c 100644
--- a/lib/ppc64/mmu.c
+++ b/lib/ppc64/mmu.c
@@ -42,6 +42,7 @@ void mmu_enable(pgd_t *pgtable)
cpu->pgtable = pgtable;
+ assert(!in_usermode());
mtmsr(mfmsr() | (MSR_IR|MSR_DR));
}
@@ -51,6 +52,7 @@ void mmu_disable(void)
cpu->pgtable = NULL;
+ assert(!in_usermode());
mtmsr(mfmsr() & ~(MSR_IR|MSR_DR));
}
diff --git a/powerpc/interrupts.c b/powerpc/interrupts.c
index 6bed26e41..ba965ff76 100644
--- a/powerpc/interrupts.c
+++ b/powerpc/interrupts.c
@@ -326,6 +326,33 @@ static void test_illegal(void)
report_prefix_pop();
}
+static void dec_ignore_handler(struct pt_regs *regs, void *data)
+{
+ mtspr(SPR_DEC, 0x7fffffff);
+}
+
+static void test_privileged(void)
+{
+ unsigned long msr;
+
+ if (!mmu_enabled())
+ return;
+
+ report_prefix_push("privileged instruction");
+
+ handle_exception(0x700, &program_handler, NULL);
+ handle_exception(0x900, &dec_ignore_handler, NULL);
+ enter_usermode();
+ asm volatile("mfmsr %0" : "=r"(msr) :: "memory");
+ exit_usermode();
+ report(got_interrupt, "interrupt on privileged instruction");
+ got_interrupt = false;
+ handle_exception(0x900, NULL, NULL);
+ handle_exception(0x700, NULL, NULL);
+
+ report_prefix_pop();
+}
+
static void sc_handler(struct pt_regs *regs, void *data)
{
got_interrupt = true;
@@ -478,6 +505,7 @@ int main(int argc, char **argv)
test_mce();
test_mmu();
test_illegal();
+ test_privileged();
test_dec();
test_sc();
test_trace();
--
2.42.0
next prev parent reply other threads:[~2024-03-19 8:22 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-03-19 7:58 [kvm-unit-tests PATCH v7 00/35] migration, powerpc improvements Nicholas Piggin
2024-03-19 7:58 ` [kvm-unit-tests PATCH v7 01/35] arch-run: Add functions to help handle migration directives from test Nicholas Piggin
2024-03-25 15:54 ` Thomas Huth
2024-03-19 7:58 ` [kvm-unit-tests PATCH v7 02/35] arch-run: Keep infifo open Nicholas Piggin
2024-03-19 7:58 ` [kvm-unit-tests PATCH v7 03/35] migration: Add a migrate_skip command Nicholas Piggin
2024-03-19 7:58 ` [kvm-unit-tests PATCH v7 04/35] (arm|s390): Use migrate_skip in test cases Nicholas Piggin
2024-03-19 7:58 ` [kvm-unit-tests PATCH v7 05/35] arch-run: Add a "continuous" migration option for tests Nicholas Piggin
2024-03-19 7:58 ` [kvm-unit-tests PATCH v7 06/35] gitlab-ci: Run migration selftest on s390x and powerpc Nicholas Piggin
2024-03-25 16:08 ` Thomas Huth
2024-03-28 8:16 ` Nicholas Piggin
2024-03-19 7:58 ` [kvm-unit-tests PATCH v7 07/35] common: add memory dirtying vs migration test Nicholas Piggin
2024-03-28 17:37 ` Thomas Huth
2024-04-05 4:54 ` Nicholas Piggin
2024-03-19 7:58 ` [kvm-unit-tests PATCH v7 08/35] powerpc: Fix KVM caps on POWER9 hosts Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 09/35] powerpc: Fix stack backtrace termination Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 10/35] powerpc: interrupt stack backtracing Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 11/35] powerpc/sprs: Specify SPRs with data rather than code Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 12/35] powerpc/sprs: Avoid taking PMU interrupts caused by register fuzzing Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 13/35] doc: start documentation directory with unittests.cfg doc Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 14/35] scripts: allow machine option to be specified in unittests.cfg Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 15/35] scripts: Accommodate powerpc powernv machine differences Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 16/35] powerpc: Support powernv machine with QEMU TCG Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 17/35] powerpc: Fix emulator illegal instruction test for powernv Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 18/35] powerpc/sprs: Test hypervisor registers on powernv machine Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 19/35] powerpc: general interrupt tests Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 20/35] powerpc: Add rtas stop-self support Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 21/35] powerpc: Remove broken SMP exception stack setup Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 22/35] powerpc: add SMP and IPI support Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 23/35] powerpc: Permit ACCEL=tcg,thread=single Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 24/35] powerpc: Avoid using larx/stcx. in spinlocks when only one CPU is running Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 25/35] powerpc: Add atomics tests Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 26/35] powerpc: Add timebase tests Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 27/35] powerpc: Add MMU support Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 28/35] common/sieve: Use vmalloc.h for setup_mmu definition Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 29/35] common/sieve: Support machines without MMU Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 30/35] powerpc: Add sieve.c common test Nicholas Piggin
2024-03-19 7:59 ` Nicholas Piggin [this message]
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 32/35] powerpc: add pmu tests Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 33/35] configure: Make arch_libdir a first-class entity Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 34/35] powerpc: Remove remnants of ppc64 directory and build structure Nicholas Piggin
2024-03-19 7:59 ` [kvm-unit-tests PATCH v7 35/35] powerpc: gitlab CI update Nicholas Piggin
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=20240319075926.2422707-32-npiggin@gmail.com \
--to=npiggin@gmail.com \
--cc=andrew.jones@linux.dev \
--cc=kvm@vger.kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=lvivier@redhat.com \
--cc=pbonzini@redhat.com \
--cc=thuth@redhat.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).