* [PATCH 0/5] KVM: selftests: Reserve memslot 1 for ucall MMIO
@ 2026-10-17 11:02 Tharit Tangkijwanichakul
2026-10-17 11:02 ` [PATCH 1/5] KVM: selftests: Introduce a shared base for test memslots Tharit Tangkijwanichakul
` (4 more replies)
0 siblings, 5 replies; 10+ messages in thread
From: Tharit Tangkijwanichakul @ 2026-10-17 11:02 UTC (permalink / raw)
To: Paolo Bonzini, Sean Christopherson
Cc: Shuah Khan, Marc Zyngier, Oliver Upton, Fuad Tabba, Joey Gouly,
Steffen Eiden, Suzuki K Poulose, Zenghui Yu, Anup Patel,
Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, kvm, linux-kernel, linux-kselftest,
linux-arm-kernel, kvmarm, kvm-riscv, linux-riscv,
linux-kernel-mentees, skhan, me, jkoolstra,
Tharit Tangkijwanichakul
This series addresses the TODO in __vm_create() to reserve memslot 1
for the ucall MMIO region. It introduces a shared base for test
memslots, migrates existing test users, and adds a read-only region to
prevent overlapping allocations.
A regression test verifies overlap rejection and continued ucall
operation.
Testing:
- Intel Core i5-10210U and Rockchip RK3588 (arm64).
These tests are changed but not tested:
- arm64/sea_to_user.c: not enough memory allocation.
- x86/nested_vmsave_vmload_test.c: requires X86_FEATURE_SVM.
- riscv/sbi_pmu_test.c: riscv hardware unavailability.
The following test failures reproduce on both the unmodified base
<8edffbc1f6272db167037e1a8c49b99e9cd04803> with host kernel
7.3.0-rc1-gd4b7fb647204 on RK3588 and with this series applied:
- arm64/vgic_its_save.c
- arm64/hypercalls.c
These failures are unchanged by this series.
Tharit Tangkijwanichakul (5):
KVM: selftests: Introduce a shared base for test memslots
KVM: selftests: Use the shared memslot base in memslot_perf_test
KVM: selftests: Use the shared memslot base in memstress
KVM: selftests: Reserve memslot 1 for the ucall MMIO address
KVM: selftests: Test protection of the ucall MMIO region
tools/testing/selftests/kvm/Makefile.kvm | 1 +
.../testing/selftests/kvm/arm64/hypercalls.c | 3 +-
.../testing/selftests/kvm/arm64/sea_to_user.c | 2 +-
.../kvm/arm64/stage2_block_transitions.c | 2 +-
.../selftests/kvm/arm64/vgic_its_save.c | 2 +-
.../selftests/kvm/arm64/vgic_lpi_stress.c | 2 +-
tools/testing/selftests/kvm/dirty_log_test.c | 2 +-
.../testing/selftests/kvm/guest_memfd_test.c | 2 +-
.../testing/selftests/kvm/include/kvm_util.h | 1 +
.../testing/selftests/kvm/include/memstress.h | 2 +-
.../selftests/kvm/kvm_page_table_test.c | 2 +-
tools/testing/selftests/kvm/lib/kvm_util.c | 19 ++++--
.../testing/selftests/kvm/memslot_perf_test.c | 62 +++++++++++--------
tools/testing/selftests/kvm/mmu_stress_test.c | 2 +-
.../selftests/kvm/reserved_slot_test.c | 61 ++++++++++++++++++
.../selftests/kvm/riscv/sbi_pmu_test.c | 3 +-
tools/testing/selftests/kvm/steal_time.c | 3 +-
.../selftests/kvm/x86/nested_dirty_log_test.c | 2 +-
.../kvm/x86/nested_vmsave_vmload_test.c | 2 +-
19 files changed, 128 insertions(+), 47 deletions(-)
create mode 100644 tools/testing/selftests/kvm/reserved_slot_test.c
--
2.53.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/5] KVM: selftests: Introduce a shared base for test memslots
2026-10-17 11:02 [PATCH 0/5] KVM: selftests: Reserve memslot 1 for ucall MMIO Tharit Tangkijwanichakul
@ 2026-10-17 11:02 ` Tharit Tangkijwanichakul
2026-10-17 11:14 ` sashiko-bot
2026-10-17 11:02 ` [PATCH 2/5] KVM: selftests: Use the shared memslot base in memslot_perf_test Tharit Tangkijwanichakul
` (3 subsequent siblings)
4 siblings, 1 reply; 10+ messages in thread
From: Tharit Tangkijwanichakul @ 2026-10-17 11:02 UTC (permalink / raw)
To: Paolo Bonzini, Sean Christopherson
Cc: Shuah Khan, Marc Zyngier, Oliver Upton, Fuad Tabba, Joey Gouly,
Steffen Eiden, Suzuki K Poulose, Zenghui Yu, Anup Patel,
Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, kvm, linux-kernel, linux-kselftest,
linux-arm-kernel, kvmarm, kvm-riscv, linux-riscv,
linux-kernel-mentees, skhan, me, jkoolstra,
Tharit Tangkijwanichakul
Replace hardcoded slot 1 assignments with TEST_MEM_SLOT_BASE
This prepares tests for reserving slot 1 for library use.
Signed-off-by: Tharit Tangkijwanichakul <tharitt97@gmail.com>
---
tools/testing/selftests/kvm/arm64/hypercalls.c | 3 ++-
tools/testing/selftests/kvm/arm64/sea_to_user.c | 2 +-
tools/testing/selftests/kvm/arm64/stage2_block_transitions.c | 2 +-
tools/testing/selftests/kvm/arm64/vgic_its_save.c | 2 +-
tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c | 2 +-
tools/testing/selftests/kvm/dirty_log_test.c | 2 +-
tools/testing/selftests/kvm/guest_memfd_test.c | 2 +-
tools/testing/selftests/kvm/include/kvm_util.h | 1 +
tools/testing/selftests/kvm/kvm_page_table_test.c | 2 +-
tools/testing/selftests/kvm/mmu_stress_test.c | 2 +-
tools/testing/selftests/kvm/riscv/sbi_pmu_test.c | 3 ++-
tools/testing/selftests/kvm/steal_time.c | 3 ++-
tools/testing/selftests/kvm/x86/nested_dirty_log_test.c | 2 +-
tools/testing/selftests/kvm/x86/nested_vmsave_vmload_test.c | 2 +-
14 files changed, 17 insertions(+), 13 deletions(-)
diff --git a/tools/testing/selftests/kvm/arm64/hypercalls.c b/tools/testing/selftests/kvm/arm64/hypercalls.c
index 391e2ba58b0b..ff7c21738a96 100644
--- a/tools/testing/selftests/kvm/arm64/hypercalls.c
+++ b/tools/testing/selftests/kvm/arm64/hypercalls.c
@@ -191,7 +191,8 @@ static void steal_time_init(struct kvm_vcpu *vcpu)
unsigned int gpages;
gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE);
- vm_userspace_mem_region_add(vcpu->vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0);
+ vm_userspace_mem_region_add(vcpu->vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE,
+ TEST_MEM_SLOT_BASE, gpages, 0);
vcpu_device_attr_set(vcpu, KVM_ARM_VCPU_PVTIME_CTRL,
KVM_ARM_VCPU_PVTIME_IPA, &st_ipa);
diff --git a/tools/testing/selftests/kvm/arm64/sea_to_user.c b/tools/testing/selftests/kvm/arm64/sea_to_user.c
index d4af6e0eed28..bb552debc61c 100644
--- a/tools/testing/selftests/kvm/arm64/sea_to_user.c
+++ b/tools/testing/selftests/kvm/arm64/sea_to_user.c
@@ -323,7 +323,7 @@ static struct kvm_vm *vm_create_with_sea_handler(struct kvm_vcpu **vcpu)
/*vm=*/vm,
/*src_type=*/src_type,
/*gpa=*/start_gpa,
- /*slot=*/1,
+ /*slot=*/TEST_MEM_SLOT_BASE,
/*npages=*/num_guest_pages,
/*flags=*/0);
diff --git a/tools/testing/selftests/kvm/arm64/stage2_block_transitions.c b/tools/testing/selftests/kvm/arm64/stage2_block_transitions.c
index 5fd47f4ada1f..0e23d7b55782 100644
--- a/tools/testing/selftests/kvm/arm64/stage2_block_transitions.c
+++ b/tools/testing/selftests/kvm/arm64/stage2_block_transitions.c
@@ -41,7 +41,7 @@
#include "test_util.h"
#include "ucall.h"
-#define DATA_SLOT 1
+#define DATA_SLOT TEST_MEM_SLOT_BASE
#define TEST_GVA 0xc0000000UL
#define BLOCK_SIZE SZ_2M
diff --git a/tools/testing/selftests/kvm/arm64/vgic_its_save.c b/tools/testing/selftests/kvm/arm64/vgic_its_save.c
index 864da01539f3..e858a4aa741d 100644
--- a/tools/testing/selftests/kvm/arm64/vgic_its_save.c
+++ b/tools/testing/selftests/kvm/arm64/vgic_its_save.c
@@ -29,7 +29,7 @@
#include "ucall.h"
#include "vgic.h"
-#define TEST_MEMSLOT_INDEX 1
+#define TEST_MEMSLOT_INDEX TEST_MEM_SLOT_BASE
/* All three ITS table entry sizes are 8 bytes in ABI 0. */
#define ESZ 8
diff --git a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c
index 9a69c439a0f8..1d5c56481053 100644
--- a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c
+++ b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c
@@ -18,7 +18,7 @@
#include "ucall.h"
#include "vgic.h"
-#define TEST_MEMSLOT_INDEX 1
+#define TEST_MEMSLOT_INDEX TEST_MEM_SLOT_BASE
#define GIC_LPI_OFFSET 8192
diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c
index af5eb0334a74..75084fe3bec6 100644
--- a/tools/testing/selftests/kvm/dirty_log_test.c
+++ b/tools/testing/selftests/kvm/dirty_log_test.c
@@ -26,7 +26,7 @@
#define PAGE_SHIFT_4K 12
/* The memory slot index to track dirty pages */
-#define TEST_MEM_SLOT_INDEX 1
+#define TEST_MEM_SLOT_INDEX TEST_MEM_SLOT_BASE
/* Default guest test virtual memory offset */
#define DEFAULT_GUEST_TEST_MEM 0xc0000000
diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c
index 2233d871a38f..231bfe238e31 100644
--- a/tools/testing/selftests/kvm/guest_memfd_test.c
+++ b/tools/testing/selftests/kvm/guest_memfd_test.c
@@ -510,7 +510,7 @@ static void test_guest_memfd_guest(void)
* the PCI hole and other MMIO regions that need to be avoided.
*/
const gpa_t gpa = SZ_4G;
- const int slot = 1;
+ const int slot = TEST_MEM_SLOT_BASE;
struct kvm_vcpu *vcpu;
struct kvm_vm *vm;
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 5a7a455b5387..759d604d44ce 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -30,6 +30,7 @@
#define KVM_DEV_PATH "/dev/kvm"
#define KVM_MAX_VCPUS 512
+#define TEST_MEM_SLOT_BASE 1
#define NSEC_PER_SEC 1000000000L
diff --git a/tools/testing/selftests/kvm/kvm_page_table_test.c b/tools/testing/selftests/kvm/kvm_page_table_test.c
index 974813ea8953..f18720109319 100644
--- a/tools/testing/selftests/kvm/kvm_page_table_test.c
+++ b/tools/testing/selftests/kvm/kvm_page_table_test.c
@@ -20,7 +20,7 @@
#include "guest_modes.h"
#include "ucall_common.h"
-#define TEST_MEM_SLOT_INDEX 1
+#define TEST_MEM_SLOT_INDEX TEST_MEM_SLOT_BASE
/* Default size(1GB) of the memory for testing */
#define DEFAULT_TEST_MEM_SIZE (1 << 30)
diff --git a/tools/testing/selftests/kvm/mmu_stress_test.c b/tools/testing/selftests/kvm/mmu_stress_test.c
index 741e343962ed..b965a8b9d214 100644
--- a/tools/testing/selftests/kvm/mmu_stress_test.c
+++ b/tools/testing/selftests/kvm/mmu_stress_test.c
@@ -273,7 +273,7 @@ int main(int argc, char *argv[])
* 1gb-3gb,but it's simpler to skip straight to 4gb.
*/
const u64 start_gpa = SZ_4G;
- const int first_slot = 1;
+ const int first_slot = TEST_MEM_SLOT_BASE;
struct timespec time_start, time_run1, time_reset, time_run2, time_ro, time_rw;
u64 max_gpa, gpa, slot_size, max_mem, i;
diff --git a/tools/testing/selftests/kvm/riscv/sbi_pmu_test.c b/tools/testing/selftests/kvm/riscv/sbi_pmu_test.c
index 20388f0b959d..6abd74870e01 100644
--- a/tools/testing/selftests/kvm/riscv/sbi_pmu_test.c
+++ b/tools/testing/selftests/kvm/riscv/sbi_pmu_test.c
@@ -605,7 +605,8 @@ static void test_vm_events_test(void *guest_code)
static void test_vm_setup_snapshot_mem(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
{
/* PMU Snapshot requires single page only */
- vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, PMU_SNAPSHOT_GPA_BASE, 1, 1, 0);
+ vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, PMU_SNAPSHOT_GPA_BASE,
+ TEST_MEM_SLOT_BASE, 1, 0);
/* PMU_SNAPSHOT_GPA_BASE is identity mapped */
virt_map(vm, PMU_SNAPSHOT_GPA_BASE, PMU_SNAPSHOT_GPA_BASE, 1);
diff --git a/tools/testing/selftests/kvm/steal_time.c b/tools/testing/selftests/kvm/steal_time.c
index 785d19f9ee8f..e386580ef540 100644
--- a/tools/testing/selftests/kvm/steal_time.c
+++ b/tools/testing/selftests/kvm/steal_time.c
@@ -509,7 +509,8 @@ static struct kvm_vm *vm_create_steal_time(u32 nr_vcpus, void *guest_code,
/* Create a VM and an identity mapped memslot for the steal time structure */
vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus);
gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE * nr_vcpus);
- vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0);
+ vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE,
+ TEST_MEM_SLOT_BASE, gpages, 0);
virt_map(vm, ST_GPA_BASE, ST_GPA_BASE, gpages);
return vm;
diff --git a/tools/testing/selftests/kvm/x86/nested_dirty_log_test.c b/tools/testing/selftests/kvm/x86/nested_dirty_log_test.c
index 26b474bf1353..e86d625b3e89 100644
--- a/tools/testing/selftests/kvm/x86/nested_dirty_log_test.c
+++ b/tools/testing/selftests/kvm/x86/nested_dirty_log_test.c
@@ -16,7 +16,7 @@
#include "vmx.h"
/* The memory slot index to track dirty pages */
-#define TEST_MEM_SLOT_INDEX 1
+#define TEST_MEM_SLOT_INDEX TEST_MEM_SLOT_BASE
/*
* Allocate four pages total. Two pages are used to verify that the KVM marks
diff --git a/tools/testing/selftests/kvm/x86/nested_vmsave_vmload_test.c b/tools/testing/selftests/kvm/x86/nested_vmsave_vmload_test.c
index a130759f39a1..4bc57e5e40e3 100644
--- a/tools/testing/selftests/kvm/x86/nested_vmsave_vmload_test.c
+++ b/tools/testing/selftests/kvm/x86/nested_vmsave_vmload_test.c
@@ -17,7 +17,7 @@
* interpreted as a direct L1 GPA or translated using NPT as an L2 GPA, depends
* on which VMCB is accessed.
*/
-#define TEST_MEM_SLOT_INDEX 1
+#define TEST_MEM_SLOT_INDEX TEST_MEM_SLOT_BASE
#define TEST_MEM_PAGES 2
#define TEST_MEM_BASE 0xc0000000
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/5] KVM: selftests: Use the shared memslot base in memslot_perf_test
2026-10-17 11:02 [PATCH 0/5] KVM: selftests: Reserve memslot 1 for ucall MMIO Tharit Tangkijwanichakul
2026-10-17 11:02 ` [PATCH 1/5] KVM: selftests: Introduce a shared base for test memslots Tharit Tangkijwanichakul
@ 2026-10-17 11:02 ` Tharit Tangkijwanichakul
2026-10-17 11:02 ` [PATCH 3/5] KVM: selftests: Use the shared memslot base in memstress Tharit Tangkijwanichakul
` (2 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: Tharit Tangkijwanichakul @ 2026-10-17 11:02 UTC (permalink / raw)
To: Paolo Bonzini, Sean Christopherson
Cc: Shuah Khan, Marc Zyngier, Oliver Upton, Fuad Tabba, Joey Gouly,
Steffen Eiden, Suzuki K Poulose, Zenghui Yu, Anup Patel,
Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, kvm, linux-kernel, linux-kselftest,
linux-arm-kernel, kvmarm, kvm-riscv, linux-riscv,
linux-kernel-mentees, skhan, me, jkoolstra,
Tharit Tangkijwanichakul
Use TEST_MEM_SLOT_BASE for test memslot IDs and account for the
reserved slots when calculating the available slot count. This
prepares memslot_perf_test for reserving slot 1 for library use.
Signed-off-by: Tharit Tangkijwanichakul <tharitt97@gmail.com>
---
.../testing/selftests/kvm/memslot_perf_test.c | 62 +++++++++++--------
1 file changed, 35 insertions(+), 27 deletions(-)
diff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c
index e1299611be32..cbb900ab58af 100644
--- a/tools/testing/selftests/kvm/memslot_perf_test.c
+++ b/tools/testing/selftests/kvm/memslot_perf_test.c
@@ -60,7 +60,7 @@
* other memslot(s).
*
* We have different number of memory slots, excluding the reserved
- * memory slot 0, on various architectures and configurations. The
+ * memory slots 0 and 1, on various architectures and configurations. The
* memory size in this test is calculated by picking the maximal
* last memory slot's memory size, with alignment to the largest
* supported page size (64KB). In this way, the selected memory
@@ -68,9 +68,9 @@
*
* architecture slots memory-per-slot memory-on-last-slot
* --------------------------------------------------------------
- * x86-4KB 32763 16KB 160KB
- * arm64-4KB 32766 16KB 112KB
- * arm64-16KB 32766 16KB 112KB
+ * x86-4KB 32762 16KB 176KB
+ * arm64-4KB 32765 16KB 128KB
+ * arm64-16KB 32765 16KB 128KB
* arm64-64KB 8192 64KB 128KB
*/
#define MEM_TEST_MOVE_SIZE (3 * SZ_64K)
@@ -276,7 +276,7 @@ static u64 get_max_slots(struct vm_data *data, u32 host_page_size)
rempages = mempages % pages_per_slot;
if (check_slot_pages(host_page_size, guest_page_size,
pages_per_slot, rempages))
- return slots + 1; /* slot 0 is reserved */
+ return slots + TEST_MEM_SLOT_BASE;
}
return 0;
@@ -313,38 +313,42 @@ static bool prepare_vm(struct vm_data *data, int nslots, u64 *maxslots,
data->hva_slots = malloc(sizeof(*data->hva_slots) * data->nslots);
TEST_ASSERT(data->hva_slots, "malloc() fail");
- pr_info_v("Adding slots 1..%i, each slot with %"PRIu64" pages + %"PRIu64" extra pages last\n",
- data->nslots, data->pages_per_slot, rempages);
+ pr_info_v("Adding slots %u..%u, each slot with %" PRIu64
+ " pages + %" PRIu64 " extra pages last\n",
+ (u32)TEST_MEM_SLOT_BASE,
+ TEST_MEM_SLOT_BASE + data->nslots - 1,
+ data->pages_per_slot, rempages);
clock_gettime(CLOCK_MONOTONIC, &tstart);
- for (slot = 1, guest_addr = MEM_GPA; slot <= data->nslots; slot++) {
+ for (slot = 0, guest_addr = MEM_GPA; slot < data->nslots; slot++) {
u64 npages;
npages = data->pages_per_slot;
- if (slot == data->nslots)
+ if (slot == data->nslots - 1)
npages += rempages;
vm_userspace_mem_region_add(data->vm, VM_MEM_SRC_ANONYMOUS,
- guest_addr, slot, npages,
- 0);
+ guest_addr, TEST_MEM_SLOT_BASE + slot,
+ npages, 0);
guest_addr += npages * guest_page_size;
}
*slot_runtime = timespec_elapsed(tstart);
- for (slot = 1, guest_addr = MEM_GPA; slot <= data->nslots; slot++) {
+ for (slot = 0, guest_addr = MEM_GPA; slot < data->nslots; slot++) {
u64 npages;
gpa_t gpa;
npages = data->pages_per_slot;
- if (slot == data->nslots)
+ if (slot == data->nslots - 1)
npages += rempages;
- gpa = vm_phy_pages_alloc(data->vm, npages, guest_addr, slot);
+ gpa = vm_phy_pages_alloc(data->vm, npages, guest_addr,
+ TEST_MEM_SLOT_BASE + slot);
TEST_ASSERT(gpa == guest_addr,
"vm_phy_pages_alloc() failed");
- data->hva_slots[slot - 1] = addr_gpa2hva(data->vm, guest_addr);
- memset(data->hva_slots[slot - 1], 0, npages * guest_page_size);
+ data->hva_slots[slot] = addr_gpa2hva(data->vm, guest_addr);
+ memset(data->hva_slots[slot], 0, npages * guest_page_size);
guest_addr += npages * guest_page_size;
}
@@ -631,9 +635,10 @@ static void test_memslot_move_loop(struct vm_data *data, struct sync_area *sync)
u64 movesrcgpa;
movesrcgpa = vm_slot2gpa(data, data->nslots - 1);
- vm_mem_region_move(data->vm, data->nslots - 1 + 1,
+ vm_mem_region_move(data->vm, TEST_MEM_SLOT_BASE + data->nslots - 1,
MEM_TEST_MOVE_GPA_DEST);
- vm_mem_region_move(data->vm, data->nslots - 1 + 1, movesrcgpa);
+ vm_mem_region_move(data->vm, TEST_MEM_SLOT_BASE + data->nslots - 1,
+ movesrcgpa);
}
static void test_memslot_do_unmap(struct vm_data *data,
@@ -988,8 +993,10 @@ static bool parse_args(int argc, char *argv[],
#endif
case 's':
targs->nslots = atoi_paranoid(optarg);
- if (targs->nslots <= 1 && targs->nslots != -1) {
- pr_info("Slot count cap must be larger than 1 or -1 for no cap\n");
+ if (targs->nslots <= TEST_MEM_SLOT_BASE &&
+ targs->nslots != -1) {
+ pr_info("Slot count cap must be larger than %d or -1 for no cap\n",
+ TEST_MEM_SLOT_BASE);
return false;
}
break;
@@ -1027,20 +1034,21 @@ static bool parse_args(int argc, char *argv[],
}
max_mem_slots = kvm_check_cap(KVM_CAP_NR_MEMSLOTS);
- if (max_mem_slots <= 1) {
- pr_info("KVM_CAP_NR_MEMSLOTS should be greater than 1\n");
+ if (max_mem_slots <= TEST_MEM_SLOT_BASE) {
+ pr_info("KVM_CAP_NR_MEMSLOTS should be greater than %d\n",
+ TEST_MEM_SLOT_BASE);
return false;
}
- /* Memory slot 0 is reserved */
+ /* Memory slots below TEST_MEM_SLOT_BASE are reserved. */
if (targs->nslots == -1)
- targs->nslots = max_mem_slots - 1;
+ targs->nslots = max_mem_slots - TEST_MEM_SLOT_BASE;
else
- targs->nslots = min_t(int, targs->nslots, max_mem_slots) - 1;
+ targs->nslots = min_t(int, targs->nslots, max_mem_slots)
+ - TEST_MEM_SLOT_BASE;
pr_info_v("Allowed Number of memory slots: %"PRIu32"\n",
- targs->nslots + 1);
-
+ (u32)(targs->nslots + TEST_MEM_SLOT_BASE));
return true;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/5] KVM: selftests: Use the shared memslot base in memstress
2026-10-17 11:02 [PATCH 0/5] KVM: selftests: Reserve memslot 1 for ucall MMIO Tharit Tangkijwanichakul
2026-10-17 11:02 ` [PATCH 1/5] KVM: selftests: Introduce a shared base for test memslots Tharit Tangkijwanichakul
2026-10-17 11:02 ` [PATCH 2/5] KVM: selftests: Use the shared memslot base in memslot_perf_test Tharit Tangkijwanichakul
@ 2026-10-17 11:02 ` Tharit Tangkijwanichakul
2026-10-17 11:02 ` [PATCH 4/5] KVM: selftests: Reserve memslot 1 for the ucall MMIO address Tharit Tangkijwanichakul
2026-10-17 11:02 ` [PATCH 5/5] KVM: selftests: Test protection of the ucall MMIO region Tharit Tangkijwanichakul
4 siblings, 0 replies; 10+ messages in thread
From: Tharit Tangkijwanichakul @ 2026-10-17 11:02 UTC (permalink / raw)
To: Paolo Bonzini, Sean Christopherson
Cc: Shuah Khan, Marc Zyngier, Oliver Upton, Fuad Tabba, Joey Gouly,
Steffen Eiden, Suzuki K Poulose, Zenghui Yu, Anup Patel,
Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, kvm, linux-kernel, linux-kselftest,
linux-arm-kernel, kvmarm, kvm-riscv, linux-riscv,
linux-kernel-mentees, skhan, me, jkoolstra,
Tharit Tangkijwanichakul
Define MEMSTRESS_MEM_SLOT_INDEX using TEST_MEM_SLOT_BASE so
memstress and its users follow the library's reserved-slot
convention.
The tests affected but require no change are:
dirty_log_perf_test.c
demand_paging_test.c
access_tracking_perf_test.c
memslot_modification_stress_test.c
x86/dirty_log_page_splitting_test.c
Signed-off-by: Tharit Tangkijwanichakul <tharitt97@gmail.com>
---
tools/testing/selftests/kvm/include/memstress.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/testing/selftests/kvm/include/memstress.h b/tools/testing/selftests/kvm/include/memstress.h
index 0d1d6230cc05..4da03541e805 100644
--- a/tools/testing/selftests/kvm/include/memstress.h
+++ b/tools/testing/selftests/kvm/include/memstress.h
@@ -17,7 +17,7 @@
#define DEFAULT_PER_VCPU_MEM_SIZE (1 << 30) /* 1G */
-#define MEMSTRESS_MEM_SLOT_INDEX 1
+#define MEMSTRESS_MEM_SLOT_INDEX TEST_MEM_SLOT_BASE
struct memstress_vcpu_args {
gpa_t gpa;
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/5] KVM: selftests: Reserve memslot 1 for the ucall MMIO address
2026-10-17 11:02 [PATCH 0/5] KVM: selftests: Reserve memslot 1 for ucall MMIO Tharit Tangkijwanichakul
` (2 preceding siblings ...)
2026-10-17 11:02 ` [PATCH 3/5] KVM: selftests: Use the shared memslot base in memstress Tharit Tangkijwanichakul
@ 2026-10-17 11:02 ` Tharit Tangkijwanichakul
2026-10-17 11:19 ` sashiko-bot
2026-10-17 11:02 ` [PATCH 5/5] KVM: selftests: Test protection of the ucall MMIO region Tharit Tangkijwanichakul
4 siblings, 1 reply; 10+ messages in thread
From: Tharit Tangkijwanichakul @ 2026-10-17 11:02 UTC (permalink / raw)
To: Paolo Bonzini, Sean Christopherson
Cc: Shuah Khan, Marc Zyngier, Oliver Upton, Fuad Tabba, Joey Gouly,
Steffen Eiden, Suzuki K Poulose, Zenghui Yu, Anup Patel,
Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, kvm, linux-kernel, linux-kselftest,
linux-arm-kernel, kvmarm, kvm-riscv, linux-riscv,
linux-kernel-mentees, skhan, me, jkoolstra,
Tharit Tangkijwanichakul
Back the ucall MMIO address with a read-only region in slot 1
when KVM_CAP_READONLY_MEM is available. Writes still exit as
MMIO, while overlapping memslot creation is rejected.
Start test memslots at slot 2, leaving slot 1 reserved by
convention even when read-only memory is unsupported.
Signed-off-by: Tharit Tangkijwanichakul <tharitt97@gmail.com>
---
.../testing/selftests/kvm/include/kvm_util.h | 2 +-
tools/testing/selftests/kvm/lib/kvm_util.c | 19 +++++++++++++------
2 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index 759d604d44ce..4dbb2ef332fc 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -30,7 +30,7 @@
#define KVM_DEV_PATH "/dev/kvm"
#define KVM_MAX_VCPUS 512
-#define TEST_MEM_SLOT_BASE 1
+#define TEST_MEM_SLOT_BASE 2
#define NSEC_PER_SEC 1000000000L
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 9ddc047d5c27..73e28814a226 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -20,6 +20,7 @@
#include <linux/kernel.h>
#define KVM_UTIL_MIN_PFN 2
+#define KVM_UCALL_MEMSLOT 1
u32 kvm_random_seed;
struct kvm_random_state kvm_rng;
@@ -492,6 +493,7 @@ struct kvm_vm *__vm_create(struct vm_shape shape, u32 nr_runnable_vcpus,
struct userspace_mem_region *slot0;
struct kvm_vm *vm;
int i, flags;
+ gpa_t mmio_gpa;
kvm_set_files_rlimit(nr_runnable_vcpus);
@@ -514,14 +516,19 @@ struct kvm_vm *__vm_create(struct vm_shape shape, u32 nr_runnable_vcpus,
kvm_vm_elf_load(vm, program_invocation_name);
- /*
- * TODO: Add proper defines to protect the library's memslots, and then
- * carve out memslot1 for the ucall MMIO address. KVM treats writes to
- * read-only memslots as MMIO, and creating a read-only memslot for the
- * MMIO region would prevent silently clobbering the MMIO region.
+ /* KVM treats writes to read-only memslots as MMIO, and creating
+ * a read-only memslot for the MMIO region would prevent silently
+ * clobbering the MMIO region.
*/
slot0 = memslot2region(vm, 0);
- ucall_init(vm, slot0->region.guest_phys_addr + slot0->region.memory_size);
+ mmio_gpa = slot0->region.guest_phys_addr + slot0->region.memory_size;
+ ucall_init(vm, mmio_gpa);
+
+ if (vm_check_cap(vm, KVM_CAP_READONLY_MEM))
+ vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
+ mmio_gpa, KVM_UCALL_MEMSLOT,
+ vm_adjust_num_guest_pages(vm->mode, 1),
+ KVM_MEM_READONLY);
if (kvm_random_seed != last_kvm_seed)
kvm_seed_rng(kvm_random_seed);
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 5/5] KVM: selftests: Test protection of the ucall MMIO region
2026-10-17 11:02 [PATCH 0/5] KVM: selftests: Reserve memslot 1 for ucall MMIO Tharit Tangkijwanichakul
` (3 preceding siblings ...)
2026-10-17 11:02 ` [PATCH 4/5] KVM: selftests: Reserve memslot 1 for the ucall MMIO address Tharit Tangkijwanichakul
@ 2026-10-17 11:02 ` Tharit Tangkijwanichakul
2026-10-17 11:16 ` sashiko-bot
2026-10-17 15:25 ` Tharit Tangkijwanichakul
4 siblings, 2 replies; 10+ messages in thread
From: Tharit Tangkijwanichakul @ 2026-10-17 11:02 UTC (permalink / raw)
To: Paolo Bonzini, Sean Christopherson
Cc: Shuah Khan, Marc Zyngier, Oliver Upton, Fuad Tabba, Joey Gouly,
Steffen Eiden, Suzuki K Poulose, Zenghui Yu, Anup Patel,
Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, kvm, linux-kernel, linux-kselftest,
linux-arm-kernel, kvmarm, kvm-riscv, linux-riscv,
linux-kernel-mentees, skhan, me, jkoolstra,
Tharit Tangkijwanichakul
Verify that creating a memslot overlapping the ucall MMIO region
fails with EEXIST and that ucalls work before and after the
attempt. Skip when MMIO ucalls or read-only memory are unsupported.
Signed-off-by: Tharit Tangkijwanichakul <tharitt97@gmail.com>
---
tools/testing/selftests/kvm/Makefile.kvm | 1 +
.../selftests/kvm/reserved_slot_test.c | 61 +++++++++++++++++++
2 files changed, 62 insertions(+)
create mode 100644 tools/testing/selftests/kvm/reserved_slot_test.c
diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
index 1f4bc2a1322d..ff4a5e9733e9 100644
--- a/tools/testing/selftests/kvm/Makefile.kvm
+++ b/tools/testing/selftests/kvm/Makefile.kvm
@@ -68,6 +68,7 @@ TEST_GEN_PROGS_COMMON += set_memory_region_test
TEST_GEN_PROGS_COMMON += memslot_modification_stress_test
TEST_GEN_PROGS_COMMON += memslot_perf_test
TEST_GEN_PROGS_COMMON += vm_types_test
+TEST_GEN_PROGS_COMMON += reserved_slot_test
# Compiled test targets
TEST_GEN_PROGS_x86 = $(TEST_GEN_PROGS_COMMON)
diff --git a/tools/testing/selftests/kvm/reserved_slot_test.c b/tools/testing/selftests/kvm/reserved_slot_test.c
new file mode 100644
index 000000000000..4a908017ca73
--- /dev/null
+++ b/tools/testing/selftests/kvm/reserved_slot_test.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "kvm_util.h"
+#include "processor.h"
+#include "test_util.h"
+
+#define CLOBBERED_SLOT TEST_MEM_SLOT_BASE
+
+static void guest_code(void)
+{
+ GUEST_SYNC(1);
+ GUEST_SYNC(2);
+}
+
+static void test_slot1_protected(void)
+{
+ struct kvm_vcpu *vcpu;
+ struct kvm_run *run;
+ struct kvm_vm *vm;
+ struct ucall uc;
+ u32 nr_pages;
+ size_t slot_size;
+ void *slot_mem;
+ int ret;
+
+ vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+ nr_pages = vm_adjust_num_guest_pages(vm->mode, 1);
+ slot_size = (size_t)nr_pages * vm->page_size;
+
+ run = vcpu->run;
+ vcpu_run(vcpu);
+ TEST_ASSERT(run->exit_reason == KVM_EXIT_MMIO,
+ "Unexpected exit reason = %u", run->exit_reason);
+ TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_SYNC && uc.args[1] == 1,
+ "Expected the first sync before clobbering the ucall GPA");
+
+ slot_mem = kvm_mmap(slot_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1);
+ ret = __vm_set_user_memory_region2(vm, CLOBBERED_SLOT, 0,
+ vm->ucall_mmio_addr, slot_size, slot_mem, 0, 0);
+ TEST_ASSERT(ret == -1 && errno == EEXIST,
+ "Expected the ucall GPA overlap to be rejected: ret=%d errno=%d",
+ ret, errno);
+
+ vcpu_run(vcpu);
+ TEST_ASSERT(run->exit_reason == KVM_EXIT_MMIO,
+ "Unexpected exit reason = %u", run->exit_reason);
+ TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_SYNC && uc.args[1] == 2,
+ "Expected the second sync after attempting to clobber the ucall GPA");
+
+ kvm_vm_free(vm);
+ TEST_ASSERT(!munmap(slot_mem, slot_size), "munmap() failed, errno=%d", errno);
+}
+
+int main(void)
+{
+ TEST_REQUIRE(UCALL_EXIT_REASON == KVM_EXIT_MMIO);
+ TEST_REQUIRE(kvm_has_cap(KVM_CAP_READONLY_MEM));
+
+ test_slot1_protected();
+ return 0;
+}
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 1/5] KVM: selftests: Introduce a shared base for test memslots
2026-10-17 11:02 ` [PATCH 1/5] KVM: selftests: Introduce a shared base for test memslots Tharit Tangkijwanichakul
@ 2026-10-17 11:14 ` sashiko-bot
0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-10-17 11:14 UTC (permalink / raw)
To: Tharit Tangkijwanichakul; +Cc: kvm, kvmarm, Oliver Upton, Marc Zyngier
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] KVM: selftests: missing TEST_MEM_SLOT_BASE conversion in arm64/vgic_v5.c
--
commit ad2bd092653828da36ea26266908671dbd05d3f3
Author: Tharit Tangkijwanichakul <tharitt97@gmail.com>
KVM: selftests: Introduce a shared base for test memslots
This commit introduces TEST_MEM_SLOT_BASE and replaces hardcoded memslot 1
assignments across KVM selftests to prepare for reserving slot 1 for library
use.
[ ... ]
> diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
> index 5a7a455b53875..759d604d44ce9 100644
> --- a/tools/testing/selftests/kvm/include/kvm_util.h
> +++ b/tools/testing/selftests/kvm/include/kvm_util.h
> @@ -30,6 +30,7 @@
>
> #define KVM_DEV_PATH "/dev/kvm"
> #define KVM_MAX_VCPUS 512
> +#define TEST_MEM_SLOT_BASE 1
>
> #define NSEC_PER_SEC 1000000000L
>
[Severity: Medium]
Should tools/testing/selftests/kvm/arm64/vgic_v5.c also be updated to use
TEST_MEM_SLOT_BASE?
Currently it defines VGIC_V5_LPI_MEMSLOT as 1:
tools/testing/selftests/kvm/arm64/vgic_v5.c:
#define VGIC_V5_LPI_MEMSLOT 1
and in vgic_v5_lpi_ist_vm_create(), it creates the VM with __vm_create() and
adds the LPI IST memslot at VGIC_V5_LPI_MEMSLOT:
v->vm = __vm_create(VM_SHAPE_DEFAULT, VGIC_V5_LPI_NR_VCPUS, 0);
...
vm_userspace_mem_region_add(v->vm, VM_MEM_SRC_ANONYMOUS,
VGIC_V5_LPI_IST_BASE_GPA,
VGIC_V5_LPI_MEMSLOT,
nr_lpi_ist_pages, 0);
Once the follow-up commit ("KVM: selftests: Reserve memslot 1 for the ucall
MMIO address") reserves slot 1 (KVM_UCALL_MEMSLOT) inside __vm_create() when
KVM_CAP_READONLY_MEM is supported (which is unconditionally enabled on
arm64), won't test_vgic_v5_lpis() and test_vgic_v5_ist_save_restore()
collide on slot 1 and fail in vm_mem_add() with TEST_FAIL() because the
memslot already exists in vm->regions.slot_hash?
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261017110213.46199-1-tharitt97@gmail.com?part=1
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 5/5] KVM: selftests: Test protection of the ucall MMIO region
2026-10-17 11:02 ` [PATCH 5/5] KVM: selftests: Test protection of the ucall MMIO region Tharit Tangkijwanichakul
@ 2026-10-17 11:16 ` sashiko-bot
2026-10-17 15:25 ` Tharit Tangkijwanichakul
1 sibling, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-10-17 11:16 UTC (permalink / raw)
To: Tharit Tangkijwanichakul; +Cc: kvm, kvmarm, Oliver Upton, Marc Zyngier
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [Medium] KVM: selftests: new standalone reserved_slot_test for single memslot check
- [Medium] KVM: selftests: reserved_slot_test omitted from TEST_GEN_PROGS_loongarch
- [Medium] KVM: selftests: reserved slot 1 in __vm_create() conflicts with vgic_v5
- [Low] KVM: selftests: open-coded kvm_munmap() and exit reason checks in test
--
commit 73bef34a870afd5da66eced7325a3e568ddcd08a
Author: Tharit Tangkijwanichakul <tharitt97@gmail.com>
KVM: selftests: Test protection of the ucall MMIO region
This commit adds a new selftest to verify that creating a memslot overlapping
the ucall MMIO region fails with EEXIST and that ucalls continue to work
before and after the attempt.
> diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
> index 1f4bc2a1322d8..ff4a5e9733e9f 100644
> --- a/tools/testing/selftests/kvm/Makefile.kvm
> +++ b/tools/testing/selftests/kvm/Makefile.kvm
> @@ -68,6 +68,7 @@ TEST_GEN_PROGS_COMMON += set_memory_region_test
> TEST_GEN_PROGS_COMMON += memslot_modification_stress_test
> TEST_GEN_PROGS_COMMON += memslot_perf_test
> TEST_GEN_PROGS_COMMON += vm_types_test
> +TEST_GEN_PROGS_COMMON += reserved_slot_test
>
> # Compiled test targets
> TEST_GEN_PROGS_x86 = $(TEST_GEN_PROGS_COMMON)
[Severity: Medium]
Should reserved_slot_test also be added to TEST_GEN_PROGS_loongarch?
In tools/testing/selftests/kvm/Makefile.kvm, TEST_GEN_PROGS_COMMON is
included by x86, arm64, s390, and riscv, whereas TEST_GEN_PROGS_loongarch
lists its targets explicitly without including $(TEST_GEN_PROGS_COMMON).
Because main() requires UCALL_EXIT_REASON == KVM_EXIT_MMIO, and across
tools/testing/selftests/kvm/include/*/ucall.h only arm64 and loongarch define
UCALL_EXIT_REASON as KVM_EXIT_MMIO, adding this target only to
TEST_GEN_PROGS_COMMON leaves it unbuilt on LoongArch while building it on
x86, s390, and riscv where it unconditionally skips.
> diff --git a/tools/testing/selftests/kvm/reserved_slot_test.c b/tools/testing/selftests/kvm/reserved_slot_test.c
> new file mode 100644
> index 0000000000000..4a908017ca73d
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/reserved_slot_test.c
> @@ -0,0 +1,61 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include "kvm_util.h"
> +#include "processor.h"
> +#include "test_util.h"
> +
> +#define CLOBBERED_SLOT TEST_MEM_SLOT_BASE
[Severity: Medium]
In the earlier commits of this series ("KVM: selftests: Introduce a shared
base for test memslots" and "KVM: selftests: Reserve memslot 1 for the ucall
MMIO address"), TEST_MEM_SLOT_BASE was bumped to 2 and __vm_create() in
tools/testing/selftests/kvm/lib/kvm_util.c was updated to reserve
KVM_UCALL_MEMSLOT (slot 1) when KVM_CAP_READONLY_MEM is supported:
if (vm_check_cap(vm, KVM_CAP_READONLY_MEM))
vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
mmio_gpa, KVM_UCALL_MEMSLOT,
vm_adjust_num_guest_pages(vm->mode, 1),
KVM_MEM_READONLY);
However, tools/testing/selftests/kvm/arm64/vgic_v5.c still defines
VGIC_V5_LPI_MEMSLOT as 1 instead of TEST_MEM_SLOT_BASE:
#define VGIC_V5_LPI_MEMSLOT 1
When vgic_v5_lpi_ist_vm_create() calls __vm_create() followed by
vm_userspace_mem_region_add() with VGIC_V5_LPI_MEMSLOT, won't vm_mem_add()
find slot 1 already present in vm->regions.slot_hash and abort with
TEST_FAIL() on arm64?
> +
> +static void guest_code(void)
> +{
> + GUEST_SYNC(1);
> + GUEST_SYNC(2);
> +}
> +
> +static void test_slot1_protected(void)
> +{
> + struct kvm_vcpu *vcpu;
> + struct kvm_run *run;
> + struct kvm_vm *vm;
> + struct ucall uc;
> + u32 nr_pages;
> + size_t slot_size;
> + void *slot_mem;
> + int ret;
> +
> + vm = vm_create_with_one_vcpu(&vcpu, guest_code);
> + nr_pages = vm_adjust_num_guest_pages(vm->mode, 1);
> + slot_size = (size_t)nr_pages * vm->page_size;
> +
> + run = vcpu->run;
> + vcpu_run(vcpu);
> + TEST_ASSERT(run->exit_reason == KVM_EXIT_MMIO,
> + "Unexpected exit reason = %u", run->exit_reason);
> + TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_SYNC && uc.args[1] == 1,
> + "Expected the first sync before clobbering the ucall GPA");
> +
> + slot_mem = kvm_mmap(slot_size, PROT_READ | PROT_WRITE,
> + MAP_PRIVATE | MAP_ANONYMOUS, -1);
> + ret = __vm_set_user_memory_region2(vm, CLOBBERED_SLOT, 0,
> + vm->ucall_mmio_addr, slot_size, slot_mem, 0, 0);
> + TEST_ASSERT(ret == -1 && errno == EEXIST,
> + "Expected the ucall GPA overlap to be rejected: ret=%d errno=%d",
> + ret, errno);
[Severity: Medium]
Could this check be added as a subtest in
tools/testing/selftests/kvm/set_memory_region_test.c instead of introducing a
separate reserved_slot_test binary?
set_memory_region_test.c already exercises KVM_SET_USER_MEMORY_REGION and
KVM_SET_USER_MEMORY_REGION2 error handling and overlapping memslot rejection,
whereas having a separate binary for this single check adds build and test
overhead for a target that immediately skips on most architectures in
TEST_GEN_PROGS_COMMON.
> +
> + vcpu_run(vcpu);
> + TEST_ASSERT(run->exit_reason == KVM_EXIT_MMIO,
> + "Unexpected exit reason = %u", run->exit_reason);
> + TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_SYNC && uc.args[1] == 2,
> + "Expected the second sync after attempting to clobber the ucall GPA");
> +
> + kvm_vm_free(vm);
> + TEST_ASSERT(!munmap(slot_mem, slot_size), "munmap() failed, errno=%d", errno);
> +}
[Severity: Low]
This isn't a bug, but could test_slot1_protected() use
TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_MMIO) from include/test_util.h for
the two exit reason checks, and kvm_munmap(slot_mem, slot_size) from
include/kvm_syscalls.h to pair with kvm_mmap()?
> +
> +int main(void)
> +{
> + TEST_REQUIRE(UCALL_EXIT_REASON == KVM_EXIT_MMIO);
> + TEST_REQUIRE(kvm_has_cap(KVM_CAP_READONLY_MEM));
> +
> + test_slot1_protected();
> + return 0;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261017110213.46199-1-tharitt97@gmail.com?part=5
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 4/5] KVM: selftests: Reserve memslot 1 for the ucall MMIO address
2026-10-17 11:02 ` [PATCH 4/5] KVM: selftests: Reserve memslot 1 for the ucall MMIO address Tharit Tangkijwanichakul
@ 2026-10-17 11:19 ` sashiko-bot
0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-10-17 11:19 UTC (permalink / raw)
To: Tharit Tangkijwanichakul; +Cc: kvm, kvmarm, Oliver Upton, Marc Zyngier
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] KVM: selftests: memslot 1 collision in vgic_v5_lpi_ist_vm_create()
--
commit 9df9f60479f8451e3b508d09149c3249f3de5c98
Author: Tharit Tangkijwanichakul <tharitt97@gmail.com>
KVM: selftests: Reserve memslot 1 for the ucall MMIO address
This commit reserves memslot 1 for a read-only ucall MMIO region in
__vm_create() when KVM_CAP_READONLY_MEM is supported, and bumps
TEST_MEM_SLOT_BASE from 1 to 2.
> diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
> index 9ddc047d5c275..f387100b1a19a 100644
> --- a/tools/testing/selftests/kvm/lib/kvm_util.c
> +++ b/tools/testing/selftests/kvm/lib/kvm_util.c
> @@ -20,6 +20,7 @@
> #include <linux/kernel.h>
>
> #define KVM_UTIL_MIN_PFN 2
> +#define KVM_UCALL_MEMSLOT 1
>
> u32 kvm_random_seed;
> struct kvm_random_state kvm_rng;
> @@ -492,6 +493,7 @@ struct kvm_vm *__vm_create(struct vm_shape shape, u32 nr_runnable_vcpus,
> struct userspace_mem_region *slot0;
> struct kvm_vm *vm;
> int i, flags;
> + gpa_t mmio_gpa;
>
> kvm_set_files_rlimit(nr_runnable_vcpus);
>
> @@ -514,14 +516,19 @@ struct kvm_vm *__vm_create(struct vm_shape shape, u32 nr_runnable_vcpus,
>
> kvm_vm_elf_load(vm, program_invocation_name);
>
> - /*
> - * TODO: Add proper defines to protect the library's memslots, and then
> - * carve out memslot1 for the ucall MMIO address. KVM treats writes to
> - * read-only memslots as MMIO, and creating a read-only memslot for the
> - * MMIO region would prevent silently clobbering the MMIO region.
> + /* KVM treats writes to read-only memslots as MMIO, and creating
> + * a read-only memslot for the MMIO region would prevent silently
> + * clobbering the MMIO region.
> */
> slot0 = memslot2region(vm, 0);
> - ucall_init(vm, slot0->region.guest_phys_addr + slot0->region.memory_size);
> + mmio_gpa = slot0->region.guest_phys_addr + slot0->region.memory_size;
> + ucall_init(vm, mmio_gpa);
> +
> + if (vm_check_cap(vm, KVM_CAP_READONLY_MEM))
> + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS,
> + mmio_gpa, KVM_UCALL_MEMSLOT,
> + vm_adjust_num_guest_pages(vm->mode, 1),
> + KVM_MEM_READONLY);
[Severity: Medium]
Does reserving KVM_UCALL_MEMSLOT (slot 1) in __vm_create() collide with
VGIC_V5_LPI_MEMSLOT in tools/testing/selftests/kvm/arm64/vgic_v5.c?
In tools/testing/selftests/kvm/arm64/vgic_v5.c, VGIC_V5_LPI_MEMSLOT is
hardcoded to 1 instead of using TEST_MEM_SLOT_BASE:
#define VGIC_V5_LPI_MEMSLOT 1
When test_vgic_v5_lpis() or test_vgic_v5_ist_save_restore() runs,
vgic_v5_lpi_ist_vm_create() creates the VM via __vm_create() (which
populates slot 1 because arm64 unconditionally supports
KVM_CAP_READONLY_MEM) and then attempts to add a memslot at
VGIC_V5_LPI_MEMSLOT:
v->vm = __vm_create(VM_SHAPE_DEFAULT, VGIC_V5_LPI_NR_VCPUS, 0);
...
vm_userspace_mem_region_add(v->vm, VM_MEM_SRC_ANONYMOUS,
VGIC_V5_LPI_IST_BASE_GPA,
VGIC_V5_LPI_MEMSLOT,
nr_lpi_ist_pages, 0);
Inside vm_userspace_mem_region_add() -> vm_mem_add(), the duplicate slot
check in vm->regions.slot_hash finds KVM_UCALL_MEMSLOT in slot 1 and
aborts the test with TEST_FAIL("A mem region with the requested slot
already exists...").
Should VGIC_V5_LPI_MEMSLOT be defined in terms of TEST_MEM_SLOT_BASE as
well?
>
> if (kvm_random_seed != last_kvm_seed)
> kvm_seed_rng(kvm_random_seed);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261017110213.46199-1-tharitt97@gmail.com?part=4
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 5/5] KVM: selftests: Test protection of the ucall MMIO region
2026-10-17 11:02 ` [PATCH 5/5] KVM: selftests: Test protection of the ucall MMIO region Tharit Tangkijwanichakul
2026-10-17 11:16 ` sashiko-bot
@ 2026-10-17 15:25 ` Tharit Tangkijwanichakul
1 sibling, 0 replies; 10+ messages in thread
From: Tharit Tangkijwanichakul @ 2026-10-17 15:25 UTC (permalink / raw)
To: Paolo Bonzini, Sean Christopherson
Cc: Shuah Khan, Marc Zyngier, Oliver Upton, Fuad Tabba, Joey Gouly,
Steffen Eiden, Suzuki K Poulose, Zenghui Yu, Anup Patel,
Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Ghiti, kvm, linux-kernel, linux-kselftest,
linux-arm-kernel, kvmarm, kvm-riscv, linux-riscv,
linux-kernel-mentees, skhan, me, jkoolstra
> +#define CLOBBERED_SLOT TEST_MEM_SLOT_BASE
Upon self-review, this should have been hardcoded to 1 (to clobber the
reserved ucal mmio).
> + ret = __vm_set_user_memory_region2(vm, CLOBBERED_SLOT, 0,
> + vm->ucall_mmio_addr, slot_size, slot_mem, 0, 0);
> + TEST_ASSERT(ret == -1 && errno == EEXIST,
> + "Expected the ucall GPA overlap to be rejected: ret=%d errno=%d",
> + ret, errno);
This should have been errno == EINVAL check to catch writing to the
exiting read-only slot.
The earlier test accidentally passed because it used a different slot
ID (=2, not reserved) and received EEXIST for overlapping the reserved
ucall GPA. It therefore tested GPA overlap rejection, not the intended
rejection of overwriting slot 1.
I will fix it in v2
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-10-17 15:25 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-17 11:02 [PATCH 0/5] KVM: selftests: Reserve memslot 1 for ucall MMIO Tharit Tangkijwanichakul
2026-10-17 11:02 ` [PATCH 1/5] KVM: selftests: Introduce a shared base for test memslots Tharit Tangkijwanichakul
2026-10-17 11:14 ` sashiko-bot
2026-10-17 11:02 ` [PATCH 2/5] KVM: selftests: Use the shared memslot base in memslot_perf_test Tharit Tangkijwanichakul
2026-10-17 11:02 ` [PATCH 3/5] KVM: selftests: Use the shared memslot base in memstress Tharit Tangkijwanichakul
2026-10-17 11:02 ` [PATCH 4/5] KVM: selftests: Reserve memslot 1 for the ucall MMIO address Tharit Tangkijwanichakul
2026-10-17 11:19 ` sashiko-bot
2026-10-17 11:02 ` [PATCH 5/5] KVM: selftests: Test protection of the ucall MMIO region Tharit Tangkijwanichakul
2026-10-17 11:16 ` sashiko-bot
2026-10-17 15:25 ` Tharit Tangkijwanichakul
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox