* [PATCH v5 0/9] KVM: selftests: add powerpc support
@ 2026-09-22 18:28 Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 1/9] KVM: PPC: selftests: add support for powerpc Ritesh Harjani (IBM)
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: Ritesh Harjani (IBM) @ 2026-09-22 18:28 UTC (permalink / raw)
To: kvm
Cc: Sean Christopherson, Paolo Bonzini, linuxppc-dev,
Michael Ellerman, Christophe Leroy, Anushree Mathur,
Venkat Rao Bagalkote, Harsh Prateek Bora, Madhavan Srinivasan,
Shrikanth Hegde, linux-kernel, Ritesh Harjani (IBM)
Patch v4 -> v5:
==============
- Fixed the issues reported by Anushree while running on kvm on powervm
(nested).
- Fixed memslot_perf_test on powerpc.
PATCH v3 -> PATCH v4:
==================
- Rebased on top of Sean's new page allocator patch series v2 [1]
This allowed to drop and patch-2 since it will now come from Sean's
v2.
- Addressed review comments from Sean - squashed patches 6-10 in patch-1 of
this.
- Dropped patch-5 to print vcpu_id when KVM_CREATE_VCPU ioctl fails.
- Added additional patch-3 to this series to allow dirty_log_test to run on all
big-endian machines.
[1]: https://lore.kernel.org/kvm/20260902164123.2546762-1-seanjc@google.com/
[v3]: https://lore.kernel.org/linuxppc-dev/2d2c46be7f051c7f1c645afaec67f57067d37a81.1781093720.git.ritesh.list@gmail.com/
Testing updates:
================
I have done some fair amount of testing of the selftests both on real HW and
using various combinations on qemu (powernv+LE (default), pseries+cap-nested-hv,
pseries+cap-nested-papr, powernv+BE). There were few powerpc kvm kernel fixes
which were identified as part of this work. I will send those patches separately
as those anyway needs to go in separately.
<pasted snippet of cover letter from previous versions>
=======================================================
Hi All,
This series primarly adds KVM selftests support for powerpc (64-bit, BookS,
radix MMU).
This patch series is originally Nick's work. I have mainly only rebased it on
the latest upstream tree. Since the rebase required few changes to all the four
patches (Patch 1-4), I have dropped the earlier Acked-by from Michael Ellerman.
Since the last series was posted three years ago [1], I am resetting the version
to RFC. This rebase was done as part of a larger effort to improve the selftests
infrastructure for Linux on PowerPC tree. Thanks to Harsh and Maddy for their
help on this.
Nicholas Piggin (1):
KVM: PPC: selftests: add support for powerpc
Ritesh Harjani (IBM) (8):
KVM: selftests: Enable kvm_create_max_vcpus test for powerpc
KVM: selftests: Don't limit LE dirty-bitmap bitops to s390x
KVM: selftests: Split out a KVM_CREATE_VCPU helper that can fail
KVM: selftests: Make kvm_create_max_vcpus tolerate ENOMEM
KVM: selftests: Limit the number of VM creates in hardware_disable_test
KVM: PPC: selftests: Make nested case on pseries LPARs as resource constrained
KVM: PPC: selftests: Skip idle-page check when running nested on pseries LPAR
KVM: selftests: Move memslot_perf_test off the 256M ELF load address
MAINTAINERS | 2 +
tools/testing/selftests/kvm/Makefile | 2 +-
tools/testing/selftests/kvm/Makefile.kvm | 10 +
.../selftests/kvm/access_tracking_perf_test.c | 11 +
tools/testing/selftests/kvm/dirty_log_test.c | 12 +-
.../selftests/kvm/hardware_disable_test.c | 7 +-
.../testing/selftests/kvm/include/kvm_util.h | 13 +
.../selftests/kvm/include/powerpc/hcall.h | 17 +
.../kvm/include/powerpc/kvm_util_arch.h | 22 +
.../selftests/kvm/include/powerpc/ppc_asm.h | 32 ++
.../selftests/kvm/include/powerpc/processor.h | 46 ++
.../selftests/kvm/include/powerpc/ucall.h | 21 +
.../selftests/kvm/kvm_create_max_vcpus.c | 29 +-
tools/testing/selftests/kvm/lib/guest_modes.c | 20 +-
tools/testing/selftests/kvm/lib/kvm_util.c | 39 +-
.../selftests/kvm/lib/powerpc/handlers.S | 93 ++++
.../testing/selftests/kvm/lib/powerpc/hcall.c | 45 ++
.../selftests/kvm/lib/powerpc/processor.c | 522 ++++++++++++++++++
.../testing/selftests/kvm/lib/powerpc/ucall.c | 22 +
.../testing/selftests/kvm/memslot_perf_test.c | 2 +-
20 files changed, 942 insertions(+), 25 deletions(-)
create mode 100644 tools/testing/selftests/kvm/include/powerpc/hcall.h
create mode 100644 tools/testing/selftests/kvm/include/powerpc/kvm_util_arch.h
create mode 100644 tools/testing/selftests/kvm/include/powerpc/ppc_asm.h
create mode 100644 tools/testing/selftests/kvm/include/powerpc/processor.h
create mode 100644 tools/testing/selftests/kvm/include/powerpc/ucall.h
create mode 100644 tools/testing/selftests/kvm/lib/powerpc/handlers.S
create mode 100644 tools/testing/selftests/kvm/lib/powerpc/hcall.c
create mode 100644 tools/testing/selftests/kvm/lib/powerpc/processor.c
create mode 100644 tools/testing/selftests/kvm/lib/powerpc/ucall.c
--
2.39.5
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v5 1/9] KVM: PPC: selftests: add support for powerpc
2026-09-22 18:28 [PATCH v5 0/9] KVM: selftests: add powerpc support Ritesh Harjani (IBM)
@ 2026-09-22 18:28 ` Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 2/9] KVM: selftests: Enable kvm_create_max_vcpus test " Ritesh Harjani (IBM)
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ritesh Harjani (IBM) @ 2026-09-22 18:28 UTC (permalink / raw)
To: kvm
Cc: Sean Christopherson, Paolo Bonzini, linuxppc-dev,
Michael Ellerman, Christophe Leroy, Anushree Mathur,
Venkat Rao Bagalkote, Harsh Prateek Bora, Madhavan Srinivasan,
Shrikanth Hegde, linux-kernel, Nicholas Piggin, Ritesh Harjani
From: Nicholas Piggin <npiggin@gmail.com>
Implement KVM selftests support for powerpc (Book3S-64).
ucalls are implemented with an unsupported PAPR hcall number which will
always cause KVM to exit to userspace.
Virtual memory is implemented for the radix MMU, and only a base page
size is supported (both 4K and 64K).
Guest interrupts are taken in real-mode, so require a page allocated at
gRA 0x0. Interrupt entry is complicated because gVA:gRA is not 1:1
mapped (like the kernel is), so the MMU can not just be switched on and
off.
This patch series also changes the following types as done in other
selftests. These changes are squashed in this main patch as discussed
here [1]:
- Use u64 instead of uint64_t
- Use s64 instead of int64_t
- Use u32 instead of uint32_t
- Use u8 instead of uint8_t
- Replace u64 gpa, u64 gva|vaddr with gpa_t and gva_t
- Adopt to the new page table allocator APIs
- Start the guest at the entry point and not the descriptor in case of
elfv1
[1]: https://lore.kernel.org/linuxppc-dev/cover.1781093720.git.ritesh.list@gmail.com/
[Rebased to latest mainline tree, "cc" to clobber list, fix the
size calculation in kvm_arch_vm_post_create()]
Co-developed-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Link: https://lore.kernel.org/linuxppc-dev/cover.1781093720.git.ritesh.list@gmail.com/
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
---
MAINTAINERS | 2 +
tools/testing/selftests/kvm/Makefile | 2 +-
tools/testing/selftests/kvm/Makefile.kvm | 10 +
.../testing/selftests/kvm/include/kvm_util.h | 9 +
.../selftests/kvm/include/powerpc/hcall.h | 17 +
.../kvm/include/powerpc/kvm_util_arch.h | 22 +
.../selftests/kvm/include/powerpc/ppc_asm.h | 32 ++
.../selftests/kvm/include/powerpc/processor.h | 39 ++
.../selftests/kvm/include/powerpc/ucall.h | 21 +
tools/testing/selftests/kvm/lib/guest_modes.c | 20 +-
tools/testing/selftests/kvm/lib/kvm_util.c | 8 +
.../selftests/kvm/lib/powerpc/handlers.S | 93 ++++
.../testing/selftests/kvm/lib/powerpc/hcall.c | 45 ++
.../selftests/kvm/lib/powerpc/processor.c | 512 ++++++++++++++++++
.../testing/selftests/kvm/lib/powerpc/ucall.c | 22 +
15 files changed, 851 insertions(+), 3 deletions(-)
create mode 100644 tools/testing/selftests/kvm/include/powerpc/hcall.h
create mode 100644 tools/testing/selftests/kvm/include/powerpc/kvm_util_arch.h
create mode 100644 tools/testing/selftests/kvm/include/powerpc/ppc_asm.h
create mode 100644 tools/testing/selftests/kvm/include/powerpc/processor.h
create mode 100644 tools/testing/selftests/kvm/include/powerpc/ucall.h
create mode 100644 tools/testing/selftests/kvm/lib/powerpc/handlers.S
create mode 100644 tools/testing/selftests/kvm/lib/powerpc/hcall.c
create mode 100644 tools/testing/selftests/kvm/lib/powerpc/processor.c
create mode 100644 tools/testing/selftests/kvm/lib/powerpc/ucall.c
diff --git a/MAINTAINERS b/MAINTAINERS
index fc320b373656..35df0c39e991 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14349,6 +14349,8 @@ F: arch/powerpc/include/asm/kvm*
F: arch/powerpc/include/uapi/asm/kvm*
F: arch/powerpc/kernel/kvm*
F: arch/powerpc/kvm/
+F: tools/testing/selftests/kvm/*/powerpc/
+F: tools/testing/selftests/kvm/powerpc/
KERNEL VIRTUAL MACHINE FOR RISC-V (KVM/riscv)
M: Anup Patel <anup@brainfault.org>
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index f2b223072b62..03d91f00092f 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -3,7 +3,7 @@ top_srcdir = ../../../..
include $(top_srcdir)/scripts/subarch.include
ARCH ?= $(SUBARCH)
-ifeq ($(ARCH),$(filter $(ARCH),arm64 s390 riscv x86 x86_64 loongarch))
+ifeq ($(ARCH),$(filter $(ARCH),arm64 s390 riscv x86 x86_64 loongarch powerpc))
# Top-level selftests allows ARCH=x86_64 :-(
ifeq ($(ARCH),x86_64)
override ARCH := x86
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 96bab7002d39..30f026084c6f 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -53,6 +53,11 @@ LIBKVM_loongarch += lib/loongarch/processor.c
LIBKVM_loongarch += lib/loongarch/ucall.c
LIBKVM_loongarch += lib/loongarch/exception.S
+LIBKVM_powerpc += lib/powerpc/handlers.S
+LIBKVM_powerpc += lib/powerpc/processor.c
+LIBKVM_powerpc += lib/powerpc/ucall.c
+LIBKVM_powerpc += lib/powerpc/hcall.c
+
# Non-compiled test targets
TEST_PROGS_x86 += x86/nx_huge_pages_test.sh
@@ -251,6 +256,11 @@ TEST_GEN_PROGS_loongarch += memslot_perf_test
TEST_GEN_PROGS_loongarch += set_memory_region_test
TEST_GEN_PROGS_loongarch += steal_time
+TEST_GEN_PROGS_powerpc = $(TEST_GEN_PROGS_COMMON)
+TEST_GEN_PROGS_powerpc += access_tracking_perf_test
+TEST_GEN_PROGS_powerpc += dirty_log_perf_test
+TEST_GEN_PROGS_powerpc += hardware_disable_test
+
SPLIT_TESTS += arch_timer
SPLIT_TESTS += get-reg-list
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 89b4fc2af751..9df16c8dc82a 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -241,6 +241,9 @@ enum vm_guest_mode {
VM_MODE_P41V48_4K,
VM_MODE_P41V39_4K,
+ VM_MODE_P52V52_4K, /* For powerpc64 */
+ VM_MODE_P52V52_64K,
+
NUM_VM_MODES,
};
@@ -300,6 +303,12 @@ extern enum vm_guest_mode vm_mode_default;
#define MIN_PAGE_SHIFT 12U
#define ptes_per_page(page_size) ((page_size) / 8)
+#elif defined(__powerpc64__)
+
+#define VM_MODE_DEFAULT vm_mode_default
+#define MIN_PAGE_SHIFT 12U
+#define ptes_per_page(page_size) ((page_size) / 8)
+
#endif
#define VM_SHAPE_DEFAULT VM_SHAPE(VM_MODE_DEFAULT)
diff --git a/tools/testing/selftests/kvm/include/powerpc/hcall.h b/tools/testing/selftests/kvm/include/powerpc/hcall.h
new file mode 100644
index 000000000000..21b2bf9180f1
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/powerpc/hcall.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * powerpc hcall defines
+ */
+#ifndef SELFTEST_KVM_HCALL_H
+#define SELFTEST_KVM_HCALL_H
+
+#include <linux/compiler.h>
+
+/* Ucalls use unimplemented PAPR hcall 0 which exits KVM */
+#define H_UCALL 0
+
+s64 hcall0(u64 token);
+s64 hcall1(u64 token, u64 arg1);
+s64 hcall2(u64 token, u64 arg1, u64 arg2);
+
+#endif
diff --git a/tools/testing/selftests/kvm/include/powerpc/kvm_util_arch.h b/tools/testing/selftests/kvm/include/powerpc/kvm_util_arch.h
new file mode 100644
index 000000000000..5d45c25cd299
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/powerpc/kvm_util_arch.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef SELFTEST_KVM_UTIL_ARCH_H
+#define SELFTEST_KVM_UTIL_ARCH_H
+
+#include <stdint.h>
+
+#include "kvm_util_types.h"
+
+struct kvm_mmu_arch {};
+
+/* Page table fragment cache for guest page tables < page size */
+struct vm_pt_frag_cache {
+ gpa_t page;
+ size_t page_nr_used;
+};
+
+struct kvm_vm_arch {
+ gpa_t prtb; /* process table */
+ struct vm_pt_frag_cache pt_frag_cache[2]; /* 256B and 4KB PT caches */
+};
+
+#endif /* SELFTEST_KVM_UTIL_ARCH_H */
diff --git a/tools/testing/selftests/kvm/include/powerpc/ppc_asm.h b/tools/testing/selftests/kvm/include/powerpc/ppc_asm.h
new file mode 100644
index 000000000000..b9df64659792
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/powerpc/ppc_asm.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * powerpc asm specific defines
+ */
+#ifndef SELFTEST_KVM_PPC_ASM_H
+#define SELFTEST_KVM_PPC_ASM_H
+
+#define STACK_FRAME_MIN_SIZE 112 /* Could be 32 on ELFv2 */
+#define STACK_REDZONE_SIZE 512
+
+#define INT_FRAME_SIZE (STACK_FRAME_MIN_SIZE + STACK_REDZONE_SIZE)
+
+#define SPR_SRR0 0x01a
+#define SPR_SRR1 0x01b
+#define SPR_CFAR 0x01c
+
+#define MSR_SF 0x8000000000000000ULL
+#define MSR_HV 0x1000000000000000ULL
+#define MSR_VEC 0x0000000002000000ULL
+#define MSR_VSX 0x0000000000800000ULL
+#define MSR_EE 0x0000000000008000ULL
+#define MSR_PR 0x0000000000004000ULL
+#define MSR_FP 0x0000000000002000ULL
+#define MSR_ME 0x0000000000001000ULL
+#define MSR_IR 0x0000000000000020ULL
+#define MSR_DR 0x0000000000000010ULL
+#define MSR_RI 0x0000000000000002ULL
+#define MSR_LE 0x0000000000000001ULL
+
+#define LPCR_ILE 0x0000000002000000ULL
+
+#endif
diff --git a/tools/testing/selftests/kvm/include/powerpc/processor.h b/tools/testing/selftests/kvm/include/powerpc/processor.h
new file mode 100644
index 000000000000..f0ee21a8e2d4
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/powerpc/processor.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * powerpc processor specific defines
+ */
+#ifndef SELFTEST_KVM_PROCESSOR_H
+#define SELFTEST_KVM_PROCESSOR_H
+
+#include <linux/compiler.h>
+#include "ppc_asm.h"
+#include "kvm_util_types.h"
+
+extern unsigned char __interrupts_start[];
+extern unsigned char __interrupts_end[];
+
+struct kvm_vm;
+struct kvm_vcpu;
+
+struct ex_regs {
+ u64 gprs[32];
+ u64 nia;
+ u64 msr;
+ u64 cfar;
+ u64 lr;
+ u64 ctr;
+ u64 xer;
+ u32 cr;
+ u32 trap;
+ gva_t gva; /* gva of this struct */
+};
+
+void vm_install_exception_handler(struct kvm_vm *vm, int vector,
+ void (*handler)(struct ex_regs *));
+
+static inline void cpu_relax(void)
+{
+ asm volatile("" ::: "memory");
+}
+
+#endif
diff --git a/tools/testing/selftests/kvm/include/powerpc/ucall.h b/tools/testing/selftests/kvm/include/powerpc/ucall.h
new file mode 100644
index 000000000000..e0dbe91e8848
--- /dev/null
+++ b/tools/testing/selftests/kvm/include/powerpc/ucall.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef SELFTEST_KVM_UCALL_H
+#define SELFTEST_KVM_UCALL_H
+
+#include "hcall.h"
+
+#define UCALL_EXIT_REASON KVM_EXIT_PAPR_HCALL
+
+#define UCALL_R4_UCALL 0x5715 /* regular ucall, r5 contains ucall pointer */
+#define UCALL_R4_SIMPLE 0x0000 /* simple exit usable by asm with no ucall data */
+
+static inline void ucall_arch_init(struct kvm_vm *vm, gpa_t mmio_gpa)
+{
+}
+
+static inline void ucall_arch_do_ucall(gva_t uc)
+{
+ hcall2(H_UCALL, UCALL_R4_UCALL, (uintptr_t)(uc));
+}
+
+#endif
diff --git a/tools/testing/selftests/kvm/lib/guest_modes.c b/tools/testing/selftests/kvm/lib/guest_modes.c
index 7a96c43b5704..439766fad693 100644
--- a/tools/testing/selftests/kvm/lib/guest_modes.c
+++ b/tools/testing/selftests/kvm/lib/guest_modes.c
@@ -4,16 +4,20 @@
*/
#include "guest_modes.h"
-#if defined(__aarch64__) || defined(__riscv)
+#if defined(__aarch64__) || defined(__riscv) || defined(__powerpc64__)
#include "processor.h"
enum vm_guest_mode vm_mode_default;
#endif
+#if defined(__powerpc64__)
+#include <unistd.h>
+#endif
+
struct guest_mode guest_modes[NUM_VM_MODES];
void guest_modes_append_default(void)
{
-#if !defined(__aarch64__) && !defined(__riscv)
+#if !defined(__aarch64__) && !defined(__riscv) && !defined(__powerpc64__)
guest_mode_append(VM_MODE_DEFAULT, true);
#endif
@@ -108,6 +112,18 @@ void guest_modes_append_default(void)
TEST_ASSERT(vm_mode_default != NUM_VM_MODES, "No supported mode!");
}
#endif
+#ifdef __powerpc64__
+ {
+ TEST_REQUIRE(kvm_has_cap(KVM_CAP_PPC_MMU_RADIX));
+ /* Radix guest EA and RA are 52-bit on POWER9 and POWER10 */
+ if (sysconf(_SC_PAGESIZE) == 4096)
+ vm_mode_default = VM_MODE_P52V52_4K;
+ else
+ vm_mode_default = VM_MODE_P52V52_64K;
+ guest_mode_append(VM_MODE_P52V52_4K, true);
+ guest_mode_append(VM_MODE_P52V52_64K, true);
+ }
+#endif
}
void for_each_guest_mode(void (*func)(enum vm_guest_mode, void *), void *arg)
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 57b653fbd0b1..2be79c240ebf 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -227,6 +227,8 @@ const char *vm_guest_mode_string(u32 i)
[VM_MODE_P41V57_4K] = "PA-bits:41, VA-bits:57, 4K pages",
[VM_MODE_P41V48_4K] = "PA-bits:41, VA-bits:48, 4K pages",
[VM_MODE_P41V39_4K] = "PA-bits:41, VA-bits:39, 4K pages",
+ [VM_MODE_P52V52_4K] = "PA-bits:52, VA-bits:52, 4K pages",
+ [VM_MODE_P52V52_64K] = "PA-bits:52, VA-bits:52, 64K pages",
};
_Static_assert(sizeof(strings)/sizeof(char *) == NUM_VM_MODES,
"Missing new mode strings?");
@@ -263,6 +265,8 @@ const struct vm_guest_mode_params vm_guest_mode_params[] = {
[VM_MODE_P41V57_4K] = { 41, 57, 0x1000, 12 },
[VM_MODE_P41V48_4K] = { 41, 48, 0x1000, 12 },
[VM_MODE_P41V39_4K] = { 41, 39, 0x1000, 12 },
+ [VM_MODE_P52V52_4K] = { 52, 52, 0x1000, 12 },
+ [VM_MODE_P52V52_64K] = { 52, 52, 0x10000, 16 },
};
_Static_assert(sizeof(vm_guest_mode_params)/sizeof(struct vm_guest_mode_params) == NUM_VM_MODES,
"Missing new mode params?");
@@ -383,6 +387,10 @@ struct kvm_vm *____vm_create(struct vm_shape shape)
case VM_MODE_P41V39_4K:
vm->mmu.pgtable_levels = 3;
break;
+ case VM_MODE_P52V52_4K:
+ case VM_MODE_P52V52_64K:
+ vm->mmu.pgtable_levels = 4;
+ break;
default:
TEST_FAIL("Unknown guest mode: 0x%x", vm->mode);
}
diff --git a/tools/testing/selftests/kvm/lib/powerpc/handlers.S b/tools/testing/selftests/kvm/lib/powerpc/handlers.S
new file mode 100644
index 000000000000..b860f6a520a1
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/powerpc/handlers.S
@@ -0,0 +1,93 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <ppc_asm.h>
+
+.macro INTERRUPT vec
+. = __interrupts_start + \vec
+ std %r0,(0*8)(%r13)
+ std %r3,(3*8)(%r13)
+ mfspr %r0,SPR_CFAR
+ li %r3,\vec
+ b handle_interrupt
+.endm
+
+.balign 0x1000
+.global __interrupts_start
+__interrupts_start:
+INTERRUPT 0x100
+INTERRUPT 0x200
+INTERRUPT 0x300
+INTERRUPT 0x380
+INTERRUPT 0x400
+INTERRUPT 0x480
+INTERRUPT 0x500
+INTERRUPT 0x600
+INTERRUPT 0x700
+INTERRUPT 0x800
+INTERRUPT 0x900
+INTERRUPT 0xa00
+INTERRUPT 0xc00
+INTERRUPT 0xd00
+INTERRUPT 0xf00
+INTERRUPT 0xf20
+INTERRUPT 0xf40
+INTERRUPT 0xf60
+
+virt_handle_interrupt:
+ stdu %r1,-INT_FRAME_SIZE(%r1)
+ mr %r3,%r31
+ bl route_interrupt
+ ld %r4,(32*8)(%r31) /* NIA */
+ ld %r5,(33*8)(%r31) /* MSR */
+ ld %r6,(35*8)(%r31) /* LR */
+ ld %r7,(36*8)(%r31) /* CTR */
+ ld %r8,(37*8)(%r31) /* XER */
+ lwz %r9,(38*8)(%r31) /* CR */
+ mtspr SPR_SRR0,%r4
+ mtspr SPR_SRR1,%r5
+ mtlr %r6
+ mtctr %r7
+ mtxer %r8
+ mtcr %r9
+reg=4
+ ld %r0,(0*8)(%r31)
+ ld %r3,(3*8)(%r31)
+.rept 28
+ ld reg,(reg*8)(%r31)
+ reg=reg+1
+.endr
+ addi %r1,%r1,INT_FRAME_SIZE
+ rfid
+
+virt_handle_interrupt_p:
+ .llong virt_handle_interrupt
+
+handle_interrupt:
+reg=4
+.rept 28
+ std reg,(reg*8)(%r13)
+ reg=reg+1
+.endr
+ mfspr %r4,SPR_SRR0
+ mfspr %r5,SPR_SRR1
+ mflr %r6
+ mfctr %r7
+ mfxer %r8
+ mfcr %r9
+ std %r4,(32*8)(%r13) /* NIA */
+ std %r5,(33*8)(%r13) /* MSR */
+ std %r0,(34*8)(%r13) /* CFAR */
+ std %r6,(35*8)(%r13) /* LR */
+ std %r7,(36*8)(%r13) /* CTR */
+ std %r8,(37*8)(%r13) /* XER */
+ stw %r9,(38*8 + 0)(%r13) /* CR */
+ stw %r3,(38*8 + 4)(%r13) /* TRAP */
+
+ ld %r31,(39*8)(%r13) /* vaddr */
+ ld %r4,virt_handle_interrupt_p - __interrupts_start(0)
+ mtspr SPR_SRR0,%r4
+ /* Reuse SRR1 */
+
+ rfid
+.global __interrupts_end
+__interrupts_end:
diff --git a/tools/testing/selftests/kvm/lib/powerpc/hcall.c b/tools/testing/selftests/kvm/lib/powerpc/hcall.c
new file mode 100644
index 000000000000..d5f5282654ee
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/powerpc/hcall.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PAPR (pseries) hcall support.
+ */
+#include "kvm_util.h"
+#include "hcall.h"
+
+s64 hcall0(u64 token)
+{
+ register uintptr_t r3 asm ("r3") = token;
+
+ asm volatile("sc 1" : "+r"(r3) :
+ : "r0", "r4", "r5", "r6", "r7", "r8", "r9",
+ "r10", "r11", "r12", "ctr", "xer",
+ "cc", "memory");
+
+ return r3;
+}
+
+s64 hcall1(u64 token, u64 arg1)
+{
+ register uintptr_t r3 asm ("r3") = token;
+ register uintptr_t r4 asm ("r4") = arg1;
+
+ asm volatile("sc 1" : "+r"(r3), "+r"(r4) :
+ : "r0", "r5", "r6", "r7", "r8", "r9",
+ "r10", "r11", "r12", "ctr", "xer",
+ "cc", "memory");
+
+ return r3;
+}
+
+s64 hcall2(u64 token, u64 arg1, u64 arg2)
+{
+ register uintptr_t r3 asm ("r3") = token;
+ register uintptr_t r4 asm ("r4") = arg1;
+ register uintptr_t r5 asm ("r5") = arg2;
+
+ asm volatile("sc 1" : "+r"(r3), "+r"(r4), "+r"(r5) :
+ : "r0", "r6", "r7", "r8", "r9",
+ "r10", "r11", "r12", "ctr", "xer",
+ "cc", "memory");
+
+ return r3;
+}
diff --git a/tools/testing/selftests/kvm/lib/powerpc/processor.c b/tools/testing/selftests/kvm/lib/powerpc/processor.c
new file mode 100644
index 000000000000..301455024571
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/powerpc/processor.c
@@ -0,0 +1,512 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * KVM selftest powerpc library code - CPU-related functions (page tables...)
+ */
+
+#include <linux/sizes.h>
+
+#include "processor.h"
+#include "kvm_util.h"
+#include "ucall_common.h"
+#include "guest_modes.h"
+#include "hcall.h"
+
+#define RADIX_TREE_SIZE ((0x2UL << 61) | (0x5UL << 5)) /* 52-bits */
+#define RADIX_PGD_INDEX_SIZE 13
+
+/*
+ * A radix table must be aligned to its size, and the tables are larger than
+ * the guest base page size for several level/page size combinations.
+ */
+bool kvm_arch_needs_naturally_aligned_page_tables(void)
+{
+ return true;
+}
+
+static void set_proc_table(struct kvm_vm *vm, int pid, u64 dw0, u64 dw1)
+{
+ u64 *proc_table;
+
+ proc_table = addr_gpa2hva(vm, vm->arch.prtb);
+ proc_table[pid * 2 + 0] = cpu_to_be64(dw0);
+ proc_table[pid * 2 + 1] = cpu_to_be64(dw1);
+}
+
+static void set_radix_proc_table(struct kvm_vm *vm, int pid, gpa_t pgd)
+{
+ set_proc_table(vm, pid, pgd | RADIX_TREE_SIZE | RADIX_PGD_INDEX_SIZE, 0);
+}
+
+void virt_arch_pgd_alloc(struct kvm_vm *vm)
+{
+ struct kvm_ppc_mmuv3_cfg mmu_cfg;
+ gpa_t prtb, pgtb;
+ size_t pgd_pages;
+
+ TEST_ASSERT((vm->mode == VM_MODE_P52V52_4K) ||
+ (vm->mode == VM_MODE_P52V52_64K),
+ "Unsupported guest mode, mode: 0x%x", vm->mode);
+
+ if (vm->mmu.pgd_created)
+ return;
+
+ prtb = vm_alloc_page_table(vm);
+ vm->arch.prtb = prtb;
+
+ pgd_pages = (1UL << (RADIX_PGD_INDEX_SIZE + 3)) >> vm->page_shift;
+ if (!pgd_pages)
+ pgd_pages = 1;
+ pgtb = vm_alloc_page_table_pages(vm, pgd_pages);
+ vm->mmu.pgd = pgtb;
+
+ /* Set the base page directory in the proc table */
+ set_radix_proc_table(vm, 0, pgtb);
+
+ if (vm->mode == VM_MODE_P52V52_4K)
+ mmu_cfg.process_table = prtb | 0x8000000000000000UL | 0x0; /* 4K size */
+ else /* vm->mode == VM_MODE_P52V52_64K */
+ mmu_cfg.process_table = prtb | 0x8000000000000000UL | 0x4; /* 64K size */
+ mmu_cfg.flags = KVM_PPC_MMUV3_RADIX | KVM_PPC_MMUV3_GTSE;
+
+ vm_ioctl(vm, KVM_PPC_CONFIGURE_V3_MMU, &mmu_cfg);
+
+ vm->mmu.pgd_created = true;
+}
+
+static int pt_shift(struct kvm_vm *vm, int level)
+{
+ switch (level) {
+ case 1:
+ return 13;
+ case 2:
+ case 3:
+ return 9;
+ case 4:
+ if (vm->mode == VM_MODE_P52V52_4K)
+ return 9;
+ else /* vm->mode == VM_MODE_P52V52_64K */
+ return 5;
+ default:
+ TEST_ASSERT(false, "Invalid page table level %d\n", level);
+ return 0;
+ }
+}
+
+static u64 pt_entry_coverage(struct kvm_vm *vm, int level)
+{
+ u64 size = vm->page_size;
+
+ if (level == 4)
+ return size;
+ size <<= pt_shift(vm, 4);
+ if (level == 3)
+ return size;
+ size <<= pt_shift(vm, 3);
+ if (level == 2)
+ return size;
+ size <<= pt_shift(vm, 2);
+ return size;
+}
+
+static int pt_idx(struct kvm_vm *vm, gva_t gva, int level, u64 *nls)
+{
+ switch (level) {
+ case 1:
+ if (nls)
+ *nls = 0x9;
+ return (gva >> 39) & 0x1fff;
+ case 2:
+ if (nls)
+ *nls = 0x9;
+ return (gva >> 30) & 0x1ff;
+ case 3:
+ if (vm->mode == VM_MODE_P52V52_4K) {
+ if (nls)
+ *nls = 0x9;
+ } else { /* vm->mode == VM_MODE_P52V52_64K */
+ if (nls)
+ *nls = 0x5;
+ }
+ return (gva >> 21) & 0x1ff;
+ case 4:
+ if (vm->mode == VM_MODE_P52V52_4K)
+ return (gva >> 12) & 0x1ff;
+ else /* vm->mode == VM_MODE_P52V52_64K */
+ return (gva >> 16) & 0x1f;
+ default:
+ TEST_ASSERT(false, "Invalid page table level %d\n", level);
+ return 0;
+ }
+}
+
+static u64 *virt_get_pte(struct kvm_vm *vm, gpa_t pt,
+ gva_t gva, int level, u64 *nls)
+{
+ int idx = pt_idx(vm, gva, level, nls);
+ u64 *ptep = addr_gpa2hva(vm, pt + idx * 8);
+
+ return ptep;
+}
+
+#define PTE_VALID 0x8000000000000000ull
+#define PTE_LEAF 0x4000000000000000ull
+#define PTE_REFERENCED 0x0000000000000100ull
+#define PTE_CHANGED 0x0000000000000080ull
+#define PTE_PRIV 0x0000000000000008ull
+#define PTE_READ 0x0000000000000004ull
+#define PTE_RW 0x0000000000000002ull
+#define PTE_EXEC 0x0000000000000001ull
+#define PTE_PAGE_MASK 0x01fffffffffff000ull
+
+#define PDE_VALID PTE_VALID
+#define PDE_NLS 0x0000000000000011ull
+#define PDE_PT_MASK 0x0fffffffffffff00ull
+
+static gpa_t __vm_alloc_pt(struct kvm_vm *vm, u64 pt_shift)
+{
+ gpa_t pt;
+
+ if (pt_shift >= vm->page_shift) {
+ size_t pt_pages = 1ULL << (pt_shift - vm->page_shift);
+
+ pt = vm_alloc_page_table_pages(vm, pt_pages);
+ } else {
+ struct vm_pt_frag_cache *pt_frag_cache;
+
+ if (pt_shift == 8) {
+ pt_frag_cache = &vm->arch.pt_frag_cache[0];
+ } else if (pt_shift == 12) {
+ pt_frag_cache = &vm->arch.pt_frag_cache[1];
+ } else {
+ TEST_ASSERT(0, "Invalid pt_shift:%lu\n", pt_shift);
+ return 0;
+ }
+
+ if (!pt_frag_cache->page)
+ pt_frag_cache->page = vm_alloc_page_table(vm);
+ pt = pt_frag_cache->page + pt_frag_cache->page_nr_used;
+ pt_frag_cache->page_nr_used += (1 << pt_shift);
+ if (pt_frag_cache->page_nr_used == vm->page_size) {
+ pt_frag_cache->page = 0;
+ pt_frag_cache->page_nr_used = 0;
+ }
+ }
+
+ return pt;
+}
+
+void virt_arch_pg_map(struct kvm_vm *vm, gva_t gva, gpa_t gpa)
+{
+ gpa_t pt = vm->mmu.pgd;
+ u64 *ptep, pte;
+ int level;
+
+ for (level = 1; level <= 3; level++) {
+ u64 nls;
+ u64 *pdep = virt_get_pte(vm, pt, gva, level, &nls);
+ u64 pde = be64_to_cpu(*pdep);
+
+ if (pde) {
+ TEST_ASSERT((pde & PDE_VALID) && !(pde & PTE_LEAF),
+ "Invalid PDE at level: %u gva: 0x%lx pde:0x%lx\n",
+ level, gva, pde);
+ pt = pde & PDE_PT_MASK;
+ continue;
+ }
+
+ pt = __vm_alloc_pt(vm, nls + 3);
+ pde = PDE_VALID | nls | pt;
+ *pdep = cpu_to_be64(pde);
+ }
+
+ ptep = virt_get_pte(vm, pt, gva, level, NULL);
+ pte = be64_to_cpu(*ptep);
+
+ TEST_ASSERT(!pte, "PTE already present at level: %u gva: 0x%lx pte:0x%lx\n",
+ level, gva, pte);
+
+ pte = PTE_VALID | PTE_LEAF | PTE_REFERENCED | PTE_CHANGED | PTE_PRIV |
+ PTE_READ | PTE_RW | PTE_EXEC | (gpa & PTE_PAGE_MASK);
+ *ptep = cpu_to_be64(pte);
+}
+
+gpa_t addr_arch_gva2gpa(struct kvm_vm *vm, gva_t gva)
+{
+ gpa_t pt = vm->mmu.pgd;
+ u64 *ptep, pte;
+ int level;
+
+ for (level = 1; level <= 3; level++) {
+ u64 nls;
+ u64 *pdep = virt_get_pte(vm, pt, gva, level, &nls);
+ u64 pde = be64_to_cpu(*pdep);
+
+ TEST_ASSERT((pde & PDE_VALID) && !(pde & PTE_LEAF),
+ "PDE not present at level: %u gva: 0x%lx pde:0x%lx\n",
+ level, gva, pde);
+ pt = pde & PDE_PT_MASK;
+ }
+
+ ptep = virt_get_pte(vm, pt, gva, level, NULL);
+ pte = be64_to_cpu(*ptep);
+
+ TEST_ASSERT(pte,
+ "PTE not present at level: %u gva: 0x%lx pte:0x%lx\n",
+ level, gva, pte);
+
+ TEST_ASSERT((pte & PTE_VALID) && (pte & PTE_LEAF),
+ "PTE not valid at level: %u gva: 0x%lx pte:0x%lx\n",
+ level, gva, pte);
+
+ return (pte & PTE_PAGE_MASK) + (gva & (vm->page_size - 1));
+}
+
+static void virt_dump_pt(FILE *stream, struct kvm_vm *vm, gpa_t pt,
+ gva_t va, int level, u8 indent)
+{
+ int size, idx;
+
+ size = 1U << (pt_shift(vm, level) + 3);
+
+ for (idx = 0; idx < size; idx += 8, va += pt_entry_coverage(vm, level)) {
+ u64 *page_table = addr_gpa2hva(vm, pt + idx);
+ u64 pte = be64_to_cpu(*page_table);
+
+ if (!(pte & PTE_VALID))
+ continue;
+
+ if (pte & PTE_LEAF) {
+ fprintf(stream,
+ "%*s PTE[%d] gVA:0x%016lx -> gRA:0x%016llx\n",
+ indent, "", idx / 8, va, pte & PTE_PAGE_MASK);
+ } else {
+ fprintf(stream, "%*sPDE%d[%d] gVA:0x%016lx\n",
+ indent, "", level, idx / 8, va);
+ virt_dump_pt(stream, vm, pte & PDE_PT_MASK, va,
+ level + 1, indent + 2);
+ }
+ }
+
+}
+
+void virt_arch_dump(FILE *stream, struct kvm_vm *vm, u8 indent)
+{
+ gpa_t pt = vm->mmu.pgd;
+
+ if (!vm->mmu.pgd_created)
+ return;
+
+ virt_dump_pt(stream, vm, pt, 0, 1, indent);
+}
+
+static unsigned long get_r2(void)
+{
+ unsigned long r2;
+
+ asm("mr %0,%%r2" : "=r"(r2));
+
+ return r2;
+}
+
+/*
+ * Under ELFv1 a function pointer is the address of a descriptor holding the
+ * entry point and the TOC, not the entry point itself. ELFv2 dropped
+ * descriptors, i.e. the pointer is already the entry point. Dereference the
+ * descriptor as needed so that the guest starts executing code and not data.
+ */
+static uintptr_t function_entry(void *fn)
+{
+#if defined(_CALL_ELF) && _CALL_ELF == 2
+ return (uintptr_t)fn;
+#else
+ return ((const u64 *)fn)[0];
+#endif
+}
+
+void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code)
+{
+ uintptr_t entry = function_entry(guest_code);
+ struct kvm_regs regs;
+
+ vcpu_regs_get(vcpu, ®s);
+ regs.pc = entry;
+ regs.gpr[12] = entry;
+ vcpu_regs_set(vcpu, ®s);
+}
+
+struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, u32 vcpu_id)
+{
+ const size_t stack_size = SZ_64K;
+ gva_t stack_vaddr, ex_regs_vaddr;
+ gpa_t ex_regs_paddr;
+ struct ex_regs *ex_regs;
+ struct kvm_regs regs;
+ struct kvm_vcpu *vcpu;
+ u64 lpcr;
+
+ stack_vaddr = __vm_alloc(vm, stack_size,
+ DEFAULT_GUEST_STACK_VADDR_MIN,
+ MEM_REGION_DATA);
+
+ ex_regs_vaddr = __vm_alloc(vm, stack_size,
+ DEFAULT_GUEST_STACK_VADDR_MIN,
+ MEM_REGION_DATA);
+ ex_regs_paddr = addr_gva2gpa(vm, ex_regs_vaddr);
+ ex_regs = addr_gpa2hva(vm, ex_regs_paddr);
+ ex_regs->gva = ex_regs_vaddr;
+
+ vcpu = __vm_vcpu_add(vm, vcpu_id);
+
+ vcpu_enable_cap(vcpu, KVM_CAP_PPC_PAPR, 1);
+
+ /* Setup guest registers */
+ vcpu_regs_get(vcpu, ®s);
+ lpcr = vcpu_get_reg(vcpu, KVM_REG_PPC_LPCR_64);
+
+ regs.gpr[1] = stack_vaddr + stack_size - 256;
+ regs.gpr[2] = (uintptr_t)get_r2();
+ regs.gpr[13] = (uintptr_t)ex_regs_paddr;
+
+ regs.msr = MSR_SF | MSR_VEC | MSR_VSX | MSR_FP |
+ MSR_ME | MSR_IR | MSR_DR | MSR_RI;
+
+ if (BYTE_ORDER == LITTLE_ENDIAN) {
+ regs.msr |= MSR_LE;
+ lpcr |= LPCR_ILE;
+ } else {
+ lpcr &= ~LPCR_ILE;
+ }
+
+ vcpu_regs_set(vcpu, ®s);
+ vcpu_set_reg(vcpu, KVM_REG_PPC_LPCR_64, lpcr);
+
+ return vcpu;
+}
+
+void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...)
+{
+ va_list ap;
+ struct kvm_regs regs;
+ int i;
+
+ TEST_ASSERT(num >= 1 && num <= 5, "Unsupported number of args: %u\n",
+ num);
+
+ va_start(ap, num);
+ vcpu_regs_get(vcpu, ®s);
+
+ for (i = 0; i < num; i++)
+ regs.gpr[i + 3] = va_arg(ap, u64);
+
+ vcpu_regs_set(vcpu, ®s);
+ va_end(ap);
+}
+
+void vcpu_arch_dump(FILE *stream, struct kvm_vcpu *vcpu, u8 indent)
+{
+ struct kvm_regs regs;
+
+ vcpu_regs_get(vcpu, ®s);
+
+ fprintf(stream, "%*sNIA: 0x%016llx MSR: 0x%016llx\n",
+ indent, "", regs.pc, regs.msr);
+ fprintf(stream, "%*sLR: 0x%016llx CTR :0x%016llx\n",
+ indent, "", regs.lr, regs.ctr);
+ fprintf(stream, "%*sCR: 0x%08llx XER :0x%016llx\n",
+ indent, "", regs.cr, regs.xer);
+}
+
+void kvm_arch_vm_post_create(struct kvm_vm *vm, unsigned int nr_vcpus)
+{
+ size_t excp_size = __interrupts_end - __interrupts_start;
+ size_t excp_pages = (excp_size + vm->page_size - 1) / vm->page_size;
+ gpa_t excp_paddr;
+ void *mem;
+
+ /*
+ * Guest interrupts are taken in real-mode, i.e. the vectors must live
+ * at gPA 0. Use the innermost allocator to override the minimum GPA
+ * that MEM_REGION_DATA would otherwise impose.
+ */
+ excp_paddr = ____vm_phy_pages_alloc(vm, excp_pages, 0,
+ vm->memslots[MEM_REGION_DATA],
+ vm_arch_has_protected_memory(vm),
+ false);
+
+ TEST_ASSERT(excp_paddr == 0,
+ "Interrupt vectors not allocated at gPA address 0: (0x%lx)",
+ excp_paddr);
+
+ mem = addr_gpa2hva(vm, excp_paddr);
+ memcpy(mem, __interrupts_start, excp_size);
+}
+
+void assert_on_unhandled_exception(struct kvm_vcpu *vcpu)
+{
+ struct ucall uc;
+
+ if (get_ucall(vcpu, &uc) == UCALL_UNHANDLED) {
+ gpa_t ex_regs_paddr;
+ struct ex_regs *ex_regs;
+ struct kvm_regs regs;
+
+ vcpu_regs_get(vcpu, ®s);
+ ex_regs_paddr = (gpa_t)regs.gpr[13];
+ ex_regs = addr_gpa2hva(vcpu->vm, ex_regs_paddr);
+
+ TEST_FAIL("Unexpected interrupt in guest NIA:0x%016lx MSR:0x%016lx TRAP:0x%04x",
+ ex_regs->nia, ex_regs->msr, ex_regs->trap);
+ }
+}
+
+struct handler {
+ void (*fn)(struct ex_regs *regs);
+ int trap;
+};
+
+#define NR_HANDLERS 10
+static struct handler handlers[NR_HANDLERS];
+
+void route_interrupt(struct ex_regs *regs)
+{
+ int i;
+
+ for (i = 0; i < NR_HANDLERS; i++) {
+ if (handlers[i].trap == regs->trap) {
+ handlers[i].fn(regs);
+ return;
+ }
+ }
+
+ ucall(UCALL_UNHANDLED, 0);
+}
+
+void vm_install_exception_handler(struct kvm_vm *vm, int trap,
+ void (*fn)(struct ex_regs *))
+{
+ int i;
+
+ for (i = 0; i < NR_HANDLERS; i++) {
+ if (!handlers[i].trap || handlers[i].trap == trap) {
+ if (fn == NULL)
+ trap = 0; /* Clear handler */
+ handlers[i].trap = trap;
+ handlers[i].fn = fn;
+ sync_global_to_guest(vm, handlers[i]);
+ return;
+ }
+ }
+
+ TEST_FAIL("Out of exception handlers");
+}
+
+void kvm_selftest_arch_init(void)
+{
+ TEST_REQUIRE(kvm_has_cap(KVM_CAP_PPC_MMU_RADIX));
+
+ /*
+ * powerpc default mode is set by host page size and not static,
+ * so start by computing that early.
+ */
+ guest_modes_append_default();
+}
diff --git a/tools/testing/selftests/kvm/lib/powerpc/ucall.c b/tools/testing/selftests/kvm/lib/powerpc/ucall.c
new file mode 100644
index 000000000000..3481a7a0b850
--- /dev/null
+++ b/tools/testing/selftests/kvm/lib/powerpc/ucall.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ucall support. A ucall is a "hypercall to host userspace".
+ */
+#include "kvm_util.h"
+#include "ucall_common.h"
+#include "hcall.h"
+
+void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu)
+{
+ struct kvm_run *run = vcpu->run;
+
+ if (run->exit_reason == UCALL_EXIT_REASON &&
+ run->papr_hcall.nr == H_UCALL) {
+ struct kvm_regs regs;
+
+ vcpu_regs_get(vcpu, ®s);
+ if (regs.gpr[4] == UCALL_R4_UCALL)
+ return (void *)regs.gpr[5];
+ }
+ return NULL;
+}
--
2.39.5
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v5 2/9] KVM: selftests: Enable kvm_create_max_vcpus test for powerpc
2026-09-22 18:28 [PATCH v5 0/9] KVM: selftests: add powerpc support Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 1/9] KVM: PPC: selftests: add support for powerpc Ritesh Harjani (IBM)
@ 2026-09-22 18:28 ` Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 3/9] KVM: selftests: Don't limit LE dirty-bitmap bitops to s390x Ritesh Harjani (IBM)
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ritesh Harjani (IBM) @ 2026-09-22 18:28 UTC (permalink / raw)
To: kvm
Cc: Sean Christopherson, Paolo Bonzini, linuxppc-dev,
Michael Ellerman, Christophe Leroy, Anushree Mathur,
Venkat Rao Bagalkote, Harsh Prateek Bora, Madhavan Srinivasan,
Shrikanth Hegde, linux-kernel, Ritesh Harjani (IBM)
powerpc's maximum permitted vCPU ID depends on the VM's SMT mode, and
the maximum reported by KVM_CAP_MAX_VCPU_ID exceeds a simple non-SMT
VM's limit.
The powerpc KVM selftest port uses non-SMT VMs, so add a workaround
to the kvm_create_max_vcpus test case to limit vCPU IDs to
KVM_CAP_MAX_VCPUS on powerpc.
This patch allows us to skip the vCPU ID test when running on PowerPC
with SMT support, in which case system topology is encoded into the vCPU
ID, and so a VM can't use the full advertised vCPU ID range without
crafting a valid platform specific topology.
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
---
tools/testing/selftests/kvm/kvm_create_max_vcpus.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c
index c5310736ed06..59ddc3757943 100644
--- a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c
+++ b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c
@@ -58,7 +58,13 @@ int main(int argc, char *argv[])
test_vcpu_creation(0, kvm_max_vcpus);
- if (kvm_max_vcpu_id > kvm_max_vcpus)
+ /*
+ * Skip the vCPU ID test when running on PowerPC with SMT support, in
+ * which case system topology is encoded into the vCPU ID, and so a VM
+ * can't use the full advertised vCPU ID range without crafting a valid
+ * platform specific topology.
+ */
+ if (kvm_max_vcpu_id > kvm_max_vcpus && !kvm_check_cap(KVM_CAP_PPC_SMT))
test_vcpu_creation(
kvm_max_vcpu_id - kvm_max_vcpus, kvm_max_vcpus);
--
2.39.5
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v5 3/9] KVM: selftests: Don't limit LE dirty-bitmap bitops to s390x
2026-09-22 18:28 [PATCH v5 0/9] KVM: selftests: add powerpc support Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 1/9] KVM: PPC: selftests: add support for powerpc Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 2/9] KVM: selftests: Enable kvm_create_max_vcpus test " Ritesh Harjani (IBM)
@ 2026-09-22 18:28 ` Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 4/9] KVM: selftests: Split out a KVM_CREATE_VCPU helper that can fail Ritesh Harjani (IBM)
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ritesh Harjani (IBM) @ 2026-09-22 18:28 UTC (permalink / raw)
To: kvm
Cc: Sean Christopherson, Paolo Bonzini, linuxppc-dev,
Michael Ellerman, Christophe Leroy, Anushree Mathur,
Venkat Rao Bagalkote, Harsh Prateek Bora, Madhavan Srinivasan,
Shrikanth Hegde, linux-kernel, Ritesh Harjani (IBM)
dirty_log_test already has BITOP_LE_SWIZZLE helpers, but they were
compiled in only for s390x, so every other big-endian host used native
test_bit().
The test fails on big-endian powerpc because it treated dirty host pages
as clean (because of the endianness issue)
w/o the fix the test fails with:
Clear page 1 value (1) >= iteration (1)
Fixes: a049a377164c ("KVM: selftests: Enable dirty_log_test on s390x")
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
---
tools/testing/selftests/kvm/dirty_log_test.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c
index af5eb0334a74..8189eaac713c 100644
--- a/tools/testing/selftests/kvm/dirty_log_test.c
+++ b/tools/testing/selftests/kvm/dirty_log_test.c
@@ -44,8 +44,11 @@
#define TEST_MIN_WRITES_PER_ITERATION 0x100
/* Dirty bitmaps are always little endian, so we need to swap on big endian */
-#if defined(__s390x__)
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define BITOP_LE_SWIZZLE ((BITS_PER_LONG-1) & ~0x7)
+#else
+# define BITOP_LE_SWIZZLE 0
+#endif
# define test_bit_le(nr, addr) \
test_bit((nr) ^ BITOP_LE_SWIZZLE, addr)
# define __set_bit_le(nr, addr) \
@@ -56,13 +59,6 @@
__test_and_set_bit((nr) ^ BITOP_LE_SWIZZLE, addr)
# define __test_and_clear_bit_le(nr, addr) \
__test_and_clear_bit((nr) ^ BITOP_LE_SWIZZLE, addr)
-#else
-# define test_bit_le test_bit
-# define __set_bit_le __set_bit
-# define __clear_bit_le __clear_bit
-# define __test_and_set_bit_le __test_and_set_bit
-# define __test_and_clear_bit_le __test_and_clear_bit
-#endif
#define TEST_DIRTY_RING_COUNT 65536
--
2.39.5
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v5 4/9] KVM: selftests: Split out a KVM_CREATE_VCPU helper that can fail
2026-09-22 18:28 [PATCH v5 0/9] KVM: selftests: add powerpc support Ritesh Harjani (IBM)
` (2 preceding siblings ...)
2026-09-22 18:28 ` [PATCH v5 3/9] KVM: selftests: Don't limit LE dirty-bitmap bitops to s390x Ritesh Harjani (IBM)
@ 2026-09-22 18:28 ` Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 5/9] KVM: selftests: Make kvm_create_max_vcpus tolerate ENOMEM Ritesh Harjani (IBM)
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ritesh Harjani (IBM) @ 2026-09-22 18:28 UTC (permalink / raw)
To: kvm
Cc: Sean Christopherson, Paolo Bonzini, linuxppc-dev,
Michael Ellerman, Christophe Leroy, Anushree Mathur,
Venkat Rao Bagalkote, Harsh Prateek Bora, Madhavan Srinivasan,
Shrikanth Hegde, linux-kernel, Ritesh Harjani (IBM)
__vm_vcpu_add() currently asserts on KVM_CREATE_VCPU, which is what most
callers want. But sometimes a test may want to handle ENOMEM without
dropping all that other setup that __vm_vcpu_add() has.
This patch adds a helper __vm_vcpu_try_add() for such test cases and
make __vm_vcpu_add() a wrapper around that.
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
---
.../testing/selftests/kvm/include/kvm_util.h | 1 +
tools/testing/selftests/kvm/lib/kvm_util.c | 26 ++++++++++++++-----
2 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 9df16c8dc82a..aa521b383abe 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -784,6 +784,7 @@ void vm_mem_region_set_flags(struct kvm_vm *vm, u32 slot, u32 flags);
void vm_mem_region_reload(struct kvm_vm *vm, u32 slot);
void vm_mem_region_move(struct kvm_vm *vm, u32 slot, u64 new_gpa);
void vm_mem_region_delete(struct kvm_vm *vm, u32 slot);
+struct kvm_vcpu *__vm_vcpu_try_add(struct kvm_vm *vm, u32 vcpu_id);
struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, u32 vcpu_id);
void vm_populate_gva_bitmap(struct kvm_vm *vm);
gva_t vm_unused_gva_gap(struct kvm_vm *vm, size_t sz, gva_t min_gva);
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 2be79c240ebf..7084ed90e4cc 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -1367,11 +1367,7 @@ static bool vcpu_exists(struct kvm_vm *vm, u32 vcpu_id)
return false;
}
-/*
- * Adds a virtual CPU to the VM specified by vm with the ID given by vcpu_id.
- * No additional vCPU setup is done. Returns the vCPU.
- */
-struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, u32 vcpu_id)
+struct kvm_vcpu *__vm_vcpu_try_add(struct kvm_vm *vm, u32 vcpu_id)
{
struct kvm_vcpu *vcpu;
@@ -1385,7 +1381,13 @@ struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, u32 vcpu_id)
vcpu->vm = vm;
vcpu->id = vcpu_id;
vcpu->fd = __vm_ioctl(vm, KVM_CREATE_VCPU, (void *)(unsigned long)vcpu_id);
- TEST_ASSERT_VM_VCPU_IOCTL(vcpu->fd >= 0, KVM_CREATE_VCPU, vcpu->fd, vm);
+ if (vcpu->fd < 0) {
+ int __errno = errno;
+
+ free(vcpu);
+ errno = __errno;
+ return NULL;
+ }
TEST_ASSERT(vcpu_mmap_sz() >= sizeof(*vcpu->run), "vcpu mmap size "
"smaller than expected, vcpu_mmap_sz: %zi expected_min: %zi",
@@ -1404,6 +1406,18 @@ struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, u32 vcpu_id)
return vcpu;
}
+/*
+ * Adds a virtual CPU to the VM specified by vm with the ID given by vcpu_id.
+ * No additional vCPU setup is done. Returns the vCPU.
+ */
+struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, u32 vcpu_id)
+{
+ struct kvm_vcpu *vcpu = __vm_vcpu_try_add(vm, vcpu_id);
+
+ TEST_ASSERT_VM_VCPU_IOCTL(vcpu, KVM_CREATE_VCPU, -1, vm);
+ return vcpu;
+}
+
/*
* Within the VM specified by @vm, locates the lowest starting guest virtual
* address >= @min_gva, that has at least @sz unallocated bytes. A
--
2.39.5
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v5 5/9] KVM: selftests: Make kvm_create_max_vcpus tolerate ENOMEM
2026-09-22 18:28 [PATCH v5 0/9] KVM: selftests: add powerpc support Ritesh Harjani (IBM)
` (3 preceding siblings ...)
2026-09-22 18:28 ` [PATCH v5 4/9] KVM: selftests: Split out a KVM_CREATE_VCPU helper that can fail Ritesh Harjani (IBM)
@ 2026-09-22 18:28 ` Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 6/9] KVM: selftests: Limit the number of VM creates in hardware_disable_test Ritesh Harjani (IBM)
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ritesh Harjani (IBM) @ 2026-09-22 18:28 UTC (permalink / raw)
To: kvm
Cc: Sean Christopherson, Paolo Bonzini, linuxppc-dev,
Michael Ellerman, Christophe Leroy, Anushree Mathur,
Venkat Rao Bagalkote, Harsh Prateek Bora, Madhavan Srinivasan,
Shrikanth Hegde, linux-kernel, Ritesh Harjani (IBM)
Some hosts (like in case of nested guest the hypervisor L0 might have
quotas/limited resources for L1 guest) can run out of hypervisor
resources before hitting KVM_CAP_MAX_VCPUS.
This patch make use of the helper we introduced in the previous patch
(__vm_vcpu_try_add()) to tolerate such scenarios where an ENOMEM can
occur.
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
---
.../testing/selftests/kvm/include/kvm_util.h | 3 +++
.../selftests/kvm/kvm_create_max_vcpus.c | 21 +++++++++++++++----
tools/testing/selftests/kvm/lib/kvm_util.c | 5 +++++
3 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index aa521b383abe..576bbebe0679 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -1064,6 +1064,9 @@ const char *exit_reason_str(unsigned int exit_reason);
bool kvm_arch_needs_naturally_aligned_page_tables(void);
+/* True if KVM_CREATE_VM / KVM_CREATE_VCPU may return ENOMEM. */
+bool kvm_arch_vm_create_may_enomem(void);
+
gpa_t ____vm_phy_pages_alloc(struct kvm_vm *vm, size_t nr_pages, gpa_t min_gpa,
u32 memslot, bool protected, bool naturally_aligned);
gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t nr_pages,
diff --git a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c
index 59ddc3757943..45a9d8b369b5 100644
--- a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c
+++ b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c
@@ -20,16 +20,29 @@
void test_vcpu_creation(int first_vcpu_id, int num_vcpus)
{
struct kvm_vm *vm;
- int i;
+ struct kvm_vcpu *vcpu;
+ int i, created = 0;
pr_info("Testing creating %d vCPUs, with IDs %d...%d.\n",
num_vcpus, first_vcpu_id, first_vcpu_id + num_vcpus - 1);
vm = vm_create_barebones();
- for (i = first_vcpu_id; i < first_vcpu_id + num_vcpus; i++)
- /* This asserts that the vCPU was created. */
- __vm_vcpu_add(vm, i);
+ for (i = first_vcpu_id; i < first_vcpu_id + num_vcpus; i++) {
+ vcpu = __vm_vcpu_try_add(vm, i);
+ if (vcpu) {
+ created++;
+ continue;
+ }
+
+ TEST_ASSERT(errno == ENOMEM && kvm_arch_vm_create_may_enomem(),
+ "KVM_CREATE_VCPU failed for id %d, errno: %d (%s)",
+ i, errno, strerror(errno));
+ TEST_ASSERT(created > 0,
+ "KVM_CREATE_VCPU failed with ENOMEM before creating any vCPUs");
+ pr_info("Created %d vCPUs before ENOMEM at id %d\n", created, i);
+ break;
+ }
kvm_vm_free(vm);
}
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 7084ed90e4cc..b4d6b8167466 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -2112,6 +2112,11 @@ __weak bool kvm_arch_needs_naturally_aligned_page_tables(void)
return false;
}
+__weak bool kvm_arch_vm_create_may_enomem(void)
+{
+ return false;
+}
+
gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t nr_pages,
enum kvm_mem_region_type type, bool protected)
{
--
2.39.5
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v5 6/9] KVM: selftests: Limit the number of VM creates in hardware_disable_test
2026-09-22 18:28 [PATCH v5 0/9] KVM: selftests: add powerpc support Ritesh Harjani (IBM)
` (4 preceding siblings ...)
2026-09-22 18:28 ` [PATCH v5 5/9] KVM: selftests: Make kvm_create_max_vcpus tolerate ENOMEM Ritesh Harjani (IBM)
@ 2026-09-22 18:28 ` Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 7/9] KVM: PPC: selftests: Make nested case on pseries LPARs as resource constrained Ritesh Harjani (IBM)
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ritesh Harjani (IBM) @ 2026-09-22 18:28 UTC (permalink / raw)
To: kvm
Cc: Sean Christopherson, Paolo Bonzini, linuxppc-dev,
Michael Ellerman, Christophe Leroy, Anushree Mathur,
Venkat Rao Bagalkote, Harsh Prateek Bora, Madhavan Srinivasan,
Shrikanth Hegde, linux-kernel, Ritesh Harjani (IBM)
hardware_disable_test forks several VMs (NR_IERATIONS=512). This patch
limits that number to 4 when we know that we are running in constraint
host environment. The number 4 is just a safe minimum when
kvm_arch_vm_create_may_enomem() can be true.
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
---
tools/testing/selftests/kvm/hardware_disable_test.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/kvm/hardware_disable_test.c b/tools/testing/selftests/kvm/hardware_disable_test.c
index 43a36ef3ead8..e90a17b8160e 100644
--- a/tools/testing/selftests/kvm/hardware_disable_test.c
+++ b/tools/testing/selftests/kvm/hardware_disable_test.c
@@ -20,6 +20,7 @@
#define NR_VCPUS 4
#define NR_SLEEPERS_PER_VCPU 16
#define NR_ITERATIONS 512
+#define NR_ITERATIONS_LIMIT 4
#define DELAY_US_MAX 2000
static cpu_set_t threads_cpu_set;
@@ -127,7 +128,7 @@ void wait_for_child_setup(pid_t pid)
int main(int argc, char **argv)
{
cpu_set_t allowed_cpu_set;
- int s, r, cpu, i;
+ int s, r, cpu, i, nr_iterations;
pid_t pid;
kvm_sched_getaffinity(0, sizeof(cpu_set_t), &allowed_cpu_set);
@@ -141,7 +142,9 @@ int main(int argc, char **argv)
sem = sem_open("vm_sem", O_CREAT | O_EXCL, 0644, 0);
sem_unlink("vm_sem");
- for (i = 0; i < NR_ITERATIONS; ++i) {
+ nr_iterations = kvm_arch_vm_create_may_enomem() ? NR_ITERATIONS_LIMIT :
+ NR_ITERATIONS;
+ for (i = 0; i < nr_iterations; ++i) {
pid = fork();
TEST_ASSERT(pid >= 0, "%s: unable to fork", __func__);
if (pid == 0)
--
2.39.5
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v5 7/9] KVM: PPC: selftests: Make nested case on pseries LPARs as resource constrained
2026-09-22 18:28 [PATCH v5 0/9] KVM: selftests: add powerpc support Ritesh Harjani (IBM)
` (5 preceding siblings ...)
2026-09-22 18:28 ` [PATCH v5 6/9] KVM: selftests: Limit the number of VM creates in hardware_disable_test Ritesh Harjani (IBM)
@ 2026-09-22 18:28 ` Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 8/9] KVM: PPC: selftests: Skip idle-page check when running nested on pseries LPAR Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 9/9] KVM: selftests: Move memslot_perf_test off the 256M ELF load address Ritesh Harjani (IBM)
8 siblings, 0 replies; 10+ messages in thread
From: Ritesh Harjani (IBM) @ 2026-09-22 18:28 UTC (permalink / raw)
To: kvm
Cc: Sean Christopherson, Paolo Bonzini, linuxppc-dev,
Michael Ellerman, Christophe Leroy, Anushree Mathur,
Venkat Rao Bagalkote, Harsh Prateek Bora, Madhavan Srinivasan,
Shrikanth Hegde, linux-kernel, Ritesh Harjani (IBM)
For nested guest case (L1 as pseries LPAR), L0 may fail with -44
(H_NOT_ENOUGH_RESOURCES) during vm or vcpu creation, causing enomem
due to limited resource/quotas.
This adds the necessary arch hooks for the same so that it can survive
hardware_disable_test and kvm_create_max_vcpus test cases.
Reported-by: Anushree Mathur <anushree.mathur@linux.ibm.com>
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
---
.../testing/selftests/kvm/include/powerpc/processor.h | 7 +++++++
tools/testing/selftests/kvm/lib/powerpc/processor.c | 10 ++++++++++
2 files changed, 17 insertions(+)
diff --git a/tools/testing/selftests/kvm/include/powerpc/processor.h b/tools/testing/selftests/kvm/include/powerpc/processor.h
index f0ee21a8e2d4..a46f6828991c 100644
--- a/tools/testing/selftests/kvm/include/powerpc/processor.h
+++ b/tools/testing/selftests/kvm/include/powerpc/processor.h
@@ -6,6 +6,8 @@
#define SELFTEST_KVM_PROCESSOR_H
#include <linux/compiler.h>
+#include <unistd.h>
+
#include "ppc_asm.h"
#include "kvm_util_types.h"
@@ -36,4 +38,9 @@ static inline void cpu_relax(void)
asm volatile("" ::: "memory");
}
+static inline bool is_pseries_lpar(void)
+{
+ return !access("/proc/device-tree/rtas/ibm,hypertas-functions", F_OK);
+}
+
#endif
diff --git a/tools/testing/selftests/kvm/lib/powerpc/processor.c b/tools/testing/selftests/kvm/lib/powerpc/processor.c
index 301455024571..e5d84f6d82f2 100644
--- a/tools/testing/selftests/kvm/lib/powerpc/processor.c
+++ b/tools/testing/selftests/kvm/lib/powerpc/processor.c
@@ -23,6 +23,16 @@ bool kvm_arch_needs_naturally_aligned_page_tables(void)
return true;
}
+/*
+ * For nested guest case (L1 as pseries LPAR), L0 may fail with -44
+ * (H_NOT_ENOUGH_RESOURCES) during vm or vcpu creation, causing enomem
+ * due to limited resource/quotas.
+ */
+bool kvm_arch_vm_create_may_enomem(void)
+{
+ return is_pseries_lpar();
+}
+
static void set_proc_table(struct kvm_vm *vm, int pid, u64 dw0, u64 dw1)
{
u64 *proc_table;
--
2.39.5
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v5 8/9] KVM: PPC: selftests: Skip idle-page check when running nested on pseries LPAR
2026-09-22 18:28 [PATCH v5 0/9] KVM: selftests: add powerpc support Ritesh Harjani (IBM)
` (6 preceding siblings ...)
2026-09-22 18:28 ` [PATCH v5 7/9] KVM: PPC: selftests: Make nested case on pseries LPARs as resource constrained Ritesh Harjani (IBM)
@ 2026-09-22 18:28 ` Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 9/9] KVM: selftests: Move memslot_perf_test off the 256M ELF load address Ritesh Harjani (IBM)
8 siblings, 0 replies; 10+ messages in thread
From: Ritesh Harjani (IBM) @ 2026-09-22 18:28 UTC (permalink / raw)
To: kvm
Cc: Sean Christopherson, Paolo Bonzini, linuxppc-dev,
Michael Ellerman, Christophe Leroy, Anushree Mathur,
Venkat Rao Bagalkote, Harsh Prateek Bora, Madhavan Srinivasan,
Shrikanth Hegde, linux-kernel, Ritesh Harjani (IBM)
Same nested TLB/access bit issue like x86. Use the is_pseries_lpar()
check to detect when running nested kvm on pseries LPAR to only warn on
idle-page check.
Reported-by: Anushree Mathur <anushree.mathur@linux.ibm.com>
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
---
.../testing/selftests/kvm/access_tracking_perf_test.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/tools/testing/selftests/kvm/access_tracking_perf_test.c b/tools/testing/selftests/kvm/access_tracking_perf_test.c
index 4415c94b2866..94bfb82f7b79 100644
--- a/tools/testing/selftests/kvm/access_tracking_perf_test.c
+++ b/tools/testing/selftests/kvm/access_tracking_perf_test.c
@@ -470,6 +470,17 @@ static int access_tracking_unreliable(void)
puts("Skipping idle page count sanity check, because the test is run nested");
return 1;
}
+#endif
+#ifdef __powerpc64__
+ /*
+ * Nested KVM (pSeries LPAR) can hide accessed/idle, since KVM doesn't
+ * explicitely flush the TLB for access bit update. L0 keeps
+ * translations cached so the guest won't see the idle bit cleared.
+ */
+ if (is_pseries_lpar()) {
+ puts("Skipping idle page count sanity check, because the test is run nested");
+ return 1;
+ }
#endif
/*
* When NUMA balancing is enabled, guest memory will be unmapped to get
--
2.39.5
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v5 9/9] KVM: selftests: Move memslot_perf_test off the 256M ELF load address
2026-09-22 18:28 [PATCH v5 0/9] KVM: selftests: add powerpc support Ritesh Harjani (IBM)
` (7 preceding siblings ...)
2026-09-22 18:28 ` [PATCH v5 8/9] KVM: PPC: selftests: Skip idle-page check when running nested on pseries LPAR Ritesh Harjani (IBM)
@ 2026-09-22 18:28 ` Ritesh Harjani (IBM)
8 siblings, 0 replies; 10+ messages in thread
From: Ritesh Harjani (IBM) @ 2026-09-22 18:28 UTC (permalink / raw)
To: kvm
Cc: Sean Christopherson, Paolo Bonzini, linuxppc-dev,
Michael Ellerman, Christophe Leroy, Anushree Mathur,
Venkat Rao Bagalkote, Harsh Prateek Bora, Madhavan Srinivasan,
Shrikanth Hegde, linux-kernel, Ritesh Harjani (IBM)
KVM selftests are built with -fno-PIE/-no-pie so the binary uses fixed
load addresses.
On powerpc64, GNU ld default links at 0x10000000 (256M) which is also
the MEM_GPA, so the identity map trips with the error:
PTE already present at level: 4 gva: 0x10000000 pte:0xc00000000002018f
Put the test slots at 512M instead which is past the ELF.
e.g. failure w/o this fix:
./memslot_perf_test -s 514
Random seed: 0x423558ef
Testing map performance with 1 runs, 5 seconds each
==== Test Assertion Failure ====
lib/powerpc/processor.c:235: !pte
pid=371 tid=371 errno=2 - No such file or directory
1 0x0000000010018293: virt_arch_pg_map at processor.c:235
2 0x0000000010008b3f: virt_pg_map at kvm_util.h:1325
3 (inlined by) virt_map at kvm_util.c:1571
4 0x0000000010001cab: prepare_vm at memslot_perf_test.c:353
5 (inlined by) test_execute at memslot_perf_test.c:816
6 (inlined by) test_loop at memslot_perf_test.c:1062
7 (inlined by) main at memslot_perf_test.c:1136
8 0x000000001001d713: __libc_start_call_main at libc-start.o:?
9 0x000000001001db47: __libc_start_main_impl at ??:?
PTE already present at level: 4 gva: 0x10000000 pte:0xc00000000002018f
Signed-off-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
---
tools/testing/selftests/kvm/memslot_perf_test.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c
index 844ea9b7bb41..2913a4de4cc9 100644
--- a/tools/testing/selftests/kvm/memslot_perf_test.c
+++ b/tools/testing/selftests/kvm/memslot_perf_test.c
@@ -30,7 +30,7 @@
#define MEM_EXTRA_SIZE SZ_64K
#define MEM_SIZE (SZ_512M + MEM_EXTRA_SIZE)
-#define MEM_GPA SZ_256M
+#define MEM_GPA SZ_512M
#define MEM_AUX_GPA MEM_GPA
#define MEM_SYNC_GPA MEM_AUX_GPA
#define MEM_TEST_GPA (MEM_AUX_GPA + MEM_EXTRA_SIZE)
--
2.39.5
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-09-22 18:30 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-22 18:28 [PATCH v5 0/9] KVM: selftests: add powerpc support Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 1/9] KVM: PPC: selftests: add support for powerpc Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 2/9] KVM: selftests: Enable kvm_create_max_vcpus test " Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 3/9] KVM: selftests: Don't limit LE dirty-bitmap bitops to s390x Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 4/9] KVM: selftests: Split out a KVM_CREATE_VCPU helper that can fail Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 5/9] KVM: selftests: Make kvm_create_max_vcpus tolerate ENOMEM Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 6/9] KVM: selftests: Limit the number of VM creates in hardware_disable_test Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 7/9] KVM: PPC: selftests: Make nested case on pseries LPARs as resource constrained Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 8/9] KVM: PPC: selftests: Skip idle-page check when running nested on pseries LPAR Ritesh Harjani (IBM)
2026-09-22 18:28 ` [PATCH v5 9/9] KVM: selftests: Move memslot_perf_test off the 256M ELF load address Ritesh Harjani (IBM)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®