Re: [PATCH] arch/powerpc/kvm: Add support for reading VPA counters for pseries guests

2024-03-20 Thread Nicholas Piggin
On Wed Mar 20, 2024 at 12:28 AM AEST, Gautam Menghani wrote:
> PAPR hypervisor has introduced three new counters in the VPA area of
> LPAR CPUs for KVM L2 guest (see [1] for terminology) observability - 2
> for context switches from host to guest and vice versa, and 1 counter
> for getting the total time spent inside the KVM guest. Add a tracepoint
> that enables reading the counters for use by ftrace/perf. Note that this
> tracepoint is only available for nestedv2 API (i.e, KVM on PowerVM).
>
> [1] Terminology:
> a. L1 refers to the VM (LPAR) booted on top of PAPR hypervisor
> b. L2 refers to the KVM guest booted on top of L1.
>
> Signed-off-by: Vaibhav Jain 
> Signed-off-by: Gautam Menghani 
> ---
>  arch/powerpc/include/asm/kvm_host.h |  5 +
>  arch/powerpc/include/asm/lppaca.h   | 11 ---
>  arch/powerpc/kvm/book3s_hv.c| 20 
>  arch/powerpc/kvm/trace_hv.h | 24 
>  4 files changed, 57 insertions(+), 3 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/kvm_host.h 
> b/arch/powerpc/include/asm/kvm_host.h
> index 8abac5321..26d7bb4b9 100644
> --- a/arch/powerpc/include/asm/kvm_host.h
> +++ b/arch/powerpc/include/asm/kvm_host.h
> @@ -847,6 +847,11 @@ struct kvm_vcpu_arch {
>   gpa_t nested_io_gpr;
>   /* For nested APIv2 guests*/
>   struct kvmhv_nestedv2_io nestedv2_io;
> +
> + /* For VPA counters having context switch and guest run time info (in 
> ns) */
> + u64 l1_to_l2_cs;
> + u64 l2_to_l1_cs;
> + u64 l2_runtime;
>  #endif
>  
>  #ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING

These aren't required here if it's just used for tracing over
a single run vcpu call are they?

> diff --git a/arch/powerpc/include/asm/lppaca.h 
> b/arch/powerpc/include/asm/lppaca.h
> index 61ec2447d..bda6b86b9 100644
> --- a/arch/powerpc/include/asm/lppaca.h
> +++ b/arch/powerpc/include/asm/lppaca.h
> @@ -62,7 +62,8 @@ struct lppaca {
>   u8  donate_dedicated_cpu;   /* Donate dedicated CPU cycles */
>   u8  fpregs_in_use;
>   u8  pmcregs_in_use;
> - u8  reserved8[28];
> + u8  l2_accumul_cntrs_enable;  /* Enable usage of counters for KVM 
> guest */
> + u8  reserved8[27];
>   __be64  wait_state_cycles;  /* Wait cycles for this proc */
>   u8  reserved9[28];
>   __be16  slb_count;  /* # of SLBs to maintain */
> @@ -92,9 +93,13 @@ struct lppaca {
>   /* cacheline 4-5 */
>  
>   __be32  page_ins;   /* CMO Hint - # page ins by OS */
> - u8  reserved12[148];
> + u8  reserved12[28];
> + volatile __be64 l1_to_l2_cs_tb;
> + volatile __be64 l2_to_l1_cs_tb;
> + volatile __be64 l2_runtime_tb;
> + u8 reserved13[96];
>   volatile __be64 dtl_idx;/* Dispatch Trace Log head index */
> - u8  reserved13[96];
> + u8  reserved14[96];
>  } cacheline_aligned;
>  
>  #define lppaca_of(cpu)   (*paca_ptrs[cpu]->lppaca_ptr)
> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> index 2b04eba90..b94461b5f 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
> @@ -4092,6 +4092,7 @@ static int kvmhv_vcpu_entry_nestedv2(struct kvm_vcpu 
> *vcpu, u64 time_limit,
>   unsigned long msr, i;
>   int trap;
>   long rc;
> + struct lppaca *lp = get_lppaca();

Does get_lppaca() emit some inline asm that can't be optimised?
Could move it under the unlikely branches if so.

>  
>   io = >arch.nestedv2_io;
>  

KVM L0 could in theory provide this for v1 L1s too, so could this
be done at a higher level to cover both?

> @@ -4107,6 +4108,17 @@ static int kvmhv_vcpu_entry_nestedv2(struct kvm_vcpu 
> *vcpu, u64 time_limit,
>   kvmppc_gse_put_u64(io->vcpu_run_input, KVMPPC_GSID_LPCR, lpcr);
>  
>   accumulate_time(vcpu, >arch.in_guest);
> +
> + /* Reset the guest host context switch timing */
> + if (unlikely(trace_kvmppc_vcpu_exit_cs_time_enabled())) {
> + lp->l2_accumul_cntrs_enable = 1;
> + lp->l1_to_l2_cs_tb = 0;
> + lp->l2_to_l1_cs_tb = 0;
> + lp->l2_runtime_tb = 0;
> + } else {
> + lp->l2_accumul_cntrs_enable = 0;
> + }

Instead of zeroing here zero after the exit, which avoids the
else branch and possibly avoids an obscure race with the counters.
What if trace_kvmppc_vcpu_exit_cs_time_enabled() is false here...

> +
>   rc = plpar_guest_run_vcpu(0, vcpu->kvm->arch.lpid, vcpu->vcpu_id,
> , );
>  
> @@ -4133,6 +4145,14 @@ static int kvmhv_vcpu_entry_nestedv2(struct kvm_vcpu 
> *vcpu, u64 time_limit,
>  
>   timer_rearm_host_dec(*tb);
>  
> + /* Record context switch and guest_run_time data */
> + if (unlikely(trace_kvmppc_vcpu_exit_cs_time_enabled())) {
> + vcpu->arch.l1_to_l2_cs = 
> tb_to_ns(be64_to_cpu(lp->l1_to_l2_cs_tb));
> + vcpu->arch.l2_to_l1_cs = 
> 

Re: [PATCH] KVM: PPC: Book3S HV nestedv2: Cancel pending HDEC exception

2024-03-20 Thread Nicholas Piggin
On Wed Mar 13, 2024 at 5:26 PM AEST, Vaibhav Jain wrote:
> This reverts commit 180c6b072bf360b686e53d893d8dcf7dbbaec6bb ("KVM: PPC:
> Book3S HV nestedv2: Do not cancel pending decrementer exception") which
> prevented cancelling a pending HDEC exception for nestedv2 KVM guests. It
> was done to avoid overhead of a H_GUEST_GET_STATE hcall to read the 'HDEC
> expiry TB' register which was higher compared to handling extra decrementer
> exceptions.
>
> This overhead of reading 'HDEC expiry TB' register has been mitigated
> recently by the L0 hypervisor(PowerVM) by putting the value of this
> register in L2 guest-state output buffer on trap to L1. From there the
> value of this register is cached, made available in kvmhv_run_single_vcpu()
> to compare it against host(L1) timebase and cancel the pending hypervisor
> decrementer exception if needed.

Ah, I figured out the problem here. Guest entry never clears the
queued dec, because it's level triggered on the DEC MSB so it
doesn't go away when it's delivered. So upstream code is indeed
buggy and I think I take the blame for suggesting this nestedv2
workaround.

I actually don't think that is necessary though, we could treat it
like other interrupts.  I think that would solve the problem without
having to test dec here.

I am wondering though, what workload slows down that this patch
was needed in the first place. We'd only get here after a cede
returns, then we'd dequeue the dec and stop having to GET_STATE
it here.

Thanks,
Nick

>
> Fixes: 180c6b072bf3 ("KVM: PPC: Book3S HV nestedv2: Do not cancel pending 
> decrementer exception")
> Signed-off-by: Vaibhav Jain 
> ---
>  arch/powerpc/kvm/book3s_hv.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> index 0b921704da45..e47b954ce266 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
> @@ -4856,7 +4856,7 @@ int kvmhv_run_single_vcpu(struct kvm_vcpu *vcpu, u64 
> time_limit,
>* entering a nested guest in which case the decrementer is now owned
>* by L2 and the L1 decrementer is provided in hdec_expires
>*/
> - if (!kvmhv_is_nestedv2() && kvmppc_core_pending_dec(vcpu) &&
> + if (kvmppc_core_pending_dec(vcpu) &&
>   ((tb < kvmppc_dec_expires_host_tb(vcpu)) ||
>(trap == BOOK3S_INTERRUPT_SYSCALL &&
> kvmppc_get_gpr(vcpu, 3) == H_ENTER_NESTED)))



[kvm-unit-tests PATCH v7 35/35] powerpc: gitlab CI update

2024-03-19 Thread Nicholas Piggin
This adds testing for the powernv machine, and adds a gitlab-ci test
group instead of specifying all tests in .gitlab-ci.yml.

Signed-off-by: Nicholas Piggin 
---
 .gitlab-ci.yml| 20 
 powerpc/unittests.cfg | 14 --
 2 files changed, 16 insertions(+), 18 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index bd34da04f..e3638b088 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -97,12 +97,10 @@ build-ppc64be:
  - cd build
  - ../configure --arch=ppc64 --endian=big --cross-prefix=powerpc64-linux-gnu-
  - make -j2
- - ACCEL=tcg ./run_tests.sh
- selftest-setup selftest-migration selftest-migration-skip spapr_hcall
- rtas-get-time-of-day rtas-get-time-of-day-base rtas-set-time-of-day
- emulator
- | tee results.txt
- - if grep -q FAIL results.txt ; then exit 1 ; fi
+ - ACCEL=tcg MAX_SMP=8 ./run_tests.sh -g gitlab-ci | tee results.txt
+ - grep -q PASS results.txt && ! grep -q FAIL results.txt
+ - ACCEL=tcg MAX_SMP=8 MACHINE=powernv ./run_tests.sh -g gitlab-ci | tee 
results.txt
+ - grep -q PASS results.txt && ! grep -q FAIL results.txt
 
 build-ppc64le:
  extends: .intree_template
@@ -110,12 +108,10 @@ build-ppc64le:
  - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu nmap-ncat
  - ./configure --arch=ppc64 --endian=little --cross-prefix=powerpc64-linux-gnu-
  - make -j2
- - ACCEL=tcg ./run_tests.sh
- selftest-setup selftest-migration selftest-migration-skip spapr_hcall
- rtas-get-time-of-day rtas-get-time-of-day-base rtas-set-time-of-day
- emulator
- | tee results.txt
- - if grep -q FAIL results.txt ; then exit 1 ; fi
+ - ACCEL=tcg MAX_SMP=8 ./run_tests.sh -g gitlab-ci | tee results.txt
+ - grep -q PASS results.txt && ! grep -q FAIL results.txt
+ - ACCEL=tcg MAX_SMP=8 MACHINE=powernv ./run_tests.sh -g gitlab-ci | tee 
results.txt
+ - grep -q PASS results.txt && ! grep -q FAIL results.txt
 
 # build-riscv32:
 # Fedora doesn't package a riscv32 compiler for QEMU. Oh, well.
diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index 379aa166b..f6ddc4a7f 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -16,12 +16,12 @@
 file = selftest.elf
 smp = 2
 extra_params = -m 1g -append 'setup smp=2 mem=1024'
-groups = selftest
+groups = selftest gitlab-ci
 
 [selftest-migration]
 file = selftest-migration.elf
 machine = pseries
-groups = selftest migration
+groups = selftest migration gitlab-ci
 # TODO: Remove accel=kvm once the following TCG migration fix has been merged:
 # https://lore.kernel.org/qemu-devel/20240219061731.232570-1-npig...@gmail.com/
 accel = kvm
@@ -29,7 +29,7 @@ accel = kvm
 [selftest-migration-skip]
 file = selftest-migration.elf
 machine = pseries
-groups = selftest migration
+groups = selftest migration gitlab-ci
 extra_params = -append "skip"
 
 # This fails due to a QEMU TCG bug so KVM-only until QEMU is fixed upstream
@@ -42,6 +42,7 @@ groups = migration
 [spapr_hcall]
 file = spapr_hcall.elf
 machine = pseries
+groups = gitlab-ci
 
 [spapr_vpa]
 file = spapr_vpa.elf
@@ -52,24 +53,25 @@ file = rtas.elf
 machine = pseries
 timeout = 5
 extra_params = -append "get-time-of-day date=$(date +%s)"
-groups = rtas
+groups = rtas gitlab-ci
 
 [rtas-get-time-of-day-base]
 file = rtas.elf
 machine = pseries
 timeout = 5
 extra_params = -rtc base="2006-06-17" -append "get-time-of-day date=$(date 
--date="2006-06-17 UTC" +%s)"
-groups = rtas
+groups = rtas gitlab-ci
 
 [rtas-set-time-of-day]
 file = rtas.elf
 machine = pseries
 extra_params = -append "set-time-of-day"
 timeout = 5
-groups = rtas
+groups = rtas gitlab-ci
 
 [emulator]
 file = emulator.elf
+groups = gitlab-ci
 
 [interrupts]
 file = interrupts.elf
-- 
2.42.0



[kvm-unit-tests PATCH v7 34/35] powerpc: Remove remnants of ppc64 directory and build structure

2024-03-19 Thread Nicholas Piggin
This moves merges ppc64 directories and files into powerpc, and
merges the 3 makefiles into one.

The configure --arch=powerpc option is aliased to ppc64 for
good measure.

Signed-off-by: Nicholas Piggin 
---
 MAINTAINERS|   1 -
 configure  |   3 +-
 lib/{ppc64 => powerpc}/asm-offsets.c   |   0
 lib/{ppc64 => powerpc}/asm/asm-offsets.h   |   0
 lib/{ppc64 => powerpc}/asm/atomic.h|   0
 lib/{ppc64 => powerpc}/asm/barrier.h   |   4 +-
 lib/{ppc64 => powerpc}/asm/bitops.h|   4 +-
 lib/{ppc64 => powerpc}/asm/io.h|   4 +-
 lib/{ppc64 => powerpc}/asm/mmu.h   |   0
 lib/{ppc64 => powerpc}/asm/opal.h  |   4 +-
 lib/{ppc64 => powerpc}/asm/page.h  |   6 +-
 lib/{ppc64 => powerpc}/asm/pgtable-hwdef.h |   6 +-
 lib/{ppc64 => powerpc}/asm/pgtable.h   |   2 +-
 lib/{ppc64 => powerpc}/asm/ptrace.h|   6 +-
 lib/{ppc64 => powerpc}/asm/spinlock.h  |   6 +-
 lib/powerpc/asm/stack.h|   3 +
 lib/{ppc64 => powerpc}/asm/vpa.h   |   0
 lib/{ppc64 => powerpc}/mmu.c   |   0
 lib/{ppc64 => powerpc}/opal-calls.S|   0
 lib/{ppc64 => powerpc}/opal.c  |   0
 lib/{ppc64 => powerpc}/stack.c |   0
 lib/ppc64/.gitignore   |   1 -
 lib/ppc64/asm/handlers.h   |   1 -
 lib/ppc64/asm/hcall.h  |   1 -
 lib/ppc64/asm/memory_areas.h   |   6 --
 lib/ppc64/asm/ppc_asm.h|   1 -
 lib/ppc64/asm/processor.h  |   1 -
 lib/ppc64/asm/reg.h|   1 -
 lib/ppc64/asm/rtas.h   |   1 -
 lib/ppc64/asm/setup.h  |   1 -
 lib/ppc64/asm/smp.h|   1 -
 lib/ppc64/asm/stack.h  |  11 --
 powerpc/Makefile   | 111 -
 powerpc/Makefile.common|  95 --
 powerpc/Makefile.ppc64 |  31 --
 35 files changed, 136 insertions(+), 176 deletions(-)
 rename lib/{ppc64 => powerpc}/asm-offsets.c (100%)
 rename lib/{ppc64 => powerpc}/asm/asm-offsets.h (100%)
 rename lib/{ppc64 => powerpc}/asm/atomic.h (100%)
 rename lib/{ppc64 => powerpc}/asm/barrier.h (83%)
 rename lib/{ppc64 => powerpc}/asm/bitops.h (69%)
 rename lib/{ppc64 => powerpc}/asm/io.h (50%)
 rename lib/{ppc64 => powerpc}/asm/mmu.h (100%)
 rename lib/{ppc64 => powerpc}/asm/opal.h (90%)
 rename lib/{ppc64 => powerpc}/asm/page.h (94%)
 rename lib/{ppc64 => powerpc}/asm/pgtable-hwdef.h (93%)
 rename lib/{ppc64 => powerpc}/asm/pgtable.h (99%)
 rename lib/{ppc64 => powerpc}/asm/ptrace.h (89%)
 rename lib/{ppc64 => powerpc}/asm/spinlock.h (54%)
 rename lib/{ppc64 => powerpc}/asm/vpa.h (100%)
 rename lib/{ppc64 => powerpc}/mmu.c (100%)
 rename lib/{ppc64 => powerpc}/opal-calls.S (100%)
 rename lib/{ppc64 => powerpc}/opal.c (100%)
 rename lib/{ppc64 => powerpc}/stack.c (100%)
 delete mode 100644 lib/ppc64/.gitignore
 delete mode 100644 lib/ppc64/asm/handlers.h
 delete mode 100644 lib/ppc64/asm/hcall.h
 delete mode 100644 lib/ppc64/asm/memory_areas.h
 delete mode 100644 lib/ppc64/asm/ppc_asm.h
 delete mode 100644 lib/ppc64/asm/processor.h
 delete mode 100644 lib/ppc64/asm/reg.h
 delete mode 100644 lib/ppc64/asm/rtas.h
 delete mode 100644 lib/ppc64/asm/setup.h
 delete mode 100644 lib/ppc64/asm/smp.h
 delete mode 100644 lib/ppc64/asm/stack.h
 delete mode 100644 powerpc/Makefile.common
 delete mode 100644 powerpc/Makefile.ppc64

diff --git a/MAINTAINERS b/MAINTAINERS
index a2fa437da..1309863f2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -92,7 +92,6 @@ S: Maintained
 L: linuxppc-dev@lists.ozlabs.org
 F: powerpc/
 F: lib/powerpc/
-F: lib/ppc64/
 
 RISCV
 M: Andrew Jones 
diff --git a/configure b/configure
index a1308db8e..8508396af 100755
--- a/configure
+++ b/configure
@@ -215,6 +215,7 @@ fi
 
 arch_name=$arch
 [ "$arch" = "aarch64" ] && arch="arm64"
+[ "$arch" = "powerpc" ] && arch="ppc64"
 [ "$arch_name" = "arm64" ] && arch_name="aarch64"
 
 if [ "$arch" = "riscv" ]; then
@@ -337,7 +338,7 @@ elif [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then
 fi
 elif [ "$arch" = "ppc64" ]; then
 testdir=powerpc
-arch_libdir=ppc64
+arch_libdir=powerpc
 firmware="$testdir/boot_rom.bin"
 if [ "$endian" != "little" ] && [ "$endian" != "big" ]; then
 echo "You must provide endianness (big or little)!"
diff --git a/lib/ppc64/asm-offsets.c b/lib/powerpc/asm-offsets.c
similarity index 100%
rename from lib/ppc64/asm-offsets.c
rename to lib/powerpc/

[kvm-unit-tests PATCH v7 33/35] configure: Make arch_libdir a first-class entity

2024-03-19 Thread Nicholas Piggin
arch_libdir was brought in to improve the heuristic determination of
the lib/ directory based on arch and testdir names, but it did not
entirely clean that mess up.

Remove the arch_libdir->arch->testdir heuristic and just require
everybody sets arch_libdir correctly. Fail if the lib/arch or
lib/arch/asm directories can not be found.

Cc: Alexandru Elisei 
Cc: Claudio Imbrenda 
Cc: David Hildenbrand 
Cc: Eric Auger 
Cc: Janosch Frank 
Cc: Laurent Vivier 
Cc: Nico Böhr 
Cc: Paolo Bonzini 
Cc: Thomas Huth 
Cc: k...@vger.kernel.org
Cc: linux-s...@vger.kernel.org
Cc: kvm...@lists.linux.dev
Cc: kvm-ri...@lists.infradead.org
Cc: linuxppc-dev@lists.ozlabs.org
Reviewed-by: Andrew Jones 
Signed-off-by: Nicholas Piggin 
---
 Makefile  |  2 +-
 configure | 18 +-
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
index 4f35fffc6..4e0f54543 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@ include config.mak
 VPATH = $(SRCDIR)
 
 libdirs-get = $(shell [ -d "lib/$(1)" ] && echo "lib/$(1) lib/$(1)/asm")
-ARCH_LIBDIRS := $(call libdirs-get,$(ARCH_LIBDIR)) $(call 
libdirs-get,$(TEST_DIR))
+ARCH_LIBDIRS := $(call libdirs-get,$(ARCH_LIBDIR))
 OBJDIRS := $(ARCH_LIBDIRS)
 
 DESTDIR := $(PREFIX)/share/kvm-unit-tests/
diff --git a/configure b/configure
index e19ba6f0c..a1308db8e 100755
--- a/configure
+++ b/configure
@@ -216,7 +216,6 @@ fi
 arch_name=$arch
 [ "$arch" = "aarch64" ] && arch="arm64"
 [ "$arch_name" = "arm64" ] && arch_name="aarch64"
-arch_libdir=$arch
 
 if [ "$arch" = "riscv" ]; then
 echo "riscv32 or riscv64 must be specified"
@@ -286,8 +285,10 @@ fi
 
 if [ "$arch" = "i386" ] || [ "$arch" = "x86_64" ]; then
 testdir=x86
+arch_libdir=x86
 elif [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then
 testdir=arm
+arch_libdir=$arch
 if [ "$target" = "qemu" ]; then
 arm_uart_early_addr=0x0900
 elif [ "$target" = "kvmtool" ]; then
@@ -336,6 +337,7 @@ elif [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then
 fi
 elif [ "$arch" = "ppc64" ]; then
 testdir=powerpc
+arch_libdir=ppc64
 firmware="$testdir/boot_rom.bin"
 if [ "$endian" != "little" ] && [ "$endian" != "big" ]; then
 echo "You must provide endianness (big or little)!"
@@ -346,6 +348,7 @@ elif [ "$arch" = "riscv32" ] || [ "$arch" = "riscv64" ]; 
then
 arch_libdir=riscv
 elif [ "$arch" = "s390x" ]; then
 testdir=s390x
+arch_libdir=s390x
 else
 echo "arch $arch is not supported!"
 arch=
@@ -355,6 +358,10 @@ if [ ! -d "$srcdir/$testdir" ]; then
 echo "$srcdir/$testdir does not exist!"
 exit 1
 fi
+if [ ! -d "$srcdir/lib/$arch_libdir" ]; then
+echo "$srcdir/lib/$arch_libdir does not exist!"
+exit 1
+fi
 
 if [ "$efi" = "y" ] && [ -f "$srcdir/$testdir/efi/run" ]; then
 ln -fs "$srcdir/$testdir/efi/run" $testdir-run
@@ -417,10 +424,11 @@ fi
 # link lib/asm for the architecture
 rm -f lib/asm
 asm="asm-generic"
-if [ -d "$srcdir/lib/$arch/asm" ]; then
-   asm="$srcdir/lib/$arch/asm"
-elif [ -d "$srcdir/lib/$testdir/asm" ]; then
-   asm="$srcdir/lib/$testdir/asm"
+if [ -d "$srcdir/lib/$arch_libdir/asm" ]; then
+asm="$srcdir/lib/$arch_libdir/asm"
+else
+echo "$srcdir/lib/$arch_libdir/asm does not exist"
+exit 1
 fi
 mkdir -p lib
 ln -sf "$asm" lib/asm
-- 
2.42.0



[kvm-unit-tests PATCH v7 32/35] powerpc: add pmu tests

2024-03-19 Thread Nicholas Piggin
Add some initial PMU testing.

- PMC5/6 tests
- PMAE / PMI test
- BHRB basic tests

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/processor.h |   2 +
 lib/powerpc/asm/reg.h   |   9 +
 lib/powerpc/asm/setup.h |   1 +
 lib/powerpc/setup.c |  23 +++
 powerpc/Makefile.common |   3 +-
 powerpc/pmu.c   | 336 
 powerpc/unittests.cfg   |   3 +
 7 files changed, 376 insertions(+), 1 deletion(-)
 create mode 100644 powerpc/pmu.c

diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index 749155696..28239c610 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -14,6 +14,8 @@ extern bool cpu_has_hv;
 extern bool cpu_has_power_mce;
 extern bool cpu_has_siar;
 extern bool cpu_has_heai;
+extern bool cpu_has_bhrb;
+extern bool cpu_has_p10_bhrb;
 extern bool cpu_has_radix;
 extern bool cpu_has_prefix;
 extern bool cpu_has_sc_lev;
diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index 69ef21adb..602fba1b6 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -40,10 +40,19 @@
 #define SPR_LPIDR  0x13f
 #define SPR_HEIR   0x153
 #define SPR_PTCR   0x1d0
+#define SPR_MMCRA  0x312
+#define   MMCRA_BHRBRD UL(0x0020)
+#define   MMCRA_IFM_MASK   UL(0xc000)
+#define SPR_PMC5   0x317
+#define SPR_PMC6   0x318
 #define SPR_MMCR0  0x31b
 #define   MMCR0_FC UL(0x8000)
+#define   MMCR0_FCPUL(0x2000)
 #define   MMCR0_PMAE   UL(0x0400)
+#define   MMCR0_BHRBA  UL(0x0020)
+#define   MMCR0_FCPC   UL(0x1000)
 #define   MMCR0_PMAO   UL(0x0080)
+#define   MMCR0_FC56   UL(0x0010)
 #define SPR_SIAR   0x31c
 
 /* Machine State Register definitions: */
diff --git a/lib/powerpc/asm/setup.h b/lib/powerpc/asm/setup.h
index 9ca318ce6..8f0b58ed0 100644
--- a/lib/powerpc/asm/setup.h
+++ b/lib/powerpc/asm/setup.h
@@ -10,6 +10,7 @@
 #define NR_CPUS8   /* arbitrarily set for now */
 
 extern uint64_t tb_hz;
+extern uint64_t cpu_hz;
 
 #define NR_MEM_REGIONS 8
 #define MR_F_PRIMARY   (1U << 0)
diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c
index 30b988a5c..42ba06ad1 100644
--- a/lib/powerpc/setup.c
+++ b/lib/powerpc/setup.c
@@ -32,6 +32,7 @@ u32 initrd_size;
 u32 cpu_to_hwid[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) };
 int nr_cpus_present;
 uint64_t tb_hz;
+uint64_t cpu_hz;
 
 struct mem_region mem_regions[NR_MEM_REGIONS];
 phys_addr_t __physical_start, __physical_end;
@@ -41,6 +42,7 @@ struct cpu_set_params {
unsigned icache_bytes;
unsigned dcache_bytes;
uint64_t tb_hz;
+   uint64_t cpu_hz;
 };
 
 static void cpu_set(int fdtnode, u64 regval, void *info)
@@ -94,6 +96,22 @@ static void cpu_set(int fdtnode, u64 regval, void *info)
data = (u32 *)prop->data;
params->tb_hz = fdt32_to_cpu(*data);
 
+   prop = fdt_get_property(dt_fdt(), fdtnode,
+   "ibm,extended-clock-frequency", NULL);
+   if (prop) {
+   data = (u32 *)prop->data;
+   params->cpu_hz = fdt32_to_cpu(*data);
+   params->cpu_hz <<= 32;
+   data = (u32 *)prop->data + 1;
+   params->cpu_hz |= fdt32_to_cpu(*data);
+   } else {
+   prop = fdt_get_property(dt_fdt(), fdtnode,
+   "clock-frequency", NULL);
+   assert(prop != NULL);
+   data = (u32 *)prop->data;
+   params->cpu_hz = fdt32_to_cpu(*data);
+   }
+
read_common_info = true;
}
 }
@@ -102,6 +120,8 @@ bool cpu_has_hv;
 bool cpu_has_power_mce; /* POWER CPU machine checks */
 bool cpu_has_siar;
 bool cpu_has_heai;
+bool cpu_has_bhrb;
+bool cpu_has_p10_bhrb;
 bool cpu_has_radix;
 bool cpu_has_prefix;
 bool cpu_has_sc_lev; /* sc interrupt has LEV field in SRR1 */
@@ -118,12 +138,14 @@ static void cpu_init_params(void)
__icache_bytes = params.icache_bytes;
__dcache_bytes = params.dcache_bytes;
tb_hz = params.tb_hz;
+   cpu_hz = params.cpu_hz;
 
switch (mfspr(SPR_PVR) & PVR_VERSION_MASK) {
case PVR_VER_POWER10:
cpu_has_prefix = true;
cpu_has_sc_lev = true;
cpu_has_pause_short = true;
+   cpu_has_p10_bhrb = true;
case PVR_VER_POWER9:
cpu_has_radix = true;
case PVR_VER_POWER8E:
@@ -132,6 +154,7 @@ static void cpu_init_params(void)
cpu_has_power_mce = true;
cpu_has_heai = true;
cpu_has_siar = true;
+   cpu_has_bhrb = true;
break;
default:
  

[kvm-unit-tests PATCH v7 31/35] powerpc: add usermode support

2024-03-19 Thread Nicholas Piggin
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 
---
 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 
 #include 
 #include 
+#include 
 #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(_lock);
while (*s)
putchar(*s++);
spin_unlock(_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, usermod

[kvm-unit-tests PATCH v7 30/35] powerpc: Add sieve.c common test

2024-03-19 Thread Nicholas Piggin
Now that sieve copes with lack of MMU support, it can be run by
powerpc.

Signed-off-by: Nicholas Piggin 
---
 powerpc/Makefile.common | 1 +
 powerpc/sieve.c | 1 +
 powerpc/unittests.cfg   | 3 +++
 3 files changed, 5 insertions(+)
 create mode 12 powerpc/sieve.c

diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index 5871da47a..410a675d9 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -8,6 +8,7 @@ tests-common = \
$(TEST_DIR)/selftest.elf \
$(TEST_DIR)/selftest-migration.elf \
$(TEST_DIR)/memory-verify.elf \
+   $(TEST_DIR)/sieve.elf \
$(TEST_DIR)/spapr_hcall.elf \
$(TEST_DIR)/rtas.elf \
$(TEST_DIR)/emulator.elf \
diff --git a/powerpc/sieve.c b/powerpc/sieve.c
new file mode 12
index 0..fe299f309
--- /dev/null
+++ b/powerpc/sieve.c
@@ -0,0 +1 @@
+../common/sieve.c
\ No newline at end of file
diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index 0be787f67..351da46a6 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -121,3 +121,6 @@ file = sprs.elf
 machine = pseries
 extra_params = -append '-w'
 groups = migration
+
+[sieve]
+file = sieve.elf
-- 
2.42.0



[kvm-unit-tests PATCH v7 29/35] common/sieve: Support machines without MMU

2024-03-19 Thread Nicholas Piggin
Not all powerpc CPUs provide MMU support. Define vm_available() that is
true by default but archs can override it. Use this to run VM tests.

Cc: Paolo Bonzini 
Cc: Thomas Huth 
Cc: k...@vger.kernel.org
Reviewed-by: Andrew Jones 
Signed-off-by: Nicholas Piggin 
---
 common/sieve.c  | 14 --
 lib/ppc64/asm/mmu.h |  1 -
 lib/ppc64/mmu.c |  2 +-
 lib/vmalloc.c   |  7 +++
 lib/vmalloc.h   |  2 ++
 5 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/common/sieve.c b/common/sieve.c
index 8fe05ef13..db084691a 100644
--- a/common/sieve.c
+++ b/common/sieve.c
@@ -40,12 +40,14 @@ int main(void)
 
 printf("starting sieve\n");
 test_sieve("static", static_data, STATIC_SIZE);
-setup_vm();
-test_sieve("mapped", static_data, STATIC_SIZE);
-for (i = 0; i < 3; ++i) {
-   v = malloc(VSIZE);
-   test_sieve("virtual", v, VSIZE);
-   free(v);
+if (vm_available()) {
+   setup_vm();
+   test_sieve("mapped", static_data, STATIC_SIZE);
+   for (i = 0; i < 3; ++i) {
+   v = malloc(VSIZE);
+   test_sieve("virtual", v, VSIZE);
+   free(v);
+   }
 }
 
 return 0;
diff --git a/lib/ppc64/asm/mmu.h b/lib/ppc64/asm/mmu.h
index fadeee4bc..eaff0f1f7 100644
--- a/lib/ppc64/asm/mmu.h
+++ b/lib/ppc64/asm/mmu.h
@@ -3,7 +3,6 @@
 
 #include 
 
-bool vm_available(void);
 bool mmu_enabled(void);
 void mmu_enable(pgd_t *pgtable);
 void mmu_disable(void);
diff --git a/lib/ppc64/mmu.c b/lib/ppc64/mmu.c
index 7e445fdaf..ac9c0a285 100644
--- a/lib/ppc64/mmu.c
+++ b/lib/ppc64/mmu.c
@@ -23,7 +23,7 @@
 
 static pgd_t *identity_pgd;
 
-bool vm_available(void)
+bool vm_available(void) /* weak override */
 {
return cpu_has_radix;
 }
diff --git a/lib/vmalloc.c b/lib/vmalloc.c
index 572682576..cf2ef7a70 100644
--- a/lib/vmalloc.c
+++ b/lib/vmalloc.c
@@ -206,10 +206,17 @@ void init_alloc_vpage(void *top)
spin_unlock();
 }
 
+bool __attribute__((__weak__)) vm_available(void)
+{
+   return true;
+}
+
 void __setup_vm(void *opaque)
 {
phys_addr_t base, top;
 
+   assert_msg(vm_available(), "Virtual memory not available. Must check 
vm_available() before calling setup_vm()");
+
if (alloc_ops == _ops)
return;
 
diff --git a/lib/vmalloc.h b/lib/vmalloc.h
index 0269fdde9..e81be39f4 100644
--- a/lib/vmalloc.h
+++ b/lib/vmalloc.h
@@ -17,6 +17,8 @@ extern void setup_vm(void);
 /* As above, plus passes an opaque value to setup_mmu(). */
 extern void __setup_vm(void *opaque);
 
+/* common/ tests must check availability before calling setup_vm() */
+extern bool vm_available(void);
 /* Set up paging */
 extern void *setup_mmu(phys_addr_t top, void *opaque);
 /* Walk the page table and resolve the virtual address to a physical address */
-- 
2.42.0



[kvm-unit-tests PATCH v7 28/35] common/sieve: Use vmalloc.h for setup_mmu definition

2024-03-19 Thread Nicholas Piggin
There is no good reason to put setup_vm in libcflat.h when it's
defined in vmalloc.h.

Cc: Paolo Bonzini 
Cc: Thomas Huth 
Cc: Janosch Frank 
Cc: Claudio Imbrenda 
Cc: Nico Böhr 
Cc: David Hildenbrand 
Cc: k...@vger.kernel.org
Cc: linux-s...@vger.kernel.org
Acked-by: Andrew Jones 
Signed-off-by: Nicholas Piggin 
---
 common/sieve.c | 1 +
 lib/libcflat.h | 2 --
 lib/s390x/io.c | 1 +
 lib/s390x/uv.h | 1 +
 lib/x86/vm.h   | 1 +
 s390x/mvpg.c   | 1 +
 s390x/selftest.c   | 1 +
 x86/pmu.c  | 1 +
 x86/pmu_lbr.c  | 1 +
 x86/vmexit.c   | 1 +
 x86/vmware_backdoors.c | 1 +
 11 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/common/sieve.c b/common/sieve.c
index 8150f2d98..8fe05ef13 100644
--- a/common/sieve.c
+++ b/common/sieve.c
@@ -1,5 +1,6 @@
 #include "alloc.h"
 #include "libcflat.h"
+#include "vmalloc.h"
 
 static int sieve(char* data, int size)
 {
diff --git a/lib/libcflat.h b/lib/libcflat.h
index 700f43527..8c8dd0286 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -152,8 +152,6 @@ do {
\
 void binstr(unsigned long x, char out[BINSTR_SZ]);
 void print_binstr(unsigned long x);
 
-extern void setup_vm(void);
-
 #endif /* !__ASSEMBLY__ */
 
 #define SZ_256 (1 << 8)
diff --git a/lib/s390x/io.c b/lib/s390x/io.c
index fb7b7ddaa..2b28ccaa0 100644
--- a/lib/s390x/io.c
+++ b/lib/s390x/io.c
@@ -10,6 +10,7 @@
  */
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
diff --git a/lib/s390x/uv.h b/lib/s390x/uv.h
index 286933caa..00a370410 100644
--- a/lib/s390x/uv.h
+++ b/lib/s390x/uv.h
@@ -4,6 +4,7 @@
 
 #include 
 #include 
+#include 
 
 bool uv_os_is_guest(void);
 bool uv_os_is_host(void);
diff --git a/lib/x86/vm.h b/lib/x86/vm.h
index 4b714bad7..cf39787aa 100644
--- a/lib/x86/vm.h
+++ b/lib/x86/vm.h
@@ -2,6 +2,7 @@
 #define _X86_VM_H_
 
 #include "processor.h"
+#include "vmalloc.h"
 #include "asm/page.h"
 #include "asm/io.h"
 #include "asm/bitops.h"
diff --git a/s390x/mvpg.c b/s390x/mvpg.c
index 296338d4f..a0cfc575a 100644
--- a/s390x/mvpg.c
+++ b/s390x/mvpg.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
diff --git a/s390x/selftest.c b/s390x/selftest.c
index 92ed4e5d3..3eaae9b06 100644
--- a/s390x/selftest.c
+++ b/s390x/selftest.c
@@ -9,6 +9,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
diff --git a/x86/pmu.c b/x86/pmu.c
index 47a1a602a..7062c1ad9 100644
--- a/x86/pmu.c
+++ b/x86/pmu.c
@@ -6,6 +6,7 @@
 #include "x86/apic.h"
 #include "x86/desc.h"
 #include "x86/isr.h"
+#include "vmalloc.h"
 #include "alloc.h"
 
 #include "libcflat.h"
diff --git a/x86/pmu_lbr.c b/x86/pmu_lbr.c
index 40b63fa3d..c6f010847 100644
--- a/x86/pmu_lbr.c
+++ b/x86/pmu_lbr.c
@@ -2,6 +2,7 @@
 #include "x86/processor.h"
 #include "x86/pmu.h"
 #include "x86/desc.h"
+#include "vmalloc.h"
 
 #define N 100
 
diff --git a/x86/vmexit.c b/x86/vmexit.c
index eb5d3023a..48a38f60f 100644
--- a/x86/vmexit.c
+++ b/x86/vmexit.c
@@ -1,6 +1,7 @@
 #include "libcflat.h"
 #include "acpi.h"
 #include "smp.h"
+#include "vmalloc.h"
 #include "pci.h"
 #include "x86/vm.h"
 #include "x86/desc.h"
diff --git a/x86/vmware_backdoors.c b/x86/vmware_backdoors.c
index bc1002056..f8cf7ecb1 100644
--- a/x86/vmware_backdoors.c
+++ b/x86/vmware_backdoors.c
@@ -6,6 +6,7 @@
 #include "x86/desc.h"
 #include "x86/isr.h"
 #include "alloc.h"
+#include "vmalloc.h"
 #include "setjmp.h"
 #include "usermode.h"
 #include "fault_test.h"
-- 
2.42.0



[kvm-unit-tests PATCH v7 27/35] powerpc: Add MMU support

2024-03-19 Thread Nicholas Piggin
Add support for radix MMU, 4kB and 64kB pages.

This also adds MMU interrupt test cases, and runs the interrupts
test entirely with MMU enabled if it is available (aside from
machine check tests).

Acked-by: Andrew Jones  (configure changes)
Signed-off-by: Nicholas Piggin 
---
 configure |  39 +++--
 lib/powerpc/asm/hcall.h   |   6 +
 lib/powerpc/asm/processor.h   |   1 +
 lib/powerpc/asm/reg.h |   3 +
 lib/powerpc/asm/smp.h |   2 +
 lib/powerpc/processor.c   |   9 ++
 lib/powerpc/setup.c   |   4 +
 lib/ppc64/asm/mmu.h   |  11 ++
 lib/ppc64/asm/page.h  |  66 -
 lib/ppc64/asm/pgtable-hwdef.h |  66 +
 lib/ppc64/asm/pgtable.h   | 125 
 lib/ppc64/mmu.c   | 272 ++
 lib/ppc64/opal-calls.S|   4 +-
 powerpc/Makefile.common   |   2 +
 powerpc/Makefile.ppc64|   1 +
 powerpc/interrupts.c  |  96 ++--
 16 files changed, 680 insertions(+), 27 deletions(-)
 create mode 100644 lib/ppc64/asm/mmu.h
 create mode 100644 lib/ppc64/asm/pgtable-hwdef.h
 create mode 100644 lib/ppc64/asm/pgtable.h
 create mode 100644 lib/ppc64/mmu.c

diff --git a/configure b/configure
index 49f047cb2..e19ba6f0c 100755
--- a/configure
+++ b/configure
@@ -245,29 +245,35 @@ fi
 if [ -z "$page_size" ]; then
 if [ "$efi" = 'y' ] && [ "$arch" = "arm64" ]; then
 page_size="4096"
-elif [ "$arch" = "arm64" ]; then
+elif [ "$arch" = "arm64" ] || [ "$arch" = "ppc64" ]; then
 page_size="65536"
 elif [ "$arch" = "arm" ]; then
 page_size="4096"
 fi
 else
-if [ "$arch" != "arm64" ]; then
-echo "--page-size is not supported for $arch"
-usage
-fi
-
 if [ "${page_size: -1}" = "K" ] || [ "${page_size: -1}" = "k" ]; then
 page_size=$(( ${page_size%?} * 1024 ))
 fi
-if [ "$page_size" != "4096" ] && [ "$page_size" != "16384" ] &&
-   [ "$page_size" != "65536" ]; then
-echo "arm64 doesn't support page size of $page_size"
+
+if [ "$arch" = "arm64" ]; then
+if [ "$page_size" != "4096" ] && [ "$page_size" != "16384" ] &&
+   [ "$page_size" != "65536" ]; then
+echo "arm64 doesn't support page size of $page_size"
+usage
+fi
+if [ "$efi" = 'y' ] && [ "$page_size" != "4096" ]; then
+echo "efi must use 4K pages"
+exit 1
+fi
+elif [ "$arch" = "ppc64" ]; then
+if [ "$page_size" != "4096" ] && [ "$page_size" != "65536" ]; then
+echo "ppc64 doesn't support page size of $page_size"
+usage
+fi
+else
+echo "--page-size is not supported for $arch"
 usage
 fi
-if [ "$efi" = 'y' ] && [ "$page_size" != "4096" ]; then
-echo "efi must use 4K pages"
-exit 1
-fi
 fi
 
 [ -z "$processor" ] && processor="$arch"
@@ -472,6 +478,13 @@ cat <> lib/config.h
 
 #define CONFIG_UART_EARLY_BASE ${arm_uart_early_addr}
 #define CONFIG_ERRATA_FORCE ${errata_force}
+
+EOF
+fi
+
+if [ "$arch" = "arm" ] || [ "$arch" = "arm64" ] || [ "$arch" = "ppc64" ]; then
+cat <> lib/config.h
+
 #define CONFIG_PAGE_SIZE _AC(${page_size}, UL)
 
 EOF
diff --git a/lib/powerpc/asm/hcall.h b/lib/powerpc/asm/hcall.h
index e0f5009e3..3b44dd204 100644
--- a/lib/powerpc/asm/hcall.h
+++ b/lib/powerpc/asm/hcall.h
@@ -24,6 +24,12 @@
 #define H_PUT_TERM_CHAR0x58
 #define H_RANDOM   0x300
 #define H_SET_MODE 0x31C
+#define H_REGISTER_PROCESS_TABLE   0x37C
+
+#define PTBL_NEW   0x18
+#define PTBL_UNREGISTER0x10
+#define PTBL_RADIX 0x04
+#define PTBL_GTSE  0x01
 
 #define KVMPPC_HCALL_BASE  0xf000
 #define KVMPPC_H_RTAS  (KVMPPC_HCALL_BASE + 0x0)
diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index a3859b5d4..d348239c5 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -14,6 +14,7 @@ extern bool cpu_has_hv;
 extern bool cpu_has_power_mce;
 extern bool cpu_has_siar;
 extern bool cpu_has_heai;
+extern bool cpu_has_radix;
 extern bool cpu_has_prefix;
 extern bool cpu_has_sc_lev;
 extern bool cpu_has_pause_short;
diff --git

[kvm-unit-tests PATCH v7 26/35] powerpc: Add timebase tests

2024-03-19 Thread Nicholas Piggin
This has a known failure on QEMU TCG machines where the decrementer
interrupt is not lowered when the DEC wraps from -ve to +ve.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/reg.h   |   1 +
 powerpc/Makefile.common |   1 +
 powerpc/timebase.c  | 329 
 powerpc/unittests.cfg   |   8 +
 4 files changed, 339 insertions(+)
 create mode 100644 powerpc/timebase.c

diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index d2ca964c4..12f9e8ac6 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -35,6 +35,7 @@
 #define SPR_HSRR1  0x13b
 #define SPR_LPCR   0x13e
 #define   LPCR_HDICE   UL(0x1)
+#define   LPCR_LD  UL(0x2)
 #define SPR_HEIR   0x153
 #define SPR_MMCR0  0x31b
 #define   MMCR0_FC UL(0x8000)
diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index b6f9b3b85..1348f658b 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -15,6 +15,7 @@ tests-common = \
$(TEST_DIR)/tm.elf \
$(TEST_DIR)/smp.elf \
$(TEST_DIR)/sprs.elf \
+   $(TEST_DIR)/timebase.elf \
$(TEST_DIR)/interrupts.elf
 
 tests-all = $(tests-common) $(tests)
diff --git a/powerpc/timebase.c b/powerpc/timebase.c
new file mode 100644
index 0..1908ca838
--- /dev/null
+++ b/powerpc/timebase.c
@@ -0,0 +1,329 @@
+/* SPDX-License-Identifier: LGPL-2.0-only */
+/*
+ * Test Timebase
+ *
+ * Copyright 2024 Nicholas Piggin, IBM Corp.
+ *
+ * This contains tests of timebase facility, TB, DEC, etc.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static int dec_bits = 0;
+
+static void cpu_dec_bits(int fdtnode, u64 regval __unused, void *arg __unused)
+{
+   const struct fdt_property *prop;
+   int plen;
+
+   prop = fdt_get_property(dt_fdt(), fdtnode, "ibm,dec-bits", );
+   if (!prop) {
+   dec_bits = 32;
+   return;
+   }
+
+   /* Sanity check for the property layout (first two bytes are header) */
+   assert(plen == 4);
+
+   dec_bits = fdt32_to_cpu(*(uint32_t *)prop->data);
+}
+
+/* Check amount of CPUs nodes that have the TM flag */
+static int find_dec_bits(void)
+{
+   int ret;
+
+   ret = dt_for_each_cpu_node(cpu_dec_bits, NULL);
+   if (ret < 0)
+   return ret;
+
+   return dec_bits;
+}
+
+
+static bool do_migrate = false;
+static volatile bool got_interrupt;
+static volatile struct pt_regs recorded_regs;
+
+static uint64_t dec_max;
+static uint64_t dec_min;
+
+static void test_tb(int argc, char **argv)
+{
+   uint64_t tb;
+
+   tb = get_tb();
+   if (do_migrate)
+   migrate();
+   report(get_tb() >= tb, "timebase is incrementing");
+}
+
+static void dec_stop_handler(struct pt_regs *regs, void *data)
+{
+   mtspr(SPR_DEC, dec_max);
+}
+
+static void dec_handler(struct pt_regs *regs, void *data)
+{
+   got_interrupt = true;
+   memcpy((void *)_regs, regs, sizeof(struct pt_regs));
+   regs->msr &= ~MSR_EE;
+}
+
+static void test_dec(int argc, char **argv)
+{
+   uint64_t tb1, tb2, dec;
+   int i;
+
+   handle_exception(0x900, _handler, NULL);
+
+   for (i = 0; i < 100; i++) {
+   tb1 = get_tb();
+   mtspr(SPR_DEC, dec_max);
+   dec = mfspr(SPR_DEC);
+   tb2 = get_tb();
+   if (tb2 - tb1 < dec_max - dec)
+   break;
+   }
+   report(tb2 - tb1 >= dec_max - dec, "decrementer remains within TB after 
mtDEC");
+
+   tb1 = get_tb();
+   mtspr(SPR_DEC, dec_max);
+   mdelay(1000);
+   dec = mfspr(SPR_DEC);
+   tb2 = get_tb();
+   report(tb2 - tb1 >= dec_max - dec, "decrementer remains within TB after 
1s");
+
+   mtspr(SPR_DEC, dec_max);
+   local_irq_enable();
+   local_irq_disable();
+   if (mfspr(SPR_DEC) <= dec_max) {
+   report(!got_interrupt, "no interrupt on decrementer positive");
+   }
+   got_interrupt = false;
+
+   mtspr(SPR_DEC, 1);
+   mdelay(100); /* Give the timer a chance to run */
+   if (do_migrate)
+   migrate();
+   local_irq_enable();
+   local_irq_disable();
+   report(got_interrupt, "interrupt on decrementer underflow");
+   got_interrupt = false;
+
+   if (do_migrate)
+   migrate();
+   local_irq_enable();
+   local_irq_disable();
+   report(got_interrupt, "interrupt on decrementer still underflown");
+   got_interrupt = false;
+
+   mtspr(SPR_DEC, 0);
+   mdelay(100); /* Give the timer a chance to run */
+   if (do_migrate)
+   migrate();
+   local_irq_enable();
+   local_irq_disable();
+   report(got_interrupt, "DEC deal with set to 0");
+   got_interrupt = fa

[kvm-unit-tests PATCH v7 25/35] powerpc: Add atomics tests

2024-03-19 Thread Nicholas Piggin
Signed-off-by: Nicholas Piggin 
---
 powerpc/Makefile.common |   1 +
 powerpc/atomics.c   | 374 
 powerpc/unittests.cfg   |   9 +
 3 files changed, 384 insertions(+)
 create mode 100644 powerpc/atomics.c

diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index 02af54b83..b6f9b3b85 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -11,6 +11,7 @@ tests-common = \
$(TEST_DIR)/spapr_hcall.elf \
$(TEST_DIR)/rtas.elf \
$(TEST_DIR)/emulator.elf \
+   $(TEST_DIR)/atomics.elf \
$(TEST_DIR)/tm.elf \
$(TEST_DIR)/smp.elf \
$(TEST_DIR)/sprs.elf \
diff --git a/powerpc/atomics.c b/powerpc/atomics.c
new file mode 100644
index 0..c3d1cef52
--- /dev/null
+++ b/powerpc/atomics.c
@@ -0,0 +1,374 @@
+/* SPDX-License-Identifier: LGPL-2.0-only */
+/*
+ * Test some powerpc instructions
+ *
+ * Copyright 2024 Nicholas Piggin, IBM Corp.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static bool do_migrate;
+static bool do_record;
+
+#define RSV_SIZE 128
+
+static uint8_t granule[RSV_SIZE] __attribute((__aligned__(RSV_SIZE)));
+
+static void spin_lock(unsigned int *lock)
+{
+   unsigned int old;
+
+   asm volatile ("1:"
+ "lwarx%0,0,%2;"
+ "cmpwi%0,0;"
+ "bne  1b;"
+ "stwcx.   %1,0,%2;"
+ "bne- 1b;"
+ "lwsync;"
+ : "="(old) : "r"(1), "r"(lock) : "cr0", "memory");
+}
+
+static void spin_unlock(unsigned int *lock)
+{
+   asm volatile("lwsync;"
+"stw   %1,%0;"
+: "+m"(*lock) : "r"(0) : "memory");
+}
+
+static volatile bool got_interrupt;
+static volatile struct pt_regs recorded_regs;
+
+static void interrupt_handler(struct pt_regs *regs, void *opaque)
+{
+   assert(!got_interrupt);
+   got_interrupt = true;
+   memcpy((void *)_regs, regs, sizeof(struct pt_regs));
+   regs_advance_insn(regs);
+}
+
+static void test_lwarx_stwcx(int argc, char *argv[])
+{
+   unsigned int *var = (unsigned int *)granule;
+   unsigned int old;
+   unsigned int result;
+
+   *var = 0;
+   asm volatile ("1:"
+ "lwarx%0,0,%2;"
+ "stwcx.   %1,0,%2;"
+ "bne- 1b;"
+ : "="(old) : "r"(1), "r"(var) : "cr0", "memory");
+   report(old == 0 && *var == 1, "simple update");
+
+   *var = 0;
+   asm volatile ("li   %0,0;"
+ "stwcx.   %1,0,%2;"
+ "stwcx.   %1,0,%2;"
+ "bne- 1f;"
+ "li   %0,1;"
+ "1:"
+ : "="(result)
+ : "r"(1), "r"(var) : "cr0", "memory");
+   report(result == 0 && *var == 0, "failed stwcx. (no reservation)");
+
+   *var = 0;
+   asm volatile ("li   %0,0;"
+ "lwarx%1,0,%4;"
+ "stw  %3,0(%4);"
+ "stwcx.   %2,0,%4;"
+ "bne- 1f;"
+ "li   %0,1;"
+ "1:"
+ : "="(result), "="(old)
+ : "r"(1), "r"(2), "r"(var) : "cr0", "memory");
+   /* This is implementation specific, so don't fail */
+   if (result == 0 && *var == 2)
+   report(true, "failed stwcx. (intervening store)");
+   else
+   report(true, "succeeded stwcx. (intervening store)");
+
+   handle_exception(0x600, interrupt_handler, NULL);
+   handle_exception(0x700, interrupt_handler, NULL);
+
+   /* Implementations may not necessarily invoke the alignment interrupt */
+   old = 10;
+   *var = 0;
+   asm volatile (
+ "lwarx%0,0,%1;"
+ : "+"(old) : "r"((char *)var + 1));
+   report(old == 10 && got_interrupt && recorded_regs.trap == 0x600, 
"unaligned lwarx causes fault");
+   got_interrupt = false;
+
+   /*
+* Unaligned stwcx. is more difficult to test, at least under QEMU,
+* the store does not proceed if there is no matching reservation, so
+* the alignment handler does not get i

[kvm-unit-tests PATCH v7 24/35] powerpc: Avoid using larx/stcx. in spinlocks when only one CPU is running

2024-03-19 Thread Nicholas Piggin
The test harness uses spinlocks if they are implemented with larx/stcx.
it can prevent some test scenarios such as testing migration of a
reservation.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/smp.h|  1 +
 lib/powerpc/smp.c|  5 +
 lib/powerpc/spinlock.c   | 29 +
 lib/ppc64/asm/spinlock.h |  7 ++-
 powerpc/Makefile.common  |  1 +
 5 files changed, 42 insertions(+), 1 deletion(-)
 create mode 100644 lib/powerpc/spinlock.c

diff --git a/lib/powerpc/asm/smp.h b/lib/powerpc/asm/smp.h
index 4519e5436..6ef3ae521 100644
--- a/lib/powerpc/asm/smp.h
+++ b/lib/powerpc/asm/smp.h
@@ -15,6 +15,7 @@ struct cpu {
 
 extern int nr_cpus_present;
 extern int nr_cpus_online;
+extern bool multithreaded;
 extern struct cpu cpus[];
 
 register struct cpu *__current_cpu asm("r13");
diff --git a/lib/powerpc/smp.c b/lib/powerpc/smp.c
index a3bf85d44..f3b2a3faf 100644
--- a/lib/powerpc/smp.c
+++ b/lib/powerpc/smp.c
@@ -276,6 +276,8 @@ static void start_each_secondary(int fdtnode, u64 regval 
__unused, void *info)
start_core(fdtnode, datap->entry);
 }
 
+bool multithreaded = false;
+
 /*
  * Start all stopped cpus on the guest at entry with register 3 set to r3
  * We expect that we come in with only one thread currently started
@@ -290,6 +292,7 @@ bool start_all_cpus(secondary_entry_fn entry)
 
assert(nr_cpus_online == 1);
assert(nr_started == 1);
+   multithreaded = true;
ret = dt_for_each_cpu_node(start_each_secondary, );
assert(ret == 0);
assert(nr_started == nr_cpus_present);
@@ -308,8 +311,10 @@ bool start_all_cpus(secondary_entry_fn entry)
 
 void stop_all_cpus(void)
 {
+   assert(multithreaded);
while (nr_cpus_online > 1)
cpu_relax();
mb();
nr_started = 1;
+   multithreaded = false;
 }
diff --git a/lib/powerpc/spinlock.c b/lib/powerpc/spinlock.c
new file mode 100644
index 0..623a1f2c1
--- /dev/null
+++ b/lib/powerpc/spinlock.c
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: LGPL-2.0 */
+#include 
+#include 
+
+/*
+ * Skip the atomic when single-threaded, which helps avoid larx/stcx. in
+ * the harness when testing tricky larx/stcx. sequences (e.g., migration
+ * vs reservation).
+ */
+void spin_lock(struct spinlock *lock)
+{
+   if (!multithreaded) {
+   assert(lock->v == 0);
+   lock->v = 1;
+   } else {
+   while (__sync_lock_test_and_set(>v, 1))
+   ;
+   }
+}
+
+void spin_unlock(struct spinlock *lock)
+{
+   assert(lock->v == 1);
+   if (!multithreaded) {
+   lock->v = 0;
+   } else {
+   __sync_lock_release(>v);
+   }
+}
diff --git a/lib/ppc64/asm/spinlock.h b/lib/ppc64/asm/spinlock.h
index f59eed191..b952386da 100644
--- a/lib/ppc64/asm/spinlock.h
+++ b/lib/ppc64/asm/spinlock.h
@@ -1,6 +1,11 @@
 #ifndef _ASMPPC64_SPINLOCK_H_
 #define _ASMPPC64_SPINLOCK_H_
 
-#include 
+struct spinlock {
+   unsigned int v;
+};
+
+void spin_lock(struct spinlock *lock);
+void spin_unlock(struct spinlock *lock);
 
 #endif /* _ASMPPC64_SPINLOCK_H_ */
diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index 744dfc1f7..02af54b83 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -48,6 +48,7 @@ cflatobjs += lib/powerpc/rtas.o
 cflatobjs += lib/powerpc/processor.o
 cflatobjs += lib/powerpc/handlers.o
 cflatobjs += lib/powerpc/smp.o
+cflatobjs += lib/powerpc/spinlock.o
 
 OBJDIRS += lib/powerpc
 
-- 
2.42.0



[kvm-unit-tests PATCH v7 23/35] powerpc: Permit ACCEL=tcg,thread=single

2024-03-19 Thread Nicholas Piggin
Modify run script to permit single vs mttcg threading, add a
thread=single smp case to unittests.cfg.

Signed-off-by: Nicholas Piggin 
---
 powerpc/run   | 4 ++--
 powerpc/unittests.cfg | 6 ++
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/powerpc/run b/powerpc/run
index 172f32a46..27abf1ef6 100755
--- a/powerpc/run
+++ b/powerpc/run
@@ -36,8 +36,8 @@ if ! $qemu -machine '?' 2>&1 | grep $MACHINE > /dev/null; then
exit 2
 fi
 
+A="-accel $ACCEL$ACCEL_PROPS"
 M="-machine $MACHINE"
-M+=",accel=$ACCEL$ACCEL_PROPS"
 B=""
 D=""
 
@@ -54,7 +54,7 @@ if [[ "$MACHINE" == "powernv"* ]] ; then
D+="-device ipmi-bmc-sim,id=bmc0 -device isa-ipmi-bt,bmc=bmc0,irq=10"
 fi
 
-command="$qemu -nodefaults $M $B $D"
+command="$qemu -nodefaults $A $M $B $D"
 command+=" -display none -serial stdio -kernel"
 command="$(migration_cmd) $(timeout_cmd) $command"
 
diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index ddce409a8..71bfc935d 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -82,6 +82,12 @@ smp = 2
 file = smp.elf
 smp = 8,threads=4
 
+# mttcg is the default most places, so add a thread=single test
+[smp-thread-single]
+file = smp.elf
+smp = 8,threads=4
+accel = tcg,thread=single
+
 [h_cede_tm]
 file = tm.elf
 machine = pseries
-- 
2.42.0



[kvm-unit-tests PATCH v7 22/35] powerpc: add SMP and IPI support

2024-03-19 Thread Nicholas Piggin
powerpc SMP support is very primitive and does not set up a first-class
runtime environment for secondary CPUs.

This reworks SMP support, and provides a complete C and harness
environment for the secondaries, including interrupt handling, as well
as IPI support.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/processor.h |  23 +++
 lib/powerpc/asm/reg.h   |   1 +
 lib/powerpc/asm/setup.h |   2 -
 lib/powerpc/asm/smp.h   |  46 +++--
 lib/powerpc/io.c|  15 +-
 lib/powerpc/processor.c |   7 +-
 lib/powerpc/setup.c |  90 +++---
 lib/powerpc/smp.c   | 282 +
 lib/ppc64/asm-offsets.c |   7 +
 lib/ppc64/asm/atomic.h  |   6 +
 lib/ppc64/asm/barrier.h |   3 +
 lib/ppc64/asm/opal.h|   7 +
 powerpc/Makefile.common |   1 +
 powerpc/cstart64.S  |  49 -
 powerpc/selftest.c  |   4 +-
 powerpc/smp.c   | 348 
 powerpc/tm.c|   4 +-
 powerpc/unittests.cfg   |   8 +
 18 files changed, 818 insertions(+), 85 deletions(-)
 create mode 100644 lib/ppc64/asm/atomic.h
 create mode 100644 powerpc/smp.c

diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index eed37d1f4..a3859b5d4 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -16,6 +16,7 @@ extern bool cpu_has_siar;
 extern bool cpu_has_heai;
 extern bool cpu_has_prefix;
 extern bool cpu_has_sc_lev;
+extern bool cpu_has_pause_short;
 
 static inline uint64_t mfspr(int nr)
 {
@@ -45,6 +46,28 @@ static inline void mtmsr(uint64_t msr)
asm volatile ("mtmsrd %[msr]" :: [msr] "r" (msr) : "memory");
 }
 
+static inline void local_irq_enable(void)
+{
+   unsigned long msr;
+
+   asm volatile(
+"  mfmsr   %0  \n \
+   ori %0,%0,%1\n \
+   mtmsrd  %0,1"
+   : "=r"(msr) : "i"(MSR_EE): "memory");
+}
+
+static inline void local_irq_disable(void)
+{
+   unsigned long msr;
+
+   asm volatile(
+"  mfmsr   %0  \n \
+   andc%0,%0,%1\n \
+   mtmsrd  %0,1"
+   : "=r"(msr) : "r"(MSR_EE): "memory");
+}
+
 /*
  * This returns true on PowerNV / OPAL machines which run in hypervisor
  * mode. False on pseries / PAPR machines that run in guest mode.
diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index d6097f48f..d2ca964c4 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -19,6 +19,7 @@
 #define SPR_SPRG1  0x111
 #define SPR_SPRG2  0x112
 #define SPR_SPRG3  0x113
+#define SPR_TBU40  0x11e
 #define SPR_PVR0x11f
 #define   PVR_VERSION_MASK UL(0x)
 #define   PVR_VER_970  UL(0x0039)
diff --git a/lib/powerpc/asm/setup.h b/lib/powerpc/asm/setup.h
index cc7cf5e25..9ca318ce6 100644
--- a/lib/powerpc/asm/setup.h
+++ b/lib/powerpc/asm/setup.h
@@ -8,8 +8,6 @@
 #include 
 
 #define NR_CPUS8   /* arbitrarily set for now */
-extern u32 cpus[NR_CPUS];
-extern int nr_cpus;
 
 extern uint64_t tb_hz;
 
diff --git a/lib/powerpc/asm/smp.h b/lib/powerpc/asm/smp.h
index 21940b4bc..4519e5436 100644
--- a/lib/powerpc/asm/smp.h
+++ b/lib/powerpc/asm/smp.h
@@ -2,21 +2,45 @@
 #define _ASMPOWERPC_SMP_H_
 
 #include 
+#include 
 
-extern int nr_threads;
+typedef void (*secondary_entry_fn)(int cpu_id);
 
-struct start_threads {
-   int nr_threads;
-   int nr_started;
-};
+struct cpu {
+   unsigned long server_no;
+   unsigned long stack;
+   unsigned long exception_stack;
+   secondary_entry_fn entry;
+} __attribute__((packed)); /* used by asm */
 
-typedef void (*secondary_entry_fn)(void);
+extern int nr_cpus_present;
+extern int nr_cpus_online;
+extern struct cpu cpus[];
 
-extern void halt(void);
+register struct cpu *__current_cpu asm("r13");
+static inline struct cpu *current_cpu(void)
+{
+   return __current_cpu;
+}
 
-extern int start_thread(int cpu_id, secondary_entry_fn entry, uint32_t r3);
-extern struct start_threads start_cpu(int cpu_node, secondary_entry_fn entry,
- uint32_t r3);
-extern bool start_all_cpus(secondary_entry_fn entry, uint32_t r3);
+static inline int smp_processor_id(void)
+{
+   return current_cpu()->server_no;
+}
+
+void cpu_init(struct cpu *cpu, int cpu_id);
+
+extern void halt(int cpu_id);
+
+extern bool start_all_cpus(secondary_entry_fn entry);
+extern void stop_all_cpus(void);
+
+struct pt_regs;
+void register_ipi(void (*fn)(struct pt_regs *, void *), void *data);
+void unregister_ipi(void);
+void cpu_init_ipis(void);
+void local_ipi_enable(void);
+void local_ipi_disable(void);
+void send_ipi(int cpu_id);
 
 #endif /* _ASMPOWERPC_SMP_H_ */
diff --git a/lib/powerpc/io.c b/l

[kvm-unit-tests PATCH v7 21/35] powerpc: Remove broken SMP exception stack setup

2024-03-19 Thread Nicholas Piggin
The exception stack setup does not work correctly for SMP, because
it is the boot processor that calls cpu_set() which sets SPRG2 to
the exception stack, not the target CPU itself. So secondaries
never got their SPRG2 set to a valid exception stack.

Remove the SMP code and just set an exception stack for the boot
processor. Make the stack 64kB while we're here, to match the
size of the regular stack.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/setup.c | 16 
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c
index 9b665f59c..496af40f8 100644
--- a/lib/powerpc/setup.c
+++ b/lib/powerpc/setup.c
@@ -42,10 +42,6 @@ struct cpu_set_params {
uint64_t tb_hz;
 };
 
-#define EXCEPTION_STACK_SIZE   (32*1024) /* 32kB */
-
-static char exception_stack[NR_CPUS][EXCEPTION_STACK_SIZE];
-
 static void cpu_set(int fdtnode, u64 regval, void *info)
 {
static bool read_common_info = false;
@@ -56,10 +52,6 @@ static void cpu_set(int fdtnode, u64 regval, void *info)
 
cpus[cpu] = regval;
 
-   /* set exception stack address for this CPU (in SPGR0) */
-   asm volatile ("mtsprg0 %[addr]" ::
- [addr] "r" (exception_stack[cpu + 1]));
-
if (!read_common_info) {
const struct fdt_property *prop;
u32 *data;
@@ -180,6 +172,10 @@ static void mem_init(phys_addr_t freemem_start)
 ? __icache_bytes : __dcache_bytes);
 }
 
+#define EXCEPTION_STACK_SIZE   SZ_64K
+
+static char boot_exception_stack[EXCEPTION_STACK_SIZE];
+
 void setup(const void *fdt)
 {
void *freemem = 
@@ -189,6 +185,10 @@ void setup(const void *fdt)
 
cpu_has_hv = !!(mfmsr() & (1ULL << MSR_HV_BIT));
 
+   /* set exception stack address for this CPU (in SPGR0) */
+   asm volatile ("mtsprg0 %[addr]" ::
+ [addr] "r" (boot_exception_stack));
+
enable_mcheck();
 
/*
-- 
2.42.0



[kvm-unit-tests PATCH v7 20/35] powerpc: Add rtas stop-self support

2024-03-19 Thread Nicholas Piggin
In preparation for improved SMP support, add stop-self support to the
harness. This is non-trivial because it requires an unlocked rtas
call: a CPU can't be holding a spin lock when it goes offline or it
will deadlock other CPUs. rtas permits stop-self to be called without
serialising all other rtas operations.

Reviewed-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/rtas.h |  2 ++
 lib/powerpc/rtas.c | 78 +-
 2 files changed, 64 insertions(+), 16 deletions(-)

diff --git a/lib/powerpc/asm/rtas.h b/lib/powerpc/asm/rtas.h
index 6fb407a18..364bf9355 100644
--- a/lib/powerpc/asm/rtas.h
+++ b/lib/powerpc/asm/rtas.h
@@ -23,8 +23,10 @@ struct rtas_args {
 extern void rtas_init(void);
 extern int rtas_token(const char *service, uint32_t *token);
 extern int rtas_call(int token, int nargs, int nret, int *outputs, ...);
+extern int rtas_call_unlocked(struct rtas_args *args, int token, int nargs, 
int nret, int *outputs, ...);
 
 extern void rtas_power_off(void);
+extern void rtas_stop_self(void);
 #endif /* __ASSEMBLY__ */
 
 #define RTAS_MSR_MASK 0xfffe
diff --git a/lib/powerpc/rtas.c b/lib/powerpc/rtas.c
index 41c0a243e..b477a38e0 100644
--- a/lib/powerpc/rtas.c
+++ b/lib/powerpc/rtas.c
@@ -87,40 +87,86 @@ int rtas_token(const char *service, uint32_t *token)
return 0;
 }
 
-int rtas_call(int token, int nargs, int nret, int *outputs, ...)
+static void __rtas_call(struct rtas_args *args)
 {
-   va_list list;
-   int ret, i;
+   enter_rtas(__pa(args));
+}
 
-   spin_lock(_lock);
+static int rtas_call_unlocked_va(struct rtas_args *args,
+ int token, int nargs, int nret, int *outputs,
+ va_list list)
+{
+   int ret, i;
 
-   rtas_args.token = cpu_to_be32(token);
-   rtas_args.nargs = cpu_to_be32(nargs);
-   rtas_args.nret = cpu_to_be32(nret);
-   rtas_args.rets = _args.args[nargs];
+   args->token = cpu_to_be32(token);
+   args->nargs = cpu_to_be32(nargs);
+   args->nret = cpu_to_be32(nret);
+   args->rets = >args[nargs];
 
-   va_start(list, outputs);
for (i = 0; i < nargs; ++i)
-   rtas_args.args[i] = cpu_to_be32(va_arg(list, u32));
-   va_end(list);
+   args->args[i] = cpu_to_be32(va_arg(list, u32));
 
for (i = 0; i < nret; ++i)
-   rtas_args.rets[i] = 0;
+   args->rets[i] = 0;
 
-   enter_rtas(__pa(_args));
+   __rtas_call(args);
 
if (nret > 1 && outputs != NULL)
for (i = 0; i < nret - 1; ++i)
-   outputs[i] = be32_to_cpu(rtas_args.rets[i + 1]);
+   outputs[i] = be32_to_cpu(args->rets[i + 1]);
+
+   ret = nret > 0 ? be32_to_cpu(args->rets[0]) : 0;
+
+   return ret;
+}
+
+int rtas_call_unlocked(struct rtas_args *args, int token, int nargs, int nret, 
int *outputs, ...)
+{
+   va_list list;
+   int ret;
 
-   ret = nret > 0 ? be32_to_cpu(rtas_args.rets[0]) : 0;
+   va_start(list, outputs);
+   ret = rtas_call_unlocked_va(args, token, nargs, nret, outputs, list);
+   va_end(list);
+
+   return ret;
+}
+
+int rtas_call(int token, int nargs, int nret, int *outputs, ...)
+{
+   va_list list;
+   int ret;
+
+   spin_lock(_lock);
+
+   va_start(list, outputs);
+   ret = rtas_call_unlocked_va(_args, token, nargs, nret, outputs, 
list);
+   va_end(list);
 
spin_unlock(_lock);
+
return ret;
 }
 
+void rtas_stop_self(void)
+{
+   struct rtas_args args;
+   uint32_t token;
+   int ret;
+
+   ret = rtas_token("stop-self", );
+   if (ret) {
+   puts("RTAS stop-self not available\n");
+   return;
+   }
+
+   ret = rtas_call_unlocked(, token, 0, 1, NULL);
+   printf("RTAS stop-self returned %d\n", ret);
+}
+
 void rtas_power_off(void)
 {
+   struct rtas_args args;
uint32_t token;
int ret;
 
@@ -130,6 +176,6 @@ void rtas_power_off(void)
return;
}
 
-   ret = rtas_call(token, 2, 1, NULL, -1, -1);
+   ret = rtas_call_unlocked(, token, 2, 1, NULL, -1, -1);
printf("RTAS power-off returned %d\n", ret);
 }
-- 
2.42.0



[kvm-unit-tests PATCH v7 19/35] powerpc: general interrupt tests

2024-03-19 Thread Nicholas Piggin
Add basic testing of various kinds of interrupts, machine check,
page fault, illegal, decrementer, trace, syscall, etc.

This has a known failure on QEMU TCG pseries machines where MSR[ME]
can be incorrectly set to 0.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/processor.h |   4 +
 lib/powerpc/asm/reg.h   |  17 ++
 lib/powerpc/setup.c |  11 +
 lib/ppc64/asm/ptrace.h  |  16 ++
 powerpc/Makefile.common |   3 +-
 powerpc/interrupts.c| 414 
 powerpc/unittests.cfg   |   3 +
 7 files changed, 467 insertions(+), 1 deletion(-)
 create mode 100644 powerpc/interrupts.c

diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index cf1b9d8ff..eed37d1f4 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -11,7 +11,11 @@ void do_handle_exception(struct pt_regs *regs);
 #endif /* __ASSEMBLY__ */
 
 extern bool cpu_has_hv;
+extern bool cpu_has_power_mce;
+extern bool cpu_has_siar;
 extern bool cpu_has_heai;
+extern bool cpu_has_prefix;
+extern bool cpu_has_sc_lev;
 
 static inline uint64_t mfspr(int nr)
 {
diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index 782e75527..d6097f48f 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -5,8 +5,15 @@
 
 #define UL(x) _AC(x, UL)
 
+#define SPR_DSISR  0x012
+#define SPR_DAR0x013
+#define SPR_DEC0x016
 #define SPR_SRR0   0x01a
 #define SPR_SRR1   0x01b
+#define   SRR1_PREFIX  UL(0x2000)
+#define SPR_FSCR   0x099
+#define   FSCR_PREFIX  UL(0x2000)
+#define SPR_HFSCR  0x0be
 #define SPR_TB 0x10c
 #define SPR_SPRG0  0x110
 #define SPR_SPRG1  0x111
@@ -22,12 +29,17 @@
 #define   PVR_VER_POWER8   UL(0x004d)
 #define   PVR_VER_POWER9   UL(0x004e)
 #define   PVR_VER_POWER10  UL(0x0080)
+#define SPR_HDEC   0x136
 #define SPR_HSRR0  0x13a
 #define SPR_HSRR1  0x13b
+#define SPR_LPCR   0x13e
+#define   LPCR_HDICE   UL(0x1)
+#define SPR_HEIR   0x153
 #define SPR_MMCR0  0x31b
 #define   MMCR0_FC UL(0x8000)
 #define   MMCR0_PMAE   UL(0x0400)
 #define   MMCR0_PMAO   UL(0x0080)
+#define SPR_SIAR   0x31c
 
 /* Machine State Register definitions: */
 #define MSR_LE_BIT 0
@@ -35,6 +47,11 @@
 #define MSR_HV_BIT 60  /* Hypervisor mode */
 #define MSR_SF_BIT 63  /* 64-bit mode */
 
+#define MSR_DR UL(0x0010)
+#define MSR_IR UL(0x0020)
+#define MSR_BE UL(0x0200)  /* Branch Trace Enable */
+#define MSR_SE UL(0x0400)  /* Single Step Enable */
+#define MSR_EE UL(0x8000)
 #define MSR_ME UL(0x1000)
 
 #endif
diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c
index 3c81aee9e..9b665f59c 100644
--- a/lib/powerpc/setup.c
+++ b/lib/powerpc/setup.c
@@ -87,7 +87,11 @@ static void cpu_set(int fdtnode, u64 regval, void *info)
 }
 
 bool cpu_has_hv;
+bool cpu_has_power_mce; /* POWER CPU machine checks */
+bool cpu_has_siar;
 bool cpu_has_heai;
+bool cpu_has_prefix;
+bool cpu_has_sc_lev; /* sc interrupt has LEV field in SRR1 */
 
 static void cpu_init(void)
 {
@@ -112,15 +116,22 @@ static void cpu_init(void)
 
switch (mfspr(SPR_PVR) & PVR_VERSION_MASK) {
case PVR_VER_POWER10:
+   cpu_has_prefix = true;
+   cpu_has_sc_lev = true;
case PVR_VER_POWER9:
case PVR_VER_POWER8E:
case PVR_VER_POWER8NVL:
case PVR_VER_POWER8:
+   cpu_has_power_mce = true;
cpu_has_heai = true;
+   cpu_has_siar = true;
break;
default:
break;
}
+
+   if (!cpu_has_hv) /* HEIR is HV register */
+   cpu_has_heai = false;
 }
 
 static void mem_init(phys_addr_t freemem_start)
diff --git a/lib/ppc64/asm/ptrace.h b/lib/ppc64/asm/ptrace.h
index 12de7499b..db263a59e 100644
--- a/lib/ppc64/asm/ptrace.h
+++ b/lib/ppc64/asm/ptrace.h
@@ -5,6 +5,9 @@
 #define STACK_FRAME_OVERHEAD112 /* size of minimum stack frame */
 
 #ifndef __ASSEMBLY__
+
+#include 
+
 struct pt_regs {
unsigned long gpr[32];
unsigned long nip;
@@ -17,6 +20,19 @@ struct pt_regs {
unsigned long _pad; /* stack must be 16-byte aligned */
 };
 
+static inline bool regs_is_prefix(volatile struct pt_regs *regs)
+{
+   return regs->msr & SRR1_PREFIX;
+}
+
+static inline void regs_advance_insn(struct pt_regs *regs)
+{
+   if (regs_is_prefix(regs))
+   regs->nip += 8;
+   else
+   regs->nip += 4;
+}
+
 #define STACK_INT_FRAME_SIZE(sizeof(struct pt_regs) + \
 STACK_FRAME_OVERHEAD + KERNEL_REDZONE_SIZE)
 
diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index 1e181da69..68165fc25 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.comm

[kvm-unit-tests PATCH v7 18/35] powerpc/sprs: Test hypervisor registers on powernv machine

2024-03-19 Thread Nicholas Piggin
This enables HV privilege registers to be tested with the powernv
machine.

Acked-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 powerpc/sprs.c | 33 +
 1 file changed, 25 insertions(+), 8 deletions(-)

diff --git a/powerpc/sprs.c b/powerpc/sprs.c
index cb1d6c980..0a82418d6 100644
--- a/powerpc/sprs.c
+++ b/powerpc/sprs.c
@@ -199,16 +199,16 @@ static const struct spr sprs_power_common[1024] = {
 [190] = { "HFSCR", 64, HV_RW, },
 [256] = { "VRSAVE",32, RW, },
 [259] = { "SPRG3", 64, RO, },
-[284] = { "TBL",   32, HV_WO, },
-[285] = { "TBU",   32, HV_WO, },
-[286] = { "TBU40", 64, HV_WO, },
+[284] = { "TBL",   32, HV_WO, }, /* Things can go a bit wonky with */
+[285] = { "TBU",   32, HV_WO, }, /* Timebase changing. Should save */
+[286] = { "TBU40", 64, HV_WO, }, /* and restore it. */
 [304] = { "HSPRG0",64, HV_RW, },
 [305] = { "HSPRG1",64, HV_RW, },
 [306] = { "HDSISR",32, HV_RW,  SPR_INT, },
 [307] = { "HDAR",  64, HV_RW,  SPR_INT, },
 [308] = { "SPURR", 64, HV_RW | OS_RO,  SPR_ASYNC, },
 [309] = { "PURR",  64, HV_RW | OS_RO,  SPR_ASYNC, },
-[313] = { "HRMOR", 64, HV_RW, },
+[313] = { "HRMOR", 64, HV_RW,  SPR_HARNESS, }, /* Harness 
can't cope with HRMOR changing */
 [314] = { "HSRR0", 64, HV_RW,  SPR_INT, },
 [315] = { "HSRR1", 64, HV_RW,  SPR_INT, },
 [318] = { "LPCR",  64, HV_RW, },
@@ -306,7 +306,7 @@ static const struct spr sprs_power9_10[1024] = {
 [921] = { "TSCR",  32, HV_RW, },
 [922] = { "TTR",   64, HV_RW, },
 [1006]= { "TRACE", 64, WO, },
-[1008]= { "HID",   64, HV_RW, },
+[1008]= { "HID",   64, HV_RW,  SPR_HARNESS, }, /* HILE would 
be unhelpful to change */
 };
 
 /* This covers POWER8 and POWER9 PMUs */
@@ -350,6 +350,22 @@ static const struct spr sprs_power10_pmu[1024] = {
 
 static struct spr sprs[1024];
 
+static bool spr_read_perms(int spr)
+{
+   if (cpu_has_hv)
+   return !!(sprs[spr].access & SPR_HV_READ);
+   else
+   return !!(sprs[spr].access & SPR_OS_READ);
+}
+
+static bool spr_write_perms(int spr)
+{
+   if (cpu_has_hv)
+   return !!(sprs[spr].access & SPR_HV_WRITE);
+   else
+   return !!(sprs[spr].access & SPR_OS_WRITE);
+}
+
 static void setup_sprs(void)
 {
int i;
@@ -461,7 +477,7 @@ static void get_sprs(uint64_t *v)
int i;
 
for (i = 0; i < 1024; i++) {
-   if (!(sprs[i].access & SPR_OS_READ))
+   if (!spr_read_perms(i))
continue;
v[i] = __mfspr(i);
}
@@ -472,8 +488,9 @@ static void set_sprs(uint64_t val)
int i;
 
for (i = 0; i < 1024; i++) {
-   if (!(sprs[i].access & SPR_OS_WRITE))
+   if (!spr_write_perms(i))
continue;
+
if (sprs[i].type & SPR_HARNESS)
continue;
__mtspr(i, val);
@@ -561,7 +578,7 @@ int main(int argc, char **argv)
for (i = 0; i < 1024; i++) {
bool pass = true;
 
-   if (!(sprs[i].access & SPR_OS_READ))
+   if (!spr_read_perms(i))
continue;
 
if (sprs[i].width == 32) {
-- 
2.42.0



[kvm-unit-tests PATCH v7 17/35] powerpc: Fix emulator illegal instruction test for powernv

2024-03-19 Thread Nicholas Piggin
Illegal instructions cause 0xe40 (HEAI) interrupts rather
than program interrupts.

Acked-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/processor.h |  1 +
 lib/powerpc/setup.c | 13 +
 powerpc/emulator.c  | 16 
 3 files changed, 30 insertions(+)

diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index 9d8061962..cf1b9d8ff 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -11,6 +11,7 @@ void do_handle_exception(struct pt_regs *regs);
 #endif /* __ASSEMBLY__ */
 
 extern bool cpu_has_hv;
+extern bool cpu_has_heai;
 
 static inline uint64_t mfspr(int nr)
 {
diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c
index 89e5157f2..3c81aee9e 100644
--- a/lib/powerpc/setup.c
+++ b/lib/powerpc/setup.c
@@ -87,6 +87,7 @@ static void cpu_set(int fdtnode, u64 regval, void *info)
 }
 
 bool cpu_has_hv;
+bool cpu_has_heai;
 
 static void cpu_init(void)
 {
@@ -108,6 +109,18 @@ static void cpu_init(void)
hcall(H_SET_MODE, 0, 4, 0, 0);
 #endif
}
+
+   switch (mfspr(SPR_PVR) & PVR_VERSION_MASK) {
+   case PVR_VER_POWER10:
+   case PVR_VER_POWER9:
+   case PVR_VER_POWER8E:
+   case PVR_VER_POWER8NVL:
+   case PVR_VER_POWER8:
+   cpu_has_heai = true;
+   break;
+   default:
+   break;
+   }
 }
 
 static void mem_init(phys_addr_t freemem_start)
diff --git a/powerpc/emulator.c b/powerpc/emulator.c
index 39dd59645..af5174944 100644
--- a/powerpc/emulator.c
+++ b/powerpc/emulator.c
@@ -31,6 +31,20 @@ static void program_check_handler(struct pt_regs *regs, void 
*opaque)
regs->nip += 4;
 }
 
+static void heai_handler(struct pt_regs *regs, void *opaque)
+{
+   int *data = opaque;
+
+   if (verbose) {
+   printf("Detected invalid instruction %#018lx: %08x\n",
+  regs->nip, *(uint32_t*)regs->nip);
+   }
+
+   *data = 8; /* Illegal instruction */
+
+   regs->nip += 4;
+}
+
 static void alignment_handler(struct pt_regs *regs, void *opaque)
 {
int *data = opaque;
@@ -363,6 +377,8 @@ int main(int argc, char **argv)
int i;
 
handle_exception(0x700, program_check_handler, (void *)_invalid);
+   if (cpu_has_heai)
+   handle_exception(0xe40, heai_handler, (void *)_invalid);
handle_exception(0x600, alignment_handler, (void *));
 
for (i = 1; i < argc; i++) {
-- 
2.42.0



[kvm-unit-tests PATCH v7 16/35] powerpc: Support powernv machine with QEMU TCG

2024-03-19 Thread Nicholas Piggin
Add support for QEMU's powernv machine. This uses standard firmware
(skiboot) rather than a minimal firmware shim.

Reviewed-by: Cédric Le Goater 
Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/processor.h | 23 +++
 lib/powerpc/asm/reg.h   |  4 ++
 lib/powerpc/hcall.c |  4 +-
 lib/powerpc/io.c| 27 -
 lib/powerpc/io.h|  6 +++
 lib/powerpc/processor.c | 37 ++
 lib/powerpc/setup.c | 14 +--
 lib/ppc64/asm/opal.h| 15 
 lib/ppc64/opal-calls.S  | 50 
 lib/ppc64/opal.c| 76 +
 powerpc/Makefile.ppc64  |  2 +
 powerpc/cstart64.S  |  7 
 powerpc/run | 42 
 powerpc/unittests.cfg   | 10 -
 14 files changed, 301 insertions(+), 16 deletions(-)
 create mode 100644 lib/ppc64/asm/opal.h
 create mode 100644 lib/ppc64/opal-calls.S
 create mode 100644 lib/ppc64/opal.c

diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index e415f9235..9d8061962 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -10,6 +10,8 @@ void handle_exception(int trap, void (*func)(struct pt_regs 
*, void *), void *);
 void do_handle_exception(struct pt_regs *regs);
 #endif /* __ASSEMBLY__ */
 
+extern bool cpu_has_hv;
+
 static inline uint64_t mfspr(int nr)
 {
uint64_t ret;
@@ -38,4 +40,25 @@ static inline void mtmsr(uint64_t msr)
asm volatile ("mtmsrd %[msr]" :: [msr] "r" (msr) : "memory");
 }
 
+/*
+ * This returns true on PowerNV / OPAL machines which run in hypervisor
+ * mode. False on pseries / PAPR machines that run in guest mode.
+ */
+static inline bool machine_is_powernv(void)
+{
+   return cpu_has_hv;
+}
+
+/*
+ * This returns true on pseries / PAPR / KVM machines which run under a
+ * hypervisor or QEMU pseries machine. False for PowerNV / OPAL.
+ */
+static inline bool machine_is_pseries(void)
+{
+   return !machine_is_powernv();
+}
+
+void enable_mcheck(void);
+void disable_mcheck(void);
+
 #endif /* _ASMPOWERPC_PROCESSOR_H_ */
diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index c80b32059..782e75527 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -30,7 +30,11 @@
 #define   MMCR0_PMAO   UL(0x0080)
 
 /* Machine State Register definitions: */
+#define MSR_LE_BIT 0
 #define MSR_EE_BIT 15  /* External Interrupts Enable */
+#define MSR_HV_BIT 60  /* Hypervisor mode */
 #define MSR_SF_BIT 63  /* 64-bit mode */
 
+#define MSR_ME UL(0x1000)
+
 #endif
diff --git a/lib/powerpc/hcall.c b/lib/powerpc/hcall.c
index b4d39ac65..45f201315 100644
--- a/lib/powerpc/hcall.c
+++ b/lib/powerpc/hcall.c
@@ -25,7 +25,7 @@ int hcall_have_broken_sc1(void)
return r3 == (unsigned long)H_PRIVILEGE;
 }
 
-void putchar(int c)
+void papr_putchar(int c)
 {
unsigned long vty = 0;  /* 0 == default */
unsigned long nr_chars = 1;
@@ -34,7 +34,7 @@ void putchar(int c)
hcall(H_PUT_TERM_CHAR, vty, nr_chars, chars);
 }
 
-int __getchar(void)
+int __papr_getchar(void)
 {
register unsigned long r3 asm("r3") = H_GET_TERM_CHAR;
register unsigned long r4 asm("r4") = 0; /* 0 == default vty */
diff --git a/lib/powerpc/io.c b/lib/powerpc/io.c
index a381688bc..ab7bb843c 100644
--- a/lib/powerpc/io.c
+++ b/lib/powerpc/io.c
@@ -9,13 +9,33 @@
 #include 
 #include 
 #include 
+#include 
 #include "io.h"
 
 static struct spinlock print_lock;
 
+void putchar(int c)
+{
+   if (machine_is_powernv())
+   opal_putchar(c);
+   else
+   papr_putchar(c);
+}
+
+int __getchar(void)
+{
+   if (machine_is_powernv())
+   return __opal_getchar();
+   else
+   return __papr_getchar();
+}
+
 void io_init(void)
 {
-   rtas_init();
+   if (machine_is_powernv())
+   assert(!opal_init());
+   else
+   rtas_init();
 }
 
 void puts(const char *s)
@@ -38,7 +58,10 @@ void exit(int code)
 // FIXME: change this print-exit/rtas-poweroff to chr_testdev_exit(),
 //maybe by plugging chr-testdev into a spapr-vty.
printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1);
-   rtas_power_off();
+   if (machine_is_powernv())
+   opal_power_off();
+   else
+   rtas_power_off();
halt(code);
__builtin_unreachable();
 }
diff --git a/lib/powerpc/io.h b/lib/powerpc/io.h
index d4f21ba15..943bf142b 100644
--- a/lib/powerpc/io.h
+++ b/lib/powerpc/io.h
@@ -8,6 +8,12 @@
 #define _POWERPC_IO_H_
 
 extern void io_init(void);
+extern int opal_init(void);
+extern void opal_power_off(void);
 extern void putchar(int c);
+extern void opal_putchar(int c);
+extern void papr_putchar(int c);
+extern int __opal_getchar

[kvm-unit-tests PATCH v7 15/35] scripts: Accommodate powerpc powernv machine differences

2024-03-19 Thread Nicholas Piggin
The QEMU powerpc powernv machine has minor differences that must be
accommodated for in output parsing:

- Summary parsing must search more lines of output for the summary
  line, to accommodate OPAL message on shutdown.
- Premature failure testing must tolerate case differences in kernel
  load error message.

Acked-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 powerpc/unittests.cfg | 1 +
 scripts/runtime.bash  | 6 --
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index 432c81d58..4929e71a1 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -4,6 +4,7 @@
 # powerpc specifics:
 #
 # file = .elf # powerpc uses .elf files
+# machine = pseries|powernv
 ##
 
 #
diff --git a/scripts/runtime.bash b/scripts/runtime.bash
index a66940ead..e4ad1962f 100644
--- a/scripts/runtime.bash
+++ b/scripts/runtime.bash
@@ -9,7 +9,7 @@ FAIL() { echo -ne "\e[31mFAIL\e[0m"; }
 extract_summary()
 {
 local cr=$'\r'
-tail -3 | grep '^SUMMARY: ' | sed 's/^SUMMARY: /(/;s/'"$cr"'\{0,1\}$/)/'
+tail -5 | grep '^SUMMARY: ' | sed 's/^SUMMARY: /(/;s/'"$cr"'\{0,1\}$/)/'
 }
 
 # We assume that QEMU is going to work if it tried to load the kernel
@@ -18,7 +18,9 @@ premature_failure()
 local log="$(eval "$(get_cmdline _NO_FILE_4Uhere_)" 2>&1)"
 
 echo "$log" | grep "_NO_FILE_4Uhere_" |
-grep -q -e "could not \(load\|open\) kernel" -e "error loading" -e 
"failed to load" &&
+grep -q -e "[Cc]ould not \(load\|open\) kernel" \
+-e "error loading" \
+-e "failed to load" &&
 return 1
 
 RUNTIME_log_stderr <<< "$log"
-- 
2.42.0



[kvm-unit-tests PATCH v7 14/35] scripts: allow machine option to be specified in unittests.cfg

2024-03-19 Thread Nicholas Piggin
This allows different machines with different requirements to be
supported by run_tests.sh, similarly to how different accelerators
are handled.

Acked-by: Thomas Huth 
Acked-by: Andrew Jones 
Signed-off-by: Nicholas Piggin 
---
 docs/unittests.txt   |  6 ++
 scripts/common.bash  |  8 ++--
 scripts/runtime.bash | 16 
 3 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/docs/unittests.txt b/docs/unittests.txt
index 53e02077c..5b184723c 100644
--- a/docs/unittests.txt
+++ b/docs/unittests.txt
@@ -42,6 +42,12 @@ For / directories that support multiple architectures, 
this restricts
 the test to the specified arch. By default, the test will run on any
 architecture.
 
+machine
+---
+For those architectures that support multiple machine types, this allows
+machine-specific tests to be created. By default, the test will run on
+any machine type.
+
 smp
 ---
 smp = 
diff --git a/scripts/common.bash b/scripts/common.bash
index b9413d683..ee1dd8659 100644
--- a/scripts/common.bash
+++ b/scripts/common.bash
@@ -10,6 +10,7 @@ function for_each_unittest()
local opts
local groups
local arch
+   local machine
local check
local accel
local timeout
@@ -21,7 +22,7 @@ function for_each_unittest()
if [[ "$line" =~ ^\[(.*)\]$ ]]; then
rematch=${BASH_REMATCH[1]}
if [ -n "${testname}" ]; then
-   $(arch_cmd) "$cmd" "$testname" "$groups" "$smp" 
"$kernel" "$opts" "$arch" "$check" "$accel" "$timeout"
+   $(arch_cmd) "$cmd" "$testname" "$groups" "$smp" 
"$kernel" "$opts" "$arch" "$machine" "$check" "$accel" "$timeout"
fi
testname=$rematch
smp=1
@@ -29,6 +30,7 @@ function for_each_unittest()
opts=""
groups=""
arch=""
+   machine=""
check=""
accel=""
timeout=""
@@ -58,6 +60,8 @@ function for_each_unittest()
groups=${BASH_REMATCH[1]}
elif [[ $line =~ ^arch\ *=\ *(.*)$ ]]; then
arch=${BASH_REMATCH[1]}
+   elif [[ $line =~ ^machine\ *=\ *(.*)$ ]]; then
+   machine=${BASH_REMATCH[1]}
elif [[ $line =~ ^check\ *=\ *(.*)$ ]]; then
check=${BASH_REMATCH[1]}
elif [[ $line =~ ^accel\ *=\ *(.*)$ ]]; then
@@ -67,7 +71,7 @@ function for_each_unittest()
fi
done
if [ -n "${testname}" ]; then
-   $(arch_cmd) "$cmd" "$testname" "$groups" "$smp" "$kernel" 
"$opts" "$arch" "$check" "$accel" "$timeout"
+   $(arch_cmd) "$cmd" "$testname" "$groups" "$smp" "$kernel" 
"$opts" "$arch" "$machine" "$check" "$accel" "$timeout"
fi
exec {fd}<&-
 }
diff --git a/scripts/runtime.bash b/scripts/runtime.bash
index 255e756f2..a66940ead 100644
--- a/scripts/runtime.bash
+++ b/scripts/runtime.bash
@@ -30,7 +30,7 @@ premature_failure()
 get_cmdline()
 {
 local kernel=$1
-echo "TESTNAME=$testname TIMEOUT=$timeout ACCEL=$accel $RUNTIME_arch_run 
$kernel -smp $smp $opts"
+echo "TESTNAME=$testname TIMEOUT=$timeout MACHINE=$machine ACCEL=$accel 
$RUNTIME_arch_run $kernel -smp $smp $opts"
 }
 
 skip_nodefault()
@@ -78,9 +78,10 @@ function run()
 local kernel="$4"
 local opts="$5"
 local arch="$6"
-local check="${CHECK:-$7}"
-local accel="$8"
-local timeout="${9:-$TIMEOUT}" # unittests.cfg overrides the default
+local machine="$7"
+local check="${CHECK:-$8}"
+local accel="$9"
+local timeout="${10:-$TIMEOUT}" # unittests.cfg overrides the default
 
 if [ "${CONFIG_EFI}" == "y" ]; then
 kernel=${kernel/%.flat/.efi}
@@ -114,6 +115,13 @@ function run()
 return 2
 fi
 
+if [ -n "$machine" ] && [ -n "$MACHINE" ] && [ "$machine" != "$MACHINE" ]; 
then
+print_result "SKIP" $testname "" "$machine only"
+return 2
+elif [ -n "$MACHINE" ]; then
+machine="$MACHINE"
+fi
+
 if [ -n "$accel" ] && [ -n "$ACCEL" ] && [ "$accel" != "$ACCEL" ]; then
 print_result "SKIP" $testname "" "$accel only, but ACCEL=$ACCEL"
 return 2
-- 
2.42.0



[kvm-unit-tests PATCH v7 13/35] doc: start documentation directory with unittests.cfg doc

2024-03-19 Thread Nicholas Piggin
Consolidate unittests.cfg documentation in one place.

Suggested-by: Andrew Jones 
Signed-off-by: Nicholas Piggin 
---
 arm/unittests.cfg | 26 ++---
 docs/unittests.txt| 89 +++
 powerpc/unittests.cfg | 25 ++--
 riscv/unittests.cfg   | 26 ++---
 s390x/unittests.cfg   | 18 ++---
 x86/unittests.cfg | 26 ++---
 6 files changed, 107 insertions(+), 103 deletions(-)
 create mode 100644 docs/unittests.txt

diff --git a/arm/unittests.cfg b/arm/unittests.cfg
index fe601cbb1..54cedea28 100644
--- a/arm/unittests.cfg
+++ b/arm/unittests.cfg
@@ -1,28 +1,10 @@
 ##
 # unittest configuration
 #
-# [unittest_name]
-# file = .flat   # Name of the flat file to be used.
-# smp  =  # Number of processors the VM will use
-#  # during this test. Use $MAX_SMP to use
-#  # the maximum the host supports. Defaults
-#  # to one.
-# extra_params = -append# Additional parameters used.
-# arch = arm|arm64 # Select one if the test case is
-#  # specific to only one.
-# groups =   ... # Used to identify test cases
-#  # with run_tests -g ...
-#  # Specify group_name=nodefault
-#  # to have test not run by
-#  # default
-# accel = kvm|tcg  # Optionally specify if test must run with
-#  # kvm or tcg. If not specified, then kvm will
-#  # be used when available.
-# timeout =  # Optionally specify a timeout.
-# check = = # check a file for a particular value before running
-## a test. The check line can contain multiple files
-## to check separated by a space but each check
-## parameter needs to be of the form =
+# arm specifics:
+#
+# file = .flat# arm uses .flat files
+# arch = arm|arm64
 ##
 
 #
diff --git a/docs/unittests.txt b/docs/unittests.txt
new file mode 100644
index 0..53e02077c
--- /dev/null
+++ b/docs/unittests.txt
@@ -0,0 +1,89 @@
+unittests
+*
+
+run_tests.sh is driven by the /unittests.cfg file. That file defines
+test cases by specifying an executable (target image) under the /
+directory, and how to run it. This way, for example, a single file can
+provide multiple test cases by being run with different host configurations
+and/or different parameters passed to it.
+
+Detailed output from run_tests.sh unit tests are stored in files under
+the logs/ directory.
+
+unittests.cfg format
+
+
+# is the comment symbol, all following contents of the line is ignored.
+
+Each unit test is defined as with a [unit-test-name] line, followed by
+a set of parameters that control how the test case is run. The name is
+arbitrary and appears in the status reporting output.
+
+Parameters appear on their own lines under the test name, and have a
+param = value format.
+
+Available parameters
+
+Note! Some parameters like smp and extra_params modify how a test is run,
+while others like arch and accel restrict the configurations in which the
+test is run.
+
+file
+
+file = 
+
+This parameter is mandatory and specifies which binary under the /
+directory to run. Typically this is .flat or .elf, depending
+on the arch. The directory name is not included, only the file name.
+
+arch
+
+For / directories that support multiple architectures, this restricts
+the test to the specified arch. By default, the test will run on any
+architecture.
+
+smp
+---
+smp = 
+
+Optional, the number of processors created in the machine to run the test.
+Defaults to 1. $MAX_SMP can be used to specify the maximum supported.
+
+extra_params
+
+These are extra parameters supplied to the QEMU process. -append '...' can
+be used to pass arguments into the test case argv. Multiple parameters can
+be added, for example:
+
+extra_params = -m 256 -append 'smp=2'
+
+groups
+--
+groups =   ...
+
+Used to group the test cases for the `run_tests.sh -g ...` run group
+option. Adding a test to the nodefault group will cause it to not be
+run by default.
+
+accel
+-
+accel = kvm|tcg
+
+This restricts the test to the specified accelerator. By default, the
+test will run on either accelerator. (Note, the accelerator can be
+specified with ACCEL= environment variable, and defaults to KVM if
+available).
+
+timeout
+---
+timeout = 
+
+Optional timeout in seconds, after which the test will be killed and fail.
+
+check
+-
+check = =<
+
+Check a f

[kvm-unit-tests PATCH v7 12/35] powerpc/sprs: Avoid taking PMU interrupts caused by register fuzzing

2024-03-19 Thread Nicholas Piggin
Storing certain values in MMCR0 can cause PMU interrupts when msleep
enables MSR[EE], and this crashes the test. Freeze the PMU counters
and clear any PMU exception before calling msleep.

Reviewed-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/reg.h |  4 
 powerpc/sprs.c| 17 +++--
 2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index 1f991288e..c80b32059 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -24,6 +24,10 @@
 #define   PVR_VER_POWER10  UL(0x0080)
 #define SPR_HSRR0  0x13a
 #define SPR_HSRR1  0x13b
+#define SPR_MMCR0  0x31b
+#define   MMCR0_FC UL(0x8000)
+#define   MMCR0_PMAE   UL(0x0400)
+#define   MMCR0_PMAO   UL(0x0080)
 
 /* Machine State Register definitions: */
 #define MSR_EE_BIT 15  /* External Interrupts Enable */
diff --git a/powerpc/sprs.c b/powerpc/sprs.c
index 44edd0d7b..cb1d6c980 100644
--- a/powerpc/sprs.c
+++ b/powerpc/sprs.c
@@ -476,12 +476,7 @@ static void set_sprs(uint64_t val)
continue;
if (sprs[i].type & SPR_HARNESS)
continue;
-   if (!strcmp(sprs[i].name, "MMCR0")) {
-   /* XXX: could use a comment or better abstraction! */
-   __mtspr(i, (val & 0xfbab3fffULL) | 0xfa0b2070);
-   } else {
-   __mtspr(i, val);
-   }
+   __mtspr(i, val);
}
 }
 
@@ -538,6 +533,16 @@ int main(int argc, char **argv)
if (sprs[895].name)
before[895] = mfspr(895);
} else {
+   /*
+* msleep will enable MSR[EE] and take a decrementer
+* interrupt. Must account for changed registers and
+* prevent taking unhandled interrupts.
+*/
+   /* Prevent PMU interrupt */
+   mtspr(SPR_MMCR0, (mfspr(SPR_MMCR0) | MMCR0_FC) &
+   ~(MMCR0_PMAO | MMCR0_PMAE));
+   before[SPR_MMCR0] = mfspr(SPR_MMCR0);
+   before[779] = mfspr(SPR_MMCR0);
msleep(2000);
 
/* Reload regs changed by dec interrupt */
-- 
2.42.0



[kvm-unit-tests PATCH v7 11/35] powerpc/sprs: Specify SPRs with data rather than code

2024-03-19 Thread Nicholas Piggin
A significant rework that builds an array of 'struct spr', where each
element describes an SPR. This makes various metadata about the SPR
like name and access type easier to carry and use.

Hypervisor privileged registers are described despite not being used
at the moment for completeness, but also the code might one day be
reused for a hypervisor-privileged test.

Acked-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/reg.h |   2 +
 powerpc/sprs.c| 647 +-
 2 files changed, 457 insertions(+), 192 deletions(-)

diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index 6810c1d82..1f991288e 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -5,6 +5,8 @@
 
 #define UL(x) _AC(x, UL)
 
+#define SPR_SRR0   0x01a
+#define SPR_SRR1   0x01b
 #define SPR_TB 0x10c
 #define SPR_SPRG0  0x110
 #define SPR_SPRG1  0x111
diff --git a/powerpc/sprs.c b/powerpc/sprs.c
index a19d80a1a..44edd0d7b 100644
--- a/powerpc/sprs.c
+++ b/powerpc/sprs.c
@@ -30,229 +30,458 @@
 #include 
 #include 
 
-uint64_t before[1024], after[1024];
-
-/* Common SPRs for all PowerPC CPUs */
-static void set_sprs_common(uint64_t val)
+/* "Indirect" mfspr/mtspr which accept a non-constant spr number */
+static uint64_t __mfspr(unsigned spr)
 {
-   mtspr(9, val);  /* CTR */
-   // mtspr(273, val); /* SPRG1 */  /* Used by our exception handler */
-   mtspr(274, val);/* SPRG2 */
-   mtspr(275, val);/* SPRG3 */
+   uint64_t tmp;
+   uint64_t ret;
+
+   asm volatile(
+"  bcl 20, 31, 1f  \n"
+"1:mflr%0  \n"
+"  addi%0, %0, (2f-1b) \n"
+"  add %0, %0, %2  \n"
+"  mtctr   %0  \n"
+"  bctr\n"
+"2:\n"
+".LSPR=0   \n"
+".rept 1024\n"
+"  mfspr   %1, .LSPR   \n"
+"  b   3f  \n"
+"  .LSPR=.LSPR+1   \n"
+".endr \n"
+"3:\n"
+   : "="(tmp),
+ "=r"(ret)
+   : "r"(spr*8) /* 8 bytes per 'mfspr ; b' block */
+   : "lr", "ctr");
+
+   return ret;
 }
 
-/* SPRs from PowerPC Operating Environment Architecture, Book III, Vers. 2.01 
*/
-static void set_sprs_book3s_201(uint64_t val)
+static void __mtspr(unsigned spr, uint64_t val)
 {
-   mtspr(18, val); /* DSISR */
-   mtspr(19, val); /* DAR */
-   mtspr(152, val);/* CTRL */
-   mtspr(256, val);/* VRSAVE */
-   mtspr(786, val);/* MMCRA */
-   mtspr(795, val);/* MMCR0 */
-   mtspr(798, val);/* MMCR1 */
+   uint64_t tmp;
+
+   asm volatile(
+"  bcl 20, 31, 1f  \n"
+"1:mflr%0  \n"
+"  addi%0, %0, (2f-1b) \n"
+"  add %0, %0, %2  \n"
+"  mtctr   %0  \n"
+"  bctr\n"
+"2:\n"
+".LSPR=0   \n"
+".rept 1024\n"
+"  mtspr   .LSPR, %1   \n"
+"  b   3f  \n"
+"  .LSPR=.LSPR+1   \n"
+".endr \n"
+"3:\n"
+   : "="(tmp)
+   : "r"(val),
+ "r"(spr*8) /* 8 bytes per 'mfspr ; b' block */
+   : "lr", "ctr", "xer");
 }
 
+static uint64_t before[1024], after[1024];
+
+#define SPR_PR_READ0x0001
+#define SPR_PR_WRITE   0x0002
+#define SPR_OS_READ0x0010
+#define SPR_OS_WRITE   0x0020
+#define SPR_HV_READ0x0100
+#define SPR_HV_WRITE   0x0200
+
+#define RW 0x333
+#define RO 0x111
+#define WO 0x222
+#define OS_RW  0x330
+#define OS_RO  0x110
+#define OS_WO  0x220
+#define HV_RW  0x300
+#define HV_RO  0x100
+#define HV_WO  0x200
+
+#define SPR_ASYNC  0x1000  /* May be updated asynchronously */
+#define SPR_INT0x2000  /* May be updated by synchronous 
interrupt */
+#define SPR_HARNESS0x4000  /* Test harness uses the register */
+
+struct spr {
+   const char  *name;
+   uint8_t width;
+   uint16_taccess;
+   uint16_ttype;
+};
+
+/* SPRs common denominator back to PowerPC Operating Envir

[kvm-unit-tests PATCH v7 10/35] powerpc: interrupt stack backtracing

2024-03-19 Thread Nicholas Piggin
Add support for backtracing across interrupt stacks, and add
interrupt frame backtrace for unhandled interrupts.

This requires a back-chain created from initial interrupt stack
frame to the r1 value of the interrupted context. A label is
added at the return location of the exception handler call, so
the unwinder can recognize the initial interrupt frame.

The additional cstart entry-frame is no longer required because
the unwinder now looks for frame == 0 as well as address == 0.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/processor.c |  4 +++-
 lib/ppc64/asm/stack.h   |  3 +++
 lib/ppc64/stack.c   | 53 +
 powerpc/Makefile.ppc64  |  1 +
 powerpc/cstart64.S  | 15 +++-
 5 files changed, 63 insertions(+), 13 deletions(-)
 create mode 100644 lib/ppc64/stack.c

diff --git a/lib/powerpc/processor.c b/lib/powerpc/processor.c
index ad0d95666..114584024 100644
--- a/lib/powerpc/processor.c
+++ b/lib/powerpc/processor.c
@@ -51,7 +51,9 @@ void do_handle_exception(struct pt_regs *regs)
return;
}
 
-   printf("unhandled cpu exception %#lx at NIA:0x%016lx MSR:0x%016lx\n", 
regs->trap, regs->nip, regs->msr);
+   printf("Unhandled cpu exception %#lx at NIA:0x%016lx MSR:0x%016lx\n",
+   regs->trap, regs->nip, regs->msr);
+   dump_frame_stack((void *)regs->nip, (void *)regs->gpr[1]);
abort();
 }
 
diff --git a/lib/ppc64/asm/stack.h b/lib/ppc64/asm/stack.h
index 9734bbb8f..94fd1021c 100644
--- a/lib/ppc64/asm/stack.h
+++ b/lib/ppc64/asm/stack.h
@@ -5,4 +5,7 @@
 #error Do not directly include . Just use .
 #endif
 
+#define HAVE_ARCH_BACKTRACE
+#define HAVE_ARCH_BACKTRACE_FRAME
+
 #endif
diff --git a/lib/ppc64/stack.c b/lib/ppc64/stack.c
new file mode 100644
index 0..e6f259de7
--- /dev/null
+++ b/lib/ppc64/stack.c
@@ -0,0 +1,53 @@
+#include 
+#include 
+#include 
+
+extern char do_handle_exception_return[];
+
+int arch_backtrace_frame(const void *frame, const void **return_addrs,
+int max_depth, bool current_frame)
+{
+   static int walking;
+   int depth = 0;
+   const unsigned long *bp = (unsigned long *)frame;
+   void *return_addr;
+
+   asm volatile("" ::: "lr"); /* Force it to save LR */
+
+   if (walking) {
+   printf("RECURSIVE STACK WALK!!!\n");
+   return 0;
+   }
+   walking = 1;
+
+   if (current_frame)
+   bp = __builtin_frame_address(0);
+
+   bp = (unsigned long *)bp[0];
+   return_addr = (void *)bp[2];
+
+   for (depth = 0; bp && depth < max_depth; depth++) {
+   return_addrs[depth] = return_addr;
+   if (return_addrs[depth] == 0)
+   break;
+   if (return_addrs[depth] == do_handle_exception_return) {
+   struct pt_regs *regs;
+
+   regs = (void *)bp + STACK_FRAME_OVERHEAD;
+   bp = (unsigned long *)bp[0];
+   /* Represent interrupt frame with vector number */
+   return_addr = (void *)regs->trap;
+   if (depth + 1 < max_depth) {
+   depth++;
+   return_addrs[depth] = return_addr;
+   return_addr = (void *)regs->nip;
+   }
+   } else {
+   bp = (unsigned long *)bp[0];
+   return_addr = (void *)bp[2];
+   }
+   }
+
+   walking = 0;
+   return depth;
+}
diff --git a/powerpc/Makefile.ppc64 b/powerpc/Makefile.ppc64
index b0ed2b104..eb682c226 100644
--- a/powerpc/Makefile.ppc64
+++ b/powerpc/Makefile.ppc64
@@ -17,6 +17,7 @@ cstart.o = $(TEST_DIR)/cstart64.o
 reloc.o  = $(TEST_DIR)/reloc64.o
 
 OBJDIRS += lib/ppc64
+cflatobjs += lib/ppc64/stack.o
 
 # ppc64 specific tests
 tests = $(TEST_DIR)/spapr_vpa.elf
diff --git a/powerpc/cstart64.S b/powerpc/cstart64.S
index 80baabe8f..07d297f61 100644
--- a/powerpc/cstart64.S
+++ b/powerpc/cstart64.S
@@ -51,16 +51,6 @@ start:
std r0,0(r1)
std r0,16(r1)
 
-   /*
-* Create entry frame of 64-bytes, same as the initial frame. A callee
-* may use the caller frame to store LR, and backtrace() termination
-* looks for return address == NULL, so the initial stack frame can't
-* be used to call C or else it could overwrite the zeroed LR save slot
-* and break backtrace termination.  This frame would be unnecessary if
-* backtrace looked for a zeroed frame address.
-*/
-   stdur1,-64(r1)
-
/* save DTB pointer */
std r3, 56(r1)
 
@@ -195,6 +185,7 @@ call_handler:
.endr
mfsprg1 r0
std r0,GPR1(r1)
+   std r0,0(r1) /* Backchain from interrupt stack to regular s

[kvm-unit-tests PATCH v7 09/35] powerpc: Fix stack backtrace termination

2024-03-19 Thread Nicholas Piggin
The backtrace handler terminates when it sees a NULL caller address,
but the powerpc stack setup does not keep such a NULL caller frame
at the start of the stack.

This happens to work on pseries because the memory at 0 is mapped and
it contains 0 at the location of the return address pointer if it
were a stack frame. But this is fragile, and does not work with powernv
where address 0 contains firmware instructions.

Use the existing dummy frame on stack as the NULL caller, and create a
new frame on stack for the entry code.

Signed-off-by: Nicholas Piggin 
---
 powerpc/cstart64.S | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/powerpc/cstart64.S b/powerpc/cstart64.S
index e18ae9a22..80baabe8f 100644
--- a/powerpc/cstart64.S
+++ b/powerpc/cstart64.S
@@ -46,6 +46,21 @@ start:
add r1, r1, r31
add r2, r2, r31
 
+   /* Zero backpointers in initial stack frame so backtrace() stops */
+   li  r0,0
+   std r0,0(r1)
+   std r0,16(r1)
+
+   /*
+* Create entry frame of 64-bytes, same as the initial frame. A callee
+* may use the caller frame to store LR, and backtrace() termination
+* looks for return address == NULL, so the initial stack frame can't
+* be used to call C or else it could overwrite the zeroed LR save slot
+* and break backtrace termination.  This frame would be unnecessary if
+* backtrace looked for a zeroed frame address.
+*/
+   stdur1,-64(r1)
+
/* save DTB pointer */
std r3, 56(r1)
 
-- 
2.42.0



[kvm-unit-tests PATCH v7 08/35] powerpc: Fix KVM caps on POWER9 hosts

2024-03-19 Thread Nicholas Piggin
KVM does not like to run on POWER9 hosts without cap-ccf-assist=off.

Reviewed-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 powerpc/run | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/powerpc/run b/powerpc/run
index e469f1eb3..5cdb94194 100755
--- a/powerpc/run
+++ b/powerpc/run
@@ -24,6 +24,8 @@ M+=",accel=$ACCEL$ACCEL_PROPS"
 
 if [[ "$ACCEL" == "tcg" ]] ; then
M+=",cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken,cap-ccf-assist=off"
+elif [[ "$ACCEL" == "kvm" ]] ; then
+   M+=",cap-ccf-assist=off"
 fi
 
 command="$qemu -nodefaults $M -bios $FIRMWARE"
-- 
2.42.0



[kvm-unit-tests PATCH v7 07/35] common: add memory dirtying vs migration test

2024-03-19 Thread Nicholas Piggin
This test stores to a bunch of pages and verifies previous stores,
while being continually migrated. Default runtime is 5 seconds.

Add this test to ppc64 and s390x builds. This can fail due to a QEMU
TCG physical memory dirty bitmap bug, so it is not enabled in unittests
for TCG yet.

The selftest-migration test time is reduced significantly because
this test

Signed-off-by: Nicholas Piggin 
---
 common/memory-verify.c  | 67 +
 common/selftest-migration.c |  8 ++---
 powerpc/Makefile.common |  1 +
 powerpc/memory-verify.c |  1 +
 powerpc/unittests.cfg   |  7 
 s390x/Makefile  |  1 +
 s390x/memory-verify.c   |  1 +
 s390x/unittests.cfg |  6 
 8 files changed, 88 insertions(+), 4 deletions(-)
 create mode 100644 common/memory-verify.c
 create mode 12 powerpc/memory-verify.c
 create mode 12 s390x/memory-verify.c

diff --git a/common/memory-verify.c b/common/memory-verify.c
new file mode 100644
index 0..e78fb4338
--- /dev/null
+++ b/common/memory-verify.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Simple memory verification test, used to exercise dirty memory migration.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define NR_PAGES 32
+
+static unsigned time_sec = 5;
+
+static void do_getopts(int argc, char **argv)
+{
+   int i;
+
+   for (i = 0; i < argc; ++i) {
+   if (strcmp(argv[i], "-t") == 0) {
+   i++;
+   if (i == argc)
+   break;
+   time_sec = atol(argv[i]);
+   }
+   }
+
+   printf("running for %d secs\n", time_sec);
+}
+
+int main(int argc, char **argv)
+{
+   void *mem = malloc(NR_PAGES*PAGE_SIZE);
+   bool success = true;
+   uint64_t ms;
+   long i;
+
+   do_getopts(argc, argv);
+
+   report_prefix_push("memory");
+
+   memset(mem, 0, NR_PAGES*PAGE_SIZE);
+
+   migrate_begin_continuous();
+   ms = get_clock_ms();
+   i = 0;
+   do {
+   int j;
+
+   for (j = 0; j < NR_PAGES*PAGE_SIZE; j += PAGE_SIZE) {
+   if (*(volatile long *)(mem + j) != i) {
+   success = false;
+   goto out;
+   }
+   *(volatile long *)(mem + j) = i + 1;
+   }
+   i++;
+   } while (get_clock_ms() - ms < time_sec * 1000);
+out:
+   migrate_end_continuous();
+
+   report(success, "memory verification stress test");
+
+   report_prefix_pop();
+
+   return report_summary();
+}
diff --git a/common/selftest-migration.c b/common/selftest-migration.c
index 9a9b61835..3693148aa 100644
--- a/common/selftest-migration.c
+++ b/common/selftest-migration.c
@@ -11,7 +11,7 @@
 #include 
 #include 
 
-#define NR_MIGRATIONS 15
+#define NR_MIGRATIONS 5
 
 int main(int argc, char **argv)
 {
@@ -28,11 +28,11 @@ int main(int argc, char **argv)
report(true, "cooperative migration");
 
migrate_begin_continuous();
-   mdelay(2000);
-   migrate_end_continuous();
mdelay(1000);
+   migrate_end_continuous();
+   mdelay(500);
migrate_begin_continuous();
-   mdelay(2000);
+   mdelay(1000);
migrate_end_continuous();
report(true, "continuous migration");
}
diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index da4a7bbb8..1e181da69 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -7,6 +7,7 @@
 tests-common = \
$(TEST_DIR)/selftest.elf \
$(TEST_DIR)/selftest-migration.elf \
+   $(TEST_DIR)/memory-verify.elf \
$(TEST_DIR)/spapr_hcall.elf \
$(TEST_DIR)/rtas.elf \
$(TEST_DIR)/emulator.elf \
diff --git a/powerpc/memory-verify.c b/powerpc/memory-verify.c
new file mode 12
index 0..5985c730f
--- /dev/null
+++ b/powerpc/memory-verify.c
@@ -0,0 +1 @@
+../common/memory-verify.c
\ No newline at end of file
diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index cae4949e8..e65217c18 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -49,6 +49,13 @@ machine = pseries
 groups = selftest migration
 extra_params = -append "skip"
 
+# This fails due to a QEMU TCG bug so KVM-only until QEMU is fixed upstream
+[migration-memory]
+file = memory-verify.elf
+accel = kvm
+machine = pseries
+groups = migration
+
 [spapr_hcall]
 file = spapr_hcall.elf
 
diff --git a/s390x/Makefile b/s390x/Makefile
index 344d46d68..ddc0969f3 100644
--- a/s390x/Makefile
+++ b/s390x/Makefile
@@ -1,5 +1,6 @@
 tests = $(TEST_DIR)/selftest.elf
 tests += $(TEST_DIR)/selftest-migration.elf
+tests += $(TEST_DIR)/memory-verify.elf
 tests += $(TEST_DIR)/i

[kvm-unit-tests PATCH v7 06/35] gitlab-ci: Run migration selftest on s390x and powerpc

2024-03-19 Thread Nicholas Piggin
The migration harness is complicated and easy to break so CI will
be helpful.

Signed-off-by: Nicholas Piggin 
---
 .gitlab-ci.yml  | 18 +++---
 s390x/unittests.cfg |  8 
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index ff34b1f50..bd34da04f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -92,26 +92,28 @@ build-arm:
 build-ppc64be:
  extends: .outoftree_template
  script:
- - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu
+ - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu nmap-ncat
  - mkdir build
  - cd build
  - ../configure --arch=ppc64 --endian=big --cross-prefix=powerpc64-linux-gnu-
  - make -j2
  - ACCEL=tcg ./run_tests.sh
- selftest-setup spapr_hcall rtas-get-time-of-day rtas-get-time-of-day-base
- rtas-set-time-of-day emulator
+ selftest-setup selftest-migration selftest-migration-skip spapr_hcall
+ rtas-get-time-of-day rtas-get-time-of-day-base rtas-set-time-of-day
+ emulator
  | tee results.txt
  - if grep -q FAIL results.txt ; then exit 1 ; fi
 
 build-ppc64le:
  extends: .intree_template
  script:
- - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu
+ - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu nmap-ncat
  - ./configure --arch=ppc64 --endian=little --cross-prefix=powerpc64-linux-gnu-
  - make -j2
  - ACCEL=tcg ./run_tests.sh
- selftest-setup spapr_hcall rtas-get-time-of-day rtas-get-time-of-day-base
- rtas-set-time-of-day emulator
+ selftest-setup selftest-migration selftest-migration-skip spapr_hcall
+ rtas-get-time-of-day rtas-get-time-of-day-base rtas-set-time-of-day
+ emulator
  | tee results.txt
  - if grep -q FAIL results.txt ; then exit 1 ; fi
 
@@ -135,7 +137,7 @@ build-riscv64:
 build-s390x:
  extends: .outoftree_template
  script:
- - dnf install -y qemu-system-s390x gcc-s390x-linux-gnu
+ - dnf install -y qemu-system-s390x gcc-s390x-linux-gnu nmap-ncat
  - mkdir build
  - cd build
  - ../configure --arch=s390x --cross-prefix=s390x-linux-gnu-
@@ -161,6 +163,8 @@ build-s390x:
   sclp-1g
   sclp-3g
   selftest-setup
+  selftest-migration-kvm
+  selftest-migration-skip
   sieve
   smp
   stsi
diff --git a/s390x/unittests.cfg b/s390x/unittests.cfg
index 49e3e4608..b79b99416 100644
--- a/s390x/unittests.cfg
+++ b/s390x/unittests.cfg
@@ -31,6 +31,14 @@ groups = selftest migration
 # https://lore.kernel.org/qemu-devel/20240219061731.232570-1-npig...@gmail.com/
 accel = kvm
 
+[selftest-migration-kvm]
+file = selftest-migration.elf
+groups = nodefault
+accel = kvm
+# This is a special test for gitlab-ci that can must not use TCG until the
+# TCG migration fix has made its way into CI environment's QEMU.
+# https://lore.kernel.org/qemu-devel/20240219061731.232570-1-npig...@gmail.com/
+
 [selftest-migration-skip]
 file = selftest-migration.elf
 groups = selftest migration
-- 
2.42.0



[kvm-unit-tests PATCH v7 04/35] (arm|s390): Use migrate_skip in test cases

2024-03-19 Thread Nicholas Piggin
Have tests use the new migrate_skip command in skip paths, rather than
calling migrate_once to prevent harness reporting an error.

s390x/migration.c adds a new command that looks like it was missing
previously.

Reviewed-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 arm/gic.c  | 21 -
 s390x/migration-cmm.c  |  8 
 s390x/migration-skey.c |  4 +++-
 s390x/migration.c  |  1 +
 4 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/arm/gic.c b/arm/gic.c
index c950b0d15..bbf828f17 100644
--- a/arm/gic.c
+++ b/arm/gic.c
@@ -782,13 +782,15 @@ static void test_its_migration(void)
struct its_device *dev2, *dev7;
cpumask_t mask;
 
-   if (its_setup1())
+   if (its_setup1()) {
+   migrate_skip();
return;
+   }
 
dev2 = its_get_device(2);
dev7 = its_get_device(7);
 
-   migrate_once();
+   migrate();
 
stats_reset();
cpumask_clear();
@@ -819,8 +821,10 @@ static void test_migrate_unmapped_collection(void)
int pe0 = 0;
u8 config;
 
-   if (its_setup1())
+   if (its_setup1()) {
+   migrate_skip();
return;
+   }
 
if (!errata(ERRATA_UNMAPPED_COLLECTIONS)) {
report_skip("Skipping test, as this test hangs without the fix. 
"
@@ -836,7 +840,7 @@ static void test_migrate_unmapped_collection(void)
its_send_mapti(dev2, 8192, 0, col);
gicv3_lpi_set_config(8192, LPI_PROP_DEFAULT);
 
-   migrate_once();
+   migrate();
 
/* on the destination, map the collection */
its_send_mapc(col, true);
@@ -875,8 +879,10 @@ static void test_its_pending_migration(void)
void *ptr;
int i;
 
-   if (its_prerequisites(4))
+   if (its_prerequisites(4)) {
+   migrate_skip();
return;
+   }
 
dev = its_create_device(2 /* dev id */, 8 /* nb_ites */);
its_send_mapd(dev, true);
@@ -923,7 +929,7 @@ static void test_its_pending_migration(void)
gicv3_lpi_rdist_enable(pe0);
gicv3_lpi_rdist_enable(pe1);
 
-   migrate_once();
+   migrate();
 
/* let's wait for the 256 LPIs to be handled */
mdelay(1000);
@@ -970,17 +976,14 @@ int main(int argc, char **argv)
} else if (!strcmp(argv[1], "its-migration")) {
report_prefix_push(argv[1]);
test_its_migration();
-   migrate_once();
report_prefix_pop();
} else if (!strcmp(argv[1], "its-pending-migration")) {
report_prefix_push(argv[1]);
test_its_pending_migration();
-   migrate_once();
report_prefix_pop();
} else if (!strcmp(argv[1], "its-migrate-unmapped-collection")) {
report_prefix_push(argv[1]);
test_migrate_unmapped_collection();
-   migrate_once();
report_prefix_pop();
} else if (strcmp(argv[1], "its-introspection") == 0) {
report_prefix_push(argv[1]);
diff --git a/s390x/migration-cmm.c b/s390x/migration-cmm.c
index 43673f18e..b4043a80e 100644
--- a/s390x/migration-cmm.c
+++ b/s390x/migration-cmm.c
@@ -55,12 +55,12 @@ int main(void)
 {
report_prefix_push("migration-cmm");
 
-   if (!check_essa_available())
+   if (!check_essa_available()) {
report_skip("ESSA is not available");
-   else
+   migrate_skip();
+   } else {
test_migration();
-
-   migrate_once();
+   }
 
report_prefix_pop();
return report_summary();
diff --git a/s390x/migration-skey.c b/s390x/migration-skey.c
index 8d6d8ecfe..1a196ae1e 100644
--- a/s390x/migration-skey.c
+++ b/s390x/migration-skey.c
@@ -169,6 +169,7 @@ static void test_skey_migration_parallel(void)
 
if (smp_query_num_cpus() == 1) {
report_skip("need at least 2 cpus for this test");
+   migrate_skip();
goto error;
}
 
@@ -233,6 +234,7 @@ int main(int argc, char **argv)
 
if (test_facility(169)) {
report_skip("storage key removal facility is active");
+   migrate_skip();
goto error;
}
 
@@ -247,11 +249,11 @@ int main(int argc, char **argv)
break;
default:
print_usage();
+   migrate_skip();
break;
}
 
 error:
-   migrate_once();
report_prefix_pop();
return report_summary();
 }
diff --git a/s390x/migration.c b/s390x/migration.c
index 269e272de..115afb731 100644
--- a/s390x/migration.c
+++ b/s390x/migration.c
@@ -164,6 +164,7 @@ int main(void)
 
if (smp_query_num_cpus() == 1) {
report_skip("need at least 2 cpus for this test");
+   migrate_skip();
goto done;
}
 
-- 
2.42.0



[kvm-unit-tests PATCH v7 05/35] arch-run: Add a "continuous" migration option for tests

2024-03-19 Thread Nicholas Piggin
The cooperative migration protocol is very good to control precise
pre and post conditions for a migration event. However in some cases
its intrusiveness to the test program, can mask problems and make
analysis more difficult.

For example to stress test migration vs concurrent complicated
memory access, including TLB refill, ram dirtying, etc., then the
tight spin at getchar() and resumption of the workload after
migration is unhelpful.

This adds a continuous migration mode that directs the harness to
perform migrations continually. This is added to the migration
selftests, which also sees cooperative migration iterations reduced
to avoid increasing test time too much.

Signed-off-by: Nicholas Piggin 
---
 common/selftest-migration.c | 16 +--
 lib/migrate.c   | 18 
 lib/migrate.h   |  3 ++
 scripts/arch-run.bash   | 55 -
 4 files changed, 82 insertions(+), 10 deletions(-)

diff --git a/common/selftest-migration.c b/common/selftest-migration.c
index 0afd8581c..9a9b61835 100644
--- a/common/selftest-migration.c
+++ b/common/selftest-migration.c
@@ -9,12 +9,13 @@
  */
 #include 
 #include 
+#include 
 
-#define NR_MIGRATIONS 30
+#define NR_MIGRATIONS 15
 
 int main(int argc, char **argv)
 {
-   report_prefix_push("migration");
+   report_prefix_push("migration harness");
 
if (argc > 1 && !strcmp(argv[1], "skip")) {
migrate_skip();
@@ -24,7 +25,16 @@ int main(int argc, char **argv)
 
for (i = 0; i < NR_MIGRATIONS; i++)
migrate_quiet();
-   report(true, "simple harness stress");
+   report(true, "cooperative migration");
+
+   migrate_begin_continuous();
+   mdelay(2000);
+   migrate_end_continuous();
+   mdelay(1000);
+   migrate_begin_continuous();
+   mdelay(2000);
+   migrate_end_continuous();
+   report(true, "continuous migration");
}
 
report_prefix_pop();
diff --git a/lib/migrate.c b/lib/migrate.c
index 1d22196b7..770f76d5c 100644
--- a/lib/migrate.c
+++ b/lib/migrate.c
@@ -60,3 +60,21 @@ void migrate_skip(void)
puts("Skipped VM migration (quiet)\n");
(void)getchar();
 }
+
+void migrate_begin_continuous(void)
+{
+   puts("Begin continuous migration\n");
+   (void)getchar();
+}
+
+void migrate_end_continuous(void)
+{
+   /*
+* Migration can split this output between source and dest QEMU
+* output files, print twice and match once to always cope with
+* a split.
+*/
+   puts("End continuous migration\n");
+   puts("End continuous migration (quiet)\n");
+   (void)getchar();
+}
diff --git a/lib/migrate.h b/lib/migrate.h
index db6e0c501..35b6703a2 100644
--- a/lib/migrate.h
+++ b/lib/migrate.h
@@ -11,3 +11,6 @@ void migrate_quiet(void);
 void migrate_once(void);
 
 void migrate_skip(void);
+
+void migrate_begin_continuous(void);
+void migrate_end_continuous(void);
diff --git a/scripts/arch-run.bash b/scripts/arch-run.bash
index 4a1aab48d..1901a929f 100644
--- a/scripts/arch-run.bash
+++ b/scripts/arch-run.bash
@@ -125,15 +125,17 @@ qmp_events ()
 filter_quiet_msgs ()
 {
grep -v "Now migrate the VM (quiet)" |
+   grep -v "Begin continuous migration (quiet)" |
+   grep -v "End continuous migration (quiet)" |
grep -v "Skipped VM migration (quiet)"
 }
 
 seen_migrate_msg ()
 {
if [ $skip_migration -eq 1 ]; then
-   grep -q -e "Now migrate the VM" < $1
+   grep -q -e "Now migrate the VM" -e "Begin continuous migration" 
< $1
else
-   grep -q -e "Now migrate the VM" -e "Skipped VM migration" < $1
+   grep -q -e "Now migrate the VM" -e "Begin continuous migration" 
-e "Skipped VM migration" < $1
fi
 }
 
@@ -161,6 +163,7 @@ run_migration ()
src_qmpout=/dev/null
dst_qmpout=/dev/null
skip_migration=0
+   continuous_migration=0
 
mkfifo ${src_outfifo}
mkfifo ${dst_outfifo}
@@ -186,9 +189,12 @@ run_migration ()
do_migration || return $?
 
while ps -p ${live_pid} > /dev/null ; do
-   # Wait for test exit or further migration messages.
-   if ! seen_migrate_msg ${src_out} ;  then
+   if [ ${continuous_migration} -eq 1 ] ; then
+   do_migration || return $?
+   elif ! seen_migrate_msg ${src_out} ;  then
sleep 0.1
+   elif grep -q "Begin continuous migration" < ${src_out} ; then
+   do_migration || return $?
elif 

[kvm-unit-tests PATCH v7 03/35] migration: Add a migrate_skip command

2024-03-19 Thread Nicholas Piggin
Tests that are run with MIGRATION=yes but skip due to some requirement
not being met will show as a failure due to the harness requirement to
see one successful migration. The workaround for this is to migrate in
test's skip path. Add a new command that just tells the harness to not
expect a migration.

Reviewed-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 common/selftest-migration.c | 14 -
 lib/migrate.c   | 19 -
 lib/migrate.h   |  2 ++
 powerpc/unittests.cfg   |  6 ++
 s390x/unittests.cfg |  5 +
 scripts/arch-run.bash   | 41 +
 6 files changed, 73 insertions(+), 14 deletions(-)

diff --git a/common/selftest-migration.c b/common/selftest-migration.c
index 54b5d6b2d..0afd8581c 100644
--- a/common/selftest-migration.c
+++ b/common/selftest-migration.c
@@ -14,14 +14,18 @@
 
 int main(int argc, char **argv)
 {
-   int i = 0;
-
report_prefix_push("migration");
 
-   for (i = 0; i < NR_MIGRATIONS; i++)
-   migrate_quiet();
+   if (argc > 1 && !strcmp(argv[1], "skip")) {
+   migrate_skip();
+   report(true, "migration skipping");
+   } else {
+   int i;
 
-   report(true, "simple harness stress test");
+   for (i = 0; i < NR_MIGRATIONS; i++)
+   migrate_quiet();
+   report(true, "simple harness stress");
+   }
 
report_prefix_pop();
 
diff --git a/lib/migrate.c b/lib/migrate.c
index 92d1d957d..1d22196b7 100644
--- a/lib/migrate.c
+++ b/lib/migrate.c
@@ -39,7 +39,24 @@ void migrate_once(void)
 
if (migrated)
return;
-
migrated = true;
+
migrate();
 }
+
+/*
+ * When the test has been started in migration mode, but the test case is
+ * skipped and no migration point is reached, this can be used to tell the
+ * harness not to mark it as a failure to migrate.
+ */
+void migrate_skip(void)
+{
+   static bool did_migrate_skip;
+
+   if (did_migrate_skip)
+   return;
+   did_migrate_skip = true;
+
+   puts("Skipped VM migration (quiet)\n");
+   (void)getchar();
+}
diff --git a/lib/migrate.h b/lib/migrate.h
index 95b9102b0..db6e0c501 100644
--- a/lib/migrate.h
+++ b/lib/migrate.h
@@ -9,3 +9,5 @@
 void migrate(void);
 void migrate_quiet(void);
 void migrate_once(void);
+
+void migrate_skip(void);
diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index 1559bee98..cae4949e8 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -43,6 +43,12 @@ groups = selftest migration
 # https://lore.kernel.org/qemu-devel/20240219061731.232570-1-npig...@gmail.com/
 accel = kvm
 
+[selftest-migration-skip]
+file = selftest-migration.elf
+machine = pseries
+groups = selftest migration
+extra_params = -append "skip"
+
 [spapr_hcall]
 file = spapr_hcall.elf
 
diff --git a/s390x/unittests.cfg b/s390x/unittests.cfg
index dac9e4db1..49e3e4608 100644
--- a/s390x/unittests.cfg
+++ b/s390x/unittests.cfg
@@ -31,6 +31,11 @@ groups = selftest migration
 # https://lore.kernel.org/qemu-devel/20240219061731.232570-1-npig...@gmail.com/
 accel = kvm
 
+[selftest-migration-skip]
+file = selftest-migration.elf
+groups = selftest migration
+extra_params = -append "skip"
+
 [intercept]
 file = intercept.elf
 
diff --git a/scripts/arch-run.bash b/scripts/arch-run.bash
index 39419d4e2..4a1aab48d 100644
--- a/scripts/arch-run.bash
+++ b/scripts/arch-run.bash
@@ -124,12 +124,17 @@ qmp_events ()
 
 filter_quiet_msgs ()
 {
-   grep -v "Now migrate the VM (quiet)"
+   grep -v "Now migrate the VM (quiet)" |
+   grep -v "Skipped VM migration (quiet)"
 }
 
 seen_migrate_msg ()
 {
-   grep -q -e "Now migrate the VM" < $1
+   if [ $skip_migration -eq 1 ]; then
+   grep -q -e "Now migrate the VM" < $1
+   else
+   grep -q -e "Now migrate the VM" -e "Skipped VM migration" < $1
+   fi
 }
 
 run_migration ()
@@ -142,7 +147,7 @@ run_migration ()
migcmdline=$@
 
trap 'trap - TERM ; kill 0 ; exit 2' INT TERM
-   trap 'rm -f ${src_out} ${dst_out} ${src_outfifo} ${dst_outfifo} 
${dst_incoming} ${src_qmp} ${dst_qmp} ${dst_infifo}' RETURN EXIT
+   trap 'rm -f ${src_out} ${dst_out} ${src_outfifo} ${dst_outfifo} 
${dst_incoming} ${src_qmp} ${dst_qmp} ${src_infifo} ${dst_infifo}' RETURN EXIT
 
dst_incoming=$(mktemp -u -t mig-helper-socket-incoming.XX)
src_out=$(mktemp -t mig-helper-stdout1.XX)
@@ -151,21 +156,26 @@ run_migration ()
dst_outfifo=$(mktemp -u -t mig-helper-fifo-stdout2.XX)
src_qmp=$(mktemp -u -t mig-helper-qmp1.XX)
dst_qmp=$(mktemp -u -t mig-helper-qmp2.XX)
-   dst_infifo=$(mktemp -u -t mig-helper-fif

[kvm-unit-tests PATCH v7 02/35] arch-run: Keep infifo open

2024-03-19 Thread Nicholas Piggin
The infifo fifo that is used to send characters to QEMU console is
only able to receive one character before the cat process exits.
Supporting interactions between test and harness involving multiple
characters requires the fifo to remain open.

The infifo is removed by the exit handler like other files and fifos
so it does not have to be removed explicitly.

With this we can let the cat out of the subshell, simplifying the
input pipeline.

Reviewed-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 scripts/arch-run.bash | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/scripts/arch-run.bash b/scripts/arch-run.bash
index e34d784c0..39419d4e2 100644
--- a/scripts/arch-run.bash
+++ b/scripts/arch-run.bash
@@ -158,6 +158,11 @@ run_migration ()
mkfifo ${src_outfifo}
mkfifo ${dst_outfifo}
 
+   # Holding both ends of the input fifo open prevents opens from
+   # blocking and readers getting EOF when a writer closes it.
+   mkfifo ${dst_infifo}
+   exec {dst_infifo_fd}<>${dst_infifo}
+
eval "$migcmdline" \
-chardev socket,id=mon,path=${src_qmp},server=on,wait=off \
-mon chardev=mon,mode=control > ${src_outfifo} &
@@ -191,14 +196,10 @@ run_migration ()
 
 do_migration ()
 {
-   # We have to use cat to open the named FIFO, because named FIFO's,
-   # unlike pipes, will block on open() until the other end is also
-   # opened, and that totally breaks QEMU...
-   mkfifo ${dst_infifo}
eval "$migcmdline" \
-chardev socket,id=mon,path=${dst_qmp},server=on,wait=off \
-mon chardev=mon,mode=control -incoming unix:${dst_incoming} \
-   < <(cat ${dst_infifo}) > ${dst_outfifo} &
+   < ${dst_infifo} > ${dst_outfifo} &
incoming_pid=$!
cat ${dst_outfifo} | tee ${dst_out} | filter_quiet_msgs &
 
@@ -245,7 +246,6 @@ do_migration ()
 
# keypress to dst so getchar completes and test continues
echo > ${dst_infifo}
-   rm ${dst_infifo}
 
# Wait for the incoming socket being removed, ready for next destination
while [ -S ${dst_incoming} ] ; do sleep 0.1 ; done
-- 
2.42.0



[kvm-unit-tests PATCH v7 01/35] arch-run: Add functions to help handle migration directives from test

2024-03-19 Thread Nicholas Piggin
The migration harness will be expanded to deal with more commands
from the test, moving these checks into functions helps keep things
managable.

Signed-off-by: Nicholas Piggin 
---
 scripts/arch-run.bash | 20 +++-
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/scripts/arch-run.bash b/scripts/arch-run.bash
index 413f3eda8..e34d784c0 100644
--- a/scripts/arch-run.bash
+++ b/scripts/arch-run.bash
@@ -122,6 +122,16 @@ qmp_events ()
jq -c 'select(has("event"))'
 }
 
+filter_quiet_msgs ()
+{
+   grep -v "Now migrate the VM (quiet)"
+}
+
+seen_migrate_msg ()
+{
+   grep -q -e "Now migrate the VM" < $1
+}
+
 run_migration ()
 {
if ! command -v ncat >/dev/null 2>&1; then
@@ -152,7 +162,7 @@ run_migration ()
-chardev socket,id=mon,path=${src_qmp},server=on,wait=off \
-mon chardev=mon,mode=control > ${src_outfifo} &
live_pid=$!
-   cat ${src_outfifo} | tee ${src_out} | grep -v "Now migrate the VM 
(quiet)" &
+   cat ${src_outfifo} | tee ${src_out} | filter_quiet_msgs &
 
# Start the first destination QEMU machine in advance of the test
# reaching the migration point, since we expect at least one migration.
@@ -162,7 +172,7 @@ run_migration ()
 
while ps -p ${live_pid} > /dev/null ; do
# Wait for test exit or further migration messages.
-   if ! grep -q -i "Now migrate the VM" < ${src_out} ; then
+   if ! seen_migrate_msg ${src_out} ;  then
sleep 0.1
else
do_migration || return $?
@@ -190,11 +200,11 @@ do_migration ()
-mon chardev=mon,mode=control -incoming unix:${dst_incoming} \
< <(cat ${dst_infifo}) > ${dst_outfifo} &
incoming_pid=$!
-   cat ${dst_outfifo} | tee ${dst_out} | grep -v "Now migrate the VM 
(quiet)" &
+   cat ${dst_outfifo} | tee ${dst_out} | filter_quiet_msgs &
 
# The test must prompt the user to migrate, so wait for the
-   # "Now migrate VM" console message.
-   while ! grep -q -i "Now migrate the VM" < ${src_out} ; do
+   # "Now migrate VM" or similar console message.
+   while ! seen_migrate_msg ${src_out} ; do
if ! ps -p ${live_pid} > /dev/null ; then
echo "ERROR: Test exit before migration point." >&2
echo > ${dst_infifo}
-- 
2.42.0



[kvm-unit-tests PATCH v7 00/35] migration, powerpc improvements

2024-03-19 Thread Nicholas Piggin
Tree here
https://gitlab.com/npiggin/kvm-unit-tests/-/tree/powerpc?ref_type=heads

Sorry I lost the v6 tag on the previous series. Since then,
I merged the series with the migration ones since they touch
the same things.

Addressed almost all comments since the last post, I think just
one case where a "elif kvm" branch was kept in the powerpc/run
script because I find it convenient to add KVM specific things
there if needed.

Main changes since v6 (thanks to reviewers):
- Rebased on new stack backtrace patches, and cherry picks
  from v6.
- Move new files to SPDX headers.
- Improve comments on and simplify interrupt stack frame and
  backtracing.
- Add a docs/ directory with unittests.cfg documentation
  deduplicated from arch code and moved there, and document
  new machine= option. Not exactly 1:1 move of comments, so
  suggestions and improvements welcome there.
- Made new shell script a bit more consistent with style. I
  do have shellcheck working and some patches started, btw.,
  will look at submitting that after this series.
- Fix up a few unittests and gitlab CI to avoid failing on the
  QEMU TCG migration bug. Reduced runtime of some of the new
  migration tests.

Thanks,
Nick

Nicholas Piggin (35):
  arch-run: Add functions to help handle migration directives from test
  arch-run: Keep infifo open
  migration: Add a migrate_skip command
  (arm|s390): Use migrate_skip in test cases
  arch-run: Add a "continuous" migration option for tests
  gitlab-ci: Run migration selftest on s390x and powerpc
  common: add memory dirtying vs migration test
  powerpc: Fix KVM caps on POWER9 hosts
  powerpc: Fix stack backtrace termination
  powerpc: interrupt stack backtracing
  powerpc/sprs: Specify SPRs with data rather than code
  powerpc/sprs: Avoid taking PMU interrupts caused by register fuzzing
  doc: start documentation directory with unittests.cfg doc
  scripts: allow machine option to be specified in unittests.cfg
  scripts: Accommodate powerpc powernv machine differences
  powerpc: Support powernv machine with QEMU TCG
  powerpc: Fix emulator illegal instruction test for powernv
  powerpc/sprs: Test hypervisor registers on powernv machine
  powerpc: general interrupt tests
  powerpc: Add rtas stop-self support
  powerpc: Remove broken SMP exception stack setup
  powerpc: add SMP and IPI support
  powerpc: Permit ACCEL=tcg,thread=single
  powerpc: Avoid using larx/stcx. in spinlocks when only one CPU is
running
  powerpc: Add atomics tests
  powerpc: Add timebase tests
  powerpc: Add MMU support
  common/sieve: Use vmalloc.h for setup_mmu definition
  common/sieve: Support machines without MMU
  powerpc: Add sieve.c common test
  powerpc: add usermode support
  powerpc: add pmu tests
  configure: Make arch_libdir a first-class entity
  powerpc: Remove remnants of ppc64 directory and build structure
  powerpc: gitlab CI update

 .gitlab-ci.yml   |  26 +-
 MAINTAINERS  |   1 -
 Makefile |   2 +-
 arm/gic.c|  21 +-
 arm/unittests.cfg|  26 +-
 common/memory-verify.c   |  67 +++
 common/selftest-migration.c  |  26 +-
 common/sieve.c   |  15 +-
 configure|  58 +-
 docs/unittests.txt   |  95 
 lib/libcflat.h   |   2 -
 lib/migrate.c|  37 +-
 lib/migrate.h|   5 +
 lib/{ppc64 => powerpc}/asm-offsets.c |   7 +
 lib/{ppc64 => powerpc}/asm/asm-offsets.h |   0
 lib/powerpc/asm/atomic.h |   6 +
 lib/powerpc/asm/barrier.h|  12 +
 lib/{ppc64 => powerpc}/asm/bitops.h  |   4 +-
 lib/powerpc/asm/hcall.h  |   6 +
 lib/{ppc64 => powerpc}/asm/io.h  |   4 +-
 lib/powerpc/asm/mmu.h|  10 +
 lib/powerpc/asm/opal.h   |  22 +
 lib/powerpc/asm/page.h   |  65 +++
 lib/powerpc/asm/pgtable-hwdef.h  |  66 +++
 lib/powerpc/asm/pgtable.h| 125 +
 lib/powerpc/asm/processor.h  |  63 +++
 lib/{ppc64 => powerpc}/asm/ptrace.h  |  22 +-
 lib/powerpc/asm/reg.h|  42 ++
 lib/powerpc/asm/rtas.h   |   2 +
 lib/powerpc/asm/setup.h  |   3 +-
 lib/powerpc/asm/smp.h|  50 +-
 lib/powerpc/asm/spinlock.h   |  11 +
 lib/powerpc/asm/stack.h  |   3 +
 lib/{ppc64 => powerpc}/asm/vpa.h |   0
 lib/powerpc/hcall.c  |   4 +-
 lib/powerpc/io.c |  41 +-
 lib/powerpc/io.h |   6 +
 lib/powerpc/mmu.c| 274 ++
 lib/powerpc/opal-calls.S |  50 ++
 lib/powerpc/opal.c   |  76 +++
 lib/powerpc/processor.c  

Re: [kvm-unit-tests PATCH v2 04/13] treewide: lib/stack: Make base_address arch specific

2024-03-11 Thread Nicholas Piggin
On Wed Mar 6, 2024 at 3:09 AM AEST, Andrew Jones wrote:
> Calculating the offset of an address is image specific, which is
> architecture specific. Until now, all architectures and architecture
> configurations which select CONFIG_RELOC were able to subtract
> _etext, but the EFI configuration of riscv cannot (it must subtract
> ImageBase). Make this function weak, such that an architecture may
> override it when necessary, to accommodate the image layout. Then,
> immediately supply the riscv override.
>

Thanks for making these changes. Looks good. For the generic parts,

Reviewed-by: Nicholas Piggin 

Thanks,
Nick

> Signed-off-by: Andrew Jones 
> ---
>  lib/riscv/stack.c | 18 ++
>  lib/stack.c   |  8 
>  lib/stack.h   |  2 ++
>  3 files changed, 24 insertions(+), 4 deletions(-)
>
> diff --git a/lib/riscv/stack.c b/lib/riscv/stack.c
> index d865594b9671..2cd7f012738b 100644
> --- a/lib/riscv/stack.c
> +++ b/lib/riscv/stack.c
> @@ -2,6 +2,24 @@
>  #include 
>  #include 
>  
> +#ifdef CONFIG_RELOC
> +extern char ImageBase, _text, _etext;
> +
> +bool arch_base_address(const void *rebased_addr, unsigned long *addr)
> +{
> + unsigned long ra = (unsigned long)rebased_addr;
> + unsigned long base = (unsigned long)
> + unsigned long start = (unsigned long)&_text;
> + unsigned long end = (unsigned long)&_etext;
> +
> + if (ra < start || ra >= end)
> + return false;
> +
> + *addr = ra - base;
> + return true;
> +}
> +#endif
> +
>  int arch_backtrace_frame(const void *frame, const void **return_addrs,
>int max_depth, bool current_frame)
>  {
> diff --git a/lib/stack.c b/lib/stack.c
> index dd6bfa8dac6e..086fec544a81 100644
> --- a/lib/stack.c
> +++ b/lib/stack.c
> @@ -14,7 +14,7 @@
>  #ifdef CONFIG_RELOC
>  extern char _text, _etext;
>  
> -static bool base_address(const void *rebased_addr, unsigned long *addr)
> +bool __attribute__((weak)) arch_base_address(const void *rebased_addr, 
> unsigned long *addr)
>  {
>   unsigned long ra = (unsigned long)rebased_addr;
>   unsigned long start = (unsigned long)&_text;
> @@ -27,7 +27,7 @@ static bool base_address(const void *rebased_addr, unsigned 
> long *addr)
>   return true;
>  }
>  #else
> -static bool base_address(const void *rebased_addr, unsigned long *addr)
> +bool __attribute__((weak)) arch_base_address(const void *rebased_addr, 
> unsigned long *addr)
>  {
>   *addr = (unsigned long)rebased_addr;
>   return true;
> @@ -45,13 +45,13 @@ static void print_stack(const void **return_addrs, int 
> depth,
>   /* @addr indicates a non-return address, as expected by the stack
>* pretty printer script. */
>   if (depth > 0 && !top_is_return_address) {
> - if (base_address(return_addrs[0], ))
> + if (arch_base_address(return_addrs[0], ))
>   printf(" @%lx", addr);
>   i++;
>   }
>  
>   for (; i < depth; i++) {
> - if (base_address(return_addrs[i], ))
> + if (arch_base_address(return_addrs[i], ))
>   printf(" %lx", addr);
>   }
>   printf("\n");
> diff --git a/lib/stack.h b/lib/stack.h
> index 6edc84344b51..df076d94bf8f 100644
> --- a/lib/stack.h
> +++ b/lib/stack.h
> @@ -34,4 +34,6 @@ static inline int backtrace_frame(const void *frame, const 
> void **return_addrs,
>  }
>  #endif
>  
> +bool __attribute__((weak)) arch_base_address(const void *rebased_addr, 
> unsigned long *addr);
> +
>  #endif



Re: [kvm-unit-tests PATCH 03/32] powerpc: Fix stack backtrace termination

2024-03-04 Thread Nicholas Piggin
On Tue Feb 27, 2024 at 6:50 PM AEST, Thomas Huth wrote:
> On 26/02/2024 11.11, Nicholas Piggin wrote:
> > The backtrace handler terminates when it sees a NULL caller address,
> > but the powerpc stack setup does not keep such a NULL caller frame
> > at the start of the stack.
> > 
> > This happens to work on pseries because the memory at 0 is mapped and
> > it contains 0 at the location of the return address pointer if it
> > were a stack frame. But this is fragile, and does not work with powernv
> > where address 0 contains firmware instructions.
> > 
> > Use the existing dummy frame on stack as the NULL caller, and create a
> > new frame on stack for the entry code.
> > 
> > Signed-off-by: Nicholas Piggin 
> > ---
> >   powerpc/cstart64.S | 12 ++--
> >   1 file changed, 10 insertions(+), 2 deletions(-)
>
> Thanks for tackling this! ... however, not doing powerpc work since years 
> anymore, I have some ignorant questions below...
>
> > diff --git a/powerpc/cstart64.S b/powerpc/cstart64.S
> > index e18ae9a22..14ab0c6c8 100644
> > --- a/powerpc/cstart64.S
> > +++ b/powerpc/cstart64.S
> > @@ -46,8 +46,16 @@ start:
> > add r1, r1, r31
> > add r2, r2, r31
> >   
> > +   /* Zero backpointers in initial stack frame so backtrace() stops */
> > +   li  r0,0
> > +   std r0,0(r1)
>
> 0(r1) is the back chain pointer ...
>
> > +   std r0,16(r1)
>
> ... but what is 16(r1) ? I suppose that should be the "LR save word" ? But 
> isn't that at 8(r1) instead?? (not sure whether I'm looking at the right ELF 
> abi spec right now...)
>
> Anyway, a comment in the source would be helpful here.
>
> > +
> > +   /* Create entry frame */
> > +   stdur1,-INT_FRAME_SIZE(r1)
>
> Since we already create an initial frame via stackptr from powerpc/flat.lds, 
> do we really need to create this additional one here? Or does the one from 
> flat.lds have to be completely empty, i.e. also no DTB pointer in it?

Oh you already figured the above questions. For this, we do have
one frame allocated already statically yes. But if we don't create
another one here then our callee will store LR into it, but the
unwinder only exits when it sees a NULL return address so it would
keep trying to walk.

We could make it terminate on NULL back chain pointer, but that's
a bit more change that also touches non-powerpc code in the generic
unwinder, and still needs some changes here. Maybe we should do
that after this series though. I'll include a comment to look at
redoing it later.

>
> > /* save DTB pointer */
> > -   std r3, 56(r1)
> > +   SAVE_GPR(3,r1)
>
> Isn't SAVE_GPR rather meant for the interrupt frame, not for the normal C 
> calling convention frames?
>
> Sorry for asking dumb questions ... I still have a hard time understanding 
> the changes here... :-/

Ah, that was me being lazy and using an interrupt frame for the new
frame.

Thanks,
Nick

>
> > /*
> >  * Call relocate. relocate is C code, but careful to not use
> > @@ -101,7 +109,7 @@ start:
> > stw r4, 0(r3)
> >   
> > /* complete setup */
> > -1: ld  r3, 56(r1)
> > +1: REST_GPR(3, r1)
> > bl  setup
> >   
> > /* run the test */
>
>   Thomas



Re: [kvm-unit-tests PATCH 5/7] arch-run: Add a "continuous" migration option for tests

2024-03-04 Thread Nicholas Piggin
On Mon Mar 4, 2024 at 7:19 PM AEST, Andrew Jones wrote:
> On Mon, Mar 04, 2024 at 07:17:35AM +0100, Thomas Huth wrote:
> > On 26/02/2024 10.38, Nicholas Piggin wrote:
> > > The cooperative migration protocol is very good to control precise
> > > pre and post conditions for a migration event. However in some cases
> > > its intrusiveness to the test program, can mask problems and make
> > > analysis more difficult.
> > > 
> > > For example to stress test migration vs concurrent complicated
> > > memory access, including TLB refill, ram dirtying, etc., then the
> > > tight spin at getchar() and resumption of the workload after
> > > migration is unhelpful.
> > > 
> > > This adds a continuous migration mode that directs the harness to
> > > perform migrations continually. This is added to the migration
> > > selftests, which also sees cooperative migration iterations reduced
> > > to avoid increasing test time too much.
> > > 
> > > Signed-off-by: Nicholas Piggin 
> > > ---
> > >   common/selftest-migration.c | 16 +--
> > >   lib/migrate.c   | 18 
> > >   lib/migrate.h   |  3 ++
> > >   scripts/arch-run.bash   | 55 -
> > >   4 files changed, 82 insertions(+), 10 deletions(-)
> > > 
> > > diff --git a/common/selftest-migration.c b/common/selftest-migration.c
> > > index 0afd8581c..9a9b61835 100644
> > > --- a/common/selftest-migration.c
> > > +++ b/common/selftest-migration.c
> > > @@ -9,12 +9,13 @@
> > >*/
> > >   #include 
> > >   #include 
> > > +#include 
> > > -#define NR_MIGRATIONS 30
> > > +#define NR_MIGRATIONS 15
> > >   int main(int argc, char **argv)
> > >   {
> > > - report_prefix_push("migration");
> > > + report_prefix_push("migration harness");
> > >   if (argc > 1 && !strcmp(argv[1], "skip")) {
> > >   migrate_skip();
> > > @@ -24,7 +25,16 @@ int main(int argc, char **argv)
> > >   for (i = 0; i < NR_MIGRATIONS; i++)
> > >   migrate_quiet();
> > > - report(true, "simple harness stress");
> > > + report(true, "cooperative migration");
> > > +
> > > + migrate_begin_continuous();
> > > + mdelay(2000);
> > > + migrate_end_continuous();
> > > + mdelay(1000);
> > > + migrate_begin_continuous();
> > > + mdelay(2000);
> > > + migrate_end_continuous();
> > > + report(true, "continuous migration");
> > >   }
> > >   report_prefix_pop();
> > > diff --git a/lib/migrate.c b/lib/migrate.c
> > > index 1d22196b7..770f76d5c 100644
> > > --- a/lib/migrate.c
> > > +++ b/lib/migrate.c
> > > @@ -60,3 +60,21 @@ void migrate_skip(void)
> > >   puts("Skipped VM migration (quiet)\n");
> > >   (void)getchar();
> > >   }
> > > +
> > > +void migrate_begin_continuous(void)
> > > +{
> > > + puts("Begin continuous migration\n");
> > > + (void)getchar();
> > > +}
> > > +
> > > +void migrate_end_continuous(void)
> > > +{
> > > + /*
> > > +  * Migration can split this output between source and dest QEMU
> > > +  * output files, print twice and match once to always cope with
> > > +  * a split.
> > > +  */
> > > + puts("End continuous migration\n");
> > > + puts("End continuous migration (quiet)\n");
> > > + (void)getchar();
> > > +}
> > > diff --git a/lib/migrate.h b/lib/migrate.h
> > > index db6e0c501..35b6703a2 100644
> > > --- a/lib/migrate.h
> > > +++ b/lib/migrate.h
> > > @@ -11,3 +11,6 @@ void migrate_quiet(void);
> > >   void migrate_once(void);
> > >   void migrate_skip(void);
> > > +
> > > +void migrate_begin_continuous(void);
> > > +void migrate_end_continuous(void);
> > > diff --git a/scripts/arch-run.bash b/scripts/arch-run.bash
> > > index d0f6f098f..5c7e72036 100644
> > > --- a/scripts/arch-run.bash
> > > +++ b/scripts/arch-run.bash
> > > @@ -125,15 +125,17 @@ qmp_events ()
> > >   filter_quiet_msgs ()
> > >   {
> > >   grep -v &

Re: [kvm-unit-tests PATCH 7/7] common: add memory dirtying vs migration test

2024-03-04 Thread Nicholas Piggin
On Mon Mar 4, 2024 at 4:22 PM AEST, Thomas Huth wrote:
> On 26/02/2024 10.38, Nicholas Piggin wrote:
> > This test stores to a bunch of pages and verifies previous stores,
> > while being continually migrated. This can fail due to a QEMU TCG
> > physical memory dirty bitmap bug.
>
> Good idea, but could we then please drop "continuous" test from 
> selftest-migration.c again? ... having two common tests to exercise the 
> continuous migration that take quite a bunch of seconds to finish sounds 
> like a waste of time in the long run to me.

Yeah if you like. I could shorten them up a bit. I did want to have
the selftests for just purely testing the harness with as little
"test" code as possible.

>
> > Signed-off-by: Nicholas Piggin 
> > ---
> >   common/memory-verify.c  | 48 +
> >   powerpc/Makefile.common |  1 +
> >   powerpc/memory-verify.c |  1 +
> >   powerpc/unittests.cfg   |  7 ++
> >   s390x/Makefile  |  1 +
> >   s390x/memory-verify.c   |  1 +
> >   s390x/unittests.cfg |  6 ++
> >   7 files changed, 65 insertions(+)
> >   create mode 100644 common/memory-verify.c
> >   create mode 12 powerpc/memory-verify.c
> >   create mode 12 s390x/memory-verify.c
> > 
> > diff --git a/common/memory-verify.c b/common/memory-verify.c
> > new file mode 100644
> > index 0..7c4ec087b
> > --- /dev/null
> > +++ b/common/memory-verify.c
> > @@ -0,0 +1,48 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Simple memory verification test, used to exercise dirty memory 
> > migration.
> > + *
> > + */
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +
> > +#define NR_PAGES 32
> > +
> > +int main(int argc, char **argv)
> > +{
> > +   void *mem = malloc(NR_PAGES*PAGE_SIZE);
> > +   bool success = true;
> > +   uint64_t ms;
> > +   long i;
> > +
> > +   report_prefix_push("memory");
> > +
> > +   memset(mem, 0, NR_PAGES*PAGE_SIZE);
> > +
> > +   migrate_begin_continuous();
> > +   ms = get_clock_ms();
> > +   i = 0;
> > +   do {
> > +   int j;
> > +
> > +   for (j = 0; j < NR_PAGES*PAGE_SIZE; j += PAGE_SIZE) {
> > +   if (*(volatile long *)(mem + j) != i) {
> > +   success = false;
> > +   goto out;
> > +   }
> > +   *(volatile long *)(mem + j) = i + 1;
> > +   }
> > +   i++;
> > +   } while (get_clock_ms() - ms < 5000);
>
> Maybe add a parameter so that the user can use different values for the 
> runtime than always doing 5 seconds?

Sure.

Thanks,
Nick


Re: [kvm-unit-tests PATCH 5/7] arch-run: Add a "continuous" migration option for tests

2024-03-04 Thread Nicholas Piggin
On Mon Mar 4, 2024 at 4:17 PM AEST, Thomas Huth wrote:
> On 26/02/2024 10.38, Nicholas Piggin wrote:
> > The cooperative migration protocol is very good to control precise
> > pre and post conditions for a migration event. However in some cases
> > its intrusiveness to the test program, can mask problems and make
> > analysis more difficult.
> > 
> > For example to stress test migration vs concurrent complicated
> > memory access, including TLB refill, ram dirtying, etc., then the
> > tight spin at getchar() and resumption of the workload after
> > migration is unhelpful.
> > 
> > This adds a continuous migration mode that directs the harness to
> > perform migrations continually. This is added to the migration
> > selftests, which also sees cooperative migration iterations reduced
> > to avoid increasing test time too much.
> > 
> > Signed-off-by: Nicholas Piggin 
> > ---
> >   common/selftest-migration.c | 16 +--
> >   lib/migrate.c   | 18 
> >   lib/migrate.h   |  3 ++
> >   scripts/arch-run.bash   | 55 -
> >   4 files changed, 82 insertions(+), 10 deletions(-)
> > 
> > diff --git a/common/selftest-migration.c b/common/selftest-migration.c
> > index 0afd8581c..9a9b61835 100644
> > --- a/common/selftest-migration.c
> > +++ b/common/selftest-migration.c
> > @@ -9,12 +9,13 @@
> >*/
> >   #include 
> >   #include 
> > +#include 
> >   
> > -#define NR_MIGRATIONS 30
> > +#define NR_MIGRATIONS 15
> >   
> >   int main(int argc, char **argv)
> >   {
> > -   report_prefix_push("migration");
> > +   report_prefix_push("migration harness");
> >   
> > if (argc > 1 && !strcmp(argv[1], "skip")) {
> > migrate_skip();
> > @@ -24,7 +25,16 @@ int main(int argc, char **argv)
> >   
> > for (i = 0; i < NR_MIGRATIONS; i++)
> > migrate_quiet();
> > -   report(true, "simple harness stress");
> > +   report(true, "cooperative migration");
> > +
> > +   migrate_begin_continuous();
> > +   mdelay(2000);
> > +   migrate_end_continuous();
> > +   mdelay(1000);
> > +   migrate_begin_continuous();
> > +   mdelay(2000);
> > +   migrate_end_continuous();
> > +   report(true, "continuous migration");
> > }
> >   
> > report_prefix_pop();
> > diff --git a/lib/migrate.c b/lib/migrate.c
> > index 1d22196b7..770f76d5c 100644
> > --- a/lib/migrate.c
> > +++ b/lib/migrate.c
> > @@ -60,3 +60,21 @@ void migrate_skip(void)
> > puts("Skipped VM migration (quiet)\n");
> > (void)getchar();
> >   }
> > +
> > +void migrate_begin_continuous(void)
> > +{
> > +   puts("Begin continuous migration\n");
> > +   (void)getchar();
> > +}
> > +
> > +void migrate_end_continuous(void)
> > +{
> > +   /*
> > +* Migration can split this output between source and dest QEMU
> > +* output files, print twice and match once to always cope with
> > +* a split.
> > +*/
> > +   puts("End continuous migration\n");
> > +   puts("End continuous migration (quiet)\n");
> > +   (void)getchar();
> > +}
> > diff --git a/lib/migrate.h b/lib/migrate.h
> > index db6e0c501..35b6703a2 100644
> > --- a/lib/migrate.h
> > +++ b/lib/migrate.h
> > @@ -11,3 +11,6 @@ void migrate_quiet(void);
> >   void migrate_once(void);
> >   
> >   void migrate_skip(void);
> > +
> > +void migrate_begin_continuous(void);
> > +void migrate_end_continuous(void);
> > diff --git a/scripts/arch-run.bash b/scripts/arch-run.bash
> > index d0f6f098f..5c7e72036 100644
> > --- a/scripts/arch-run.bash
> > +++ b/scripts/arch-run.bash
> > @@ -125,15 +125,17 @@ qmp_events ()
> >   filter_quiet_msgs ()
> >   {
> > grep -v "Now migrate the VM (quiet)" |
> > +   grep -v "Begin continuous migration (quiet)" |
> > +   grep -v "End continuous migration (quiet)" |
> > grep -v "Skipped VM migration (quiet)"
> >   }
> >   
> >   seen_migrate_msg ()
> >   {
> > if [ $skip_migration -eq 1 ]; then
> > -   grep -q -e "Now migrate the VM" < $1
> > +   grep -q -e "Now 

Re: [kvm-unit-tests PATCH 6/7] gitlab-ci: Run migration selftest on s390x and powerpc

2024-03-04 Thread Nicholas Piggin
On Sat Mar 2, 2024 at 12:16 AM AEST, Thomas Huth wrote:
> On 26/02/2024 10.38, Nicholas Piggin wrote:
> > The migration harness is complicated and easy to break so CI will
> > be helpful.
> > 
> > Signed-off-by: Nicholas Piggin 
> > ---
> >   .gitlab-ci.yml | 18 +++---
> >   1 file changed, 11 insertions(+), 7 deletions(-)
> > 
> > diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
> > index 71d986e98..61f196d5d 100644
> > --- a/.gitlab-ci.yml
> > +++ b/.gitlab-ci.yml
> > @@ -64,26 +64,28 @@ build-arm:
> >   build-ppc64be:
> >extends: .outoftree_template
> >script:
> > - - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu
> > + - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu nmap-ncat
> >- mkdir build
> >- cd build
> >- ../configure --arch=ppc64 --endian=big 
> > --cross-prefix=powerpc64-linux-gnu-
> >- make -j2
> >- ACCEL=tcg ./run_tests.sh
> > - selftest-setup spapr_hcall rtas-get-time-of-day 
> > rtas-get-time-of-day-base
> > - rtas-set-time-of-day emulator
> > + selftest-setup selftest-migration selftest-migration-skip spapr_hcall
> > + rtas-get-time-of-day rtas-get-time-of-day-base rtas-set-time-of-day
> > + emulator
> >| tee results.txt
> >- if grep -q FAIL results.txt ; then exit 1 ; fi
> >   
> >   build-ppc64le:
> >extends: .intree_template
> >script:
> > - - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu
> > + - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu nmap-ncat
> >- ./configure --arch=ppc64 --endian=little 
> > --cross-prefix=powerpc64-linux-gnu-
> >- make -j2
> >- ACCEL=tcg ./run_tests.sh
> > - selftest-setup spapr_hcall rtas-get-time-of-day 
> > rtas-get-time-of-day-base
> > - rtas-set-time-of-day emulator
> > + selftest-setup selftest-migration selftest-migration-skip spapr_hcall
> > + rtas-get-time-of-day rtas-get-time-of-day-base rtas-set-time-of-day
> > + emulator
> >| tee results.txt
> >- if grep -q FAIL results.txt ; then exit 1 ; fi
> >   
> > @@ -107,7 +109,7 @@ build-riscv64:
> >   build-s390x:
> >extends: .outoftree_template
> >script:
> > - - dnf install -y qemu-system-s390x gcc-s390x-linux-gnu
> > + - dnf install -y qemu-system-s390x gcc-s390x-linux-gnu nmap-ncat
> >- mkdir build
> >- cd build
> >- ../configure --arch=s390x --cross-prefix=s390x-linux-gnu-
> > @@ -133,6 +135,8 @@ build-s390x:
> > sclp-1g
> > sclp-3g
> > selftest-setup
> > +  selftest-migration
> > +  selftest-migration-skip
> > sieve
> > smp
> > stsi
>
> While I can update the qemu binary for the s390x-kvm job, the build-* jobs 
> run in a container with a normal QEMU from the corresponding distros, so I 
> think this has to wait 'til we get distros that contain your QEMU TCG 
> migration fix.

Okay. powerpc *could* run into the TCG bug too, in practice it has not.
We could try enable it there to get migration into CI, and revert it if
it starts showing random failures?

Thanks,
Nick


Re: [kvm-unit-tests PATCH 14/32] powerpc: general interrupt tests

2024-03-04 Thread Nicholas Piggin
On Sat Mar 2, 2024 at 12:14 AM AEST, Andrew Jones wrote:
> On Fri, Mar 01, 2024 at 02:57:04PM +0100, Thomas Huth wrote:
> > On 01/03/2024 14.45, Andrew Jones wrote:
> > > On Fri, Mar 01, 2024 at 01:41:22PM +0100, Thomas Huth wrote:
> > > > On 26/02/2024 11.12, Nicholas Piggin wrote:
> > > > > Add basic testing of various kinds of interrupts, machine check,
> > > > > page fault, illegal, decrementer, trace, syscall, etc.
> > > > > 
> > > > > This has a known failure on QEMU TCG pseries machines where MSR[ME]
> > > > > can be incorrectly set to 0.
> > > > 
> > > > Two questions out of curiosity:
> > > > 
> > > > Any chance that this could be fixed easily in QEMU?
> > > > 
> > > > Or is there a way to detect TCG from within the test? (for example, we 
> > > > have
> > > > a host_is_tcg() function for s390x so we can e.g. use report_xfail() for
> > > > tests that are known to fail on TCG there)
> > > 
> > > If there's nothing better, then it should be possible to check the
> > > QEMU_ACCEL environment variable which will be there with the default
> > > environ.
> > 
> > Well, but that's only available from the host side, not within the test
> > (i.e. the guest). So that does not help much with report_xfail...
>
> powerpc has had environment variables in guests since commit f266c3e8ef15
> ("powerpc: enable environ"). QEMU_ACCEL is one of the environment
> variables given to unit tests by default when ENVIRON_DEFAULT is 'yes', as
> is the default set in configure. But...
>
> > I was rather thinking of something like checking the device tree, e.g. for
> > the compatible property in /hypervisor to see whether it's KVM or TCG...?
>
> ...while QEMU_ACCEL will work when the environ is present, DT will always
> be present, so checking the hypervisor node sounds better to me.

Yeah I got that.

One issue with xfail I noted when looking at this earlier, is that it
*always* expects a fail, and fails if it succeeds. So if you fix a QEMU
bug then you introduce a fail to kvm-unit-tests. So we really want a
report_known_bug(cond, "SPRs look sane", "QEMU TCG before v9.0 and
POWER9 DD2.0 is known to fail..."); and that could report a maybe-fail
that doesn't make the test group fail.

Thanks,
Nick


Re: [kvm-unit-tests PATCH 14/32] powerpc: general interrupt tests

2024-03-04 Thread Nicholas Piggin
On Fri Mar 1, 2024 at 11:45 PM AEST, Andrew Jones wrote:
> On Fri, Mar 01, 2024 at 01:41:22PM +0100, Thomas Huth wrote:
> > On 26/02/2024 11.12, Nicholas Piggin wrote:
> > > Add basic testing of various kinds of interrupts, machine check,
> > > page fault, illegal, decrementer, trace, syscall, etc.
> > > 
> > > This has a known failure on QEMU TCG pseries machines where MSR[ME]
> > > can be incorrectly set to 0.
> > 
> > Two questions out of curiosity:
> > 
> > Any chance that this could be fixed easily in QEMU?
> > 
> > Or is there a way to detect TCG from within the test? (for example, we have
> > a host_is_tcg() function for s390x so we can e.g. use report_xfail() for
> > tests that are known to fail on TCG there)
>
> If there's nothing better, then it should be possible to check the
> QEMU_ACCEL environment variable which will be there with the default
> environ.
>
> > 
> > > @@ -0,0 +1,415 @@
> > > +/*
> > > + * Test interrupts
> > > + *
> > > + * Copyright 2024 Nicholas Piggin, IBM Corp.
> > > + *
> > > + * This work is licensed under the terms of the GNU LGPL, version 2.
> > 
> > I know, we're using this line in a lot of source files ... but maybe we
> > should do better for new files at least: "LGPL, version 2" is a little bit
> > ambiguous: Does it mean the "Library GPL version 2.0" or the "Lesser GPL
> > version 2.1"? Maybe you could clarify by additionally providing a SPDX
> > identifier here, or by explicitly writing 2.0 or 2.1.
>
> Let's only add SPDX identifiers to new files.

+1

Speaking of which, a bunch of these just got inherited from the file
that was copied to begin with (I tried not to remove copyright
notices unless there was really nothing of the original remaining).
So for new code/files, is there any particular preference for the
license to use? I don't much mind between the *GPL*. Looks like almost
all the SPDX code use GPL 2.0 only, but that could be just from
coming from Linux. I might just go with that.

Thanks,
Nick


Re: [kvm-unit-tests PATCH 1/7] arch-run: Keep infifo open

2024-03-04 Thread Nicholas Piggin
On Fri Mar 1, 2024 at 11:32 PM AEST, Thomas Huth wrote:
> On 26/02/2024 10.38, Nicholas Piggin wrote:
> > The infifo fifo that is used to send characters to QEMU console is
> > only able to receive one character before the cat process exits.
> > Supporting interactions between test and harness involving multiple
> > characters requires the fifo to remain open.
> > 
> > This also allows us to let the cat out of the bag, simplifying the
> > input pipeline.
>
> LOL, we rather let the cat out of the subshell now, but I like the play on 
> words :-)

It was a bit of a stretch, but I'm glad you liked it :) I may
incorporate your suggestion to improve it.

>
> > Signed-off-by: Nicholas Piggin 
> > ---
> >   scripts/arch-run.bash | 12 ++--
> >   1 file changed, 6 insertions(+), 6 deletions(-)
> > 
> > diff --git a/scripts/arch-run.bash b/scripts/arch-run.bash
> > index 6daef3218..e5b36a07b 100644
> > --- a/scripts/arch-run.bash
> > +++ b/scripts/arch-run.bash
> > @@ -158,6 +158,11 @@ run_migration ()
> > mkfifo ${src_outfifo}
> > mkfifo ${dst_outfifo}
> >   
> > +   # Holding both ends of the input fifo open prevents opens from
> > +   # blocking and readers getting EOF when a writer closes it.
> > +   mkfifo ${dst_infifo}
> > +   exec {dst_infifo_fd}<>${dst_infifo}
> > +
> > eval "$migcmdline" \
> > -chardev socket,id=mon,path=${src_qmp},server=on,wait=off \
> > -mon chardev=mon,mode=control > ${src_outfifo} &
> > @@ -191,14 +196,10 @@ run_migration ()
> >   
> >   do_migration ()
> >   {
> > -   # We have to use cat to open the named FIFO, because named FIFO's,
> > -   # unlike pipes, will block on open() until the other end is also
> > -   # opened, and that totally breaks QEMU...
> > -   mkfifo ${dst_infifo}
> > eval "$migcmdline" \
> > -chardev socket,id=mon,path=${dst_qmp},server=on,wait=off \
> > -mon chardev=mon,mode=control -incoming unix:${dst_incoming} \
> > -   < <(cat ${dst_infifo}) > ${dst_outfifo} &
> > +   < ${dst_infifo} > ${dst_outfifo} &
> > incoming_pid=$!
> > cat ${dst_outfifo} | tee ${dst_out} | filter_quiet_msgs &
> >   
> > @@ -245,7 +246,6 @@ do_migration ()
> >   
> > # keypress to dst so getchar completes and test continues
> > echo > ${dst_infifo}
> > -   rm ${dst_infifo}
>
> I assume it will not get deleted by the trap handler? ... sounds fine to me, 
> so I dare to say:

Yep, deleted by trap handler.

>
> Reviewed-by: Thomas Huth 

Thanks,
Nick


Re: [kvm-unit-tests PATCH 14/32] powerpc: general interrupt tests

2024-03-04 Thread Nicholas Piggin
On Fri Mar 1, 2024 at 10:41 PM AEST, Thomas Huth wrote:
> On 26/02/2024 11.12, Nicholas Piggin wrote:
> > Add basic testing of various kinds of interrupts, machine check,
> > page fault, illegal, decrementer, trace, syscall, etc.
> > 
> > This has a known failure on QEMU TCG pseries machines where MSR[ME]
> > can be incorrectly set to 0.
>
> Two questions out of curiosity:
>
> Any chance that this could be fixed easily in QEMU?

Yes I have a fix on the mailing list. It should get into 9.0 and
probably stable.

> Or is there a way to detect TCG from within the test? (for example, we have 
> a host_is_tcg() function for s390x so we can e.g. use report_xfail() for 
> tests that are known to fail on TCG there)

I do have a half-done patch which adds exactly this.

One (minor) annoyance is that it doesn't seem possible to detect QEMU
version to add workarounds. E.g., we would like to test the fixed
functionality, but older qemu should not. Maybe that's going too much
into a rabbit hole. We *could* put a QEMU version into device tree
to deal with this though...

Thanks,
Nick
>
> > Signed-off-by: Nicholas Piggin 
> > ---
> >   lib/powerpc/asm/processor.h |   4 +
> >   lib/powerpc/asm/reg.h   |  17 ++
> >   lib/powerpc/setup.c |  11 +
> >   lib/ppc64/asm/ptrace.h  |  16 ++
> >   powerpc/Makefile.common |   3 +-
> >   powerpc/interrupts.c| 415 
> >   powerpc/unittests.cfg   |   3 +
> >   7 files changed, 468 insertions(+), 1 deletion(-)
> >   create mode 100644 powerpc/interrupts.c
> > 
> > diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
> > index cf1b9d8ff..eed37d1f4 100644
> > --- a/lib/powerpc/asm/processor.h
> > +++ b/lib/powerpc/asm/processor.h
> > @@ -11,7 +11,11 @@ void do_handle_exception(struct pt_regs *regs);
> >   #endif /* __ASSEMBLY__ */
> >   
> >   extern bool cpu_has_hv;
> > +extern bool cpu_has_power_mce;
> > +extern bool cpu_has_siar;
> >   extern bool cpu_has_heai;
> > +extern bool cpu_has_prefix;
> > +extern bool cpu_has_sc_lev;
> >   
> >   static inline uint64_t mfspr(int nr)
> >   {
> > diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
> > index 782e75527..d6097f48f 100644
> > --- a/lib/powerpc/asm/reg.h
> > +++ b/lib/powerpc/asm/reg.h
> > @@ -5,8 +5,15 @@
> >   
> >   #define UL(x) _AC(x, UL)
> >   
> > +#define SPR_DSISR  0x012
> > +#define SPR_DAR0x013
> > +#define SPR_DEC0x016
> >   #define SPR_SRR0  0x01a
> >   #define SPR_SRR1  0x01b
> > +#define   SRR1_PREFIX  UL(0x2000)
> > +#define SPR_FSCR   0x099
> > +#define   FSCR_PREFIX  UL(0x2000)
> > +#define SPR_HFSCR  0x0be
> >   #define SPR_TB0x10c
> >   #define SPR_SPRG0 0x110
> >   #define SPR_SPRG1 0x111
> > @@ -22,12 +29,17 @@
> >   #define   PVR_VER_POWER8  UL(0x004d)
> >   #define   PVR_VER_POWER9  UL(0x004e)
> >   #define   PVR_VER_POWER10 UL(0x0080)
> > +#define SPR_HDEC   0x136
> >   #define SPR_HSRR0 0x13a
> >   #define SPR_HSRR1 0x13b
> > +#define SPR_LPCR   0x13e
> > +#define   LPCR_HDICE   UL(0x1)
> > +#define SPR_HEIR   0x153
> >   #define SPR_MMCR0 0x31b
> >   #define   MMCR0_FCUL(0x8000)
> >   #define   MMCR0_PMAE  UL(0x0400)
> >   #define   MMCR0_PMAO  UL(0x0080)
> > +#define SPR_SIAR   0x31c
> >   
> >   /* Machine State Register definitions: */
> >   #define MSR_LE_BIT0
> > @@ -35,6 +47,11 @@
> >   #define MSR_HV_BIT60  /* Hypervisor mode */
> >   #define MSR_SF_BIT63  /* 64-bit mode */
> >   
> > +#define MSR_DR UL(0x0010)
> > +#define MSR_IR UL(0x0020)
> > +#define MSR_BE UL(0x0200)  /* Branch Trace Enable 
> > */
> > +#define MSR_SE UL(0x0400)  /* Single Step Enable */
> > +#define MSR_EE UL(0x8000)
> >   #define MSR_MEUL(0x1000)
> >   
> >   #endif
> > diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c
> > index 3c81aee9e..9b665f59c 100644
> > --- a/lib/powerpc/setup.c
> > +++ b/lib/powerpc/setup.c
> > @@ -87,7 +87,11 @@ static void cpu_set(int fdtnode, u64 regval, void *info)
> >   }
> >   
> >   bool cpu_has_hv;
> > +bool cpu_has_power_mce; /* POWER CPU machine checks */
> > +bool cpu_has_siar;
> >   bool cpu_has_heai;

Re: [kvm-unit-tests PATCH 12/32] powerpc: Fix emulator illegal instruction test for powernv

2024-03-04 Thread Nicholas Piggin
On Fri Mar 1, 2024 at 9:50 PM AEST, Thomas Huth wrote:
> On 26/02/2024 11.11, Nicholas Piggin wrote:
> > Illegal instructions cause 0xe40 (HEAI) interrupts rather
> > than program interrupts.
> > 
> > Acked-by: Thomas Huth 
> > Signed-off-by: Nicholas Piggin 
> > ---
> >   lib/powerpc/asm/processor.h |  1 +
> >   lib/powerpc/setup.c | 13 +
> >   powerpc/emulator.c  | 21 -
> >   3 files changed, 34 insertions(+), 1 deletion(-)
> > 
> > diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
> > index 9d8061962..cf1b9d8ff 100644
> > --- a/lib/powerpc/asm/processor.h
> > +++ b/lib/powerpc/asm/processor.h
> > @@ -11,6 +11,7 @@ void do_handle_exception(struct pt_regs *regs);
> >   #endif /* __ASSEMBLY__ */
> >   
> >   extern bool cpu_has_hv;
> > +extern bool cpu_has_heai;
> >   
> >   static inline uint64_t mfspr(int nr)
> >   {
> > diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c
> > index 89e5157f2..3c81aee9e 100644
> > --- a/lib/powerpc/setup.c
> > +++ b/lib/powerpc/setup.c
> > @@ -87,6 +87,7 @@ static void cpu_set(int fdtnode, u64 regval, void *info)
> >   }
> >   
> >   bool cpu_has_hv;
> > +bool cpu_has_heai;
> >   
> >   static void cpu_init(void)
> >   {
> > @@ -108,6 +109,18 @@ static void cpu_init(void)
> > hcall(H_SET_MODE, 0, 4, 0, 0);
> >   #endif
> > }
> > +
> > +   switch (mfspr(SPR_PVR) & PVR_VERSION_MASK) {
> > +   case PVR_VER_POWER10:
> > +   case PVR_VER_POWER9:
> > +   case PVR_VER_POWER8E:
> > +   case PVR_VER_POWER8NVL:
> > +   case PVR_VER_POWER8:
> > +   cpu_has_heai = true;
> > +   break;
> > +   default:
> > +   break;
> > +   }
> >   }
> >   
> >   static void mem_init(phys_addr_t freemem_start)
> > diff --git a/powerpc/emulator.c b/powerpc/emulator.c
> > index 39dd59645..c9b17f742 100644
> > --- a/powerpc/emulator.c
> > +++ b/powerpc/emulator.c
> > @@ -31,6 +31,20 @@ static void program_check_handler(struct pt_regs *regs, 
> > void *opaque)
> > regs->nip += 4;
> >   }
> >   
> > +static void heai_handler(struct pt_regs *regs, void *opaque)
> > +{
> > +   int *data = opaque;
> > +
> > +   if (verbose) {
> > +   printf("Detected invalid instruction %#018lx: %08x\n",
> > +  regs->nip, *(uint32_t*)regs->nip);
> > +   }
> > +
> > +   *data = 8; /* Illegal instruction */
> > +
> > +   regs->nip += 4;
> > +}
> > +
> >   static void alignment_handler(struct pt_regs *regs, void *opaque)
> >   {
> > int *data = opaque;
> > @@ -362,7 +376,12 @@ int main(int argc, char **argv)
> >   {
> > int i;
> >   
> > -   handle_exception(0x700, program_check_handler, (void *)_invalid);
> > +   if (cpu_has_heai) {
> > +   handle_exception(0xe40, heai_handler, (void *)_invalid);
> > +   handle_exception(0x700, program_check_handler, (void 
> > *)_invalid);
> > +   } else {
> > +   handle_exception(0x700, program_check_handler, (void 
> > *)_invalid);
>
> The 0x700 line looks identical to the other part of the if-statement ... I'd 
> suggest to leave it outside of the if-statement, drop the else-part and just 
> set 0xe40 if cpu_has_heai.

Can do.

Thanks,
Nick


Re: [kvm-unit-tests PATCH 07/32] powerpc/sprs: Don't fail changed SPRs that are used by the test harness

2024-03-04 Thread Nicholas Piggin
On Fri Mar 1, 2024 at 9:15 PM AEST, Thomas Huth wrote:
> On 26/02/2024 11.11, Nicholas Piggin wrote:
> > SPRs annotated with SPR_HARNESS can change between consecutive reads
> > because the test harness code has changed them. Avoid failing the
> > test in this case.
> > 
> > Signed-off-by: Nicholas Piggin 
> > ---
> >   powerpc/sprs.c | 2 +-
> >   1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/powerpc/sprs.c b/powerpc/sprs.c
> > index 8253ea971..44edd0d7b 100644
> > --- a/powerpc/sprs.c
> > +++ b/powerpc/sprs.c
> > @@ -563,7 +563,7 @@ int main(int argc, char **argv)
> > if (before[i] >> 32)
> > pass = false;
> > }
> > -   if (!(sprs[i].type & SPR_ASYNC) && (before[i] != after[i]))
> > +   if (!(sprs[i].type & (SPR_HARNESS|SPR_ASYNC)) && (before[i] != 
> > after[i]))
> > pass = false;
> >   
> > if (sprs[i].width == 32 && !(before[i] >> 32) && !(after[i] >> 
> > 32))
>
> I guess you could also squash this into the previous patch (to avoid 
> problems with bisecting later?) ...

Yeah, I guess it doesn't make much sense to split out since lots of
other stuff changes in the previous patch too.

>
> Anyway:
> Reviewed-by: Thomas Huth 

Thanks,
Nick


Re: [kvm-unit-tests PATCH 04/32] powerpc: interrupt stack backtracing

2024-03-04 Thread Nicholas Piggin
On Fri Mar 1, 2024 at 7:53 PM AEST, Thomas Huth wrote:
> On 26/02/2024 11.11, Nicholas Piggin wrote:
> > Add support for backtracing across interrupt stacks, and
> > add interrupt frame backtrace for unhandled interrupts.
> > 
> > Signed-off-by: Nicholas Piggin 
> > ---
> >   lib/powerpc/processor.c |  4 ++-
> >   lib/ppc64/asm/stack.h   |  3 +++
> >   lib/ppc64/stack.c   | 55 +
> >   powerpc/Makefile.ppc64  |  1 +
> >   powerpc/cstart64.S  |  7 --
> >   5 files changed, 67 insertions(+), 3 deletions(-)
> >   create mode 100644 lib/ppc64/stack.c
> > 
> > diff --git a/lib/powerpc/processor.c b/lib/powerpc/processor.c
> > index ad0d95666..114584024 100644
> > --- a/lib/powerpc/processor.c
> > +++ b/lib/powerpc/processor.c
> > @@ -51,7 +51,9 @@ void do_handle_exception(struct pt_regs *regs)
> > return;
> > }
> >   
> > -   printf("unhandled cpu exception %#lx at NIA:0x%016lx MSR:0x%016lx\n", 
> > regs->trap, regs->nip, regs->msr);
> > +   printf("Unhandled cpu exception %#lx at NIA:0x%016lx MSR:0x%016lx\n",
> > +   regs->trap, regs->nip, regs->msr);
> > +   dump_frame_stack((void *)regs->nip, (void *)regs->gpr[1]);
> > abort();
> >   }
> >   
> > diff --git a/lib/ppc64/asm/stack.h b/lib/ppc64/asm/stack.h
> > index 9734bbb8f..94fd1021c 100644
> > --- a/lib/ppc64/asm/stack.h
> > +++ b/lib/ppc64/asm/stack.h
> > @@ -5,4 +5,7 @@
> >   #error Do not directly include . Just use .
> >   #endif
> >   
> > +#define HAVE_ARCH_BACKTRACE
> > +#define HAVE_ARCH_BACKTRACE_FRAME
> > +
> >   #endif
> > diff --git a/lib/ppc64/stack.c b/lib/ppc64/stack.c
> > new file mode 100644
> > index 0..fcb7fa860
> > --- /dev/null
> > +++ b/lib/ppc64/stack.c
> > @@ -0,0 +1,55 @@
> > +#include 
> > +#include 
> > +#include 
> > +
> > +extern char exception_stack_marker[];
> > +
> > +int backtrace_frame(const void *frame, const void **return_addrs, int 
> > max_depth)
> > +{
> > +   static int walking;
> > +   int depth = 0;
> > +   const unsigned long *bp = (unsigned long *)frame;
> > +   void *return_addr;
> > +
> > +   asm volatile("" ::: "lr"); /* Force it to save LR */
> > +
> > +   if (walking) {
> > +   printf("RECURSIVE STACK WALK!!!\n");
> > +   return 0;
> > +   }
> > +   walking = 1;
> > +
> > +   bp = (unsigned long *)bp[0];
> > +   return_addr = (void *)bp[2];
> > +
> > +   for (depth = 0; bp && depth < max_depth; depth++) {
> > +   return_addrs[depth] = return_addr;
> > +   if (return_addrs[depth] == 0)
> > +   break;
> > +   if (return_addrs[depth] == exception_stack_marker) {
> > +   struct pt_regs *regs;
> > +
> > +   regs = (void *)bp + STACK_FRAME_OVERHEAD;
> > +   bp = (unsigned long *)bp[0];
> > +   /* Represent interrupt frame with vector number */
> > +   return_addr = (void *)regs->trap;
> > +   if (depth + 1 < max_depth) {
> > +   depth++;
> > +   return_addrs[depth] = return_addr;
> > +   return_addr = (void *)regs->nip;
> > +   }
> > +   } else {
> > +   bp = (unsigned long *)bp[0];
> > +   return_addr = (void *)bp[2];
> > +   }
> > +   }
> > +
> > +   walking = 0;
> > +   return depth;
> > +}
> > +
> > +int backtrace(const void **return_addrs, int max_depth)
> > +{
> > +   return backtrace_frame(__builtin_frame_address(0), return_addrs,
> > +  max_depth);
> > +}
> > diff --git a/powerpc/Makefile.ppc64 b/powerpc/Makefile.ppc64
> > index b0ed2b104..eb682c226 100644
> > --- a/powerpc/Makefile.ppc64
> > +++ b/powerpc/Makefile.ppc64
> > @@ -17,6 +17,7 @@ cstart.o = $(TEST_DIR)/cstart64.o
> >   reloc.o  = $(TEST_DIR)/reloc64.o
> >   
> >   OBJDIRS += lib/ppc64
> > +cflatobjs += lib/ppc64/stack.o
> >   
> >   # ppc64 specific tests
> >   tests = $(TEST_DIR)/spapr_vpa.elf
> > diff --git a/powerpc/cstart64.S b/powerpc/cstart64.S
> > index 14ab0c6c8..278af84a6 100644
> > --- a/powerpc/cstart64.S
> > +++ b/powerpc/cstart64.S
>

Re: [kvm-unit-tests PATCH 03/32] powerpc: Fix stack backtrace termination

2024-03-04 Thread Nicholas Piggin
On Fri Mar 1, 2024 at 7:45 PM AEST, Thomas Huth wrote:
> On 27/02/2024 09.50, Thomas Huth wrote:
> > On 26/02/2024 11.11, Nicholas Piggin wrote:
> >> The backtrace handler terminates when it sees a NULL caller address,
> >> but the powerpc stack setup does not keep such a NULL caller frame
> >> at the start of the stack.
> >>
> >> This happens to work on pseries because the memory at 0 is mapped and
> >> it contains 0 at the location of the return address pointer if it
> >> were a stack frame. But this is fragile, and does not work with powernv
> >> where address 0 contains firmware instructions.
> >>
> >> Use the existing dummy frame on stack as the NULL caller, and create a
> >> new frame on stack for the entry code.
> >>
> >> Signed-off-by: Nicholas Piggin 
> >> ---
> >>   powerpc/cstart64.S | 12 ++--
> >>   1 file changed, 10 insertions(+), 2 deletions(-)
> > 
> > Thanks for tackling this! ... however, not doing powerpc work since years 
> > anymore, I have some ignorant questions below...
> > 
> >> diff --git a/powerpc/cstart64.S b/powerpc/cstart64.S
> >> index e18ae9a22..14ab0c6c8 100644
> >> --- a/powerpc/cstart64.S
> >> +++ b/powerpc/cstart64.S
> >> @@ -46,8 +46,16 @@ start:
> >>   add    r1, r1, r31
> >>   add    r2, r2, r31
> >> +    /* Zero backpointers in initial stack frame so backtrace() stops */
> >> +    li    r0,0
> >> +    std    r0,0(r1)
> > 
> > 0(r1) is the back chain pointer ...
> > 
> >> +    std    r0,16(r1)
> > 
> > ... but what is 16(r1) ? I suppose that should be the "LR save word" ? But 
> > isn't that at 8(r1) instead?? (not sure whether I'm looking at the right 
> > ELF 
> > abi spec right now...)
>
> Ok, I was looking at the wrong ELF spec, indeed (it was an ancient 32-bit 
> spec, not the 64-bit ABI). Sorry for the confusion. Having a proper #define 
> or a comment for the 16 here would still be helpful, though.

Thanks for the deailed reviews as always. I've been a little busy with
QEMU so may not get another series out for a bit. I'll probably wait for
Andrew's stack backtrace changes to land too before resend.

But, yes a comment makes sense. I'll add.

Thanks,
Nick


Re: [kvm-unit-tests PATCH 32/32] powerpc: gitlab CI update

2024-02-28 Thread Nicholas Piggin
On Wed Feb 28, 2024 at 10:16 PM AEST, Andrew Jones wrote:
> On Mon, Feb 26, 2024 at 08:12:18PM +1000, Nicholas Piggin wrote:
> > This adds testing for the powernv machine, and adds a gitlab-ci test
> > group instead of specifying all tests in .gitlab-ci.yml.
> > 
> > Signed-off-by: Nicholas Piggin 
> > ---
> >  .gitlab-ci.yml| 16 ++--
> >  powerpc/unittests.cfg | 15 ---
> >  2 files changed, 14 insertions(+), 17 deletions(-)
> > 
> > diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
> > index 61f196d5d..51a593021 100644
> > --- a/.gitlab-ci.yml
> > +++ b/.gitlab-ci.yml
> > @@ -69,11 +69,9 @@ build-ppc64be:
> >   - cd build
> >   - ../configure --arch=ppc64 --endian=big 
> > --cross-prefix=powerpc64-linux-gnu-
> >   - make -j2
> > - - ACCEL=tcg ./run_tests.sh
> > - selftest-setup selftest-migration selftest-migration-skip spapr_hcall
> > - rtas-get-time-of-day rtas-get-time-of-day-base rtas-set-time-of-day
> > - emulator
> > - | tee results.txt
> > + - ACCEL=tcg MAX_SMP=8 ./run_tests.sh -g gitlab-ci | tee results.txt
> > + - if grep -q FAIL results.txt ; then exit 1 ; fi
> > + - ACCEL=tcg MAX_SMP=8 MACHINE=powernv ./run_tests.sh -g gitlab-ci | tee 
> > results.txt
> >   - if grep -q FAIL results.txt ; then exit 1 ; fi
> >  
> >  build-ppc64le:
> > @@ -82,11 +80,9 @@ build-ppc64le:
> >   - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu nmap-ncat
> >   - ./configure --arch=ppc64 --endian=little 
> > --cross-prefix=powerpc64-linux-gnu-
> >   - make -j2
> > - - ACCEL=tcg ./run_tests.sh
> > - selftest-setup selftest-migration selftest-migration-skip spapr_hcall
> > - rtas-get-time-of-day rtas-get-time-of-day-base rtas-set-time-of-day
> > - emulator
> > - | tee results.txt
> > + - ACCEL=tcg MAX_SMP=8 ./run_tests.sh -g gitlab-ci | tee results.txt
> > + - if grep -q FAIL results.txt ; then exit 1 ; fi
> > + - ACCEL=tcg MAX_SMP=8 MACHINE=powernv ./run_tests.sh -g gitlab-ci | tee 
> > results.txt
> >   - if grep -q FAIL results.txt ; then exit 1 ; fi
> >  
>
> We're slowly migrating all tests like these to
>
>  grep -q PASS results.txt && ! grep -q FAIL results.txt
>
> Here's a good opportunity to change ppc's.

Sure, I'll do that.

Thanks,
Nick


Re: [kvm-unit-tests PATCH 09/32] scripts: allow machine option to be specified in unittests.cfg

2024-02-28 Thread Nicholas Piggin
On Wed Feb 28, 2024 at 9:47 PM AEST, Andrew Jones wrote:
> On Mon, Feb 26, 2024 at 08:11:55PM +1000, Nicholas Piggin wrote:
> > This allows different machines with different requirements to be
> > supported by run_tests.sh, similarly to how different accelerators
> > are handled.
> > 
> > Acked-by: Thomas Huth 
> > Signed-off-by: Nicholas Piggin 
> > ---
> >  scripts/common.bash  |  8 ++--
> >  scripts/runtime.bash | 16 
> >  2 files changed, 18 insertions(+), 6 deletions(-)
>
> Please also update the unittests.cfg documentation.

Yeah good catch, I will do.

> Currently that
> documentation lives in the header of each unittests.cfg file, but
> we could maybe change each file to have a single line which points
> at a single document.

I'll take a look and do something if it's simple enough,
otherwise I'll just update the unittests.cfg.

Thanks,
Nick


Re: [kvm-unit-tests PATCH 04/32] powerpc: interrupt stack backtracing

2024-02-28 Thread Nicholas Piggin
On Wed Feb 28, 2024 at 9:46 PM AEST, Andrew Jones wrote:
> On Mon, Feb 26, 2024 at 08:11:50PM +1000, Nicholas Piggin wrote:
> > Add support for backtracing across interrupt stacks, and
> > add interrupt frame backtrace for unhandled interrupts.
> > 
> > Signed-off-by: Nicholas Piggin 
> > ---
> >  lib/powerpc/processor.c |  4 ++-
> >  lib/ppc64/asm/stack.h   |  3 +++
> >  lib/ppc64/stack.c   | 55 +
> >  powerpc/Makefile.ppc64  |  1 +
> >  powerpc/cstart64.S  |  7 --
> >  5 files changed, 67 insertions(+), 3 deletions(-)
> >  create mode 100644 lib/ppc64/stack.c
> > 
> > diff --git a/lib/powerpc/processor.c b/lib/powerpc/processor.c
> > index ad0d95666..114584024 100644
> > --- a/lib/powerpc/processor.c
> > +++ b/lib/powerpc/processor.c
> > @@ -51,7 +51,9 @@ void do_handle_exception(struct pt_regs *regs)
> > return;
> > }
> >  
> > -   printf("unhandled cpu exception %#lx at NIA:0x%016lx MSR:0x%016lx\n", 
> > regs->trap, regs->nip, regs->msr);
> > +   printf("Unhandled cpu exception %#lx at NIA:0x%016lx MSR:0x%016lx\n",
> > +   regs->trap, regs->nip, regs->msr);
> > +   dump_frame_stack((void *)regs->nip, (void *)regs->gpr[1]);
> > abort();
> >  }
> >  
> > diff --git a/lib/ppc64/asm/stack.h b/lib/ppc64/asm/stack.h
> > index 9734bbb8f..94fd1021c 100644
> > --- a/lib/ppc64/asm/stack.h
> > +++ b/lib/ppc64/asm/stack.h
> > @@ -5,4 +5,7 @@
> >  #error Do not directly include . Just use .
> >  #endif
> >  
> > +#define HAVE_ARCH_BACKTRACE
> > +#define HAVE_ARCH_BACKTRACE_FRAME
> > +
> >  #endif
> > diff --git a/lib/ppc64/stack.c b/lib/ppc64/stack.c
> > new file mode 100644
> > index 0..fcb7fa860
> > --- /dev/null
> > +++ b/lib/ppc64/stack.c
> > @@ -0,0 +1,55 @@
> > +#include 
> > +#include 
> > +#include 
> > +
> > +extern char exception_stack_marker[];
> > +
> > +int backtrace_frame(const void *frame, const void **return_addrs, int 
> > max_depth)
> > +{
> > +   static int walking;
> > +   int depth = 0;
> > +   const unsigned long *bp = (unsigned long *)frame;
> > +   void *return_addr;
> > +
> > +   asm volatile("" ::: "lr"); /* Force it to save LR */
> > +
> > +   if (walking) {
> > +   printf("RECURSIVE STACK WALK!!!\n");
> > +   return 0;
> > +   }
> > +   walking = 1;
> > +
> > +   bp = (unsigned long *)bp[0];
> > +   return_addr = (void *)bp[2];
> > +
> > +   for (depth = 0; bp && depth < max_depth; depth++) {
> > +   return_addrs[depth] = return_addr;
> > +   if (return_addrs[depth] == 0)
> > +   break;
> > +   if (return_addrs[depth] == exception_stack_marker) {
> > +   struct pt_regs *regs;
> > +
> > +   regs = (void *)bp + STACK_FRAME_OVERHEAD;
> > +   bp = (unsigned long *)bp[0];
> > +   /* Represent interrupt frame with vector number */
> > +   return_addr = (void *)regs->trap;
> > +   if (depth + 1 < max_depth) {
> > +   depth++;
> > +   return_addrs[depth] = return_addr;
> > +   return_addr = (void *)regs->nip;
> > +   }
> > +   } else {
> > +   bp = (unsigned long *)bp[0];
> > +   return_addr = (void *)bp[2];
> > +   }
> > +   }
> > +
> > +   walking = 0;
> > +   return depth;
> > +}
> > +
> > +int backtrace(const void **return_addrs, int max_depth)
> > +{
> > +   return backtrace_frame(__builtin_frame_address(0), return_addrs,
> > +  max_depth);
> > +}
>
> I'm about to post a series which has a couple treewide tracing changes
> in them. Depending on which series goes first the other will need to
> accommodate.

Yeah that's fine.

Thanks,
Nick


Re: [kvm-unit-tests PATCH 04/13] treewide: lib/stack: Make base_address arch specific

2024-02-28 Thread Nicholas Piggin
On Thu Feb 29, 2024 at 1:04 AM AEST, Andrew Jones wrote:
> Calculating the offset of an address is image specific, which is
> architecture specific. Until now, all architectures and architecture
> configurations which select CONFIG_RELOC were able to subtract
> _etext, but the EFI configuration of riscv cannot (it must subtract
> ImageBase). Make this function architecture specific, since the
> architecture's image layout already is.

arch_base_address()?

How about a default implementation unlesss HAVE_ARCH_BASE_ADDRESS?

Thanks,
Nick

>
> Signed-off-by: Andrew Jones 
> ---
>  lib/arm64/stack.c | 17 +
>  lib/riscv/stack.c | 18 ++
>  lib/stack.c   | 19 ++-
>  lib/stack.h   |  2 ++
>  lib/x86/stack.c   | 17 +
>  5 files changed, 56 insertions(+), 17 deletions(-)
>
> diff --git a/lib/arm64/stack.c b/lib/arm64/stack.c
> index f5eb57fd8892..3369031a74f7 100644
> --- a/lib/arm64/stack.c
> +++ b/lib/arm64/stack.c
> @@ -6,6 +6,23 @@
>  #include 
>  #include 
>  
> +#ifdef CONFIG_RELOC
> +extern char _text, _etext;
> +
> +bool base_address(const void *rebased_addr, unsigned long *addr)
> +{
> + unsigned long ra = (unsigned long)rebased_addr;
> + unsigned long start = (unsigned long)&_text;
> + unsigned long end = (unsigned long)&_etext;
> +
> + if (ra < start || ra >= end)
> + return false;
> +
> + *addr = ra - start;
> + return true;
> +}
> +#endif
> +
>  extern char vector_stub_start, vector_stub_end;
>  
>  int arch_backtrace_frame(const void *frame, const void **return_addrs,
> diff --git a/lib/riscv/stack.c b/lib/riscv/stack.c
> index d865594b9671..a143c22a570a 100644
> --- a/lib/riscv/stack.c
> +++ b/lib/riscv/stack.c
> @@ -2,6 +2,24 @@
>  #include 
>  #include 
>  
> +#ifdef CONFIG_RELOC
> +extern char ImageBase, _text, _etext;
> +
> +bool base_address(const void *rebased_addr, unsigned long *addr)
> +{
> + unsigned long ra = (unsigned long)rebased_addr;
> + unsigned long base = (unsigned long)
> + unsigned long start = (unsigned long)&_text;
> + unsigned long end = (unsigned long)&_etext;
> +
> + if (ra < start || ra >= end)
> + return false;
> +
> + *addr = ra - base;
> + return true;
> +}
> +#endif
> +
>  int arch_backtrace_frame(const void *frame, const void **return_addrs,
>int max_depth, bool current_frame)
>  {
> diff --git a/lib/stack.c b/lib/stack.c
> index dd6bfa8dac6e..e5099e207388 100644
> --- a/lib/stack.c
> +++ b/lib/stack.c
> @@ -11,23 +11,8 @@
>  
>  #define MAX_DEPTH 20
>  
> -#ifdef CONFIG_RELOC
> -extern char _text, _etext;
> -
> -static bool base_address(const void *rebased_addr, unsigned long *addr)
> -{
> - unsigned long ra = (unsigned long)rebased_addr;
> - unsigned long start = (unsigned long)&_text;
> - unsigned long end = (unsigned long)&_etext;
> -
> - if (ra < start || ra >= end)
> - return false;
> -
> - *addr = ra - start;
> - return true;
> -}
> -#else
> -static bool base_address(const void *rebased_addr, unsigned long *addr)
> +#ifndef CONFIG_RELOC
> +bool base_address(const void *rebased_addr, unsigned long *addr)
>  {
>   *addr = (unsigned long)rebased_addr;
>   return true;
> diff --git a/lib/stack.h b/lib/stack.h
> index 6edc84344b51..f8def4ad4d49 100644
> --- a/lib/stack.h
> +++ b/lib/stack.h
> @@ -10,6 +10,8 @@
>  #include 
>  #include 
>  
> +bool base_address(const void *rebased_addr, unsigned long *addr);
> +
>  #ifdef HAVE_ARCH_BACKTRACE_FRAME
>  extern int arch_backtrace_frame(const void *frame, const void **return_addrs,
>   int max_depth, bool current_frame);
> diff --git a/lib/x86/stack.c b/lib/x86/stack.c
> index 58ab6c4b293a..7ba73becbd69 100644
> --- a/lib/x86/stack.c
> +++ b/lib/x86/stack.c
> @@ -1,6 +1,23 @@
>  #include 
>  #include 
>  
> +#ifdef CONFIG_RELOC
> +extern char _text, _etext;
> +
> +bool base_address(const void *rebased_addr, unsigned long *addr)
> +{
> + unsigned long ra = (unsigned long)rebased_addr;
> + unsigned long start = (unsigned long)&_text;
> + unsigned long end = (unsigned long)&_etext;
> +
> + if (ra < start || ra >= end)
> + return false;
> +
> + *addr = ra - start;
> + return true;
> +}
> +#endif
> +
>  int arch_backtrace_frame(const void *frame, const void **return_addrs,
>int max_depth, bool current_frame)
>  {



Re: [kvm-unit-tests PATCH 03/13] treewide: lib/stack: Fix backtrace

2024-02-28 Thread Nicholas Piggin
ace_frame(const void *frame, const void **return_addrs, int 
> max_depth)
> +int arch_backtrace_frame(const void *frame, const void **return_addrs,
> +  int max_depth, bool current_frame)
>  {
>   int depth = 0;
>   struct stack_frame *stack = (struct stack_frame *)frame;
>  
> + if (current_frame)
> + stack = __builtin_frame_address(0);
> +
>   for (depth = 0; stack && depth < max_depth; depth++) {
>   return_addrs[depth] = (void *)stack->grs[8];
>   stack = stack->back_chain;
> @@ -28,9 +32,3 @@ int backtrace_frame(const void *frame, const void 
> **return_addrs, int max_depth)
>  
>   return depth;
>  }
> -
> -int backtrace(const void **return_addrs, int max_depth)
> -{
> - return backtrace_frame(__builtin_frame_address(0),
> -return_addrs, max_depth);
> -}
> diff --git a/lib/stack.h b/lib/stack.h
> index 10fc2f793354..6edc84344b51 100644
> --- a/lib/stack.h
> +++ b/lib/stack.h
> @@ -11,17 +11,27 @@
>  #include 
>  
>  #ifdef HAVE_ARCH_BACKTRACE_FRAME
> -extern int backtrace_frame(const void *frame, const void **return_addrs,
> -int max_depth);
> +extern int arch_backtrace_frame(const void *frame, const void **return_addrs,
> + int max_depth, bool current_frame);
> +
> +static inline int backtrace_frame(const void *frame, const void 
> **return_addrs,
> +   int max_depth)
> +{
> + return arch_backtrace_frame(frame, return_addrs, max_depth, false);
> +}
> +
> +static inline int backtrace(const void **return_addrs, int max_depth)
> +{
> + return arch_backtrace_frame(NULL, return_addrs, max_depth, true);
> +}
>  #else
> -static inline int
> -backtrace_frame(const void *frame __unused, const void **return_addrs 
> __unused,
> - int max_depth __unused)
> +extern int backtrace(const void **return_addrs, int max_depth);
> +
> +static inline int backtrace_frame(const void *frame, const void 
> **return_addrs,
> +   int max_depth)
>  {
>   return 0;
>  }
>  #endif
>  
> -extern int backtrace(const void **return_addrs, int max_depth);
> -
>  #endif

Is there a reason to add the inline wrappers rather than just externs
and drop the arch_ prefix?

Do we want to just generally have all arch specific functions have an
arch_ prefix? Fine by me.

Reviewed-by: Nicholas Piggin 

I'm fine to rebase the powerpc patch on top of this if it goes in first.
Thanks for the heads up.

Thanks,
Nick


[kvm-unit-tests PATCH 32/32] powerpc: gitlab CI update

2024-02-26 Thread Nicholas Piggin
This adds testing for the powernv machine, and adds a gitlab-ci test
group instead of specifying all tests in .gitlab-ci.yml.

Signed-off-by: Nicholas Piggin 
---
 .gitlab-ci.yml| 16 ++--
 powerpc/unittests.cfg | 15 ---
 2 files changed, 14 insertions(+), 17 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 61f196d5d..51a593021 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -69,11 +69,9 @@ build-ppc64be:
  - cd build
  - ../configure --arch=ppc64 --endian=big --cross-prefix=powerpc64-linux-gnu-
  - make -j2
- - ACCEL=tcg ./run_tests.sh
- selftest-setup selftest-migration selftest-migration-skip spapr_hcall
- rtas-get-time-of-day rtas-get-time-of-day-base rtas-set-time-of-day
- emulator
- | tee results.txt
+ - ACCEL=tcg MAX_SMP=8 ./run_tests.sh -g gitlab-ci | tee results.txt
+ - if grep -q FAIL results.txt ; then exit 1 ; fi
+ - ACCEL=tcg MAX_SMP=8 MACHINE=powernv ./run_tests.sh -g gitlab-ci | tee 
results.txt
  - if grep -q FAIL results.txt ; then exit 1 ; fi
 
 build-ppc64le:
@@ -82,11 +80,9 @@ build-ppc64le:
  - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu nmap-ncat
  - ./configure --arch=ppc64 --endian=little --cross-prefix=powerpc64-linux-gnu-
  - make -j2
- - ACCEL=tcg ./run_tests.sh
- selftest-setup selftest-migration selftest-migration-skip spapr_hcall
- rtas-get-time-of-day rtas-get-time-of-day-base rtas-set-time-of-day
- emulator
- | tee results.txt
+ - ACCEL=tcg MAX_SMP=8 ./run_tests.sh -g gitlab-ci | tee results.txt
+ - if grep -q FAIL results.txt ; then exit 1 ; fi
+ - ACCEL=tcg MAX_SMP=8 MACHINE=powernv ./run_tests.sh -g gitlab-ci | tee 
results.txt
  - if grep -q FAIL results.txt ; then exit 1 ; fi
 
 # build-riscv32:
diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index e275f389b..21071a1a1 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -34,17 +34,17 @@
 file = selftest.elf
 smp = 2
 extra_params = -m 1g -append 'setup smp=2 mem=1024'
-groups = selftest
+groups = selftest gitlab-ci
 
 [selftest-migration]
 file = selftest-migration.elf
 machine = pseries
-groups = selftest migration
+groups = selftest migration gitlab-ci
 
 [selftest-migration-skip]
 file = selftest-migration.elf
 machine = pseries
-groups = selftest migration
+groups = selftest migration gitlab-ci
 extra_params = -append "skip"
 
 # This fails due to a QEMU TCG bug so KVM-only until QEMU is fixed upstream
@@ -56,7 +56,7 @@ groups = migration
 
 [spapr_hcall]
 file = spapr_hcall.elf
-machine = pseries
+machine = pseries gitlab-ci
 
 [spapr_vpa]
 file = spapr_vpa.elf
@@ -67,24 +67,25 @@ file = rtas.elf
 machine = pseries
 timeout = 5
 extra_params = -append "get-time-of-day date=$(date +%s)"
-groups = rtas
+groups = rtas gitlab-ci
 
 [rtas-get-time-of-day-base]
 file = rtas.elf
 machine = pseries
 timeout = 5
 extra_params = -rtc base="2006-06-17" -append "get-time-of-day date=$(date 
--date="2006-06-17 UTC" +%s)"
-groups = rtas
+groups = rtas gitlab-ci
 
 [rtas-set-time-of-day]
 file = rtas.elf
 machine = pseries
 extra_params = -append "set-time-of-day"
 timeout = 5
-groups = rtas
+groups = rtas gitlab-ci
 
 [emulator]
 file = emulator.elf
+groups = gitlab-ci
 
 [interrupts]
 file = interrupts.elf
-- 
2.42.0



[kvm-unit-tests PATCH 31/32] powerpc: Remove remnants of ppc64 directory and build structure

2024-02-26 Thread Nicholas Piggin
This moves merges ppc64 directories and files into powerpc, and
merges the 3 makefiles into one.

The configure --arch=powerpc option is aliased to ppc64 for
good measure.

Signed-off-by: Nicholas Piggin 
---
 MAINTAINERS|   1 -
 configure  |   3 +-
 lib/{ppc64 => powerpc}/asm-offsets.c   |   0
 lib/{ppc64 => powerpc}/asm/asm-offsets.h   |   0
 lib/{ppc64 => powerpc}/asm/atomic.h|   0
 lib/{ppc64 => powerpc}/asm/barrier.h   |   4 +-
 lib/{ppc64 => powerpc}/asm/bitops.h|   4 +-
 lib/{ppc64 => powerpc}/asm/io.h|   4 +-
 lib/{ppc64 => powerpc}/asm/mmu.h   |   0
 lib/{ppc64 => powerpc}/asm/opal.h  |   4 +-
 lib/{ppc64 => powerpc}/asm/page.h  |   6 +-
 lib/{ppc64 => powerpc}/asm/pgtable-hwdef.h |   6 +-
 lib/{ppc64 => powerpc}/asm/pgtable.h   |   2 +-
 lib/{ppc64 => powerpc}/asm/ptrace.h|   6 +-
 lib/{ppc64 => powerpc}/asm/spinlock.h  |   6 +-
 lib/powerpc/asm/stack.h|   3 +
 lib/{ppc64 => powerpc}/asm/vpa.h   |   0
 lib/{ppc64 => powerpc}/mmu.c   |   0
 lib/{ppc64 => powerpc}/opal-calls.S|   0
 lib/{ppc64 => powerpc}/opal.c  |   0
 lib/{ppc64 => powerpc}/stack.c |   0
 lib/ppc64/.gitignore   |   1 -
 lib/ppc64/asm/handlers.h   |   1 -
 lib/ppc64/asm/hcall.h  |   1 -
 lib/ppc64/asm/memory_areas.h   |   6 --
 lib/ppc64/asm/ppc_asm.h|   1 -
 lib/ppc64/asm/processor.h  |   1 -
 lib/ppc64/asm/reg.h|   1 -
 lib/ppc64/asm/rtas.h   |   1 -
 lib/ppc64/asm/setup.h  |   1 -
 lib/ppc64/asm/smp.h|   1 -
 lib/ppc64/asm/stack.h  |  11 --
 powerpc/Makefile   | 111 -
 powerpc/Makefile.common|  95 --
 powerpc/Makefile.ppc64 |  31 --
 35 files changed, 136 insertions(+), 176 deletions(-)
 rename lib/{ppc64 => powerpc}/asm-offsets.c (100%)
 rename lib/{ppc64 => powerpc}/asm/asm-offsets.h (100%)
 rename lib/{ppc64 => powerpc}/asm/atomic.h (100%)
 rename lib/{ppc64 => powerpc}/asm/barrier.h (83%)
 rename lib/{ppc64 => powerpc}/asm/bitops.h (69%)
 rename lib/{ppc64 => powerpc}/asm/io.h (50%)
 rename lib/{ppc64 => powerpc}/asm/mmu.h (100%)
 rename lib/{ppc64 => powerpc}/asm/opal.h (90%)
 rename lib/{ppc64 => powerpc}/asm/page.h (94%)
 rename lib/{ppc64 => powerpc}/asm/pgtable-hwdef.h (93%)
 rename lib/{ppc64 => powerpc}/asm/pgtable.h (99%)
 rename lib/{ppc64 => powerpc}/asm/ptrace.h (89%)
 rename lib/{ppc64 => powerpc}/asm/spinlock.h (54%)
 rename lib/{ppc64 => powerpc}/asm/vpa.h (100%)
 rename lib/{ppc64 => powerpc}/mmu.c (100%)
 rename lib/{ppc64 => powerpc}/opal-calls.S (100%)
 rename lib/{ppc64 => powerpc}/opal.c (100%)
 rename lib/{ppc64 => powerpc}/stack.c (100%)
 delete mode 100644 lib/ppc64/.gitignore
 delete mode 100644 lib/ppc64/asm/handlers.h
 delete mode 100644 lib/ppc64/asm/hcall.h
 delete mode 100644 lib/ppc64/asm/memory_areas.h
 delete mode 100644 lib/ppc64/asm/ppc_asm.h
 delete mode 100644 lib/ppc64/asm/processor.h
 delete mode 100644 lib/ppc64/asm/reg.h
 delete mode 100644 lib/ppc64/asm/rtas.h
 delete mode 100644 lib/ppc64/asm/setup.h
 delete mode 100644 lib/ppc64/asm/smp.h
 delete mode 100644 lib/ppc64/asm/stack.h
 delete mode 100644 powerpc/Makefile.common
 delete mode 100644 powerpc/Makefile.ppc64

diff --git a/MAINTAINERS b/MAINTAINERS
index a2fa437da..1309863f2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -92,7 +92,6 @@ S: Maintained
 L: linuxppc-dev@lists.ozlabs.org
 F: powerpc/
 F: lib/powerpc/
-F: lib/ppc64/
 
 RISCV
 M: Andrew Jones 
diff --git a/configure b/configure
index 8c0e3506f..2dbc101cb 100755
--- a/configure
+++ b/configure
@@ -198,6 +198,7 @@ fi
 
 arch_name=$arch
 [ "$arch" = "aarch64" ] && arch="arm64"
+[ "$arch" = "powerpc" ] && arch="ppc64"
 [ "$arch_name" = "arm64" ] && arch_name="aarch64"
 
 if [ "$arch" = "riscv" ]; then
@@ -315,7 +316,7 @@ elif [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then
 fi
 elif [ "$arch" = "ppc64" ]; then
 testdir=powerpc
-arch_libdir=ppc64
+arch_libdir=powerpc
 firmware="$testdir/boot_rom.bin"
 if [ "$endian" != "little" ] && [ "$endian" != "big" ]; then
 echo "You must provide endianness (big or little)!"
diff --git a/lib/ppc64/asm-offsets.c b/lib/powerpc/asm-offsets.c
similarity index 100%
rename from lib/ppc64/asm-offsets.c
rename to lib/powerpc/

[kvm-unit-tests PATCH 30/32] configure: Make arch_libdir a first-class entity

2024-02-26 Thread Nicholas Piggin
arch_libdir was brought in to improve the heuristic determination of
the lib/ directory based on arch and testdir names, but it did not
entirely clean that mess up.

Remove the arch_libdir->arch->testdir heuristic and just require
everybody sets arch_libdir correctly. Fail if the lib/arch or
lib/arch/asm directories can not be found.

Cc: Alexandru Elisei 
Cc: Andrew Jones 
Cc: Claudio Imbrenda 
Cc: David Hildenbrand 
Cc: Eric Auger 
Cc: Janosch Frank 
Cc: Laurent Vivier 
Cc: Nico Böhr 
Cc: Paolo Bonzini 
Cc: Thomas Huth 
Cc: k...@vger.kernel.org
Cc: linux-s...@vger.kernel.org
Cc: kvm...@lists.linux.dev
Cc: kvm-ri...@lists.infradead.org
Cc: linuxppc-dev@lists.ozlabs.org
Signed-off-by: Nicholas Piggin 
---
 Makefile  |  2 +-
 configure | 18 +-
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
index 4f35fffc6..4e0f54543 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@ include config.mak
 VPATH = $(SRCDIR)
 
 libdirs-get = $(shell [ -d "lib/$(1)" ] && echo "lib/$(1) lib/$(1)/asm")
-ARCH_LIBDIRS := $(call libdirs-get,$(ARCH_LIBDIR)) $(call 
libdirs-get,$(TEST_DIR))
+ARCH_LIBDIRS := $(call libdirs-get,$(ARCH_LIBDIR))
 OBJDIRS := $(ARCH_LIBDIRS)
 
 DESTDIR := $(PREFIX)/share/kvm-unit-tests/
diff --git a/configure b/configure
index ae522c556..8c0e3506f 100755
--- a/configure
+++ b/configure
@@ -199,7 +199,6 @@ fi
 arch_name=$arch
 [ "$arch" = "aarch64" ] && arch="arm64"
 [ "$arch_name" = "arm64" ] && arch_name="aarch64"
-arch_libdir=$arch
 
 if [ "$arch" = "riscv" ]; then
 echo "riscv32 or riscv64 must be specified"
@@ -264,8 +263,10 @@ fi
 
 if [ "$arch" = "i386" ] || [ "$arch" = "x86_64" ]; then
 testdir=x86
+arch_libdir=x86
 elif [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then
 testdir=arm
+arch_libdir=$arch
 if [ "$target" = "qemu" ]; then
 arm_uart_early_addr=0x0900
 elif [ "$target" = "kvmtool" ]; then
@@ -314,6 +315,7 @@ elif [ "$arch" = "arm" ] || [ "$arch" = "arm64" ]; then
 fi
 elif [ "$arch" = "ppc64" ]; then
 testdir=powerpc
+arch_libdir=ppc64
 firmware="$testdir/boot_rom.bin"
 if [ "$endian" != "little" ] && [ "$endian" != "big" ]; then
 echo "You must provide endianness (big or little)!"
@@ -324,6 +326,7 @@ elif [ "$arch" = "riscv32" ] || [ "$arch" = "riscv64" ]; 
then
 arch_libdir=riscv
 elif [ "$arch" = "s390x" ]; then
 testdir=s390x
+arch_libdir=s390x
 else
 echo "arch $arch is not supported!"
 arch=
@@ -333,6 +336,10 @@ if [ ! -d "$srcdir/$testdir" ]; then
 echo "$srcdir/$testdir does not exist!"
 exit 1
 fi
+if [ ! -d "$srcdir/lib/$arch_libdir" ]; then
+echo "$srcdir/lib/$arch_libdir does not exist!"
+exit 1
+fi
 
 if [ "$efi" = "y" ] && [ -f "$srcdir/$testdir/efi/run" ]; then
 ln -fs "$srcdir/$testdir/efi/run" $testdir-run
@@ -395,10 +402,11 @@ fi
 # link lib/asm for the architecture
 rm -f lib/asm
 asm="asm-generic"
-if [ -d "$srcdir/lib/$arch/asm" ]; then
-   asm="$srcdir/lib/$arch/asm"
-elif [ -d "$srcdir/lib/$testdir/asm" ]; then
-   asm="$srcdir/lib/$testdir/asm"
+if [ -d "$srcdir/lib/$arch_libdir/asm" ]; then
+asm="$srcdir/lib/$arch_libdir/asm"
+else
+echo "$srcdir/lib/$arch_libdir/asm does not exist"
+exit 1
 fi
 mkdir -p lib
 ln -sf "$asm" lib/asm
-- 
2.42.0



[kvm-unit-tests PATCH 29/32] configure: Fail on unknown arch

2024-02-26 Thread Nicholas Piggin
configure will accept an unknown arch, and if it is the name of a
directory in the source tree the command will silently succeed. Make
it only accept supported arch names.

Also print the full path of a missing test directory to disambiguate
the error in out of tree builds.

Cc: Alexandru Elisei 
Cc: Andrew Jones 
Cc: Claudio Imbrenda 
Cc: David Hildenbrand 
Cc: Eric Auger 
Cc: Janosch Frank 
Cc: Laurent Vivier 
Cc: Nico Böhr 
Cc: Paolo Bonzini 
Cc: Thomas Huth 
Cc: k...@vger.kernel.org
Cc: linux-s...@vger.kernel.org
Cc: kvm...@lists.linux.dev
Cc: kvm-ri...@lists.infradead.org
Cc: linuxppc-dev@lists.ozlabs.org
Signed-off-by: Nicholas Piggin 
---
 configure | 11 ---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/configure b/configure
index 6907ccbbb..ae522c556 100755
--- a/configure
+++ b/configure
@@ -45,7 +45,8 @@ usage() {
Usage: $0 [options]
 
Options include:
-   --arch=ARCHarchitecture to compile for ($arch)
+   --arch=ARCHarchitecture to compile for ($arch). ARCH 
can be one of:
+  arm, arm64, i386, ppc64, riscv32, riscv64, 
s390x, x86_64
--processor=PROCESSOR  processor to compile for ($arch)
--target=TARGETtarget platform that the tests will be 
running on (qemu or
   kvmtool, default is qemu) (arm/arm64 only)
@@ -321,11 +322,15 @@ elif [ "$arch" = "ppc64" ]; then
 elif [ "$arch" = "riscv32" ] || [ "$arch" = "riscv64" ]; then
 testdir=riscv
 arch_libdir=riscv
+elif [ "$arch" = "s390x" ]; then
+testdir=s390x
 else
-testdir=$arch
+echo "arch $arch is not supported!"
+arch=
+usage
 fi
 if [ ! -d "$srcdir/$testdir" ]; then
-echo "$testdir does not exist!"
+echo "$srcdir/$testdir does not exist!"
 exit 1
 fi
 
-- 
2.42.0



[kvm-unit-tests PATCH 28/32] powerpc: add pmu tests

2024-02-26 Thread Nicholas Piggin
Add some initial PMU testing.

- PMC5/6 tests
- PMAE / PMI test
- BHRB basic tests

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/processor.h |   2 +
 lib/powerpc/asm/reg.h   |   9 +
 lib/powerpc/asm/setup.h |   1 +
 lib/powerpc/setup.c |  23 +++
 powerpc/Makefile.common |   3 +-
 powerpc/pmu.c   | 337 
 powerpc/unittests.cfg   |   3 +
 7 files changed, 377 insertions(+), 1 deletion(-)
 create mode 100644 powerpc/pmu.c

diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index 749155696..28239c610 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -14,6 +14,8 @@ extern bool cpu_has_hv;
 extern bool cpu_has_power_mce;
 extern bool cpu_has_siar;
 extern bool cpu_has_heai;
+extern bool cpu_has_bhrb;
+extern bool cpu_has_p10_bhrb;
 extern bool cpu_has_radix;
 extern bool cpu_has_prefix;
 extern bool cpu_has_sc_lev;
diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index 69ef21adb..602fba1b6 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -40,10 +40,19 @@
 #define SPR_LPIDR  0x13f
 #define SPR_HEIR   0x153
 #define SPR_PTCR   0x1d0
+#define SPR_MMCRA  0x312
+#define   MMCRA_BHRBRD UL(0x0020)
+#define   MMCRA_IFM_MASK   UL(0xc000)
+#define SPR_PMC5   0x317
+#define SPR_PMC6   0x318
 #define SPR_MMCR0  0x31b
 #define   MMCR0_FC UL(0x8000)
+#define   MMCR0_FCPUL(0x2000)
 #define   MMCR0_PMAE   UL(0x0400)
+#define   MMCR0_BHRBA  UL(0x0020)
+#define   MMCR0_FCPC   UL(0x1000)
 #define   MMCR0_PMAO   UL(0x0080)
+#define   MMCR0_FC56   UL(0x0010)
 #define SPR_SIAR   0x31c
 
 /* Machine State Register definitions: */
diff --git a/lib/powerpc/asm/setup.h b/lib/powerpc/asm/setup.h
index 9ca318ce6..8f0b58ed0 100644
--- a/lib/powerpc/asm/setup.h
+++ b/lib/powerpc/asm/setup.h
@@ -10,6 +10,7 @@
 #define NR_CPUS8   /* arbitrarily set for now */
 
 extern uint64_t tb_hz;
+extern uint64_t cpu_hz;
 
 #define NR_MEM_REGIONS 8
 #define MR_F_PRIMARY   (1U << 0)
diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c
index 30b988a5c..42ba06ad1 100644
--- a/lib/powerpc/setup.c
+++ b/lib/powerpc/setup.c
@@ -32,6 +32,7 @@ u32 initrd_size;
 u32 cpu_to_hwid[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) };
 int nr_cpus_present;
 uint64_t tb_hz;
+uint64_t cpu_hz;
 
 struct mem_region mem_regions[NR_MEM_REGIONS];
 phys_addr_t __physical_start, __physical_end;
@@ -41,6 +42,7 @@ struct cpu_set_params {
unsigned icache_bytes;
unsigned dcache_bytes;
uint64_t tb_hz;
+   uint64_t cpu_hz;
 };
 
 static void cpu_set(int fdtnode, u64 regval, void *info)
@@ -94,6 +96,22 @@ static void cpu_set(int fdtnode, u64 regval, void *info)
data = (u32 *)prop->data;
params->tb_hz = fdt32_to_cpu(*data);
 
+   prop = fdt_get_property(dt_fdt(), fdtnode,
+   "ibm,extended-clock-frequency", NULL);
+   if (prop) {
+   data = (u32 *)prop->data;
+   params->cpu_hz = fdt32_to_cpu(*data);
+   params->cpu_hz <<= 32;
+   data = (u32 *)prop->data + 1;
+   params->cpu_hz |= fdt32_to_cpu(*data);
+   } else {
+   prop = fdt_get_property(dt_fdt(), fdtnode,
+   "clock-frequency", NULL);
+   assert(prop != NULL);
+   data = (u32 *)prop->data;
+   params->cpu_hz = fdt32_to_cpu(*data);
+   }
+
read_common_info = true;
}
 }
@@ -102,6 +120,8 @@ bool cpu_has_hv;
 bool cpu_has_power_mce; /* POWER CPU machine checks */
 bool cpu_has_siar;
 bool cpu_has_heai;
+bool cpu_has_bhrb;
+bool cpu_has_p10_bhrb;
 bool cpu_has_radix;
 bool cpu_has_prefix;
 bool cpu_has_sc_lev; /* sc interrupt has LEV field in SRR1 */
@@ -118,12 +138,14 @@ static void cpu_init_params(void)
__icache_bytes = params.icache_bytes;
__dcache_bytes = params.dcache_bytes;
tb_hz = params.tb_hz;
+   cpu_hz = params.cpu_hz;
 
switch (mfspr(SPR_PVR) & PVR_VERSION_MASK) {
case PVR_VER_POWER10:
cpu_has_prefix = true;
cpu_has_sc_lev = true;
cpu_has_pause_short = true;
+   cpu_has_p10_bhrb = true;
case PVR_VER_POWER9:
cpu_has_radix = true;
case PVR_VER_POWER8E:
@@ -132,6 +154,7 @@ static void cpu_init_params(void)
cpu_has_power_mce = true;
cpu_has_heai = true;
cpu_has_siar = true;
+   cpu_has_bhrb = true;
break;
default:
  

[kvm-unit-tests PATCH 27/32] powerpc: add usermode support

2024-02-26 Thread Nicholas Piggin
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 
---
 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 
 #include 
 #include 
+#include 
 #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(_lock);
while (*s)
putchar(*s++);
spin_unlock(_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, usermod

[kvm-unit-tests PATCH 26/32] powerpc: Add sieve.c common test

2024-02-26 Thread Nicholas Piggin
Now that sieve copes with lack of MMU support, it can be run by
powerpc.

Signed-off-by: Nicholas Piggin 
---
 powerpc/Makefile.common | 1 +
 powerpc/sieve.c | 1 +
 powerpc/unittests.cfg   | 3 +++
 3 files changed, 5 insertions(+)
 create mode 12 powerpc/sieve.c

diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index 5871da47a..410a675d9 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -8,6 +8,7 @@ tests-common = \
$(TEST_DIR)/selftest.elf \
$(TEST_DIR)/selftest-migration.elf \
$(TEST_DIR)/memory-verify.elf \
+   $(TEST_DIR)/sieve.elf \
$(TEST_DIR)/spapr_hcall.elf \
$(TEST_DIR)/rtas.elf \
$(TEST_DIR)/emulator.elf \
diff --git a/powerpc/sieve.c b/powerpc/sieve.c
new file mode 12
index 0..fe299f309
--- /dev/null
+++ b/powerpc/sieve.c
@@ -0,0 +1 @@
+../common/sieve.c
\ No newline at end of file
diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index 3ebdf9dd3..008559b43 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -136,3 +136,6 @@ file = sprs.elf
 machine = pseries
 extra_params = -append '-w'
 groups = migration
+
+[sieve]
+file = sieve.elf
-- 
2.42.0



[kvm-unit-tests PATCH 25/32] common/sieve: Support machines without MMU

2024-02-26 Thread Nicholas Piggin
Not all powerpc CPUs provide MMU support. Define vm_available() that is
true by default but archs can override it. Use this to run VM tests.

Cc: Paolo Bonzini 
Cc: Thomas Huth 
Cc: Andrew Jones 
Cc: k...@vger.kernel.org
Signed-off-by: Nicholas Piggin 
---
 common/sieve.c  | 14 --
 lib/ppc64/asm/mmu.h |  1 -
 lib/ppc64/mmu.c |  2 +-
 lib/vmalloc.c   |  7 +++
 lib/vmalloc.h   |  2 ++
 5 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/common/sieve.c b/common/sieve.c
index 8fe05ef13..db084691a 100644
--- a/common/sieve.c
+++ b/common/sieve.c
@@ -40,12 +40,14 @@ int main(void)
 
 printf("starting sieve\n");
 test_sieve("static", static_data, STATIC_SIZE);
-setup_vm();
-test_sieve("mapped", static_data, STATIC_SIZE);
-for (i = 0; i < 3; ++i) {
-   v = malloc(VSIZE);
-   test_sieve("virtual", v, VSIZE);
-   free(v);
+if (vm_available()) {
+   setup_vm();
+   test_sieve("mapped", static_data, STATIC_SIZE);
+   for (i = 0; i < 3; ++i) {
+   v = malloc(VSIZE);
+   test_sieve("virtual", v, VSIZE);
+   free(v);
+   }
 }
 
 return 0;
diff --git a/lib/ppc64/asm/mmu.h b/lib/ppc64/asm/mmu.h
index fadeee4bc..eaff0f1f7 100644
--- a/lib/ppc64/asm/mmu.h
+++ b/lib/ppc64/asm/mmu.h
@@ -3,7 +3,6 @@
 
 #include 
 
-bool vm_available(void);
 bool mmu_enabled(void);
 void mmu_enable(pgd_t *pgtable);
 void mmu_disable(void);
diff --git a/lib/ppc64/mmu.c b/lib/ppc64/mmu.c
index 6adf94151..f1219033a 100644
--- a/lib/ppc64/mmu.c
+++ b/lib/ppc64/mmu.c
@@ -24,7 +24,7 @@
 
 static pgd_t *identity_pgd;
 
-bool vm_available(void)
+bool vm_available(void) /* weak override */
 {
return cpu_has_radix;
 }
diff --git a/lib/vmalloc.c b/lib/vmalloc.c
index 572682576..cf2ef7a70 100644
--- a/lib/vmalloc.c
+++ b/lib/vmalloc.c
@@ -206,10 +206,17 @@ void init_alloc_vpage(void *top)
spin_unlock();
 }
 
+bool __attribute__((__weak__)) vm_available(void)
+{
+   return true;
+}
+
 void __setup_vm(void *opaque)
 {
phys_addr_t base, top;
 
+   assert_msg(vm_available(), "Virtual memory not available. Must check 
vm_available() before calling setup_vm()");
+
if (alloc_ops == _ops)
return;
 
diff --git a/lib/vmalloc.h b/lib/vmalloc.h
index 0269fdde9..e81be39f4 100644
--- a/lib/vmalloc.h
+++ b/lib/vmalloc.h
@@ -17,6 +17,8 @@ extern void setup_vm(void);
 /* As above, plus passes an opaque value to setup_mmu(). */
 extern void __setup_vm(void *opaque);
 
+/* common/ tests must check availability before calling setup_vm() */
+extern bool vm_available(void);
 /* Set up paging */
 extern void *setup_mmu(phys_addr_t top, void *opaque);
 /* Walk the page table and resolve the virtual address to a physical address */
-- 
2.42.0



[kvm-unit-tests PATCH 24/32] common/sieve: Use vmalloc.h for setup_mmu definition

2024-02-26 Thread Nicholas Piggin
There is no good reason to put setup_vm in libcflat.h when it's
defined in vmalloc.h.

Cc: Paolo Bonzini 
Cc: Thomas Huth 
Cc: Andrew Jones 
Cc: Janosch Frank 
Cc: Claudio Imbrenda 
Cc: Nico Böhr 
Cc: David Hildenbrand 
Cc: k...@vger.kernel.org
Cc: linux-s...@vger.kernel.org
Signed-off-by: Nicholas Piggin 
---
 common/sieve.c | 1 +
 lib/libcflat.h | 2 --
 lib/s390x/io.c | 1 +
 lib/s390x/uv.h | 1 +
 lib/x86/vm.h   | 1 +
 s390x/mvpg.c   | 1 +
 s390x/selftest.c   | 1 +
 x86/pmu.c  | 1 +
 x86/pmu_lbr.c  | 1 +
 x86/vmexit.c   | 1 +
 x86/vmware_backdoors.c | 1 +
 11 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/common/sieve.c b/common/sieve.c
index 8150f2d98..8fe05ef13 100644
--- a/common/sieve.c
+++ b/common/sieve.c
@@ -1,5 +1,6 @@
 #include "alloc.h"
 #include "libcflat.h"
+#include "vmalloc.h"
 
 static int sieve(char* data, int size)
 {
diff --git a/lib/libcflat.h b/lib/libcflat.h
index 700f43527..8c8dd0286 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -152,8 +152,6 @@ do {
\
 void binstr(unsigned long x, char out[BINSTR_SZ]);
 void print_binstr(unsigned long x);
 
-extern void setup_vm(void);
-
 #endif /* !__ASSEMBLY__ */
 
 #define SZ_256 (1 << 8)
diff --git a/lib/s390x/io.c b/lib/s390x/io.c
index fb7b7ddaa..2b28ccaa0 100644
--- a/lib/s390x/io.c
+++ b/lib/s390x/io.c
@@ -10,6 +10,7 @@
  */
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
diff --git a/lib/s390x/uv.h b/lib/s390x/uv.h
index 286933caa..00a370410 100644
--- a/lib/s390x/uv.h
+++ b/lib/s390x/uv.h
@@ -4,6 +4,7 @@
 
 #include 
 #include 
+#include 
 
 bool uv_os_is_guest(void);
 bool uv_os_is_host(void);
diff --git a/lib/x86/vm.h b/lib/x86/vm.h
index 4b714bad7..cf39787aa 100644
--- a/lib/x86/vm.h
+++ b/lib/x86/vm.h
@@ -2,6 +2,7 @@
 #define _X86_VM_H_
 
 #include "processor.h"
+#include "vmalloc.h"
 #include "asm/page.h"
 #include "asm/io.h"
 #include "asm/bitops.h"
diff --git a/s390x/mvpg.c b/s390x/mvpg.c
index 296338d4f..a0cfc575a 100644
--- a/s390x/mvpg.c
+++ b/s390x/mvpg.c
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
diff --git a/s390x/selftest.c b/s390x/selftest.c
index 92ed4e5d3..3eaae9b06 100644
--- a/s390x/selftest.c
+++ b/s390x/selftest.c
@@ -9,6 +9,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
diff --git a/x86/pmu.c b/x86/pmu.c
index 47a1a602a..7062c1ad9 100644
--- a/x86/pmu.c
+++ b/x86/pmu.c
@@ -6,6 +6,7 @@
 #include "x86/apic.h"
 #include "x86/desc.h"
 #include "x86/isr.h"
+#include "vmalloc.h"
 #include "alloc.h"
 
 #include "libcflat.h"
diff --git a/x86/pmu_lbr.c b/x86/pmu_lbr.c
index 40b63fa3d..c6f010847 100644
--- a/x86/pmu_lbr.c
+++ b/x86/pmu_lbr.c
@@ -2,6 +2,7 @@
 #include "x86/processor.h"
 #include "x86/pmu.h"
 #include "x86/desc.h"
+#include "vmalloc.h"
 
 #define N 100
 
diff --git a/x86/vmexit.c b/x86/vmexit.c
index eb5d3023a..48a38f60f 100644
--- a/x86/vmexit.c
+++ b/x86/vmexit.c
@@ -1,6 +1,7 @@
 #include "libcflat.h"
 #include "acpi.h"
 #include "smp.h"
+#include "vmalloc.h"
 #include "pci.h"
 #include "x86/vm.h"
 #include "x86/desc.h"
diff --git a/x86/vmware_backdoors.c b/x86/vmware_backdoors.c
index bc1002056..f8cf7ecb1 100644
--- a/x86/vmware_backdoors.c
+++ b/x86/vmware_backdoors.c
@@ -6,6 +6,7 @@
 #include "x86/desc.h"
 #include "x86/isr.h"
 #include "alloc.h"
+#include "vmalloc.h"
 #include "setjmp.h"
 #include "usermode.h"
 #include "fault_test.h"
-- 
2.42.0



[kvm-unit-tests PATCH 23/32] powerpc: Add MMU support

2024-02-26 Thread Nicholas Piggin
Add support for radix MMU, 4kB and 64kB pages.

This also adds MMU interrupt test cases, and runs the interrupts
test entirely with MMU enabled if it is available (aside from
machine check tests).

Signed-off-by: Nicholas Piggin 
---
 configure |  39 +++--
 lib/powerpc/asm/hcall.h   |   6 +
 lib/powerpc/asm/processor.h   |   1 +
 lib/powerpc/asm/reg.h |   3 +
 lib/powerpc/asm/smp.h |   2 +
 lib/powerpc/processor.c   |   9 ++
 lib/powerpc/setup.c   |   4 +
 lib/ppc64/asm/mmu.h   |  11 ++
 lib/ppc64/asm/page.h  |  67 -
 lib/ppc64/asm/pgtable-hwdef.h |  67 +
 lib/ppc64/asm/pgtable.h   | 126 
 lib/ppc64/mmu.c   | 273 ++
 lib/ppc64/opal-calls.S|   4 +-
 powerpc/Makefile.common   |   2 +
 powerpc/Makefile.ppc64|   1 +
 powerpc/interrupts.c  |  96 ++--
 16 files changed, 684 insertions(+), 27 deletions(-)
 create mode 100644 lib/ppc64/asm/mmu.h
 create mode 100644 lib/ppc64/asm/pgtable-hwdef.h
 create mode 100644 lib/ppc64/asm/pgtable.h
 create mode 100644 lib/ppc64/mmu.c

diff --git a/configure b/configure
index 05e6702ea..6907ccbbb 100755
--- a/configure
+++ b/configure
@@ -222,29 +222,35 @@ fi
 if [ -z "$page_size" ]; then
 if [ "$efi" = 'y' ] && [ "$arch" = "arm64" ]; then
 page_size="4096"
-elif [ "$arch" = "arm64" ]; then
+elif [ "$arch" = "arm64" ] || [ "$arch" = "ppc64" ]; then
 page_size="65536"
 elif [ "$arch" = "arm" ]; then
 page_size="4096"
 fi
 else
-if [ "$arch" != "arm64" ]; then
-echo "--page-size is not supported for $arch"
-usage
-fi
-
 if [ "${page_size: -1}" = "K" ] || [ "${page_size: -1}" = "k" ]; then
 page_size=$(( ${page_size%?} * 1024 ))
 fi
-if [ "$page_size" != "4096" ] && [ "$page_size" != "16384" ] &&
-   [ "$page_size" != "65536" ]; then
-echo "arm64 doesn't support page size of $page_size"
+
+if [ "$arch" = "arm64" ]; then
+if [ "$page_size" != "4096" ] && [ "$page_size" != "16384" ] &&
+   [ "$page_size" != "65536" ]; then
+echo "arm64 doesn't support page size of $page_size"
+usage
+fi
+if [ "$efi" = 'y' ] && [ "$page_size" != "4096" ]; then
+echo "efi must use 4K pages"
+exit 1
+fi
+elif [ "$arch" = "ppc64" ]; then
+if [ "$page_size" != "4096" ] && [ "$page_size" != "65536" ]; then
+echo "ppc64 doesn't support page size of $page_size"
+usage
+fi
+else
+echo "--page-size is not supported for $arch"
 usage
 fi
-if [ "$efi" = 'y' ] && [ "$page_size" != "4096" ]; then
-echo "efi must use 4K pages"
-exit 1
-fi
 fi
 
 [ -z "$processor" ] && processor="$arch"
@@ -444,6 +450,13 @@ cat <> lib/config.h
 
 #define CONFIG_UART_EARLY_BASE ${arm_uart_early_addr}
 #define CONFIG_ERRATA_FORCE ${errata_force}
+
+EOF
+fi
+
+if [ "$arch" = "arm" ] || [ "$arch" = "arm64" ] || [ "$arch" = "ppc64" ]; then
+cat <> lib/config.h
+
 #define CONFIG_PAGE_SIZE _AC(${page_size}, UL)
 
 EOF
diff --git a/lib/powerpc/asm/hcall.h b/lib/powerpc/asm/hcall.h
index e0f5009e3..3b44dd204 100644
--- a/lib/powerpc/asm/hcall.h
+++ b/lib/powerpc/asm/hcall.h
@@ -24,6 +24,12 @@
 #define H_PUT_TERM_CHAR0x58
 #define H_RANDOM   0x300
 #define H_SET_MODE 0x31C
+#define H_REGISTER_PROCESS_TABLE   0x37C
+
+#define PTBL_NEW   0x18
+#define PTBL_UNREGISTER0x10
+#define PTBL_RADIX 0x04
+#define PTBL_GTSE  0x01
 
 #define KVMPPC_HCALL_BASE  0xf000
 #define KVMPPC_H_RTAS  (KVMPPC_HCALL_BASE + 0x0)
diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index a3859b5d4..d348239c5 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -14,6 +14,7 @@ extern bool cpu_has_hv;
 extern bool cpu_has_power_mce;
 extern bool cpu_has_siar;
 extern bool cpu_has_heai;
+extern bool cpu_has_radix;
 extern bool cpu_has_prefix;
 extern bool cpu_has_sc_lev;
 extern bool cpu_has_pause_short;
diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h

[kvm-unit-tests PATCH 22/32] powerpc: Add timebase tests

2024-02-26 Thread Nicholas Piggin
This has a known failure on QEMU TCG machines where the decrementer
interrupt is not lowered when the DEC wraps from -ve to +ve.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/reg.h   |   1 +
 powerpc/Makefile.common |   1 +
 powerpc/timebase.c  | 330 
 powerpc/unittests.cfg   |   8 +
 4 files changed, 340 insertions(+)
 create mode 100644 powerpc/timebase.c

diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index d2ca964c4..12f9e8ac6 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -35,6 +35,7 @@
 #define SPR_HSRR1  0x13b
 #define SPR_LPCR   0x13e
 #define   LPCR_HDICE   UL(0x1)
+#define   LPCR_LD  UL(0x2)
 #define SPR_HEIR   0x153
 #define SPR_MMCR0  0x31b
 #define   MMCR0_FC UL(0x8000)
diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index b6f9b3b85..1348f658b 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -15,6 +15,7 @@ tests-common = \
$(TEST_DIR)/tm.elf \
$(TEST_DIR)/smp.elf \
$(TEST_DIR)/sprs.elf \
+   $(TEST_DIR)/timebase.elf \
$(TEST_DIR)/interrupts.elf
 
 tests-all = $(tests-common) $(tests)
diff --git a/powerpc/timebase.c b/powerpc/timebase.c
new file mode 100644
index 0..6d8d54cb1
--- /dev/null
+++ b/powerpc/timebase.c
@@ -0,0 +1,330 @@
+/*
+ * Test Timebase
+ *
+ * Copyright 2024 Nicholas Piggin, IBM Corp.
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ *
+ * This contains tests of timebase facility, TB, DEC, etc.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static int dec_bits = 0;
+
+static void cpu_dec_bits(int fdtnode, u64 regval __unused, void *arg __unused)
+{
+   const struct fdt_property *prop;
+   int plen;
+
+   prop = fdt_get_property(dt_fdt(), fdtnode, "ibm,dec-bits", );
+   if (!prop) {
+   dec_bits = 32;
+   return;
+   }
+
+   /* Sanity check for the property layout (first two bytes are header) */
+   assert(plen == 4);
+
+   dec_bits = fdt32_to_cpu(*(uint32_t *)prop->data);
+}
+
+/* Check amount of CPUs nodes that have the TM flag */
+static int find_dec_bits(void)
+{
+   int ret;
+
+   ret = dt_for_each_cpu_node(cpu_dec_bits, NULL);
+   if (ret < 0)
+   return ret;
+
+   return dec_bits;
+}
+
+
+static bool do_migrate = false;
+static volatile bool got_interrupt;
+static volatile struct pt_regs recorded_regs;
+
+static uint64_t dec_max;
+static uint64_t dec_min;
+
+static void test_tb(int argc, char **argv)
+{
+   uint64_t tb;
+
+   tb = get_tb();
+   if (do_migrate)
+   migrate();
+   report(get_tb() >= tb, "timebase is incrementing");
+}
+
+static void dec_stop_handler(struct pt_regs *regs, void *data)
+{
+   mtspr(SPR_DEC, dec_max);
+}
+
+static void dec_handler(struct pt_regs *regs, void *data)
+{
+   got_interrupt = true;
+   memcpy((void *)_regs, regs, sizeof(struct pt_regs));
+   regs->msr &= ~MSR_EE;
+}
+
+static void test_dec(int argc, char **argv)
+{
+   uint64_t tb1, tb2, dec;
+   int i;
+
+   handle_exception(0x900, _handler, NULL);
+
+   for (i = 0; i < 100; i++) {
+   tb1 = get_tb();
+   mtspr(SPR_DEC, dec_max);
+   dec = mfspr(SPR_DEC);
+   tb2 = get_tb();
+   if (tb2 - tb1 < dec_max - dec)
+   break;
+   }
+   report(tb2 - tb1 >= dec_max - dec, "decrementer remains within TB after 
mtDEC");
+
+   tb1 = get_tb();
+   mtspr(SPR_DEC, dec_max);
+   mdelay(1000);
+   dec = mfspr(SPR_DEC);
+   tb2 = get_tb();
+   report(tb2 - tb1 >= dec_max - dec, "decrementer remains within TB after 
1s");
+
+   mtspr(SPR_DEC, dec_max);
+   local_irq_enable();
+   local_irq_disable();
+   if (mfspr(SPR_DEC) <= dec_max) {
+   report(!got_interrupt, "no interrupt on decrementer positive");
+   }
+   got_interrupt = false;
+
+   mtspr(SPR_DEC, 1);
+   mdelay(100); /* Give the timer a chance to run */
+   if (do_migrate)
+   migrate();
+   local_irq_enable();
+   local_irq_disable();
+   report(got_interrupt, "interrupt on decrementer underflow");
+   got_interrupt = false;
+
+   if (do_migrate)
+   migrate();
+   local_irq_enable();
+   local_irq_disable();
+   report(got_interrupt, "interrupt on decrementer still underflown");
+   got_interrupt = false;
+
+   mtspr(SPR_DEC, 0);
+   mdelay(100); /* Give the timer a chance to run */
+   if (do_migrate)
+   migrate();
+   local_irq_enable();
+   local_irq_disable();
+   report(got_interrupt, "DEC deal with set to 0");
+

[kvm-unit-tests PATCH 21/32] powerpc: Add atomics tests

2024-02-26 Thread Nicholas Piggin
Signed-off-by: Nicholas Piggin 
---
 powerpc/Makefile.common |   1 +
 powerpc/atomics.c   | 373 
 powerpc/unittests.cfg   |   9 +
 3 files changed, 383 insertions(+)
 create mode 100644 powerpc/atomics.c

diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index 02af54b83..b6f9b3b85 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -11,6 +11,7 @@ tests-common = \
$(TEST_DIR)/spapr_hcall.elf \
$(TEST_DIR)/rtas.elf \
$(TEST_DIR)/emulator.elf \
+   $(TEST_DIR)/atomics.elf \
$(TEST_DIR)/tm.elf \
$(TEST_DIR)/smp.elf \
$(TEST_DIR)/sprs.elf \
diff --git a/powerpc/atomics.c b/powerpc/atomics.c
new file mode 100644
index 0..d79e70eaa
--- /dev/null
+++ b/powerpc/atomics.c
@@ -0,0 +1,373 @@
+/*
+ * Test some powerpc instructions
+ *
+ * Copyright 2024 Nicholas Piggin, IBM Corp.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+static bool do_migrate;
+static bool do_record;
+
+#define RSV_SIZE 128
+
+static uint8_t granule[RSV_SIZE] __attribute((__aligned__(RSV_SIZE)));
+
+static void spin_lock(unsigned int *lock)
+{
+   unsigned int old;
+
+   asm volatile ("1:"
+ "lwarx%0,0,%2;"
+ "cmpwi%0,0;"
+ "bne  1b;"
+ "stwcx.   %1,0,%2;"
+ "bne- 1b;"
+ "lwsync;"
+ : "="(old) : "r"(1), "r"(lock) : "cr0", "memory");
+}
+
+static void spin_unlock(unsigned int *lock)
+{
+   asm volatile("lwsync;"
+"stw   %1,%0;"
+: "+m"(*lock) : "r"(0) : "memory");
+}
+
+static volatile bool got_interrupt;
+static volatile struct pt_regs recorded_regs;
+
+static void interrupt_handler(struct pt_regs *regs, void *opaque)
+{
+   assert(!got_interrupt);
+   got_interrupt = true;
+   memcpy((void *)_regs, regs, sizeof(struct pt_regs));
+   regs_advance_insn(regs);
+}
+
+static void test_lwarx_stwcx(int argc, char *argv[])
+{
+   unsigned int *var = (unsigned int *)granule;
+   unsigned int old;
+   unsigned int result;
+
+   *var = 0;
+   asm volatile ("1:"
+ "lwarx%0,0,%2;"
+ "stwcx.   %1,0,%2;"
+ "bne- 1b;"
+ : "="(old) : "r"(1), "r"(var) : "cr0", "memory");
+   report(old == 0 && *var == 1, "simple update");
+
+   *var = 0;
+   asm volatile ("li   %0,0;"
+ "stwcx.   %1,0,%2;"
+ "stwcx.   %1,0,%2;"
+ "bne- 1f;"
+ "li   %0,1;"
+ "1:"
+ : "="(result)
+ : "r"(1), "r"(var) : "cr0", "memory");
+   report(result == 0 && *var == 0, "failed stwcx. (no reservation)");
+
+   *var = 0;
+   asm volatile ("li   %0,0;"
+ "lwarx%1,0,%4;"
+ "stw  %3,0(%4);"
+ "stwcx.   %2,0,%4;"
+ "bne- 1f;"
+ "li   %0,1;"
+ "1:"
+ : "="(result), "="(old)
+ : "r"(1), "r"(2), "r"(var) : "cr0", "memory");
+   /* This is implementation specific, so don't fail */
+   if (result == 0 && *var == 2)
+   report(true, "failed stwcx. (intervening store)");
+   else
+   report(true, "succeeded stwcx. (intervening store)");
+
+   handle_exception(0x600, interrupt_handler, NULL);
+   handle_exception(0x700, interrupt_handler, NULL);
+
+   /* Implementations may not necessarily invoke the alignment interrupt */
+   old = 10;
+   *var = 0;
+   asm volatile (
+ "lwarx%0,0,%1;"
+ : "+"(old) : "r"((char *)var + 1));
+   report(old == 10 && got_interrupt && recorded_regs.trap == 0x600, 
"unaligned lwarx causes fault");
+   got_interrupt = false;
+
+   /*
+* Unaligned stwcx. is more difficult to test, at least under QEMU,
+* the store does not proceed if there is no matching reservation, so
+* the alignment handler does not get invoked. This is okay according
+  

[kvm-unit-tests PATCH 20/32] powerpc: Avoid using larx/stcx. in spinlocks when only one CPU is running

2024-02-26 Thread Nicholas Piggin
The test harness uses spinlocks if they are implemented with larx/stcx.
it can prevent some test scenarios such as testing migration of a
reservation.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/smp.h|  1 +
 lib/powerpc/smp.c|  5 +
 lib/powerpc/spinlock.c   | 28 
 lib/ppc64/asm/spinlock.h |  7 ++-
 powerpc/Makefile.common  |  1 +
 5 files changed, 41 insertions(+), 1 deletion(-)
 create mode 100644 lib/powerpc/spinlock.c

diff --git a/lib/powerpc/asm/smp.h b/lib/powerpc/asm/smp.h
index 4519e5436..6ef3ae521 100644
--- a/lib/powerpc/asm/smp.h
+++ b/lib/powerpc/asm/smp.h
@@ -15,6 +15,7 @@ struct cpu {
 
 extern int nr_cpus_present;
 extern int nr_cpus_online;
+extern bool multithreaded;
 extern struct cpu cpus[];
 
 register struct cpu *__current_cpu asm("r13");
diff --git a/lib/powerpc/smp.c b/lib/powerpc/smp.c
index a3bf85d44..f3b2a3faf 100644
--- a/lib/powerpc/smp.c
+++ b/lib/powerpc/smp.c
@@ -276,6 +276,8 @@ static void start_each_secondary(int fdtnode, u64 regval 
__unused, void *info)
start_core(fdtnode, datap->entry);
 }
 
+bool multithreaded = false;
+
 /*
  * Start all stopped cpus on the guest at entry with register 3 set to r3
  * We expect that we come in with only one thread currently started
@@ -290,6 +292,7 @@ bool start_all_cpus(secondary_entry_fn entry)
 
assert(nr_cpus_online == 1);
assert(nr_started == 1);
+   multithreaded = true;
ret = dt_for_each_cpu_node(start_each_secondary, );
assert(ret == 0);
assert(nr_started == nr_cpus_present);
@@ -308,8 +311,10 @@ bool start_all_cpus(secondary_entry_fn entry)
 
 void stop_all_cpus(void)
 {
+   assert(multithreaded);
while (nr_cpus_online > 1)
cpu_relax();
mb();
nr_started = 1;
+   multithreaded = false;
 }
diff --git a/lib/powerpc/spinlock.c b/lib/powerpc/spinlock.c
new file mode 100644
index 0..238549f12
--- /dev/null
+++ b/lib/powerpc/spinlock.c
@@ -0,0 +1,28 @@
+#include 
+#include 
+
+/*
+ * Skip the atomic when single-threaded, which helps avoid larx/stcx. in
+ * the harness when testing tricky larx/stcx. sequences (e.g., migration
+ * vs reservation).
+ */
+void spin_lock(struct spinlock *lock)
+{
+   if (!multithreaded) {
+   assert(lock->v == 0);
+   lock->v = 1;
+   } else {
+   while (__sync_lock_test_and_set(>v, 1))
+   ;
+   }
+}
+
+void spin_unlock(struct spinlock *lock)
+{
+   assert(lock->v == 1);
+   if (!multithreaded) {
+   lock->v = 0;
+   } else {
+   __sync_lock_release(>v);
+   }
+}
diff --git a/lib/ppc64/asm/spinlock.h b/lib/ppc64/asm/spinlock.h
index f59eed191..b952386da 100644
--- a/lib/ppc64/asm/spinlock.h
+++ b/lib/ppc64/asm/spinlock.h
@@ -1,6 +1,11 @@
 #ifndef _ASMPPC64_SPINLOCK_H_
 #define _ASMPPC64_SPINLOCK_H_
 
-#include 
+struct spinlock {
+   unsigned int v;
+};
+
+void spin_lock(struct spinlock *lock);
+void spin_unlock(struct spinlock *lock);
 
 #endif /* _ASMPPC64_SPINLOCK_H_ */
diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index 744dfc1f7..02af54b83 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -48,6 +48,7 @@ cflatobjs += lib/powerpc/rtas.o
 cflatobjs += lib/powerpc/processor.o
 cflatobjs += lib/powerpc/handlers.o
 cflatobjs += lib/powerpc/smp.o
+cflatobjs += lib/powerpc/spinlock.o
 
 OBJDIRS += lib/powerpc
 
-- 
2.42.0



[kvm-unit-tests PATCH 19/32] powerpc: Permit ACCEL=tcg,thread=single

2024-02-26 Thread Nicholas Piggin
Modify run script to permit single vs mttcg threading, add a
thread=single smp case to unittests.cfg.

Signed-off-by: Nicholas Piggin 
---
 powerpc/run   | 4 ++--
 powerpc/unittests.cfg | 6 ++
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/powerpc/run b/powerpc/run
index 172f32a46..27abf1ef6 100755
--- a/powerpc/run
+++ b/powerpc/run
@@ -36,8 +36,8 @@ if ! $qemu -machine '?' 2>&1 | grep $MACHINE > /dev/null; then
exit 2
 fi
 
+A="-accel $ACCEL$ACCEL_PROPS"
 M="-machine $MACHINE"
-M+=",accel=$ACCEL$ACCEL_PROPS"
 B=""
 D=""
 
@@ -54,7 +54,7 @@ if [[ "$MACHINE" == "powernv"* ]] ; then
D+="-device ipmi-bmc-sim,id=bmc0 -device isa-ipmi-bt,bmc=bmc0,irq=10"
 fi
 
-command="$qemu -nodefaults $M $B $D"
+command="$qemu -nodefaults $A $M $B $D"
 command+=" -display none -serial stdio -kernel"
 command="$(migration_cmd) $(timeout_cmd) $command"
 
diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index 97a549c0d..915b6a482 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -97,6 +97,12 @@ smp = 2
 file = smp.elf
 smp = 8,threads=4
 
+# mttcg is the default most places, so add a thread=single test
+[smp-thread-single]
+file = smp.elf
+smp = 8,threads=4
+accel = tcg,thread=single
+
 [h_cede_tm]
 file = tm.elf
 machine = pseries
-- 
2.42.0



[kvm-unit-tests PATCH 18/32] powerpc: add SMP and IPI support

2024-02-26 Thread Nicholas Piggin
powerpc SMP support is very primitive and does not set up a first-class
runtime environment for secondary CPUs.

This reworks SMP support, and provides a complete C and harness
environment for the secondaries, including interrupt handling, as well
as IPI support.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/processor.h |  23 +++
 lib/powerpc/asm/reg.h   |   1 +
 lib/powerpc/asm/setup.h |   2 -
 lib/powerpc/asm/smp.h   |  46 +++--
 lib/powerpc/io.c|  15 +-
 lib/powerpc/processor.c |   7 +-
 lib/powerpc/setup.c |  90 +++---
 lib/powerpc/smp.c   | 282 +
 lib/ppc64/asm-offsets.c |   7 +
 lib/ppc64/asm/atomic.h  |   6 +
 lib/ppc64/asm/barrier.h |   3 +
 lib/ppc64/asm/opal.h|   7 +
 powerpc/Makefile.common |   1 +
 powerpc/cstart64.S  |  52 +-
 powerpc/selftest.c  |   4 +-
 powerpc/smp.c   | 349 
 powerpc/tm.c|   4 +-
 powerpc/unittests.cfg   |   8 +
 18 files changed, 822 insertions(+), 85 deletions(-)
 create mode 100644 lib/ppc64/asm/atomic.h
 create mode 100644 powerpc/smp.c

diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index eed37d1f4..a3859b5d4 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -16,6 +16,7 @@ extern bool cpu_has_siar;
 extern bool cpu_has_heai;
 extern bool cpu_has_prefix;
 extern bool cpu_has_sc_lev;
+extern bool cpu_has_pause_short;
 
 static inline uint64_t mfspr(int nr)
 {
@@ -45,6 +46,28 @@ static inline void mtmsr(uint64_t msr)
asm volatile ("mtmsrd %[msr]" :: [msr] "r" (msr) : "memory");
 }
 
+static inline void local_irq_enable(void)
+{
+   unsigned long msr;
+
+   asm volatile(
+"  mfmsr   %0  \n \
+   ori %0,%0,%1\n \
+   mtmsrd  %0,1"
+   : "=r"(msr) : "i"(MSR_EE): "memory");
+}
+
+static inline void local_irq_disable(void)
+{
+   unsigned long msr;
+
+   asm volatile(
+"  mfmsr   %0  \n \
+   andc%0,%0,%1\n \
+   mtmsrd  %0,1"
+   : "=r"(msr) : "r"(MSR_EE): "memory");
+}
+
 /*
  * This returns true on PowerNV / OPAL machines which run in hypervisor
  * mode. False on pseries / PAPR machines that run in guest mode.
diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index d6097f48f..d2ca964c4 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -19,6 +19,7 @@
 #define SPR_SPRG1  0x111
 #define SPR_SPRG2  0x112
 #define SPR_SPRG3  0x113
+#define SPR_TBU40  0x11e
 #define SPR_PVR0x11f
 #define   PVR_VERSION_MASK UL(0x)
 #define   PVR_VER_970  UL(0x0039)
diff --git a/lib/powerpc/asm/setup.h b/lib/powerpc/asm/setup.h
index cc7cf5e25..9ca318ce6 100644
--- a/lib/powerpc/asm/setup.h
+++ b/lib/powerpc/asm/setup.h
@@ -8,8 +8,6 @@
 #include 
 
 #define NR_CPUS8   /* arbitrarily set for now */
-extern u32 cpus[NR_CPUS];
-extern int nr_cpus;
 
 extern uint64_t tb_hz;
 
diff --git a/lib/powerpc/asm/smp.h b/lib/powerpc/asm/smp.h
index 21940b4bc..4519e5436 100644
--- a/lib/powerpc/asm/smp.h
+++ b/lib/powerpc/asm/smp.h
@@ -2,21 +2,45 @@
 #define _ASMPOWERPC_SMP_H_
 
 #include 
+#include 
 
-extern int nr_threads;
+typedef void (*secondary_entry_fn)(int cpu_id);
 
-struct start_threads {
-   int nr_threads;
-   int nr_started;
-};
+struct cpu {
+   unsigned long server_no;
+   unsigned long stack;
+   unsigned long exception_stack;
+   secondary_entry_fn entry;
+} __attribute__((packed)); /* used by asm */
 
-typedef void (*secondary_entry_fn)(void);
+extern int nr_cpus_present;
+extern int nr_cpus_online;
+extern struct cpu cpus[];
 
-extern void halt(void);
+register struct cpu *__current_cpu asm("r13");
+static inline struct cpu *current_cpu(void)
+{
+   return __current_cpu;
+}
 
-extern int start_thread(int cpu_id, secondary_entry_fn entry, uint32_t r3);
-extern struct start_threads start_cpu(int cpu_node, secondary_entry_fn entry,
- uint32_t r3);
-extern bool start_all_cpus(secondary_entry_fn entry, uint32_t r3);
+static inline int smp_processor_id(void)
+{
+   return current_cpu()->server_no;
+}
+
+void cpu_init(struct cpu *cpu, int cpu_id);
+
+extern void halt(int cpu_id);
+
+extern bool start_all_cpus(secondary_entry_fn entry);
+extern void stop_all_cpus(void);
+
+struct pt_regs;
+void register_ipi(void (*fn)(struct pt_regs *, void *), void *data);
+void unregister_ipi(void);
+void cpu_init_ipis(void);
+void local_ipi_enable(void);
+void local_ipi_disable(void);
+void send_ipi(int cpu_id);
 
 #endif /* _ASMPOWERPC_SMP_H_ */
diff --git a/lib/powerpc/io.c b/l

[kvm-unit-tests PATCH 17/32] arch-run: Fix handling multiple exit status messages

2024-02-26 Thread Nicholas Piggin
In SMP tests, it's possible for multiple CPUs to print an exit
message if they abort concurrently, confusing the harness:

  EXIT: STATUS=127

  EXIT: STATUS=127
  scripts/arch-run.bash: line 85: [: too many arguments
  scripts/arch-run.bash: line 93: return: too many arguments

lib/arch code should probably serialise this to prevent it, but
at the moment not all do. So make the parser handle this by
just looking at the first EXIT.

Cc: Paolo Bonzini 
Cc: Thomas Huth 
Cc: Andrew Jones 
Cc: k...@vger.kernel.org
Signed-off-by: Nicholas Piggin 
---
 scripts/arch-run.bash | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/arch-run.bash b/scripts/arch-run.bash
index 5c7e72036..4af670f1c 100644
--- a/scripts/arch-run.bash
+++ b/scripts/arch-run.bash
@@ -79,7 +79,7 @@ run_qemu_status ()
exec {stdout}>&-
 
if [ $ret -eq 1 ]; then
-   testret=$(grep '^EXIT: ' <<<"$lines" | sed 
's/.*STATUS=\([0-9][0-9]*\).*/\1/')
+   testret=$(grep '^EXIT: ' <<<"$lines" | head -n1 | sed 
's/.*STATUS=\([0-9][0-9]*\).*/\1/')
if [ "$testret" ]; then
if [ $testret -eq 1 ]; then
ret=0
-- 
2.42.0



[kvm-unit-tests PATCH 16/32] powerpc: Remove broken SMP exception stack setup

2024-02-26 Thread Nicholas Piggin
The exception stack setup does not work correctly for SMP, because
it is the boot processor that calls cpu_set() which sets SPRG2 to
the exception stack, not the target CPU itself. So secondaries
never got their SPRG2 set to a valid exception stack.

Remove the SMP code and just set an exception stack for the boot
processor. Make the stack 64kB while we're here, to match the
size of the regular stack.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/setup.c | 16 
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c
index 9b665f59c..496af40f8 100644
--- a/lib/powerpc/setup.c
+++ b/lib/powerpc/setup.c
@@ -42,10 +42,6 @@ struct cpu_set_params {
uint64_t tb_hz;
 };
 
-#define EXCEPTION_STACK_SIZE   (32*1024) /* 32kB */
-
-static char exception_stack[NR_CPUS][EXCEPTION_STACK_SIZE];
-
 static void cpu_set(int fdtnode, u64 regval, void *info)
 {
static bool read_common_info = false;
@@ -56,10 +52,6 @@ static void cpu_set(int fdtnode, u64 regval, void *info)
 
cpus[cpu] = regval;
 
-   /* set exception stack address for this CPU (in SPGR0) */
-   asm volatile ("mtsprg0 %[addr]" ::
- [addr] "r" (exception_stack[cpu + 1]));
-
if (!read_common_info) {
const struct fdt_property *prop;
u32 *data;
@@ -180,6 +172,10 @@ static void mem_init(phys_addr_t freemem_start)
 ? __icache_bytes : __dcache_bytes);
 }
 
+#define EXCEPTION_STACK_SIZE   SZ_64K
+
+static char boot_exception_stack[EXCEPTION_STACK_SIZE];
+
 void setup(const void *fdt)
 {
void *freemem = 
@@ -189,6 +185,10 @@ void setup(const void *fdt)
 
cpu_has_hv = !!(mfmsr() & (1ULL << MSR_HV_BIT));
 
+   /* set exception stack address for this CPU (in SPGR0) */
+   asm volatile ("mtsprg0 %[addr]" ::
+ [addr] "r" (boot_exception_stack));
+
enable_mcheck();
 
/*
-- 
2.42.0



[kvm-unit-tests PATCH 15/32] powerpc: Add rtas stop-self support

2024-02-26 Thread Nicholas Piggin
In preparation for improved SMP support, add stop-self support to the
harness. This is non-trivial because it requires an unlocked rtas
call: a CPU can't be holding a spin lock when it goes offline or it
will deadlock other CPUs. rtas permits stop-self to be called without
serialising all other rtas operations.

Reviewed-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/rtas.h |  2 ++
 lib/powerpc/rtas.c | 78 +-
 2 files changed, 64 insertions(+), 16 deletions(-)

diff --git a/lib/powerpc/asm/rtas.h b/lib/powerpc/asm/rtas.h
index 6fb407a18..364bf9355 100644
--- a/lib/powerpc/asm/rtas.h
+++ b/lib/powerpc/asm/rtas.h
@@ -23,8 +23,10 @@ struct rtas_args {
 extern void rtas_init(void);
 extern int rtas_token(const char *service, uint32_t *token);
 extern int rtas_call(int token, int nargs, int nret, int *outputs, ...);
+extern int rtas_call_unlocked(struct rtas_args *args, int token, int nargs, 
int nret, int *outputs, ...);
 
 extern void rtas_power_off(void);
+extern void rtas_stop_self(void);
 #endif /* __ASSEMBLY__ */
 
 #define RTAS_MSR_MASK 0xfffe
diff --git a/lib/powerpc/rtas.c b/lib/powerpc/rtas.c
index 41c0a243e..b477a38e0 100644
--- a/lib/powerpc/rtas.c
+++ b/lib/powerpc/rtas.c
@@ -87,40 +87,86 @@ int rtas_token(const char *service, uint32_t *token)
return 0;
 }
 
-int rtas_call(int token, int nargs, int nret, int *outputs, ...)
+static void __rtas_call(struct rtas_args *args)
 {
-   va_list list;
-   int ret, i;
+   enter_rtas(__pa(args));
+}
 
-   spin_lock(_lock);
+static int rtas_call_unlocked_va(struct rtas_args *args,
+ int token, int nargs, int nret, int *outputs,
+ va_list list)
+{
+   int ret, i;
 
-   rtas_args.token = cpu_to_be32(token);
-   rtas_args.nargs = cpu_to_be32(nargs);
-   rtas_args.nret = cpu_to_be32(nret);
-   rtas_args.rets = _args.args[nargs];
+   args->token = cpu_to_be32(token);
+   args->nargs = cpu_to_be32(nargs);
+   args->nret = cpu_to_be32(nret);
+   args->rets = >args[nargs];
 
-   va_start(list, outputs);
for (i = 0; i < nargs; ++i)
-   rtas_args.args[i] = cpu_to_be32(va_arg(list, u32));
-   va_end(list);
+   args->args[i] = cpu_to_be32(va_arg(list, u32));
 
for (i = 0; i < nret; ++i)
-   rtas_args.rets[i] = 0;
+   args->rets[i] = 0;
 
-   enter_rtas(__pa(_args));
+   __rtas_call(args);
 
if (nret > 1 && outputs != NULL)
for (i = 0; i < nret - 1; ++i)
-   outputs[i] = be32_to_cpu(rtas_args.rets[i + 1]);
+   outputs[i] = be32_to_cpu(args->rets[i + 1]);
+
+   ret = nret > 0 ? be32_to_cpu(args->rets[0]) : 0;
+
+   return ret;
+}
+
+int rtas_call_unlocked(struct rtas_args *args, int token, int nargs, int nret, 
int *outputs, ...)
+{
+   va_list list;
+   int ret;
 
-   ret = nret > 0 ? be32_to_cpu(rtas_args.rets[0]) : 0;
+   va_start(list, outputs);
+   ret = rtas_call_unlocked_va(args, token, nargs, nret, outputs, list);
+   va_end(list);
+
+   return ret;
+}
+
+int rtas_call(int token, int nargs, int nret, int *outputs, ...)
+{
+   va_list list;
+   int ret;
+
+   spin_lock(_lock);
+
+   va_start(list, outputs);
+   ret = rtas_call_unlocked_va(_args, token, nargs, nret, outputs, 
list);
+   va_end(list);
 
spin_unlock(_lock);
+
return ret;
 }
 
+void rtas_stop_self(void)
+{
+   struct rtas_args args;
+   uint32_t token;
+   int ret;
+
+   ret = rtas_token("stop-self", );
+   if (ret) {
+   puts("RTAS stop-self not available\n");
+   return;
+   }
+
+   ret = rtas_call_unlocked(, token, 0, 1, NULL);
+   printf("RTAS stop-self returned %d\n", ret);
+}
+
 void rtas_power_off(void)
 {
+   struct rtas_args args;
uint32_t token;
int ret;
 
@@ -130,6 +176,6 @@ void rtas_power_off(void)
return;
}
 
-   ret = rtas_call(token, 2, 1, NULL, -1, -1);
+   ret = rtas_call_unlocked(, token, 2, 1, NULL, -1, -1);
printf("RTAS power-off returned %d\n", ret);
 }
-- 
2.42.0



[kvm-unit-tests PATCH 14/32] powerpc: general interrupt tests

2024-02-26 Thread Nicholas Piggin
Add basic testing of various kinds of interrupts, machine check,
page fault, illegal, decrementer, trace, syscall, etc.

This has a known failure on QEMU TCG pseries machines where MSR[ME]
can be incorrectly set to 0.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/processor.h |   4 +
 lib/powerpc/asm/reg.h   |  17 ++
 lib/powerpc/setup.c |  11 +
 lib/ppc64/asm/ptrace.h  |  16 ++
 powerpc/Makefile.common |   3 +-
 powerpc/interrupts.c| 415 
 powerpc/unittests.cfg   |   3 +
 7 files changed, 468 insertions(+), 1 deletion(-)
 create mode 100644 powerpc/interrupts.c

diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index cf1b9d8ff..eed37d1f4 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -11,7 +11,11 @@ void do_handle_exception(struct pt_regs *regs);
 #endif /* __ASSEMBLY__ */
 
 extern bool cpu_has_hv;
+extern bool cpu_has_power_mce;
+extern bool cpu_has_siar;
 extern bool cpu_has_heai;
+extern bool cpu_has_prefix;
+extern bool cpu_has_sc_lev;
 
 static inline uint64_t mfspr(int nr)
 {
diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index 782e75527..d6097f48f 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -5,8 +5,15 @@
 
 #define UL(x) _AC(x, UL)
 
+#define SPR_DSISR  0x012
+#define SPR_DAR0x013
+#define SPR_DEC0x016
 #define SPR_SRR0   0x01a
 #define SPR_SRR1   0x01b
+#define   SRR1_PREFIX  UL(0x2000)
+#define SPR_FSCR   0x099
+#define   FSCR_PREFIX  UL(0x2000)
+#define SPR_HFSCR  0x0be
 #define SPR_TB 0x10c
 #define SPR_SPRG0  0x110
 #define SPR_SPRG1  0x111
@@ -22,12 +29,17 @@
 #define   PVR_VER_POWER8   UL(0x004d)
 #define   PVR_VER_POWER9   UL(0x004e)
 #define   PVR_VER_POWER10  UL(0x0080)
+#define SPR_HDEC   0x136
 #define SPR_HSRR0  0x13a
 #define SPR_HSRR1  0x13b
+#define SPR_LPCR   0x13e
+#define   LPCR_HDICE   UL(0x1)
+#define SPR_HEIR   0x153
 #define SPR_MMCR0  0x31b
 #define   MMCR0_FC UL(0x8000)
 #define   MMCR0_PMAE   UL(0x0400)
 #define   MMCR0_PMAO   UL(0x0080)
+#define SPR_SIAR   0x31c
 
 /* Machine State Register definitions: */
 #define MSR_LE_BIT 0
@@ -35,6 +47,11 @@
 #define MSR_HV_BIT 60  /* Hypervisor mode */
 #define MSR_SF_BIT 63  /* 64-bit mode */
 
+#define MSR_DR UL(0x0010)
+#define MSR_IR UL(0x0020)
+#define MSR_BE UL(0x0200)  /* Branch Trace Enable */
+#define MSR_SE UL(0x0400)  /* Single Step Enable */
+#define MSR_EE UL(0x8000)
 #define MSR_ME UL(0x1000)
 
 #endif
diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c
index 3c81aee9e..9b665f59c 100644
--- a/lib/powerpc/setup.c
+++ b/lib/powerpc/setup.c
@@ -87,7 +87,11 @@ static void cpu_set(int fdtnode, u64 regval, void *info)
 }
 
 bool cpu_has_hv;
+bool cpu_has_power_mce; /* POWER CPU machine checks */
+bool cpu_has_siar;
 bool cpu_has_heai;
+bool cpu_has_prefix;
+bool cpu_has_sc_lev; /* sc interrupt has LEV field in SRR1 */
 
 static void cpu_init(void)
 {
@@ -112,15 +116,22 @@ static void cpu_init(void)
 
switch (mfspr(SPR_PVR) & PVR_VERSION_MASK) {
case PVR_VER_POWER10:
+   cpu_has_prefix = true;
+   cpu_has_sc_lev = true;
case PVR_VER_POWER9:
case PVR_VER_POWER8E:
case PVR_VER_POWER8NVL:
case PVR_VER_POWER8:
+   cpu_has_power_mce = true;
cpu_has_heai = true;
+   cpu_has_siar = true;
break;
default:
break;
}
+
+   if (!cpu_has_hv) /* HEIR is HV register */
+   cpu_has_heai = false;
 }
 
 static void mem_init(phys_addr_t freemem_start)
diff --git a/lib/ppc64/asm/ptrace.h b/lib/ppc64/asm/ptrace.h
index 12de7499b..db263a59e 100644
--- a/lib/ppc64/asm/ptrace.h
+++ b/lib/ppc64/asm/ptrace.h
@@ -5,6 +5,9 @@
 #define STACK_FRAME_OVERHEAD112 /* size of minimum stack frame */
 
 #ifndef __ASSEMBLY__
+
+#include 
+
 struct pt_regs {
unsigned long gpr[32];
unsigned long nip;
@@ -17,6 +20,19 @@ struct pt_regs {
unsigned long _pad; /* stack must be 16-byte aligned */
 };
 
+static inline bool regs_is_prefix(volatile struct pt_regs *regs)
+{
+   return regs->msr & SRR1_PREFIX;
+}
+
+static inline void regs_advance_insn(struct pt_regs *regs)
+{
+   if (regs_is_prefix(regs))
+   regs->nip += 8;
+   else
+   regs->nip += 4;
+}
+
 #define STACK_INT_FRAME_SIZE(sizeof(struct pt_regs) + \
 STACK_FRAME_OVERHEAD + KERNEL_REDZONE_SIZE)
 
diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index 1e181da69..68165fc25 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.comm

[kvm-unit-tests PATCH 13/32] powerpc/sprs: Test hypervisor registers on powernv machine

2024-02-26 Thread Nicholas Piggin
This enables HV privilege registers to be tested with the powernv
machine.

Acked-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 powerpc/sprs.c | 33 +
 1 file changed, 25 insertions(+), 8 deletions(-)

diff --git a/powerpc/sprs.c b/powerpc/sprs.c
index cb1d6c980..0a82418d6 100644
--- a/powerpc/sprs.c
+++ b/powerpc/sprs.c
@@ -199,16 +199,16 @@ static const struct spr sprs_power_common[1024] = {
 [190] = { "HFSCR", 64, HV_RW, },
 [256] = { "VRSAVE",32, RW, },
 [259] = { "SPRG3", 64, RO, },
-[284] = { "TBL",   32, HV_WO, },
-[285] = { "TBU",   32, HV_WO, },
-[286] = { "TBU40", 64, HV_WO, },
+[284] = { "TBL",   32, HV_WO, }, /* Things can go a bit wonky with */
+[285] = { "TBU",   32, HV_WO, }, /* Timebase changing. Should save */
+[286] = { "TBU40", 64, HV_WO, }, /* and restore it. */
 [304] = { "HSPRG0",64, HV_RW, },
 [305] = { "HSPRG1",64, HV_RW, },
 [306] = { "HDSISR",32, HV_RW,  SPR_INT, },
 [307] = { "HDAR",  64, HV_RW,  SPR_INT, },
 [308] = { "SPURR", 64, HV_RW | OS_RO,  SPR_ASYNC, },
 [309] = { "PURR",  64, HV_RW | OS_RO,  SPR_ASYNC, },
-[313] = { "HRMOR", 64, HV_RW, },
+[313] = { "HRMOR", 64, HV_RW,  SPR_HARNESS, }, /* Harness 
can't cope with HRMOR changing */
 [314] = { "HSRR0", 64, HV_RW,  SPR_INT, },
 [315] = { "HSRR1", 64, HV_RW,  SPR_INT, },
 [318] = { "LPCR",  64, HV_RW, },
@@ -306,7 +306,7 @@ static const struct spr sprs_power9_10[1024] = {
 [921] = { "TSCR",  32, HV_RW, },
 [922] = { "TTR",   64, HV_RW, },
 [1006]= { "TRACE", 64, WO, },
-[1008]= { "HID",   64, HV_RW, },
+[1008]= { "HID",   64, HV_RW,  SPR_HARNESS, }, /* HILE would 
be unhelpful to change */
 };
 
 /* This covers POWER8 and POWER9 PMUs */
@@ -350,6 +350,22 @@ static const struct spr sprs_power10_pmu[1024] = {
 
 static struct spr sprs[1024];
 
+static bool spr_read_perms(int spr)
+{
+   if (cpu_has_hv)
+   return !!(sprs[spr].access & SPR_HV_READ);
+   else
+   return !!(sprs[spr].access & SPR_OS_READ);
+}
+
+static bool spr_write_perms(int spr)
+{
+   if (cpu_has_hv)
+   return !!(sprs[spr].access & SPR_HV_WRITE);
+   else
+   return !!(sprs[spr].access & SPR_OS_WRITE);
+}
+
 static void setup_sprs(void)
 {
int i;
@@ -461,7 +477,7 @@ static void get_sprs(uint64_t *v)
int i;
 
for (i = 0; i < 1024; i++) {
-   if (!(sprs[i].access & SPR_OS_READ))
+   if (!spr_read_perms(i))
continue;
v[i] = __mfspr(i);
}
@@ -472,8 +488,9 @@ static void set_sprs(uint64_t val)
int i;
 
for (i = 0; i < 1024; i++) {
-   if (!(sprs[i].access & SPR_OS_WRITE))
+   if (!spr_write_perms(i))
continue;
+
if (sprs[i].type & SPR_HARNESS)
continue;
__mtspr(i, val);
@@ -561,7 +578,7 @@ int main(int argc, char **argv)
for (i = 0; i < 1024; i++) {
bool pass = true;
 
-   if (!(sprs[i].access & SPR_OS_READ))
+   if (!spr_read_perms(i))
continue;
 
if (sprs[i].width == 32) {
-- 
2.42.0



[kvm-unit-tests PATCH 12/32] powerpc: Fix emulator illegal instruction test for powernv

2024-02-26 Thread Nicholas Piggin
Illegal instructions cause 0xe40 (HEAI) interrupts rather
than program interrupts.

Acked-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/processor.h |  1 +
 lib/powerpc/setup.c | 13 +
 powerpc/emulator.c  | 21 -
 3 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index 9d8061962..cf1b9d8ff 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -11,6 +11,7 @@ void do_handle_exception(struct pt_regs *regs);
 #endif /* __ASSEMBLY__ */
 
 extern bool cpu_has_hv;
+extern bool cpu_has_heai;
 
 static inline uint64_t mfspr(int nr)
 {
diff --git a/lib/powerpc/setup.c b/lib/powerpc/setup.c
index 89e5157f2..3c81aee9e 100644
--- a/lib/powerpc/setup.c
+++ b/lib/powerpc/setup.c
@@ -87,6 +87,7 @@ static void cpu_set(int fdtnode, u64 regval, void *info)
 }
 
 bool cpu_has_hv;
+bool cpu_has_heai;
 
 static void cpu_init(void)
 {
@@ -108,6 +109,18 @@ static void cpu_init(void)
hcall(H_SET_MODE, 0, 4, 0, 0);
 #endif
}
+
+   switch (mfspr(SPR_PVR) & PVR_VERSION_MASK) {
+   case PVR_VER_POWER10:
+   case PVR_VER_POWER9:
+   case PVR_VER_POWER8E:
+   case PVR_VER_POWER8NVL:
+   case PVR_VER_POWER8:
+   cpu_has_heai = true;
+   break;
+   default:
+   break;
+   }
 }
 
 static void mem_init(phys_addr_t freemem_start)
diff --git a/powerpc/emulator.c b/powerpc/emulator.c
index 39dd59645..c9b17f742 100644
--- a/powerpc/emulator.c
+++ b/powerpc/emulator.c
@@ -31,6 +31,20 @@ static void program_check_handler(struct pt_regs *regs, void 
*opaque)
regs->nip += 4;
 }
 
+static void heai_handler(struct pt_regs *regs, void *opaque)
+{
+   int *data = opaque;
+
+   if (verbose) {
+   printf("Detected invalid instruction %#018lx: %08x\n",
+  regs->nip, *(uint32_t*)regs->nip);
+   }
+
+   *data = 8; /* Illegal instruction */
+
+   regs->nip += 4;
+}
+
 static void alignment_handler(struct pt_regs *regs, void *opaque)
 {
int *data = opaque;
@@ -362,7 +376,12 @@ int main(int argc, char **argv)
 {
int i;
 
-   handle_exception(0x700, program_check_handler, (void *)_invalid);
+   if (cpu_has_heai) {
+   handle_exception(0xe40, heai_handler, (void *)_invalid);
+   handle_exception(0x700, program_check_handler, (void 
*)_invalid);
+   } else {
+   handle_exception(0x700, program_check_handler, (void 
*)_invalid);
+   }
handle_exception(0x600, alignment_handler, (void *));
 
for (i = 1; i < argc; i++) {
-- 
2.42.0



[kvm-unit-tests PATCH 11/32] powerpc: Support powernv machine with QEMU TCG

2024-02-26 Thread Nicholas Piggin
Add support for QEMU's powernv machine. This uses standard firmware
(skiboot) rather than a minimal firmware shim.

Reviewed-by: Cédric Le Goater 
Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/processor.h | 23 +++
 lib/powerpc/asm/reg.h   |  4 ++
 lib/powerpc/hcall.c |  4 +-
 lib/powerpc/io.c| 27 -
 lib/powerpc/io.h|  6 +++
 lib/powerpc/processor.c | 37 ++
 lib/powerpc/setup.c | 14 +--
 lib/ppc64/asm/opal.h| 15 
 lib/ppc64/opal-calls.S  | 50 
 lib/ppc64/opal.c| 76 +
 powerpc/Makefile.ppc64  |  2 +
 powerpc/cstart64.S  |  7 
 powerpc/run | 42 
 powerpc/unittests.cfg   | 10 -
 14 files changed, 301 insertions(+), 16 deletions(-)
 create mode 100644 lib/ppc64/asm/opal.h
 create mode 100644 lib/ppc64/opal-calls.S
 create mode 100644 lib/ppc64/opal.c

diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index e415f9235..9d8061962 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -10,6 +10,8 @@ void handle_exception(int trap, void (*func)(struct pt_regs 
*, void *), void *);
 void do_handle_exception(struct pt_regs *regs);
 #endif /* __ASSEMBLY__ */
 
+extern bool cpu_has_hv;
+
 static inline uint64_t mfspr(int nr)
 {
uint64_t ret;
@@ -38,4 +40,25 @@ static inline void mtmsr(uint64_t msr)
asm volatile ("mtmsrd %[msr]" :: [msr] "r" (msr) : "memory");
 }
 
+/*
+ * This returns true on PowerNV / OPAL machines which run in hypervisor
+ * mode. False on pseries / PAPR machines that run in guest mode.
+ */
+static inline bool machine_is_powernv(void)
+{
+   return cpu_has_hv;
+}
+
+/*
+ * This returns true on pseries / PAPR / KVM machines which run under a
+ * hypervisor or QEMU pseries machine. False for PowerNV / OPAL.
+ */
+static inline bool machine_is_pseries(void)
+{
+   return !machine_is_powernv();
+}
+
+void enable_mcheck(void);
+void disable_mcheck(void);
+
 #endif /* _ASMPOWERPC_PROCESSOR_H_ */
diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index c80b32059..782e75527 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -30,7 +30,11 @@
 #define   MMCR0_PMAO   UL(0x0080)
 
 /* Machine State Register definitions: */
+#define MSR_LE_BIT 0
 #define MSR_EE_BIT 15  /* External Interrupts Enable */
+#define MSR_HV_BIT 60  /* Hypervisor mode */
 #define MSR_SF_BIT 63  /* 64-bit mode */
 
+#define MSR_ME UL(0x1000)
+
 #endif
diff --git a/lib/powerpc/hcall.c b/lib/powerpc/hcall.c
index b4d39ac65..45f201315 100644
--- a/lib/powerpc/hcall.c
+++ b/lib/powerpc/hcall.c
@@ -25,7 +25,7 @@ int hcall_have_broken_sc1(void)
return r3 == (unsigned long)H_PRIVILEGE;
 }
 
-void putchar(int c)
+void papr_putchar(int c)
 {
unsigned long vty = 0;  /* 0 == default */
unsigned long nr_chars = 1;
@@ -34,7 +34,7 @@ void putchar(int c)
hcall(H_PUT_TERM_CHAR, vty, nr_chars, chars);
 }
 
-int __getchar(void)
+int __papr_getchar(void)
 {
register unsigned long r3 asm("r3") = H_GET_TERM_CHAR;
register unsigned long r4 asm("r4") = 0; /* 0 == default vty */
diff --git a/lib/powerpc/io.c b/lib/powerpc/io.c
index a381688bc..ab7bb843c 100644
--- a/lib/powerpc/io.c
+++ b/lib/powerpc/io.c
@@ -9,13 +9,33 @@
 #include 
 #include 
 #include 
+#include 
 #include "io.h"
 
 static struct spinlock print_lock;
 
+void putchar(int c)
+{
+   if (machine_is_powernv())
+   opal_putchar(c);
+   else
+   papr_putchar(c);
+}
+
+int __getchar(void)
+{
+   if (machine_is_powernv())
+   return __opal_getchar();
+   else
+   return __papr_getchar();
+}
+
 void io_init(void)
 {
-   rtas_init();
+   if (machine_is_powernv())
+   assert(!opal_init());
+   else
+   rtas_init();
 }
 
 void puts(const char *s)
@@ -38,7 +58,10 @@ void exit(int code)
 // FIXME: change this print-exit/rtas-poweroff to chr_testdev_exit(),
 //maybe by plugging chr-testdev into a spapr-vty.
printf("\nEXIT: STATUS=%d\n", ((code) << 1) | 1);
-   rtas_power_off();
+   if (machine_is_powernv())
+   opal_power_off();
+   else
+   rtas_power_off();
halt(code);
__builtin_unreachable();
 }
diff --git a/lib/powerpc/io.h b/lib/powerpc/io.h
index d4f21ba15..943bf142b 100644
--- a/lib/powerpc/io.h
+++ b/lib/powerpc/io.h
@@ -8,6 +8,12 @@
 #define _POWERPC_IO_H_
 
 extern void io_init(void);
+extern int opal_init(void);
+extern void opal_power_off(void);
 extern void putchar(int c);
+extern void opal_putchar(int c);
+extern void papr_putchar(int c);
+extern int __opal_getchar

[kvm-unit-tests PATCH 10/32] scripts: Accommodate powerpc powernv machine differences

2024-02-26 Thread Nicholas Piggin
The QEMU powerpc powernv machine has minor differences that must be
accommodated for in output parsing:

- Summary parsing must search more lines of output for the summary
  line, to accommodate OPAL message on shutdown.
- Premature failure testing must tolerate case differences in kernel
  load error message.

Acked-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 scripts/runtime.bash | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/scripts/runtime.bash b/scripts/runtime.bash
index 8f9672d0d..bb32c0d10 100644
--- a/scripts/runtime.bash
+++ b/scripts/runtime.bash
@@ -9,7 +9,7 @@ FAIL() { echo -ne "\e[31mFAIL\e[0m"; }
 extract_summary()
 {
 local cr=$'\r'
-tail -3 | grep '^SUMMARY: ' | sed 's/^SUMMARY: /(/;s/'"$cr"'\{0,1\}$/)/'
+tail -5 | grep '^SUMMARY: ' | sed 's/^SUMMARY: /(/;s/'"$cr"'\{0,1\}$/)/'
 }
 
 # We assume that QEMU is going to work if it tried to load the kernel
@@ -18,7 +18,7 @@ premature_failure()
 local log="$(eval "$(get_cmdline _NO_FILE_4Uhere_)" 2>&1)"
 
 echo "$log" | grep "_NO_FILE_4Uhere_" |
-grep -q -e "could not \(load\|open\) kernel" -e "error loading" &&
+grep -q -e "[Cc]ould not \(load\|open\) kernel" -e "error loading" &&
 return 1
 
 RUNTIME_log_stderr <<< "$log"
-- 
2.42.0



[kvm-unit-tests PATCH 09/32] scripts: allow machine option to be specified in unittests.cfg

2024-02-26 Thread Nicholas Piggin
This allows different machines with different requirements to be
supported by run_tests.sh, similarly to how different accelerators
are handled.

Acked-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 scripts/common.bash  |  8 ++--
 scripts/runtime.bash | 16 
 2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/scripts/common.bash b/scripts/common.bash
index b9413d683..ee1dd8659 100644
--- a/scripts/common.bash
+++ b/scripts/common.bash
@@ -10,6 +10,7 @@ function for_each_unittest()
local opts
local groups
local arch
+   local machine
local check
local accel
local timeout
@@ -21,7 +22,7 @@ function for_each_unittest()
if [[ "$line" =~ ^\[(.*)\]$ ]]; then
rematch=${BASH_REMATCH[1]}
if [ -n "${testname}" ]; then
-   $(arch_cmd) "$cmd" "$testname" "$groups" "$smp" 
"$kernel" "$opts" "$arch" "$check" "$accel" "$timeout"
+   $(arch_cmd) "$cmd" "$testname" "$groups" "$smp" 
"$kernel" "$opts" "$arch" "$machine" "$check" "$accel" "$timeout"
fi
testname=$rematch
smp=1
@@ -29,6 +30,7 @@ function for_each_unittest()
opts=""
groups=""
arch=""
+   machine=""
check=""
accel=""
timeout=""
@@ -58,6 +60,8 @@ function for_each_unittest()
groups=${BASH_REMATCH[1]}
elif [[ $line =~ ^arch\ *=\ *(.*)$ ]]; then
arch=${BASH_REMATCH[1]}
+   elif [[ $line =~ ^machine\ *=\ *(.*)$ ]]; then
+   machine=${BASH_REMATCH[1]}
elif [[ $line =~ ^check\ *=\ *(.*)$ ]]; then
check=${BASH_REMATCH[1]}
elif [[ $line =~ ^accel\ *=\ *(.*)$ ]]; then
@@ -67,7 +71,7 @@ function for_each_unittest()
fi
done
if [ -n "${testname}" ]; then
-   $(arch_cmd) "$cmd" "$testname" "$groups" "$smp" "$kernel" 
"$opts" "$arch" "$check" "$accel" "$timeout"
+   $(arch_cmd) "$cmd" "$testname" "$groups" "$smp" "$kernel" 
"$opts" "$arch" "$machine" "$check" "$accel" "$timeout"
fi
exec {fd}<&-
 }
diff --git a/scripts/runtime.bash b/scripts/runtime.bash
index c73fb0240..8f9672d0d 100644
--- a/scripts/runtime.bash
+++ b/scripts/runtime.bash
@@ -30,7 +30,7 @@ premature_failure()
 get_cmdline()
 {
 local kernel=$1
-echo "TESTNAME=$testname TIMEOUT=$timeout ACCEL=$accel $RUNTIME_arch_run 
$kernel -smp $smp $opts"
+echo "TESTNAME=$testname TIMEOUT=$timeout MACHINE=$machine ACCEL=$accel 
$RUNTIME_arch_run $kernel -smp $smp $opts"
 }
 
 skip_nodefault()
@@ -78,9 +78,10 @@ function run()
 local kernel="$4"
 local opts="$5"
 local arch="$6"
-local check="${CHECK:-$7}"
-local accel="$8"
-local timeout="${9:-$TIMEOUT}" # unittests.cfg overrides the default
+local machine="$7"
+local check="${CHECK:-$8}"
+local accel="$9"
+local timeout="${10:-$TIMEOUT}" # unittests.cfg overrides the default
 
 if [ "${CONFIG_EFI}" == "y" ]; then
 kernel=${kernel/%.flat/.efi}
@@ -114,6 +115,13 @@ function run()
 return 2
 fi
 
+if [ -n "$machine" ] && [ -n "$MACHINE" ] && [ "$machine" != "$MACHINE" ]; 
then
+print_result "SKIP" $testname "" "$machine only"
+return 2
+elif [ -n "$MACHINE" ]; then
+machine="$MACHINE"
+fi
+
 if [ -n "$accel" ] && [ -n "$ACCEL" ] && [ "$accel" != "$ACCEL" ]; then
 print_result "SKIP" $testname "" "$accel only, but ACCEL=$ACCEL"
 return 2
-- 
2.42.0



[kvm-unit-tests PATCH 08/32] powerpc/sprs: Avoid taking PMU interrupts caused by register fuzzing

2024-02-26 Thread Nicholas Piggin
Storing certain values in MMCR0 can cause PMU interrupts when msleep
enables MSR[EE], and this crashes the test. Freeze the PMU counters
and clear any PMU exception before calling msleep.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/reg.h |  4 
 powerpc/sprs.c| 17 +++--
 2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index 1f991288e..c80b32059 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -24,6 +24,10 @@
 #define   PVR_VER_POWER10  UL(0x0080)
 #define SPR_HSRR0  0x13a
 #define SPR_HSRR1  0x13b
+#define SPR_MMCR0  0x31b
+#define   MMCR0_FC UL(0x8000)
+#define   MMCR0_PMAE   UL(0x0400)
+#define   MMCR0_PMAO   UL(0x0080)
 
 /* Machine State Register definitions: */
 #define MSR_EE_BIT 15  /* External Interrupts Enable */
diff --git a/powerpc/sprs.c b/powerpc/sprs.c
index 44edd0d7b..cb1d6c980 100644
--- a/powerpc/sprs.c
+++ b/powerpc/sprs.c
@@ -476,12 +476,7 @@ static void set_sprs(uint64_t val)
continue;
if (sprs[i].type & SPR_HARNESS)
continue;
-   if (!strcmp(sprs[i].name, "MMCR0")) {
-   /* XXX: could use a comment or better abstraction! */
-   __mtspr(i, (val & 0xfbab3fffULL) | 0xfa0b2070);
-   } else {
-   __mtspr(i, val);
-   }
+   __mtspr(i, val);
}
 }
 
@@ -538,6 +533,16 @@ int main(int argc, char **argv)
if (sprs[895].name)
before[895] = mfspr(895);
} else {
+   /*
+* msleep will enable MSR[EE] and take a decrementer
+* interrupt. Must account for changed registers and
+* prevent taking unhandled interrupts.
+*/
+   /* Prevent PMU interrupt */
+   mtspr(SPR_MMCR0, (mfspr(SPR_MMCR0) | MMCR0_FC) &
+   ~(MMCR0_PMAO | MMCR0_PMAE));
+   before[SPR_MMCR0] = mfspr(SPR_MMCR0);
+   before[779] = mfspr(SPR_MMCR0);
msleep(2000);
 
/* Reload regs changed by dec interrupt */
-- 
2.42.0



[kvm-unit-tests PATCH 07/32] powerpc/sprs: Don't fail changed SPRs that are used by the test harness

2024-02-26 Thread Nicholas Piggin
SPRs annotated with SPR_HARNESS can change between consecutive reads
because the test harness code has changed them. Avoid failing the
test in this case.

Signed-off-by: Nicholas Piggin 
---
 powerpc/sprs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/powerpc/sprs.c b/powerpc/sprs.c
index 8253ea971..44edd0d7b 100644
--- a/powerpc/sprs.c
+++ b/powerpc/sprs.c
@@ -563,7 +563,7 @@ int main(int argc, char **argv)
if (before[i] >> 32)
pass = false;
}
-   if (!(sprs[i].type & SPR_ASYNC) && (before[i] != after[i]))
+   if (!(sprs[i].type & (SPR_HARNESS|SPR_ASYNC)) && (before[i] != 
after[i]))
pass = false;
 
if (sprs[i].width == 32 && !(before[i] >> 32) && !(after[i] >> 
32))
-- 
2.42.0



[kvm-unit-tests PATCH 06/32] powerpc/sprs: Specify SPRs with data rather than code

2024-02-26 Thread Nicholas Piggin
A significant rework that builds an array of 'struct spr', where each
element describes an SPR. This makes various metadata about the SPR
like name and access type easier to carry and use.

Hypervisor privileged registers are described despite not being used
at the moment for completeness, but also the code might one day be
reused for a hypervisor-privileged test.

Acked-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/reg.h |   2 +
 powerpc/sprs.c| 647 +-
 2 files changed, 457 insertions(+), 192 deletions(-)

diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
index 6810c1d82..1f991288e 100644
--- a/lib/powerpc/asm/reg.h
+++ b/lib/powerpc/asm/reg.h
@@ -5,6 +5,8 @@
 
 #define UL(x) _AC(x, UL)
 
+#define SPR_SRR0   0x01a
+#define SPR_SRR1   0x01b
 #define SPR_TB 0x10c
 #define SPR_SPRG0  0x110
 #define SPR_SPRG1  0x111
diff --git a/powerpc/sprs.c b/powerpc/sprs.c
index a19d80a1a..8253ea971 100644
--- a/powerpc/sprs.c
+++ b/powerpc/sprs.c
@@ -30,229 +30,458 @@
 #include 
 #include 
 
-uint64_t before[1024], after[1024];
-
-/* Common SPRs for all PowerPC CPUs */
-static void set_sprs_common(uint64_t val)
+/* "Indirect" mfspr/mtspr which accept a non-constant spr number */
+static uint64_t __mfspr(unsigned spr)
 {
-   mtspr(9, val);  /* CTR */
-   // mtspr(273, val); /* SPRG1 */  /* Used by our exception handler */
-   mtspr(274, val);/* SPRG2 */
-   mtspr(275, val);/* SPRG3 */
+   uint64_t tmp;
+   uint64_t ret;
+
+   asm volatile(
+"  bcl 20, 31, 1f  \n"
+"1:mflr%0  \n"
+"  addi%0, %0, (2f-1b) \n"
+"  add %0, %0, %2  \n"
+"  mtctr   %0  \n"
+"  bctr\n"
+"2:\n"
+".LSPR=0   \n"
+".rept 1024\n"
+"  mfspr   %1, .LSPR   \n"
+"  b   3f  \n"
+"  .LSPR=.LSPR+1   \n"
+".endr \n"
+"3:\n"
+   : "="(tmp),
+ "=r"(ret)
+   : "r"(spr*8) /* 8 bytes per 'mfspr ; b' block */
+   : "lr", "ctr");
+
+   return ret;
 }
 
-/* SPRs from PowerPC Operating Environment Architecture, Book III, Vers. 2.01 
*/
-static void set_sprs_book3s_201(uint64_t val)
+static void __mtspr(unsigned spr, uint64_t val)
 {
-   mtspr(18, val); /* DSISR */
-   mtspr(19, val); /* DAR */
-   mtspr(152, val);/* CTRL */
-   mtspr(256, val);/* VRSAVE */
-   mtspr(786, val);/* MMCRA */
-   mtspr(795, val);/* MMCR0 */
-   mtspr(798, val);/* MMCR1 */
+   uint64_t tmp;
+
+   asm volatile(
+"  bcl 20, 31, 1f  \n"
+"1:mflr%0  \n"
+"  addi%0, %0, (2f-1b) \n"
+"  add %0, %0, %2  \n"
+"  mtctr   %0  \n"
+"  bctr\n"
+"2:\n"
+".LSPR=0   \n"
+".rept 1024\n"
+"  mtspr   .LSPR, %1   \n"
+"  b   3f  \n"
+"  .LSPR=.LSPR+1   \n"
+".endr \n"
+"3:\n"
+   : "="(tmp)
+   : "r"(val),
+ "r"(spr*8) /* 8 bytes per 'mfspr ; b' block */
+   : "lr", "ctr", "xer");
 }
 
+static uint64_t before[1024], after[1024];
+
+#define SPR_PR_READ0x0001
+#define SPR_PR_WRITE   0x0002
+#define SPR_OS_READ0x0010
+#define SPR_OS_WRITE   0x0020
+#define SPR_HV_READ0x0100
+#define SPR_HV_WRITE   0x0200
+
+#define RW 0x333
+#define RO 0x111
+#define WO 0x222
+#define OS_RW  0x330
+#define OS_RO  0x110
+#define OS_WO  0x220
+#define HV_RW  0x300
+#define HV_RO  0x100
+#define HV_WO  0x200
+
+#define SPR_ASYNC  0x1000  /* May be updated asynchronously */
+#define SPR_INT0x2000  /* May be updated by synchronous 
interrupt */
+#define SPR_HARNESS0x4000  /* Test harness uses the register */
+
+struct spr {
+   const char  *name;
+   uint8_t width;
+   uint16_taccess;
+   uint16_ttype;
+};
+
+/* SPRs common denominator back to PowerPC Operating Envir

[kvm-unit-tests PATCH 05/32] powerpc: Cleanup SPR and MSR definitions

2024-02-26 Thread Nicholas Piggin
Move SPR and MSR defines out of ppc_asm.h and processor.h and into a
new include, asm/reg.h.

Add a define for the PVR SPR and various processor versions, and replace
the open coded numbers in the sprs.c test case.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/ppc_asm.h   |  8 +---
 lib/powerpc/asm/processor.h |  7 +--
 lib/powerpc/asm/reg.h   | 30 ++
 lib/powerpc/asm/time.h  |  1 +
 lib/ppc64/asm/reg.h |  1 +
 powerpc/sprs.c  | 21 ++---
 6 files changed, 44 insertions(+), 24 deletions(-)
 create mode 100644 lib/powerpc/asm/reg.h
 create mode 100644 lib/ppc64/asm/reg.h

diff --git a/lib/powerpc/asm/ppc_asm.h b/lib/powerpc/asm/ppc_asm.h
index 46b4be009..52a42dfbe 100644
--- a/lib/powerpc/asm/ppc_asm.h
+++ b/lib/powerpc/asm/ppc_asm.h
@@ -2,6 +2,7 @@
 #define _ASMPOWERPC_PPC_ASM_H
 
 #include 
+#include 
 
 #define SAVE_GPR(n, base)  std n,GPR0+8*(n)(base)
 #define REST_GPR(n, base)  ld  n,GPR0+8*(n)(base)
@@ -35,11 +36,4 @@
 
 #endif /* __BYTE_ORDER__ */
 
-#define SPR_HSRR0  0x13A
-#define SPR_HSRR1  0x13B
-
-/* Machine State Register definitions: */
-#define MSR_EE_BIT 15  /* External Interrupts Enable */
-#define MSR_SF_BIT 63  /* 64-bit mode */
-
 #endif /* _ASMPOWERPC_PPC_ASM_H */
diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index fe1052939..e415f9235 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -3,18 +3,13 @@
 
 #include 
 #include 
+#include 
 
 #ifndef __ASSEMBLY__
 void handle_exception(int trap, void (*func)(struct pt_regs *, void *), void 
*);
 void do_handle_exception(struct pt_regs *regs);
 #endif /* __ASSEMBLY__ */
 
-#define SPR_TB 0x10c
-#define SPR_SPRG0  0x110
-#define SPR_SPRG1  0x111
-#define SPR_SPRG2  0x112
-#define SPR_SPRG3  0x113
-
 static inline uint64_t mfspr(int nr)
 {
uint64_t ret;
diff --git a/lib/powerpc/asm/reg.h b/lib/powerpc/asm/reg.h
new file mode 100644
index 0..6810c1d82
--- /dev/null
+++ b/lib/powerpc/asm/reg.h
@@ -0,0 +1,30 @@
+#ifndef _ASMPOWERPC_REG_H
+#define _ASMPOWERPC_REG_H
+
+#include 
+
+#define UL(x) _AC(x, UL)
+
+#define SPR_TB 0x10c
+#define SPR_SPRG0  0x110
+#define SPR_SPRG1  0x111
+#define SPR_SPRG2  0x112
+#define SPR_SPRG3  0x113
+#define SPR_PVR0x11f
+#define   PVR_VERSION_MASK UL(0x)
+#define   PVR_VER_970  UL(0x0039)
+#define   PVR_VER_970FXUL(0x003c)
+#define   PVR_VER_970MPUL(0x0044)
+#define   PVR_VER_POWER8E  UL(0x004b)
+#define   PVR_VER_POWER8NVLUL(0x004c)
+#define   PVR_VER_POWER8   UL(0x004d)
+#define   PVR_VER_POWER9   UL(0x004e)
+#define   PVR_VER_POWER10  UL(0x0080)
+#define SPR_HSRR0  0x13a
+#define SPR_HSRR1  0x13b
+
+/* Machine State Register definitions: */
+#define MSR_EE_BIT 15  /* External Interrupts Enable */
+#define MSR_SF_BIT 63  /* 64-bit mode */
+
+#endif
diff --git a/lib/powerpc/asm/time.h b/lib/powerpc/asm/time.h
index 72fcb1bd0..a1f072989 100644
--- a/lib/powerpc/asm/time.h
+++ b/lib/powerpc/asm/time.h
@@ -3,6 +3,7 @@
 
 #include 
 #include 
+#include 
 
 static inline uint64_t get_tb(void)
 {
diff --git a/lib/ppc64/asm/reg.h b/lib/ppc64/asm/reg.h
new file mode 100644
index 0..bc407b555
--- /dev/null
+++ b/lib/ppc64/asm/reg.h
@@ -0,0 +1 @@
+#include "../../powerpc/asm/reg.h"
diff --git a/powerpc/sprs.c b/powerpc/sprs.c
index 285976488..a19d80a1a 100644
--- a/powerpc/sprs.c
+++ b/powerpc/sprs.c
@@ -23,6 +23,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -120,25 +121,23 @@ static void set_sprs_book3s_31(uint64_t val)
 
 static void set_sprs(uint64_t val)
 {
-   uint32_t pvr = mfspr(287);  /* Processor Version Register */
-
set_sprs_common(val);
 
-   switch (pvr >> 16) {
-   case 0x39:  /* PPC970 */
-   case 0x3C:  /* PPC970FX */
-   case 0x44:  /* PPC970MP */
+   switch (mfspr(SPR_PVR) & PVR_VERSION_MASK) {
+   case PVR_VER_970:
+   case PVR_VER_970FX:
+   case PVR_VER_970MP:
set_sprs_book3s_201(val);
break;
-   case 0x4b:  /* POWER8E */
-   case 0x4c:  /* POWER8NVL */
-   case 0x4d:  /* POWER8 */
+   case PVR_VER_POWER8E:
+   case PVR_VER_POWER8NVL:
+   case PVR_VER_POWER8:
set_sprs_book3s_207(val);
break;
-   case 0x4e:  /* POWER9 */
+   case PVR_VER_POWER9:
set_sprs_book3s_300(val);
break;
-   case 0x80:  /* POWER10 */
+   case PVR_VER_POWER10:
se

[kvm-unit-tests PATCH 04/32] powerpc: interrupt stack backtracing

2024-02-26 Thread Nicholas Piggin
Add support for backtracing across interrupt stacks, and
add interrupt frame backtrace for unhandled interrupts.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/processor.c |  4 ++-
 lib/ppc64/asm/stack.h   |  3 +++
 lib/ppc64/stack.c   | 55 +
 powerpc/Makefile.ppc64  |  1 +
 powerpc/cstart64.S  |  7 --
 5 files changed, 67 insertions(+), 3 deletions(-)
 create mode 100644 lib/ppc64/stack.c

diff --git a/lib/powerpc/processor.c b/lib/powerpc/processor.c
index ad0d95666..114584024 100644
--- a/lib/powerpc/processor.c
+++ b/lib/powerpc/processor.c
@@ -51,7 +51,9 @@ void do_handle_exception(struct pt_regs *regs)
return;
}
 
-   printf("unhandled cpu exception %#lx at NIA:0x%016lx MSR:0x%016lx\n", 
regs->trap, regs->nip, regs->msr);
+   printf("Unhandled cpu exception %#lx at NIA:0x%016lx MSR:0x%016lx\n",
+   regs->trap, regs->nip, regs->msr);
+   dump_frame_stack((void *)regs->nip, (void *)regs->gpr[1]);
abort();
 }
 
diff --git a/lib/ppc64/asm/stack.h b/lib/ppc64/asm/stack.h
index 9734bbb8f..94fd1021c 100644
--- a/lib/ppc64/asm/stack.h
+++ b/lib/ppc64/asm/stack.h
@@ -5,4 +5,7 @@
 #error Do not directly include . Just use .
 #endif
 
+#define HAVE_ARCH_BACKTRACE
+#define HAVE_ARCH_BACKTRACE_FRAME
+
 #endif
diff --git a/lib/ppc64/stack.c b/lib/ppc64/stack.c
new file mode 100644
index 0..fcb7fa860
--- /dev/null
+++ b/lib/ppc64/stack.c
@@ -0,0 +1,55 @@
+#include 
+#include 
+#include 
+
+extern char exception_stack_marker[];
+
+int backtrace_frame(const void *frame, const void **return_addrs, int 
max_depth)
+{
+   static int walking;
+   int depth = 0;
+   const unsigned long *bp = (unsigned long *)frame;
+   void *return_addr;
+
+   asm volatile("" ::: "lr"); /* Force it to save LR */
+
+   if (walking) {
+   printf("RECURSIVE STACK WALK!!!\n");
+   return 0;
+   }
+   walking = 1;
+
+   bp = (unsigned long *)bp[0];
+   return_addr = (void *)bp[2];
+
+   for (depth = 0; bp && depth < max_depth; depth++) {
+   return_addrs[depth] = return_addr;
+   if (return_addrs[depth] == 0)
+   break;
+   if (return_addrs[depth] == exception_stack_marker) {
+   struct pt_regs *regs;
+
+   regs = (void *)bp + STACK_FRAME_OVERHEAD;
+   bp = (unsigned long *)bp[0];
+   /* Represent interrupt frame with vector number */
+   return_addr = (void *)regs->trap;
+   if (depth + 1 < max_depth) {
+   depth++;
+   return_addrs[depth] = return_addr;
+   return_addr = (void *)regs->nip;
+   }
+   } else {
+   bp = (unsigned long *)bp[0];
+   return_addr = (void *)bp[2];
+   }
+   }
+
+   walking = 0;
+   return depth;
+}
+
+int backtrace(const void **return_addrs, int max_depth)
+{
+   return backtrace_frame(__builtin_frame_address(0), return_addrs,
+  max_depth);
+}
diff --git a/powerpc/Makefile.ppc64 b/powerpc/Makefile.ppc64
index b0ed2b104..eb682c226 100644
--- a/powerpc/Makefile.ppc64
+++ b/powerpc/Makefile.ppc64
@@ -17,6 +17,7 @@ cstart.o = $(TEST_DIR)/cstart64.o
 reloc.o  = $(TEST_DIR)/reloc64.o
 
 OBJDIRS += lib/ppc64
+cflatobjs += lib/ppc64/stack.o
 
 # ppc64 specific tests
 tests = $(TEST_DIR)/spapr_vpa.elf
diff --git a/powerpc/cstart64.S b/powerpc/cstart64.S
index 14ab0c6c8..278af84a6 100644
--- a/powerpc/cstart64.S
+++ b/powerpc/cstart64.S
@@ -188,6 +188,7 @@ call_handler:
.endr
mfsprg1 r0
std r0,GPR1(r1)
+   std r0,0(r1)
 
/* lr, xer, ccr */
 
@@ -206,12 +207,12 @@ call_handler:
subir31, r31, 0b - start_text
ld  r2, (p_toc_text - start_text)(r31)
 
-   /* FIXME: build stack frame */
-
/* call generic handler */
 
addir3,r1,STACK_FRAME_OVERHEAD
bl  do_handle_exception
+   .global exception_stack_marker
+exception_stack_marker:
 
/* restore context */
 
@@ -321,6 +322,7 @@ handler_trampoline:
/* nip and msr */
mfsrr0  r0
std r0, _NIP(r1)
+   std r0, INT_FRAME_SIZE+16(r1)
 
mfsrr1  r0
std r0, _MSR(r1)
@@ -337,6 +339,7 @@ handler_htrampoline:
/* nip and msr */
mfspr   r0, SPR_HSRR0
std r0, _NIP(r1)
+   std r0, INT_FRAME_SIZE+16(r1)
 
mfspr   r0, SPR_HSRR1
std r0, _MSR(r1)
-- 
2.42.0



[kvm-unit-tests PATCH 03/32] powerpc: Fix stack backtrace termination

2024-02-26 Thread Nicholas Piggin
The backtrace handler terminates when it sees a NULL caller address,
but the powerpc stack setup does not keep such a NULL caller frame
at the start of the stack.

This happens to work on pseries because the memory at 0 is mapped and
it contains 0 at the location of the return address pointer if it
were a stack frame. But this is fragile, and does not work with powernv
where address 0 contains firmware instructions.

Use the existing dummy frame on stack as the NULL caller, and create a
new frame on stack for the entry code.

Signed-off-by: Nicholas Piggin 
---
 powerpc/cstart64.S | 12 ++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/powerpc/cstart64.S b/powerpc/cstart64.S
index e18ae9a22..14ab0c6c8 100644
--- a/powerpc/cstart64.S
+++ b/powerpc/cstart64.S
@@ -46,8 +46,16 @@ start:
add r1, r1, r31
add r2, r2, r31
 
+   /* Zero backpointers in initial stack frame so backtrace() stops */
+   li  r0,0
+   std r0,0(r1)
+   std r0,16(r1)
+
+   /* Create entry frame */
+   stdur1,-INT_FRAME_SIZE(r1)
+
/* save DTB pointer */
-   std r3, 56(r1)
+   SAVE_GPR(3,r1)
 
/*
 * Call relocate. relocate is C code, but careful to not use
@@ -101,7 +109,7 @@ start:
stw r4, 0(r3)
 
/* complete setup */
-1: ld  r3, 56(r1)
+1: REST_GPR(3, r1)
bl  setup
 
/* run the test */
-- 
2.42.0



[kvm-unit-tests PATCH 02/32] powerpc: Fix pseries getchar return value

2024-02-26 Thread Nicholas Piggin
getchar() didn't get the shift value correct and never returned the
first character. This never really mattered since it was only ever
used for press-a-key-to-continue prompts. but it tripped me up when
debugging a QEMU console output problem.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/hcall.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lib/powerpc/hcall.c b/lib/powerpc/hcall.c
index 711cb1b0f..b4d39ac65 100644
--- a/lib/powerpc/hcall.c
+++ b/lib/powerpc/hcall.c
@@ -43,5 +43,5 @@ int __getchar(void)
asm volatile (" sc 1 "  : "+r"(r3), "+r"(r4), "=r"(r5)
: "r"(r3),  "r"(r4));
 
-   return r3 == H_SUCCESS && r4 > 0 ? r5 >> 48 : -1;
+   return r3 == H_SUCCESS && r4 > 0 ? r5 >> 56 : -1;
 }
-- 
2.42.0



[kvm-unit-tests PATCH 01/32] powerpc: Fix KVM caps on POWER9 hosts

2024-02-26 Thread Nicholas Piggin
KVM does not like to run on POWER9 hosts without cap-ccf-assist=off.

Signed-off-by: Nicholas Piggin 
---
 powerpc/run | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/powerpc/run b/powerpc/run
index e469f1eb3..5cdb94194 100755
--- a/powerpc/run
+++ b/powerpc/run
@@ -24,6 +24,8 @@ M+=",accel=$ACCEL$ACCEL_PROPS"
 
 if [[ "$ACCEL" == "tcg" ]] ; then
M+=",cap-cfpc=broken,cap-sbbc=broken,cap-ibs=broken,cap-ccf-assist=off"
+elif [[ "$ACCEL" == "kvm" ]] ; then
+   M+=",cap-ccf-assist=off"
 fi
 
 command="$qemu -nodefaults $M -bios $FIRMWARE"
-- 
2.42.0



[kvm-unit-tests PATCH 00/32] powerpc improvements

2024-02-26 Thread Nicholas Piggin
This is the same familiar set of powerpc patches, it's taken a
while to get them merged. And unfortunately they keep growing
with fixes and new tests.

This goes on top of the previous migration and other core
patches. Full tree can be found here.

https://gitlab.com/npiggin/kvm-unit-tests/-/tree/powerpc?ref_type=heads

I have tried to test all combinations of KVM and TCG for P8/9/10
and powernv. There are a small number of failures, some due to
bugs in TCG, QEMU, and KVM. I don't want to drop such test cases
but xfail doesn't quite work because it will start failing if we
fix implementation to now work AFAIKS. If there is concern about
that, then maybe we could add a known-failure type of report that
can document the reason and not fail the entire group of tests.

Since last posting, this adds several fixes to the start of the
series, fixes a bunch of bugs in the SPRs and other tests that
Joel and Thomas raised.  Tidied up the new new SMP support and
fixed a couple of issues there. Added MMU, usermode support,
add atomics, timebase, PMU tests, and removes the ppc64
subdirectories.

Thanks,
Nick

Nicholas Piggin (32):
  powerpc: Fix KVM caps on POWER9 hosts
  powerpc: Fix pseries getchar return value
  powerpc: Fix stack backtrace termination
  powerpc: interrupt stack backtracing
  powerpc: Cleanup SPR and MSR definitions
  powerpc/sprs: Specify SPRs with data rather than code
  powerpc/sprs: Don't fail changed SPRs that are used by the test
harness
  powerpc/sprs: Avoid taking PMU interrupts caused by register fuzzing
  scripts: allow machine option to be specified in unittests.cfg
  scripts: Accommodate powerpc powernv machine differences
  powerpc: Support powernv machine with QEMU TCG
  powerpc: Fix emulator illegal instruction test for powernv
  powerpc/sprs: Test hypervisor registers on powernv machine
  powerpc: general interrupt tests
  powerpc: Add rtas stop-self support
  powerpc: Remove broken SMP exception stack setup
  arch-run: Fix handling multiple exit status messages
  powerpc: add SMP and IPI support
  powerpc: Permit ACCEL=tcg,thread=single
  powerpc: Avoid using larx/stcx. in spinlocks when only one CPU is
running
  powerpc: Add atomics tests
  powerpc: Add timebase tests
  powerpc: Add MMU support
  common/sieve: Use vmalloc.h for setup_mmu definition
  common/sieve: Support machines without MMU
  powerpc: Add sieve.c common test
  powerpc: add usermode support
  powerpc: add pmu tests
  configure: Fail on unknown arch
  configure: Make arch_libdir a first-class entity
  powerpc: Remove remnants of ppc64 directory and build structure
  powerpc: gitlab CI update

 .gitlab-ci.yml   |  16 +-
 MAINTAINERS  |   1 -
 Makefile |   2 +-
 common/sieve.c   |  15 +-
 configure|  69 ++-
 lib/libcflat.h   |   2 -
 lib/{ppc64 => powerpc}/asm-offsets.c |   7 +
 lib/{ppc64 => powerpc}/asm/asm-offsets.h |   0
 lib/powerpc/asm/atomic.h |   6 +
 lib/powerpc/asm/barrier.h|  12 +
 lib/{ppc64 => powerpc}/asm/bitops.h  |   4 +-
 lib/powerpc/asm/hcall.h  |   6 +
 lib/{ppc64 => powerpc}/asm/io.h  |   4 +-
 lib/powerpc/asm/mmu.h|  10 +
 lib/powerpc/asm/opal.h   |  22 +
 lib/powerpc/asm/page.h   |  66 +++
 lib/powerpc/asm/pgtable-hwdef.h  |  67 +++
 lib/powerpc/asm/pgtable.h| 126 +
 lib/powerpc/asm/ppc_asm.h|   8 +-
 lib/powerpc/asm/processor.h  |  68 ++-
 lib/{ppc64 => powerpc}/asm/ptrace.h  |  22 +-
 lib/powerpc/asm/reg.h|  72 +++
 lib/powerpc/asm/rtas.h   |   2 +
 lib/powerpc/asm/setup.h  |   3 +-
 lib/powerpc/asm/smp.h|  50 +-
 lib/powerpc/asm/spinlock.h   |  11 +
 lib/powerpc/asm/stack.h  |   3 +
 lib/powerpc/asm/time.h   |   1 +
 lib/{ppc64 => powerpc}/asm/vpa.h |   0
 lib/powerpc/hcall.c  |   6 +-
 lib/powerpc/io.c |  41 +-
 lib/powerpc/io.h |   6 +
 lib/powerpc/mmu.c| 275 +
 lib/powerpc/opal-calls.S |  50 ++
 lib/powerpc/opal.c   |  76 +++
 lib/powerpc/processor.c  |  91 ++-
 lib/powerpc/rtas.c   |  81 ++-
 lib/powerpc/setup.c  | 159 +-
 lib/powerpc/smp.c| 287 --
 lib/powerpc/spinlock.c   |  32 ++
 lib/powerpc/stack.c  |  55 ++
 lib/ppc64/.gitignore |   1 -
 lib/ppc64/asm/barrier.h  |   9 -
 lib/ppc64/asm/handlers.h |   1 -
 lib/ppc64/asm/hcall.h|   1 -
 lib/ppc64/asm/memory_areas.h   

[kvm-unit-tests PATCH 7/7] common: add memory dirtying vs migration test

2024-02-26 Thread Nicholas Piggin
This test stores to a bunch of pages and verifies previous stores,
while being continually migrated. This can fail due to a QEMU TCG
physical memory dirty bitmap bug.

Signed-off-by: Nicholas Piggin 
---
 common/memory-verify.c  | 48 +
 powerpc/Makefile.common |  1 +
 powerpc/memory-verify.c |  1 +
 powerpc/unittests.cfg   |  7 ++
 s390x/Makefile  |  1 +
 s390x/memory-verify.c   |  1 +
 s390x/unittests.cfg |  6 ++
 7 files changed, 65 insertions(+)
 create mode 100644 common/memory-verify.c
 create mode 12 powerpc/memory-verify.c
 create mode 12 s390x/memory-verify.c

diff --git a/common/memory-verify.c b/common/memory-verify.c
new file mode 100644
index 0..7c4ec087b
--- /dev/null
+++ b/common/memory-verify.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Simple memory verification test, used to exercise dirty memory migration.
+ *
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define NR_PAGES 32
+
+int main(int argc, char **argv)
+{
+   void *mem = malloc(NR_PAGES*PAGE_SIZE);
+   bool success = true;
+   uint64_t ms;
+   long i;
+
+   report_prefix_push("memory");
+
+   memset(mem, 0, NR_PAGES*PAGE_SIZE);
+
+   migrate_begin_continuous();
+   ms = get_clock_ms();
+   i = 0;
+   do {
+   int j;
+
+   for (j = 0; j < NR_PAGES*PAGE_SIZE; j += PAGE_SIZE) {
+   if (*(volatile long *)(mem + j) != i) {
+   success = false;
+   goto out;
+   }
+   *(volatile long *)(mem + j) = i + 1;
+   }
+   i++;
+   } while (get_clock_ms() - ms < 5000);
+out:
+   migrate_end_continuous();
+
+   report(success, "memory verification stress test");
+
+   report_prefix_pop();
+
+   return report_summary();
+}
diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index da4a7bbb8..1e181da69 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -7,6 +7,7 @@
 tests-common = \
$(TEST_DIR)/selftest.elf \
$(TEST_DIR)/selftest-migration.elf \
+   $(TEST_DIR)/memory-verify.elf \
$(TEST_DIR)/spapr_hcall.elf \
$(TEST_DIR)/rtas.elf \
$(TEST_DIR)/emulator.elf \
diff --git a/powerpc/memory-verify.c b/powerpc/memory-verify.c
new file mode 12
index 0..5985c730f
--- /dev/null
+++ b/powerpc/memory-verify.c
@@ -0,0 +1 @@
+../common/memory-verify.c
\ No newline at end of file
diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index 89abf2095..fadd8dde6 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -46,6 +46,13 @@ machine = pseries
 groups = selftest migration
 extra_params = -append "skip"
 
+# This fails due to a QEMU TCG bug so KVM-only until QEMU is fixed upstream
+[migration-memory]
+file = memory-verify.elf
+accel = kvm
+machine = pseries
+groups = migration
+
 [spapr_hcall]
 file = spapr_hcall.elf
 
diff --git a/s390x/Makefile b/s390x/Makefile
index 344d46d68..ddc0969f3 100644
--- a/s390x/Makefile
+++ b/s390x/Makefile
@@ -1,5 +1,6 @@
 tests = $(TEST_DIR)/selftest.elf
 tests += $(TEST_DIR)/selftest-migration.elf
+tests += $(TEST_DIR)/memory-verify.elf
 tests += $(TEST_DIR)/intercept.elf
 tests += $(TEST_DIR)/emulator.elf
 tests += $(TEST_DIR)/sieve.elf
diff --git a/s390x/memory-verify.c b/s390x/memory-verify.c
new file mode 12
index 0..5985c730f
--- /dev/null
+++ b/s390x/memory-verify.c
@@ -0,0 +1 @@
+../common/memory-verify.c
\ No newline at end of file
diff --git a/s390x/unittests.cfg b/s390x/unittests.cfg
index f613602d3..a88fe9e79 100644
--- a/s390x/unittests.cfg
+++ b/s390x/unittests.cfg
@@ -33,6 +33,12 @@ file = selftest-migration.elf
 groups = selftest migration
 extra_params = -append "skip"
 
+# This fails due to a QEMU TCG bug so KVM-only until QEMU is fixed upstream
+[migration-memory]
+file = memory-verify.elf
+accel = kvm
+groups = migration
+
 [intercept]
 file = intercept.elf
 
-- 
2.42.0



[kvm-unit-tests PATCH 6/7] gitlab-ci: Run migration selftest on s390x and powerpc

2024-02-26 Thread Nicholas Piggin
The migration harness is complicated and easy to break so CI will
be helpful.

Signed-off-by: Nicholas Piggin 
---
 .gitlab-ci.yml | 18 +++---
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 71d986e98..61f196d5d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -64,26 +64,28 @@ build-arm:
 build-ppc64be:
  extends: .outoftree_template
  script:
- - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu
+ - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu nmap-ncat
  - mkdir build
  - cd build
  - ../configure --arch=ppc64 --endian=big --cross-prefix=powerpc64-linux-gnu-
  - make -j2
  - ACCEL=tcg ./run_tests.sh
- selftest-setup spapr_hcall rtas-get-time-of-day rtas-get-time-of-day-base
- rtas-set-time-of-day emulator
+ selftest-setup selftest-migration selftest-migration-skip spapr_hcall
+ rtas-get-time-of-day rtas-get-time-of-day-base rtas-set-time-of-day
+ emulator
  | tee results.txt
  - if grep -q FAIL results.txt ; then exit 1 ; fi
 
 build-ppc64le:
  extends: .intree_template
  script:
- - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu
+ - dnf install -y qemu-system-ppc gcc-powerpc64-linux-gnu nmap-ncat
  - ./configure --arch=ppc64 --endian=little --cross-prefix=powerpc64-linux-gnu-
  - make -j2
  - ACCEL=tcg ./run_tests.sh
- selftest-setup spapr_hcall rtas-get-time-of-day rtas-get-time-of-day-base
- rtas-set-time-of-day emulator
+ selftest-setup selftest-migration selftest-migration-skip spapr_hcall
+ rtas-get-time-of-day rtas-get-time-of-day-base rtas-set-time-of-day
+ emulator
  | tee results.txt
  - if grep -q FAIL results.txt ; then exit 1 ; fi
 
@@ -107,7 +109,7 @@ build-riscv64:
 build-s390x:
  extends: .outoftree_template
  script:
- - dnf install -y qemu-system-s390x gcc-s390x-linux-gnu
+ - dnf install -y qemu-system-s390x gcc-s390x-linux-gnu nmap-ncat
  - mkdir build
  - cd build
  - ../configure --arch=s390x --cross-prefix=s390x-linux-gnu-
@@ -133,6 +135,8 @@ build-s390x:
   sclp-1g
   sclp-3g
   selftest-setup
+  selftest-migration
+  selftest-migration-skip
   sieve
   smp
   stsi
-- 
2.42.0



[kvm-unit-tests PATCH 5/7] arch-run: Add a "continuous" migration option for tests

2024-02-26 Thread Nicholas Piggin
The cooperative migration protocol is very good to control precise
pre and post conditions for a migration event. However in some cases
its intrusiveness to the test program, can mask problems and make
analysis more difficult.

For example to stress test migration vs concurrent complicated
memory access, including TLB refill, ram dirtying, etc., then the
tight spin at getchar() and resumption of the workload after
migration is unhelpful.

This adds a continuous migration mode that directs the harness to
perform migrations continually. This is added to the migration
selftests, which also sees cooperative migration iterations reduced
to avoid increasing test time too much.

Signed-off-by: Nicholas Piggin 
---
 common/selftest-migration.c | 16 +--
 lib/migrate.c   | 18 
 lib/migrate.h   |  3 ++
 scripts/arch-run.bash   | 55 -
 4 files changed, 82 insertions(+), 10 deletions(-)

diff --git a/common/selftest-migration.c b/common/selftest-migration.c
index 0afd8581c..9a9b61835 100644
--- a/common/selftest-migration.c
+++ b/common/selftest-migration.c
@@ -9,12 +9,13 @@
  */
 #include 
 #include 
+#include 
 
-#define NR_MIGRATIONS 30
+#define NR_MIGRATIONS 15
 
 int main(int argc, char **argv)
 {
-   report_prefix_push("migration");
+   report_prefix_push("migration harness");
 
if (argc > 1 && !strcmp(argv[1], "skip")) {
migrate_skip();
@@ -24,7 +25,16 @@ int main(int argc, char **argv)
 
for (i = 0; i < NR_MIGRATIONS; i++)
migrate_quiet();
-   report(true, "simple harness stress");
+   report(true, "cooperative migration");
+
+   migrate_begin_continuous();
+   mdelay(2000);
+   migrate_end_continuous();
+   mdelay(1000);
+   migrate_begin_continuous();
+   mdelay(2000);
+   migrate_end_continuous();
+   report(true, "continuous migration");
}
 
report_prefix_pop();
diff --git a/lib/migrate.c b/lib/migrate.c
index 1d22196b7..770f76d5c 100644
--- a/lib/migrate.c
+++ b/lib/migrate.c
@@ -60,3 +60,21 @@ void migrate_skip(void)
puts("Skipped VM migration (quiet)\n");
(void)getchar();
 }
+
+void migrate_begin_continuous(void)
+{
+   puts("Begin continuous migration\n");
+   (void)getchar();
+}
+
+void migrate_end_continuous(void)
+{
+   /*
+* Migration can split this output between source and dest QEMU
+* output files, print twice and match once to always cope with
+* a split.
+*/
+   puts("End continuous migration\n");
+   puts("End continuous migration (quiet)\n");
+   (void)getchar();
+}
diff --git a/lib/migrate.h b/lib/migrate.h
index db6e0c501..35b6703a2 100644
--- a/lib/migrate.h
+++ b/lib/migrate.h
@@ -11,3 +11,6 @@ void migrate_quiet(void);
 void migrate_once(void);
 
 void migrate_skip(void);
+
+void migrate_begin_continuous(void);
+void migrate_end_continuous(void);
diff --git a/scripts/arch-run.bash b/scripts/arch-run.bash
index d0f6f098f..5c7e72036 100644
--- a/scripts/arch-run.bash
+++ b/scripts/arch-run.bash
@@ -125,15 +125,17 @@ qmp_events ()
 filter_quiet_msgs ()
 {
grep -v "Now migrate the VM (quiet)" |
+   grep -v "Begin continuous migration (quiet)" |
+   grep -v "End continuous migration (quiet)" |
grep -v "Skipped VM migration (quiet)"
 }
 
 seen_migrate_msg ()
 {
if [ $skip_migration -eq 1 ]; then
-   grep -q -e "Now migrate the VM" < $1
+   grep -q -e "Now migrate the VM" -e "Begin continuous migration" 
< $1
else
-   grep -q -e "Now migrate the VM" -e "Skipped VM migration" < $1
+   grep -q -e "Now migrate the VM" -e "Begin continuous migration" 
-e "Skipped VM migration" < $1
fi
 }
 
@@ -161,6 +163,7 @@ run_migration ()
src_qmpout=/dev/null
dst_qmpout=/dev/null
skip_migration=0
+   continuous_migration=0
 
mkfifo ${src_outfifo}
mkfifo ${dst_outfifo}
@@ -186,9 +189,12 @@ run_migration ()
do_migration || return $?
 
while ps -p ${live_pid} > /dev/null ; do
-   # Wait for test exit or further migration messages.
-   if ! seen_migrate_msg ${src_out} ;  then
+   if [[ ${continuous_migration} -eq 1 ]] ; then
+   do_migration || return $?
+   elif ! seen_migrate_msg ${src_out} ;  then
sleep 0.1
+   elif grep -q "Begin continuous migration" < ${src_out} ; then
+   do_migration || return $?
elif 

[kvm-unit-tests PATCH 4/7] powerpc: add asm/time.h header with delay and get_clock_us/ms

2024-02-26 Thread Nicholas Piggin
This matches s390x clock and delay APIs, so common test code can start
using time facilities.

Signed-off-by: Nicholas Piggin 
---
 lib/powerpc/asm/processor.h | 21 -
 lib/powerpc/asm/time.h  | 30 ++
 lib/powerpc/processor.c | 11 +++
 lib/powerpc/smp.c   |  1 +
 lib/ppc64/asm/time.h|  1 +
 powerpc/spapr_vpa.c |  1 +
 powerpc/sprs.c  |  1 +
 powerpc/tm.c|  1 +
 8 files changed, 46 insertions(+), 21 deletions(-)
 create mode 100644 lib/powerpc/asm/time.h
 create mode 100644 lib/ppc64/asm/time.h

diff --git a/lib/powerpc/asm/processor.h b/lib/powerpc/asm/processor.h
index 4ad6612b3..fe1052939 100644
--- a/lib/powerpc/asm/processor.h
+++ b/lib/powerpc/asm/processor.h
@@ -43,25 +43,4 @@ static inline void mtmsr(uint64_t msr)
asm volatile ("mtmsrd %[msr]" :: [msr] "r" (msr) : "memory");
 }
 
-static inline uint64_t get_tb(void)
-{
-   return mfspr(SPR_TB);
-}
-
-extern void delay(uint64_t cycles);
-extern void udelay(uint64_t us);
-extern void sleep_tb(uint64_t cycles);
-extern void usleep(uint64_t us);
-
-static inline void mdelay(uint64_t ms)
-{
-   while (ms--)
-   udelay(1000);
-}
-
-static inline void msleep(uint64_t ms)
-{
-   usleep(ms * 1000);
-}
-
 #endif /* _ASMPOWERPC_PROCESSOR_H_ */
diff --git a/lib/powerpc/asm/time.h b/lib/powerpc/asm/time.h
new file mode 100644
index 0..72fcb1bd0
--- /dev/null
+++ b/lib/powerpc/asm/time.h
@@ -0,0 +1,30 @@
+#ifndef _ASMPOWERPC_TIME_H_
+#define _ASMPOWERPC_TIME_H_
+
+#include 
+#include 
+
+static inline uint64_t get_tb(void)
+{
+   return mfspr(SPR_TB);
+}
+
+extern uint64_t get_clock_us(void);
+extern uint64_t get_clock_ms(void);
+extern void delay(uint64_t cycles);
+extern void udelay(uint64_t us);
+extern void sleep_tb(uint64_t cycles);
+extern void usleep(uint64_t us);
+
+static inline void mdelay(uint64_t ms)
+{
+   while (ms--)
+   udelay(1000);
+}
+
+static inline void msleep(uint64_t ms)
+{
+   usleep(ms * 1000);
+}
+
+#endif /* _ASMPOWERPC_TIME_H_ */
diff --git a/lib/powerpc/processor.c b/lib/powerpc/processor.c
index b224fc8eb..ad0d95666 100644
--- a/lib/powerpc/processor.c
+++ b/lib/powerpc/processor.c
@@ -7,6 +7,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -54,6 +55,16 @@ void do_handle_exception(struct pt_regs *regs)
abort();
 }
 
+uint64_t get_clock_us(void)
+{
+   return get_tb() * 100 / tb_hz;
+}
+
+uint64_t get_clock_ms(void)
+{
+   return get_tb() * 1000 / tb_hz;
+}
+
 void delay(uint64_t cycles)
 {
uint64_t start = get_tb();
diff --git a/lib/powerpc/smp.c b/lib/powerpc/smp.c
index afe436179..3e211eba8 100644
--- a/lib/powerpc/smp.c
+++ b/lib/powerpc/smp.c
@@ -7,6 +7,7 @@
  */
 
 #include 
+#include 
 #include 
 #include 
 #include 
diff --git a/lib/ppc64/asm/time.h b/lib/ppc64/asm/time.h
new file mode 100644
index 0..326d2887a
--- /dev/null
+++ b/lib/ppc64/asm/time.h
@@ -0,0 +1 @@
+#include "../../powerpc/asm/time.h"
diff --git a/powerpc/spapr_vpa.c b/powerpc/spapr_vpa.c
index 6a3fe5e3f..c2075e157 100644
--- a/powerpc/spapr_vpa.c
+++ b/powerpc/spapr_vpa.c
@@ -10,6 +10,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
diff --git a/powerpc/sprs.c b/powerpc/sprs.c
index 57e487ceb..285976488 100644
--- a/powerpc/sprs.c
+++ b/powerpc/sprs.c
@@ -26,6 +26,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 uint64_t before[1024], after[1024];
diff --git a/powerpc/tm.c b/powerpc/tm.c
index 7fa916366..6b1ceeb6e 100644
--- a/powerpc/tm.c
+++ b/powerpc/tm.c
@@ -8,6 +8,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
-- 
2.42.0



[kvm-unit-tests PATCH 3/7] (arm|s390): Use migrate_skip in test cases

2024-02-26 Thread Nicholas Piggin
Have tests use the new migrate_skip command in skip paths, rather than
calling migrate_once to prevent harness reporting an error.

s390x/migration.c adds a new command that looks like it was missing
previously.

Signed-off-by: Nicholas Piggin 
---
 arm/gic.c  | 21 -
 s390x/migration-cmm.c  |  8 
 s390x/migration-skey.c |  4 +++-
 s390x/migration.c  |  1 +
 4 files changed, 20 insertions(+), 14 deletions(-)

diff --git a/arm/gic.c b/arm/gic.c
index c950b0d15..bbf828f17 100644
--- a/arm/gic.c
+++ b/arm/gic.c
@@ -782,13 +782,15 @@ static void test_its_migration(void)
struct its_device *dev2, *dev7;
cpumask_t mask;
 
-   if (its_setup1())
+   if (its_setup1()) {
+   migrate_skip();
return;
+   }
 
dev2 = its_get_device(2);
dev7 = its_get_device(7);
 
-   migrate_once();
+   migrate();
 
stats_reset();
cpumask_clear();
@@ -819,8 +821,10 @@ static void test_migrate_unmapped_collection(void)
int pe0 = 0;
u8 config;
 
-   if (its_setup1())
+   if (its_setup1()) {
+   migrate_skip();
return;
+   }
 
if (!errata(ERRATA_UNMAPPED_COLLECTIONS)) {
report_skip("Skipping test, as this test hangs without the fix. 
"
@@ -836,7 +840,7 @@ static void test_migrate_unmapped_collection(void)
its_send_mapti(dev2, 8192, 0, col);
gicv3_lpi_set_config(8192, LPI_PROP_DEFAULT);
 
-   migrate_once();
+   migrate();
 
/* on the destination, map the collection */
its_send_mapc(col, true);
@@ -875,8 +879,10 @@ static void test_its_pending_migration(void)
void *ptr;
int i;
 
-   if (its_prerequisites(4))
+   if (its_prerequisites(4)) {
+   migrate_skip();
return;
+   }
 
dev = its_create_device(2 /* dev id */, 8 /* nb_ites */);
its_send_mapd(dev, true);
@@ -923,7 +929,7 @@ static void test_its_pending_migration(void)
gicv3_lpi_rdist_enable(pe0);
gicv3_lpi_rdist_enable(pe1);
 
-   migrate_once();
+   migrate();
 
/* let's wait for the 256 LPIs to be handled */
mdelay(1000);
@@ -970,17 +976,14 @@ int main(int argc, char **argv)
} else if (!strcmp(argv[1], "its-migration")) {
report_prefix_push(argv[1]);
test_its_migration();
-   migrate_once();
report_prefix_pop();
} else if (!strcmp(argv[1], "its-pending-migration")) {
report_prefix_push(argv[1]);
test_its_pending_migration();
-   migrate_once();
report_prefix_pop();
} else if (!strcmp(argv[1], "its-migrate-unmapped-collection")) {
report_prefix_push(argv[1]);
test_migrate_unmapped_collection();
-   migrate_once();
report_prefix_pop();
} else if (strcmp(argv[1], "its-introspection") == 0) {
report_prefix_push(argv[1]);
diff --git a/s390x/migration-cmm.c b/s390x/migration-cmm.c
index 43673f18e..b4043a80e 100644
--- a/s390x/migration-cmm.c
+++ b/s390x/migration-cmm.c
@@ -55,12 +55,12 @@ int main(void)
 {
report_prefix_push("migration-cmm");
 
-   if (!check_essa_available())
+   if (!check_essa_available()) {
report_skip("ESSA is not available");
-   else
+   migrate_skip();
+   } else {
test_migration();
-
-   migrate_once();
+   }
 
report_prefix_pop();
return report_summary();
diff --git a/s390x/migration-skey.c b/s390x/migration-skey.c
index 8d6d8ecfe..1a196ae1e 100644
--- a/s390x/migration-skey.c
+++ b/s390x/migration-skey.c
@@ -169,6 +169,7 @@ static void test_skey_migration_parallel(void)
 
if (smp_query_num_cpus() == 1) {
report_skip("need at least 2 cpus for this test");
+   migrate_skip();
goto error;
}
 
@@ -233,6 +234,7 @@ int main(int argc, char **argv)
 
if (test_facility(169)) {
report_skip("storage key removal facility is active");
+   migrate_skip();
goto error;
}
 
@@ -247,11 +249,11 @@ int main(int argc, char **argv)
break;
default:
print_usage();
+   migrate_skip();
break;
}
 
 error:
-   migrate_once();
report_prefix_pop();
return report_summary();
 }
diff --git a/s390x/migration.c b/s390x/migration.c
index 269e272de..115afb731 100644
--- a/s390x/migration.c
+++ b/s390x/migration.c
@@ -164,6 +164,7 @@ int main(void)
 
if (smp_query_num_cpus() == 1) {
report_skip("need at least 2 cpus for this test");
+   migrate_skip();
goto done;
}
 
-- 
2.42.0



[kvm-unit-tests PATCH 2/7] migration: Add a migrate_skip command

2024-02-26 Thread Nicholas Piggin
Tests that are run with MIGRATION=yes but skip due to some requirement
not being met will show as a failure due to the harness requirement to
see one successful migration. The workaround for this is to migrate in
test's skip path. Add a new command that just tells the harness to not
expect a migration.

Signed-off-by: Nicholas Piggin 
---
 common/selftest-migration.c | 14 -
 lib/migrate.c   | 19 -
 lib/migrate.h   |  2 ++
 powerpc/unittests.cfg   |  6 ++
 s390x/unittests.cfg |  5 +
 scripts/arch-run.bash   | 41 +
 6 files changed, 73 insertions(+), 14 deletions(-)

diff --git a/common/selftest-migration.c b/common/selftest-migration.c
index 54b5d6b2d..0afd8581c 100644
--- a/common/selftest-migration.c
+++ b/common/selftest-migration.c
@@ -14,14 +14,18 @@
 
 int main(int argc, char **argv)
 {
-   int i = 0;
-
report_prefix_push("migration");
 
-   for (i = 0; i < NR_MIGRATIONS; i++)
-   migrate_quiet();
+   if (argc > 1 && !strcmp(argv[1], "skip")) {
+   migrate_skip();
+   report(true, "migration skipping");
+   } else {
+   int i;
 
-   report(true, "simple harness stress test");
+   for (i = 0; i < NR_MIGRATIONS; i++)
+   migrate_quiet();
+   report(true, "simple harness stress");
+   }
 
report_prefix_pop();
 
diff --git a/lib/migrate.c b/lib/migrate.c
index 92d1d957d..1d22196b7 100644
--- a/lib/migrate.c
+++ b/lib/migrate.c
@@ -39,7 +39,24 @@ void migrate_once(void)
 
if (migrated)
return;
-
migrated = true;
+
migrate();
 }
+
+/*
+ * When the test has been started in migration mode, but the test case is
+ * skipped and no migration point is reached, this can be used to tell the
+ * harness not to mark it as a failure to migrate.
+ */
+void migrate_skip(void)
+{
+   static bool did_migrate_skip;
+
+   if (did_migrate_skip)
+   return;
+   did_migrate_skip = true;
+
+   puts("Skipped VM migration (quiet)\n");
+   (void)getchar();
+}
diff --git a/lib/migrate.h b/lib/migrate.h
index 95b9102b0..db6e0c501 100644
--- a/lib/migrate.h
+++ b/lib/migrate.h
@@ -9,3 +9,5 @@
 void migrate(void);
 void migrate_quiet(void);
 void migrate_once(void);
+
+void migrate_skip(void);
diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index 7ce57de02..89abf2095 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -40,6 +40,12 @@ groups = selftest
 file = selftest-migration.elf
 groups = selftest migration
 
+[selftest-migration-skip]
+file = selftest-migration.elf
+machine = pseries
+groups = selftest migration
+extra_params = -append "skip"
+
 [spapr_hcall]
 file = spapr_hcall.elf
 
diff --git a/s390x/unittests.cfg b/s390x/unittests.cfg
index a7ad522ca..f613602d3 100644
--- a/s390x/unittests.cfg
+++ b/s390x/unittests.cfg
@@ -28,6 +28,11 @@ extra_params = -append 'test 123'
 file = selftest-migration.elf
 groups = selftest migration
 
+[selftest-migration-skip]
+file = selftest-migration.elf
+groups = selftest migration
+extra_params = -append "skip"
+
 [intercept]
 file = intercept.elf
 
diff --git a/scripts/arch-run.bash b/scripts/arch-run.bash
index e5b36a07b..d0f6f098f 100644
--- a/scripts/arch-run.bash
+++ b/scripts/arch-run.bash
@@ -124,12 +124,17 @@ qmp_events ()
 
 filter_quiet_msgs ()
 {
-   grep -v "Now migrate the VM (quiet)"
+   grep -v "Now migrate the VM (quiet)" |
+   grep -v "Skipped VM migration (quiet)"
 }
 
 seen_migrate_msg ()
 {
-   grep -q -e "Now migrate the VM" < $1
+   if [ $skip_migration -eq 1 ]; then
+   grep -q -e "Now migrate the VM" < $1
+   else
+   grep -q -e "Now migrate the VM" -e "Skipped VM migration" < $1
+   fi
 }
 
 run_migration ()
@@ -142,7 +147,7 @@ run_migration ()
migcmdline=$@
 
trap 'trap - TERM ; kill 0 ; exit 2' INT TERM
-   trap 'rm -f ${src_out} ${dst_out} ${src_outfifo} ${dst_outfifo} 
${dst_incoming} ${src_qmp} ${dst_qmp} ${dst_infifo}' RETURN EXIT
+   trap 'rm -f ${src_out} ${dst_out} ${src_outfifo} ${dst_outfifo} 
${dst_incoming} ${src_qmp} ${dst_qmp} ${src_infifo} ${dst_infifo}' RETURN EXIT
 
dst_incoming=$(mktemp -u -t mig-helper-socket-incoming.XX)
src_out=$(mktemp -t mig-helper-stdout1.XX)
@@ -151,21 +156,26 @@ run_migration ()
dst_outfifo=$(mktemp -u -t mig-helper-fifo-stdout2.XX)
src_qmp=$(mktemp -u -t mig-helper-qmp1.XX)
dst_qmp=$(mktemp -u -t mig-helper-qmp2.XX)
-   dst_infifo=$(mktemp -u -t mig-helper-fifo-stdin.XX)
+   src_infifo=$(mktemp -u -t mig-helper-fifo-stdin1.XX)
+ 

[kvm-unit-tests PATCH 1/7] arch-run: Keep infifo open

2024-02-26 Thread Nicholas Piggin
The infifo fifo that is used to send characters to QEMU console is
only able to receive one character before the cat process exits.
Supporting interactions between test and harness involving multiple
characters requires the fifo to remain open.

This also allows us to let the cat out of the bag, simplifying the
input pipeline.

Signed-off-by: Nicholas Piggin 
---
 scripts/arch-run.bash | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/scripts/arch-run.bash b/scripts/arch-run.bash
index 6daef3218..e5b36a07b 100644
--- a/scripts/arch-run.bash
+++ b/scripts/arch-run.bash
@@ -158,6 +158,11 @@ run_migration ()
mkfifo ${src_outfifo}
mkfifo ${dst_outfifo}
 
+   # Holding both ends of the input fifo open prevents opens from
+   # blocking and readers getting EOF when a writer closes it.
+   mkfifo ${dst_infifo}
+   exec {dst_infifo_fd}<>${dst_infifo}
+
eval "$migcmdline" \
-chardev socket,id=mon,path=${src_qmp},server=on,wait=off \
-mon chardev=mon,mode=control > ${src_outfifo} &
@@ -191,14 +196,10 @@ run_migration ()
 
 do_migration ()
 {
-   # We have to use cat to open the named FIFO, because named FIFO's,
-   # unlike pipes, will block on open() until the other end is also
-   # opened, and that totally breaks QEMU...
-   mkfifo ${dst_infifo}
eval "$migcmdline" \
-chardev socket,id=mon,path=${dst_qmp},server=on,wait=off \
-mon chardev=mon,mode=control -incoming unix:${dst_incoming} \
-   < <(cat ${dst_infifo}) > ${dst_outfifo} &
+   < ${dst_infifo} > ${dst_outfifo} &
incoming_pid=$!
cat ${dst_outfifo} | tee ${dst_out} | filter_quiet_msgs &
 
@@ -245,7 +246,6 @@ do_migration ()
 
# keypress to dst so getchar completes and test continues
echo > ${dst_infifo}
-   rm ${dst_infifo}
 
# Ensure the incoming socket is removed, ready for next destination
if [ -S ${dst_incoming} ] ; then
-- 
2.42.0



[kvm-unit-tests PATCH 0/7] more migration enhancements and tests

2024-02-26 Thread Nicholas Piggin
This series applies on top of the multi-migration patches and just
has assorted things I've been collecting.

- New migrate_skip() command that tidies up the wart of using
  migrate_once() to skip migration.
- New "continuous migration" mode where the harness just
  migrates the test contually while it is running.
- Put some migration tests in gitlab CI for powerpc and s390.
- Add a test case that can reproduce the QEMU TCG dirty bitmap
  migration bug.

Nicholas Piggin (7):
  arch-run: Keep infifo open
  migration: Add a migrate_skip command
  (arm|s390): Use migrate_skip in test cases
  powerpc: add asm/time.h header with delay and get_clock_us/ms
  arch-run: Add a "continuous" migration option for tests
  gitlab-ci: Run migration selftest on s390x and powerpc
  common: add memory dirtying vs migration test

 .gitlab-ci.yml  |  18 ---
 arm/gic.c   |  21 
 common/memory-verify.c  |  48 +
 common/selftest-migration.c |  26 ++---
 lib/migrate.c   |  37 -
 lib/migrate.h   |   5 ++
 lib/powerpc/asm/processor.h |  21 
 lib/powerpc/asm/time.h  |  30 +++
 lib/powerpc/processor.c |  11 
 lib/powerpc/smp.c   |   1 +
 lib/ppc64/asm/time.h|   1 +
 powerpc/Makefile.common |   1 +
 powerpc/memory-verify.c |   1 +
 powerpc/spapr_vpa.c |   1 +
 powerpc/sprs.c  |   1 +
 powerpc/tm.c|   1 +
 powerpc/unittests.cfg   |  13 +
 s390x/Makefile  |   1 +
 s390x/memory-verify.c   |   1 +
 s390x/migration-cmm.c   |   8 +--
 s390x/migration-skey.c  |   4 +-
 s390x/migration.c   |   1 +
 s390x/unittests.cfg |  11 
 scripts/arch-run.bash   | 104 +---
 24 files changed, 299 insertions(+), 68 deletions(-)
 create mode 100644 common/memory-verify.c
 create mode 100644 lib/powerpc/asm/time.h
 create mode 100644 lib/ppc64/asm/time.h
 create mode 12 powerpc/memory-verify.c
 create mode 12 s390x/memory-verify.c

-- 
2.42.0



Re: [kvm-unit-tests PATCH v5 0/8] Multi-migration support

2024-02-26 Thread Nicholas Piggin
On Fri Feb 23, 2024 at 5:06 PM AEST, Thomas Huth wrote:
> On 21/02/2024 04.27, Nicholas Piggin wrote:
> > Now that strange arm64 hang is found to be QEMU bug, I'll repost.
> > Since arm64 requires Thomas's uart patch and it is worse affected
> > by the QEMU bug, I will just not build it on arm. The QEMU bug
> > still affects powerpc (and presumably s390x) but it's not causing
> > so much trouble for this test case.
> > 
> > I have another test case that can hit it reliably and doesn't
> > cause crashes but that takes some harness and common lib work so
> > I'll send that another time.
> > 
> > Since v4:
> > - Don't build selftest-migration on arm.
> > - Reduce selftest-migration iterations from 100 to 30 to make the
> >test run faster (it's ~0.5s per migration).
>
> Thanks, I think the series is ready to go now ... we just have to wait for 
> your QEMU TCG migration fix to get merged first. Or should we maybe mark the 
> selftest-migration with "accel = kvm" for now and remove that line later 
> once QEMU has been fixed?

Could we merge it? I'm juggling a bunch of different things and prone to
lose track of something :\ I'll need to drum up a bit of interest to
review the QEMU fixes from those who know the code too, so that may take
some time.

I left it out of arm unittests.cfg entirely, and s390 and powerpc seems
to work by luck enough to be useful for gitlab CI so I don't think there
is a chnage needed really unless you're paranoid.

I do have a later patch that adds a memory tester that does trigger it
right away on powerpc. I'll send that out after this series is merged...
but we do still have the issue that the gitlab CI image has the old QEMU
don't we? Until we update distro.

Thanks,
Nick



[kvm-unit-tests PATCH v5 8/8] migration: add a migration selftest

2024-02-20 Thread Nicholas Piggin
Add a selftest for migration support in  guest library and test harness
code. It performs migrations in a tight loop to irritate races and bugs
in the test harness code.

Include the test in s390, powerpc.

Acked-by: Claudio Imbrenda  (s390x)
Reviewed-by: Thomas Huth 
Signed-off-by: Nicholas Piggin 
---
 common/selftest-migration.c  | 29 +
 powerpc/Makefile.common  |  1 +
 powerpc/selftest-migration.c |  1 +
 powerpc/unittests.cfg|  4 
 s390x/Makefile   |  1 +
 s390x/selftest-migration.c   |  1 +
 s390x/unittests.cfg  |  4 
 7 files changed, 41 insertions(+)
 create mode 100644 common/selftest-migration.c
 create mode 12 powerpc/selftest-migration.c
 create mode 12 s390x/selftest-migration.c

diff --git a/common/selftest-migration.c b/common/selftest-migration.c
new file mode 100644
index 0..54b5d6b2d
--- /dev/null
+++ b/common/selftest-migration.c
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Machine independent migration tests
+ *
+ * This is just a very simple test that is intended to stress the migration
+ * support in the test harness. This could be expanded to test more guest
+ * library code, but architecture-specific tests should be used to test
+ * migration of tricky machine state.
+ */
+#include 
+#include 
+
+#define NR_MIGRATIONS 30
+
+int main(int argc, char **argv)
+{
+   int i = 0;
+
+   report_prefix_push("migration");
+
+   for (i = 0; i < NR_MIGRATIONS; i++)
+   migrate_quiet();
+
+   report(true, "simple harness stress test");
+
+   report_prefix_pop();
+
+   return report_summary();
+}
diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
index eb88398d8..da4a7bbb8 100644
--- a/powerpc/Makefile.common
+++ b/powerpc/Makefile.common
@@ -6,6 +6,7 @@
 
 tests-common = \
$(TEST_DIR)/selftest.elf \
+   $(TEST_DIR)/selftest-migration.elf \
$(TEST_DIR)/spapr_hcall.elf \
$(TEST_DIR)/rtas.elf \
$(TEST_DIR)/emulator.elf \
diff --git a/powerpc/selftest-migration.c b/powerpc/selftest-migration.c
new file mode 12
index 0..bd1eb266d
--- /dev/null
+++ b/powerpc/selftest-migration.c
@@ -0,0 +1 @@
+../common/selftest-migration.c
\ No newline at end of file
diff --git a/powerpc/unittests.cfg b/powerpc/unittests.cfg
index e71140aa5..7ce57de02 100644
--- a/powerpc/unittests.cfg
+++ b/powerpc/unittests.cfg
@@ -36,6 +36,10 @@ smp = 2
 extra_params = -m 256 -append 'setup smp=2 mem=256'
 groups = selftest
 
+[selftest-migration]
+file = selftest-migration.elf
+groups = selftest migration
+
 [spapr_hcall]
 file = spapr_hcall.elf
 
diff --git a/s390x/Makefile b/s390x/Makefile
index b72f7578f..344d46d68 100644
--- a/s390x/Makefile
+++ b/s390x/Makefile
@@ -1,4 +1,5 @@
 tests = $(TEST_DIR)/selftest.elf
+tests += $(TEST_DIR)/selftest-migration.elf
 tests += $(TEST_DIR)/intercept.elf
 tests += $(TEST_DIR)/emulator.elf
 tests += $(TEST_DIR)/sieve.elf
diff --git a/s390x/selftest-migration.c b/s390x/selftest-migration.c
new file mode 12
index 0..bd1eb266d
--- /dev/null
+++ b/s390x/selftest-migration.c
@@ -0,0 +1 @@
+../common/selftest-migration.c
\ No newline at end of file
diff --git a/s390x/unittests.cfg b/s390x/unittests.cfg
index f5024b6ee..a7ad522ca 100644
--- a/s390x/unittests.cfg
+++ b/s390x/unittests.cfg
@@ -24,6 +24,10 @@ groups = selftest
 # please keep the kernel cmdline in sync with $(TEST_DIR)/selftest.parmfile
 extra_params = -append 'test 123'
 
+[selftest-migration]
+file = selftest-migration.elf
+groups = selftest migration
+
 [intercept]
 file = intercept.elf
 
-- 
2.42.0



  1   2   3   4   5   6   7   8   9   10   >