From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 20955352019; Mon, 22 Jun 2026 04:01:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782100902; cv=none; b=kVqGSp6rtLQz9jOvmj20FYQVXTpjT5wyMCIfHtaiq1iDW1JI3c7gVdACtQ8GEpEpA3By/N0fUM9Nr96tawi6HPgz0piga4sh4z2pYuwYubbJ1vlTJslOLyGEgAWDJKm7m4iCcdiVltMh6RHZbjHtLOON9oGZe8FsNer5vnNdRG0= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1782100902; c=relaxed/simple; bh=rIBUZlayDDUlElwH4STZyo3eLQ1aroKzxTDoI9morMI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ezA4+OGcnj5A/Kvo56+3LryQbwygxE2Wt+krXcxEf1Nos9RCU8z+HDK3Aax2EHpLOnD2l4D1Jr5XuIBVJQborRhw9HYlwoxsbnzcG17g5blgXwWqiW51ZASpdLOCKVrB9uPI2ZieParmS4pQHIy7qrLIqJ58SCvAGnNAwAq5VwM= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Ya7NX0ie; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Ya7NX0ie" Received: by smtp.kernel.org (Postfix) with ESMTPS id 0221AC2BD04; Mon, 22 Jun 2026 04:01:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1782100902; bh=rIBUZlayDDUlElwH4STZyo3eLQ1aroKzxTDoI9morMI=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=Ya7NX0iejpWjN4INkrPT4cunQJNOz+kfjITMaADVO98IMZP7uZdFS5otKCRXh3RIc 0c5W+lkRUD4ZKeUOam0jy9vpxKe4MKjSmQ3XOPYt/DTOCVq6VEpo1TQs08PD8VUioV 7xikwqRjowWfBoW5Zpq/3qYcxU96ti+HCKQW7THW95uibOybiMuQd9FV7B/4/FrY5Y 7CvCOi9DFptWR2sr0hIvTZyHFC1tHpyRkXp1QPQH07Elf/Bny2ODi4aCgUGjpKdehH 7xLqS1vqeDnuGvUuPnNHMfjzJXAchlOtzAtI5KpzHysc/Z5NYL8ByVNUrQTJqUDaUD dat8kjhduBM5Q== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id EE473CD98F6; Mon, 22 Jun 2026 04:01:41 +0000 (UTC) From: Charlie Jenkins via B4 Relay Date: Sun, 21 Jun 2026 21:01:28 -0700 Subject: [PATCH v2 10/16] KVM: riscv: selftests: Add mmio test Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260621-riscv_insn_table-v2-10-7f0810ee2274@gmail.com> References: <20260621-riscv_insn_table-v2-0-7f0810ee2274@gmail.com> In-Reply-To: <20260621-riscv_insn_table-v2-0-7f0810ee2274@gmail.com> To: Paul Walmsley , Palmer Dabbelt , Nam Cao , Alexandre Ghiti , Anup Patel , Atish Patra , Conor Dooley , Paolo Bonzini , Andrew Morton , Shuah Khan , =?utf-8?q?Radim_Kr=C4=8Dm=C3=A1=C5=99?= Cc: linux-riscv@lists.infradead.org, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, kvm-riscv@lists.infradead.org, linux-kselftest@vger.kernel.org, Charlie Jenkins X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1782100900; l=7221; i=thecharlesjenkins@gmail.com; s=20260605; h=from:subject:message-id; bh=nCg2zsUhW9tVCXwueee6U43Tp4lvMvAC4x/Uj6w1DKc=; b=FiX8G4yh2kmXn5pRN+SXywegB4kTjVIWJ6CUVfln9IvG8p5Z0j49ic/ko/Q6oCDElSlvSzUMQ yGr78gl5jtACmSIhKleRZqcsS7hOJnL88KBuW01ZcepJnD6n0cykO4M X-Developer-Key: i=thecharlesjenkins@gmail.com; a=ed25519; pk=ajnnRQ98PIdwKp4HeMkq9U32okYbnh6Zb4G3o5XXvkg= X-Endpoint-Received: by B4 Relay for thecharlesjenkins@gmail.com/20260605 with auth_id=810 X-Original-From: Charlie Jenkins Reply-To: thecharlesjenkins@gmail.com From: Charlie Jenkins Use the test KVM device to validate that reads and writes to a device are properly emulated by KVM. This test checks all load and store instructions that are emulated by KVM. Signed-off-by: Charlie Jenkins --- tools/testing/selftests/kvm/Makefile.kvm | 1 + tools/testing/selftests/kvm/riscv/mmio_test.c | 184 ++++++++++++++++++++++++++ 2 files changed, 185 insertions(+) diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm index 9118a5a51b89..07a5fc2bf67c 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -214,6 +214,7 @@ TEST_GEN_PROGS_s390 += mmu_stress_test TEST_GEN_PROGS_riscv = $(TEST_GEN_PROGS_COMMON) TEST_GEN_PROGS_riscv += riscv/sbi_pmu_test TEST_GEN_PROGS_riscv += riscv/ebreak_test +TEST_GEN_PROGS_riscv += riscv/mmio_test TEST_GEN_PROGS_riscv += access_tracking_perf_test TEST_GEN_PROGS_riscv += arch_timer TEST_GEN_PROGS_riscv += coalesced_io_test diff --git a/tools/testing/selftests/kvm/riscv/mmio_test.c b/tools/testing/selftests/kvm/riscv/mmio_test.c new file mode 100644 index 000000000000..9726860a269a --- /dev/null +++ b/tools/testing/selftests/kvm/riscv/mmio_test.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * mmio_test.c - Tests the mmio functionality. + */ +#include "kvm_util.h" +#include "ucall_common.h" + +#define MMIO_TEST_REGION 0x20000000 + +#define test_standard_read(len, instruction, name, options) \ +static void test_##name(void) \ +{ \ + unsigned long mmio_result, reference_result; \ + /* Configure the MMIO to return 0xff for each byte to check sign extension */ \ + unsigned long reference = ((unsigned long)-1 >> ((sizeof(long) - len) * 8)); \ + *((unsigned long *)MMIO_TEST_REGION) = reference; \ + /* Check that reads through MMIO are equivalent to standard reads. */ \ + asm volatile ( \ + ".option push\n" \ + options \ + #instruction " %[mmio_res], 0(%[region])\n" \ + #instruction " %[ref_res], 0(%[ref])\n" \ + ".option pop\n" \ + : [mmio_res] "=&cr" (mmio_result), [ref_res] "=&cr" (reference_result) \ + : [region] "cr" (MMIO_TEST_REGION), [ref] "cr" (&reference) \ + ); \ + GUEST_ASSERT_EQ(mmio_result, reference_result); \ + GUEST_DONE(); \ +} + +#define test_sp_read(len, instruction, name) \ +static void test_##name(void) \ +{ \ + unsigned long mmio_result, reference_result; \ + unsigned long tmp; \ + /* Configure the MMIO to return 0xff for each byte to check sign extension */ \ + unsigned long reference = ((unsigned long)-1 >> ((sizeof(long) - len) * 8)); \ + *(((unsigned long *)MMIO_TEST_REGION)) = reference; \ + /* Check that reads through MMIO are equivalent to standard reads. */ \ + asm volatile ( \ + "mv %[tmp], sp\n" \ + "mv sp, %[region]\n" \ + ".option push\n" \ + ".option arch,+c\n" \ + #instruction " %[mmio_res], 0(sp)\n" \ + "mv sp, %[ref]\n" \ + #instruction " %[ref_res], 0(sp)\n" \ + ".option pop\n" \ + "mv sp, %[tmp]\n" \ + : [mmio_res] "=&cr" (mmio_result), [ref_res] "=&cr" (reference_result), \ + [tmp] "=&r" (tmp) \ + : [region] "r" (MMIO_TEST_REGION), [ref] "cr" (&reference) \ + ); \ + GUEST_ASSERT_EQ(mmio_result, reference_result); \ + GUEST_DONE(); \ +} + +test_standard_read(1, lb, lb, "") +test_standard_read(1, lbu, lbu, "") +test_standard_read(4, lw, lw, "") +test_standard_read(4, c.lw, c_lw, ".option arch,+c\n") +test_sp_read(4, c.lwsp, c_lwsp) + +#if __riscv_xlen == 64 +test_standard_read(2, lh, lh, "") +test_standard_read(2, lhu, lhu, "") +test_standard_read(4, lwu, lwu, "") +test_standard_read(8, ld, ld, "") +test_standard_read(8, c.ld, c_ld, ".option arch,+c\n") +test_sp_read(8, c.ldsp, c_ldsp) +#endif + +#define test_standard_write(len, write, read, name, options) \ +static void test_##name(void) \ +{ \ + unsigned long result; \ + unsigned long reference = (0x55555555UL >> ((sizeof(long) - len) * 8)); \ + /* Check that we can write and then read the same value. */ \ + asm volatile ( \ + ".option push\n" \ + options \ + #write " %[ref], 0(%[region])\n" \ + #read " %[res], 0(%[region])\n" \ + ".option pop\n" \ + : [res] "=&cr" (result) \ + : [region] "cr" (MMIO_TEST_REGION), [ref] "cr" (reference) \ + ); \ + GUEST_ASSERT_EQ(result, reference); \ + GUEST_DONE(); \ +} + +#define test_sp_write(len, write, read, name) \ +static void test_##name(void) \ +{ \ + unsigned long result; \ + unsigned long tmp; \ + unsigned long reference = (0x55555555UL >> ((sizeof(long) - len) * 8)); \ + /* Check that we can write and then read the same value. */ \ + asm volatile ( \ + "mv %[tmp], sp\n" \ + "mv sp, %[region]\n" \ + ".option push\n" \ + ".option arch,+c\n" \ + #write " %[ref], 0(sp)\n" \ + #read " %[res], 0(sp)\n" \ + ".option pop\n" \ + "mv sp, %[tmp]\n" \ + : [res] "=&cr" (result), [tmp] "=&r" (tmp) \ + : [region] "cr" (MMIO_TEST_REGION), [ref] "cr" (reference) \ + ); \ + GUEST_ASSERT_EQ(result, reference); \ + GUEST_DONE(); \ +} + +test_standard_write(1, sb, lb, sb, "") +test_standard_write(2, sh, lh, sh, "") +test_standard_write(4, sw, lw, sw, "") +test_standard_write(4, c.sw, c.lw, c_sw, ".option arch,+c\n") +test_sp_write(4, c.swsp, c.lwsp, c_swsp) + +#if __riscv_xlen == 64 +test_standard_write(8, sd, ld, sd, "") +test_standard_write(8, c.sd, c.ld, c_sd, ".option arch,+c\n") +#endif + +static void run(void *guest_code, char *instruction) +{ + struct ucall uc; + struct kvm_vm *vm; + struct kvm_vcpu *vcpu; + + vm = vm_create_with_one_vcpu(&vcpu, guest_code); + kvm_create_device(vm, KVM_DEV_TYPE_TEST); + + virt_map(vm, (unsigned long)MMIO_TEST_REGION, MMIO_TEST_REGION, 1); + + vcpu_run(vcpu); + + TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_DONE, + "MMIO with instruction '%s' failed: '%s'", instruction, + uc.buffer); + + kvm_vm_free(vm); +} + +void test_mmio_read_sign_extension(void) +{ + run(test_lb, "lb"); + run(test_lbu, "lbu"); + run(test_lw, "lw"); + run(test_c_lw, "c.lw"); + run(test_c_lwsp, "c.lwsp"); + +#if __riscv_xlen == 64 + run(test_lh, "lh"); + run(test_lhu, "lhu"); + run(test_lwu, "lwu"); + run(test_ld, "ld"); + run(test_c_ld, "c.ld"); + run(test_c_ldsp, "c.ldsp"); +#endif +} + +void test_mmio_write(void) +{ + run(test_sb, "sb"); + run(test_sh, "sh"); + run(test_sw, "sw"); + run(test_c_sw, "c.sw"); + run(test_c_swsp, "c.swsp"); + +#if __riscv_xlen == 64 + run(test_sd, "sd"); + run(test_c_sd, "c.sd"); +#endif +} + +int main(void) +{ + test_mmio_read_sign_extension(); + test_mmio_write(); + + return 0; +} -- 2.54.0