Re: [PATCH 2/2] KVM: LoongArch: selftests: Add in-kernel MMIO read fast path test
From: Huacai Chen
Date: Sat Jul 25 2026 - 05:42:29 EST
On Fri, Jul 24, 2026 at 9:28 AM Bibo Mao <maobibo@xxxxxxxxxxx> wrote:
>
>
>
> On 2026/7/23 下午7:16, Zeng Chi wrote:
> > From: Zeng Chi <zengchi@xxxxxxxxxx>
> >
> > Add a test that exercises the in-kernel MMIO read fast path of
> > kvm_emu_mmio_read(). The guest performs an MMIO read from an in-kernel
> > emulated PCH-PIC, immediately followed by a marker instruction, and the
> > test verifies that the marker instruction is executed, i.e. that the PC
> > advances by exactly one instruction instead of skipping the instruction
> > after the MMIO read.
> >
> > The test skips gracefully when the host KVM cannot create a PCH-PIC
> > device.
> >
> > Signed-off-by: Zeng Chi <zengchi@xxxxxxxxxx>
> > ---
> > tools/testing/selftests/kvm/Makefile.kvm | 3 +-
> > .../selftests/kvm/loongarch/mmio_read_test.c | 89 +++++++++++++++++++
> > 2 files changed, 91 insertions(+), 1 deletion(-)
> > create mode 100644 tools/testing/selftests/kvm/loongarch/mmio_read_test.c
> >
> > diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
> > index 6fc34e9bf8e1..4daf90caaabc 100644
> > --- a/tools/testing/selftests/kvm/Makefile.kvm
> > +++ b/tools/testing/selftests/kvm/Makefile.kvm
> > @@ -228,7 +228,8 @@ TEST_GEN_PROGS_riscv += mmu_stress_test
> > TEST_GEN_PROGS_riscv += rseq_test
> > TEST_GEN_PROGS_riscv += steal_time
> >
> > -TEST_GEN_PROGS_loongarch = loongarch/pmu_test
> > +TEST_GEN_PROGS_loongarch = loongarch/mmio_read_test
> > +TEST_GEN_PROGS_loongarch += loongarch/pmu_test
> > TEST_GEN_PROGS_loongarch += arch_timer
> > TEST_GEN_PROGS_loongarch += coalesced_io_test
> > TEST_GEN_PROGS_loongarch += demand_paging_test
> > diff --git a/tools/testing/selftests/kvm/loongarch/mmio_read_test.c b/tools/testing/selftests/kvm/loongarch/mmio_read_test.c
> > new file mode 100644
> > index 000000000000..7f64ca91ca8f
> > --- /dev/null
> > +++ b/tools/testing/selftests/kvm/loongarch/mmio_read_test.c
> > @@ -0,0 +1,89 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * LoongArch KVM in-kernel MMIO read fast path test
> > + *
> > + * When an MMIO read hits a device emulated inside KVM (such as the
> > + * PCH-PIC), kvm_emu_mmio_read() completes the access without returning
> > + * to user space and advances the guest PC by one instruction.
> > + *
> > + * This test issues such an in-kernel MMIO read immediately followed by
> > + * a marker instruction and checks that the marker instruction actually
> > + * runs, i.e. that the PC advanced by exactly one instruction (4 bytes)
> > + * rather than skipping the instruction after the MMIO read.
> > + */
> > +#include "kvm_util.h"
> > +#include "processor.h"
> > +#include "test_util.h"
> > +#include "loongarch/processor.h"
> > +
> > +/* Physical base the in-kernel PCH-PIC is mapped at (no memslot backs it) */
> > +#define PCH_PIC_BASE 0x10000000UL
> > +
> > +static void guest_code(void)
> > +{
> > + unsigned long marker = 0;
> > + unsigned int val = 0;
> > +
> > + /*
> > + * 'ld.w' faults out as an MMIO read and is emulated in kernel.
> > + * The following 'addi.d' must execute; it is skipped if the MMIO
> > + * read fast path advances the PC twice (by 8 instead of 4).
> > + */
> > + asm volatile(
> > + "ld.w %[val], %[base], 0\n\t"
> > + "addi.d %[marker], %[marker], 1\n\t"
> > + : [val] "=&r" (val), [marker] "+&r" (marker)
> > + : [base] "r" (PCH_PIC_BASE)
> > + : "memory");
> By my understanding, the kvm selftest is mainly to test function. It
> will be better if it is to verify irq handling with in-kernel PCH-PIC
> irqchip.
I think the fist patch is just enough. :)
Huacai
>
> Regards
> Bibo Mao
> > +
> > + GUEST_PRINTF("mmio read val=0x%x, marker=%lu\n", val, marker);
> > + GUEST_ASSERT_EQ(marker, 1);
> > + GUEST_DONE();
> > +}
> > +
> > +int main(int argc, char *argv[])
> > +{
> > + struct kvm_vcpu *vcpu;
> > + struct kvm_vm *vm;
> > + struct ucall uc;
> > + uint64_t addr = PCH_PIC_BASE;
> > + int dev_fd;
> > +
> > + vm = vm_create(VM_MODE_P47V47_16K);
> > + vcpu = vm_vcpu_add(vm, 0, guest_code);
> > +
> > + /* Create the in-kernel PCH-PIC and map it at PCH_PIC_BASE */
> > + dev_fd = __kvm_create_device(vm, KVM_DEV_TYPE_LOONGARCH_PCHPIC);
> > + if (dev_fd < 0) {
> > + print_skip("PCH-PIC device not supported by host KVM");
> > + kvm_vm_free(vm);
> > + return KSFT_SKIP;
> > + }
> > + kvm_device_attr_set(dev_fd, KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL,
> > + KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT, &addr);
> > + close(dev_fd);
> > +
> > + /* Identity-map the MMIO page so the guest can reach the device */
> > + virt_map(vm, PCH_PIC_BASE, PCH_PIC_BASE, 1);
> > +
> > + while (1) {
> > + vcpu_run(vcpu);
> > + switch (get_ucall(vcpu, &uc)) {
> > + case UCALL_PRINTF:
> > + pr_info("%s", uc.buffer);
> > + break;
> > + case UCALL_DONE:
> > + goto done;
> > + case UCALL_ABORT:
> > + REPORT_GUEST_ASSERT(uc);
> > + goto done;
> > + default:
> > + TEST_FAIL("Unexpected exit: %s",
> > + exit_reason_str(vcpu->run->exit_reason));
> > + }
> > + }
> > +
> > +done:
> > + kvm_vm_free(vm);
> > + return 0;
> > +}
> >
>