From nobody Mon May 25 08:10:54 2026 Received: from mail-pf1-f170.google.com (mail-pf1-f170.google.com [209.85.210.170]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 73E563FF1AD for ; Fri, 15 May 2026 16:04:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778861082; cv=none; b=MBsDoaFuVg7zZEOjwkfVo0OkdmosZhbogb6zD80VXXv7kmZ45BCoZME42XeqGv2dfDV1jTnCMCqGyMAh2gYgsEwMJ3plHXs4XRnYAfxvNNl3zuEcx2w33NN3wx4/l6f6WH5CEjNYkVy48pbq2Mj7M9iluL3f01X3c7yd87O9yiU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778861082; c=relaxed/simple; bh=QGrJLUpisUTTqdsMw2pU1CxH7bvU3JfOjYaQtOBJWYI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=MlYM8yw5XUz9hNua3SQYMmgD2fjWnl76pacweugKqqJGuLeq4oSSQvRYli6Pwqjy8y0IvvwEYt8uGVFNmiI1aPtmlB0zzZhfWdZlv3A5E9SCp1yFbmyRalMoiyQlqA2Bcli+3n4gtalgKfB5k9XpelSu4eRO1aZytcYjEyTyvU4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=BeY4dypM; arc=none smtp.client-ip=209.85.210.170 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="BeY4dypM" Received: by mail-pf1-f170.google.com with SMTP id d2e1a72fcca58-82fbdd60b64so7029536b3a.3 for ; Fri, 15 May 2026 09:04:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778861081; x=1779465881; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=tHtM3hln5E0LtkuEKr9m/vG1aJYWfiEmMpXBjaFCM6o=; b=BeY4dypMd8T0Xp+MWXDl2u8spJrzHJFF0B0cb+YnsbnAkmsj6NahyqiGH46AIW7JAL cQlJNm1on6Db5E3gxBQGf5BaviIPdB2f9gMC5hBHCRtphq9gw7A8gZ8oYEnJPjGpscHU OZOvBBWLGbCTTC+pFPFndM7dj8MvrCuN7v9GNbdjtNqkfnEOzMOV7mP5IDVPWinzIXEa b1WL45A0vM8tcHy1gdbVV7nPhTUUaeDvaEWp9qd0pqoahxgAjEAdikur0h20ZB4BJGu/ cDkFbdxKV3hM3vl16neAptGTFrMyM4KwdOo0Wu7RpHLQ/PIvCvdUhIscfc3OPiJ3iHYW +5og== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778861081; x=1779465881; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=tHtM3hln5E0LtkuEKr9m/vG1aJYWfiEmMpXBjaFCM6o=; b=lH0CuxZs8D0mnNM0uLNvtCipRaTPAqyvwoNV702dIbLK/Pk8rhFefjlHlOegGzSVWn 5kJjCFZAmcdyLlbb37h2SQDgVBHYrz2V5doKt4q9svvHvzMa+zjimUWGcc2yG0x0U1Gg rEcpG+cxlX/+feJ3OZ4SOu78G1y2CzOo3wItJ36k8ffKoq0cEYUGWWvPs+OQYTOgba0b WtR9Z+xbM9grXgWXeA7JkXRTbbfnvm5NzJvcUt0wHrZWRvrrALN0ecPB5UvPu/zNmU+R N9lYC8BX8oD1B7t+5gegl4gZ+kF5GxRNkQ9vSE94fx/c3cgUeLYYqBIiGy/AaGTh98DP cADQ== X-Forwarded-Encrypted: i=1; AFNElJ/kystEu2SjhzcXNyf2jog7V2juaQi6FsApoVD/Z45PkbDiHnuEAAzGE7XY0OMSxDiH2ADln/+ZG0jSfAE=@vger.kernel.org X-Gm-Message-State: AOJu0YwohJrRIwIt9IkQJEqPxw9Q/jl1QnTHucV+Ch8Fs8DDHhLZRPSW M1tNzz1XFcqZwT66w7x51kOqQmSewrkhxzLr47oAzUFUuyrluPnVcaRj X-Gm-Gg: Acq92OGOW6NS3hEMq544C67EskKDsTNlsCPo4g1oTOsds4P2sMy+950NTh0rZBvOpfJ L8HfoazypM5zZMte5VkB6GtzVBo2IwJSzMLItu4yfG6Pg2aB2tadBPMpdyMLBZl7WVjY6cSll/S AspyN5N/PqwcQSHxpCFYuQ+fjuuG1o5QyKoIVhAPGquTywxuz73bomG21nlFnRswVfWR0xblr2d yW5BS3AKIpas2xiTaAkgofHDxCP6kFb5Ziw7bpawy9xMSOamzMRQkNwHQEy72sSjMFjdafxz0sp g4mTucI9ZfewgtbH2gpw11El9/0+0OxaF0MpheHobUMvaDvs6lyBwnVOo/GN8wPFTvOGUwL1q9C Yt/rXBcRBrgIQRHMvU0H7jgCR/cpU9RrajBWHR48mf9kB9MMqzaF/7kIpGEBKoq7LlQonQABCwh mFGBVl48fp+UWeg2egYQqYv8OigOdHK5QRUNHQL2bHdcky6dzNjnc60V0O9g5G2Zguuyp6l4nJX w== X-Received: by 2002:a05:6a00:391e:b0:82f:623f:e5b3 with SMTP id d2e1a72fcca58-83f33de9717mr5676947b3a.34.1778861080622; Fri, 15 May 2026 09:04:40 -0700 (PDT) Received: from localhost.localdomain ([171.76.86.174]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-83f19c7c74fsm7920262b3a.49.2026.05.15.09.04.36 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Fri, 15 May 2026 09:04:39 -0700 (PDT) From: "Ritesh Harjani (IBM)" To: kvm@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org, Madhavan Srinivasan , Harsh Prateek Bora , Christophe Leroy , Venkat Rao Bagalkote , Nicholas Piggin , linux-kernel@vger.kernel.org, "Ritesh Harjani (IBM)" Subject: [RFC 1/4] KVM: selftests: Move pgd_created check into virt_pgd_alloc Date: Fri, 15 May 2026 21:34:20 +0530 Message-ID: <6e6aea750fb80d4d28dbba97c45f498f2ec06a68.1778857539.git.ritesh.list@gmail.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Nicholas Piggin virt_arch_pgd_alloc all do the same test and set of pgd_created. Move this into common code. Signed-off-by: Nicholas Piggin [Rebased to latest mainline tree] Signed-off-by: Ritesh Harjani (IBM) --- tools/testing/selftests/kvm/include/kvm_util.h | 5 +++++ tools/testing/selftests/kvm/lib/arm64/processor.c | 4 ---- tools/testing/selftests/kvm/lib/loongarch/processor.c | 4 ---- tools/testing/selftests/kvm/lib/riscv/processor.c | 4 ---- tools/testing/selftests/kvm/lib/s390/processor.c | 4 ---- tools/testing/selftests/kvm/lib/x86/processor.c | 9 +++------ 6 files changed, 8 insertions(+), 22 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing= /selftests/kvm/include/kvm_util.h index 2ecaaa0e9965..3666a8530f31 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -1197,7 +1197,12 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm); =20 static inline void virt_pgd_alloc(struct kvm_vm *vm) { + if (vm->mmu.pgd_created) + return; + virt_arch_pgd_alloc(vm); + + vm->mmu.pgd_created =3D true; } =20 /* diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/test= ing/selftests/kvm/lib/arm64/processor.c index 01325bf4d36f..498fbcb0ea16 100644 --- a/tools/testing/selftests/kvm/lib/arm64/processor.c +++ b/tools/testing/selftests/kvm/lib/arm64/processor.c @@ -112,13 +112,9 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm) { size_t nr_pages =3D vm_page_align(vm, ptrs_per_pgd(vm) * 8) / vm->page_si= ze; =20 - if (vm->mmu.pgd_created) - return; - vm->mmu.pgd =3D vm_phy_pages_alloc(vm, nr_pages, KVM_GUEST_PAGE_TABLE_MIN_PADDR, vm->memslots[MEM_REGION_PT]); - vm->mmu.pgd_created =3D true; } =20 static void _virt_pg_map(struct kvm_vm *vm, gva_t gva, gpa_t gpa, diff --git a/tools/testing/selftests/kvm/lib/loongarch/processor.c b/tools/= testing/selftests/kvm/lib/loongarch/processor.c index 64d91fb76522..207055db5f5d 100644 --- a/tools/testing/selftests/kvm/lib/loongarch/processor.c +++ b/tools/testing/selftests/kvm/lib/loongarch/processor.c @@ -51,9 +51,6 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm) int i; gpa_t child, table; =20 - if (vm->mmu.pgd_created) - return; - child =3D table =3D 0; for (i =3D 0; i < vm->mmu.pgtable_levels; i++) { invalid_pgtable[i] =3D child; @@ -64,7 +61,6 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm) child =3D table; } vm->mmu.pgd =3D table; - vm->mmu.pgd_created =3D true; } =20 static int virt_pte_none(u64 *ptep, int level) diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/test= ing/selftests/kvm/lib/riscv/processor.c index ded5429f3448..75a5d4c46001 100644 --- a/tools/testing/selftests/kvm/lib/riscv/processor.c +++ b/tools/testing/selftests/kvm/lib/riscv/processor.c @@ -66,13 +66,9 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm) { size_t nr_pages =3D vm_page_align(vm, ptrs_per_pte(vm) * 8) / vm->page_si= ze; =20 - if (vm->mmu.pgd_created) - return; - vm->mmu.pgd =3D vm_phy_pages_alloc(vm, nr_pages, KVM_GUEST_PAGE_TABLE_MIN_PADDR, vm->memslots[MEM_REGION_PT]); - vm->mmu.pgd_created =3D true; } =20 void virt_arch_pg_map(struct kvm_vm *vm, gva_t gva, gpa_t gpa) diff --git a/tools/testing/selftests/kvm/lib/s390/processor.c b/tools/testi= ng/selftests/kvm/lib/s390/processor.c index a9adb3782b35..342b7c92463e 100644 --- a/tools/testing/selftests/kvm/lib/s390/processor.c +++ b/tools/testing/selftests/kvm/lib/s390/processor.c @@ -17,16 +17,12 @@ void virt_arch_pgd_alloc(struct kvm_vm *vm) TEST_ASSERT(vm->page_size =3D=3D PAGE_SIZE, "Unsupported page size: 0x%x", vm->page_size); =20 - if (vm->mmu.pgd_created) - return; - gpa =3D vm_phy_pages_alloc(vm, PAGES_PER_REGION, KVM_GUEST_PAGE_TABLE_MIN_PADDR, vm->memslots[MEM_REGION_PT]); memset(addr_gpa2hva(vm, gpa), 0xff, PAGES_PER_REGION * vm->page_size); =20 vm->mmu.pgd =3D gpa; - vm->mmu.pgd_created =3D true; } =20 /* diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testin= g/selftests/kvm/lib/x86/processor.c index b51467d70f6e..e420afdfbcfb 100644 --- a/tools/testing/selftests/kvm/lib/x86/processor.c +++ b/tools/testing/selftests/kvm/lib/x86/processor.c @@ -164,12 +164,9 @@ bool kvm_is_tdp_enabled(void) static void virt_mmu_init(struct kvm_vm *vm, struct kvm_mmu *mmu, struct pte_masks *pte_masks) { - /* If needed, create the top-level page table. */ - if (!mmu->pgd_created) { - mmu->pgd =3D vm_alloc_page_table(vm); - mmu->pgd_created =3D true; - mmu->arch.pte_masks =3D *pte_masks; - } + /* Create the top-level page table. */ + mmu->pgd =3D vm_alloc_page_table(vm); + mmu->arch.pte_masks =3D *pte_masks; =20 TEST_ASSERT(mmu->pgtable_levels =3D=3D 4 || mmu->pgtable_levels =3D=3D 5, "Selftests MMU only supports 4-level and 5-level paging, not %u-leve= l paging", --=20 2.39.5 From nobody Mon May 25 08:10:54 2026 Received: from mail-pf1-f181.google.com (mail-pf1-f181.google.com [209.85.210.181]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 63D433F9260 for ; Fri, 15 May 2026 16:04:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778861087; cv=none; b=nuvE1V7CoBmn74XSkKg/zZi2e+wchBelfv5tYor6WHrk9uCQjAT0XKGDzJv77zPqmibOlrWdCyC2eUfHuQU/Q2Ea9hcr8E7ZKqEaTF0kNSIOqfBFl6radHXUYT7xXCalz6uZMZ2JXx1hnyazzSkTOWLZxRE3kAKe2TjmvurUsco= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778861087; c=relaxed/simple; bh=tG/vwPXG+NgCJqpeTpzbd4mkkNiN98tDPGGb1Pn/dzg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Xsp7lJEIpD1b3qUPn/fCmNvYUJN7GxdiVUmTP0IPvQ4HWKbNB1kqSbgIZ236k8dvyTKpp/xYlmW5I7lY6kcW5YLGxZ+86TjB57P3gett1uvS51rsRPY2cQogr15dFpNR1Z7m//YaUkqATfJ5HpmBxA0a4jXZdglHKSl/pRLGxm4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=P1CoDm84; arc=none smtp.client-ip=209.85.210.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="P1CoDm84" Received: by mail-pf1-f181.google.com with SMTP id d2e1a72fcca58-837b39eb078so6421859b3a.2 for ; Fri, 15 May 2026 09:04:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778861086; x=1779465886; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=dYv7n7MNQFWGtdjlWPVxo0rnA4k4aMTlnbBv8oYiho8=; b=P1CoDm841RdLfhufFvZbcH5Z5jYygOD1GqrQNBCa5nC1iV13pRnCLUvq3TQ4kKSyvb H2YSnLdPNfAp0JzM8rCnv8Xq3mIVGXKntx47mUWR67PL7ncAaf9XXOxr+xLRjNn+9FSt FAik1aD+t6eIHo9/Aex8E9Z6B4mYzRD5SjCFxcjWN+9K8lgRoiBv8m5n99ylxQFa7xTU ZJQwKJsJmpw6JYR2/BIFb06LGYbQLtoZBL4CSUW9rVMUCIFKMfdYLqxx4ZhBDLJnifQC e/o9hPB2nKda9pIoLdgmMh60ImLCVVHJyK5gX0ztJCX7Lpnqb/X5CWL0WlnOdBYVyxfb mozw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778861086; x=1779465886; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=dYv7n7MNQFWGtdjlWPVxo0rnA4k4aMTlnbBv8oYiho8=; b=PEcRs3nHpAYlOG/2jk4AIG5BvPgQePVkT0Ljg4b80L45WGjAfuRoNZ5Ne+JMcJni9u u9zsKLZReKD3lXufWkpCHKqUsbnjV+XGwoeJ2alz5QASPz0SEQyXDyvjxUo5IZDYUdVR sYH4UKVUCnibvM4+rnYdPerkLPkQwUFSpPR731b8t2KbcsPjMjxgR3FwM2rcipw/hDam OHtopPAGmjljWhtusuJSyqnAFFETuwtI1+s76dYlfh31Hs2579DWz393acxZkz8Wlor8 Xxl0yBVdZlq/hey6I9tsy3qGR67rM4rvOdHQMJ1LJZltOyEqwxYMVBakOpMCXbXvXG1n Yshg== X-Forwarded-Encrypted: i=1; AFNElJ/0K2sye/iwE03TO+9mvXZYRNNXiojH82ATIGyi1GM5LrUQ0JVqh4ZPpmaPEY27fPx69VfEqvoODpj97hg=@vger.kernel.org X-Gm-Message-State: AOJu0YwlYDBtM8iX0QoXhqQlKUQc8WWeIQGGmZ+p3OUTiVSuceLD/sgq GjLef8xmP7YZRPGucVcPUhCdAbWV2JbAq+EBjqWYHfEArX2ikceDieyJ X-Gm-Gg: Acq92OHPSlrS+XluhdIsD8NhYlm4KcZX76ul1mGVsce+yXoNU3x9g3cj5x1v3H9Cs1k AMSVziW/pUXBfm24VF73ir0E2OYf1f2ds2YspXfcf49YQHl4UwHix8O1n/WqmkBtn9LlHhd4H2E W0/WUvN/nDF1HAONqsL8nLwWF+X9j/KAujCtCTxPiw1e++SRAf0ljMK/kC14TltiHouUQmQBsWS PIEU9RTTmobyYE3s0l/K4wajTJjsoNwbMAVfBDpQAFK4jjpymBnt3igfPfJv+IgmdQiSvw2o/pH j9jvoI9bLBiK7Wf02hcNnxjaODn3x/La53aEEVIURZUvI2lx4xlTfbqOdR6X33Z2dkWR0EDOh1c j7mddzOMJdfFSlVSsDG0B9w4N6/nsCrH1q7Ls54T/ooCuy0/6lfQIzmWU6tWdgqWsr/gphlSnZr dLPHp2DmKyddfKlYcjSnXmpSkRxOXT5p9kV1SYZL6suQ8X8WygsTZD X-Received: by 2002:a05:6a00:1902:b0:834:ea1a:4b25 with SMTP id d2e1a72fcca58-83f33b2e0c9mr5587593b3a.12.1778861085597; Fri, 15 May 2026 09:04:45 -0700 (PDT) Received: from localhost.localdomain ([171.76.86.174]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-83f19c7c74fsm7920262b3a.49.2026.05.15.09.04.40 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Fri, 15 May 2026 09:04:43 -0700 (PDT) From: "Ritesh Harjani (IBM)" To: kvm@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org, Madhavan Srinivasan , Harsh Prateek Bora , Christophe Leroy , Venkat Rao Bagalkote , Nicholas Piggin , linux-kernel@vger.kernel.org, "Ritesh Harjani (IBM)" Subject: [RFC 2/4] KVM: selftests: Add aligned guest physical page allocator Date: Fri, 15 May 2026 21:34:21 +0530 Message-ID: X-Mailer: git-send-email 2.50.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Nicholas Piggin powerpc will require this to allocate MMU tables in guest memory that are larger than guest base page size. Signed-off-by: Nicholas Piggin [Rebased to latest mainline tree] Signed-off-by: Ritesh Harjani (IBM) --- .../testing/selftests/kvm/include/kvm_util.h | 20 +++++++++-- tools/testing/selftests/kvm/lib/kvm_util.c | 33 +++++++++---------- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing= /selftests/kvm/include/kvm_util.h index 3666a8530f31..c515c918c2c9 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -991,8 +991,8 @@ void kvm_gsi_routing_write(struct kvm_vm *vm, struct kv= m_irq_routing *routing); const char *exit_reason_str(unsigned int exit_reason); =20 gpa_t vm_phy_page_alloc(struct kvm_vm *vm, gpa_t min_gpa, u32 memslot); -gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, gpa_t min_gpa, - u32 memslot, bool protected); +gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, size_t align, + gpa_t min_gpa, u32 memslot, bool protected); gpa_t vm_alloc_page_table(struct kvm_vm *vm); =20 static inline gpa_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, @@ -1003,10 +1003,24 @@ static inline gpa_t vm_phy_pages_alloc(struct kvm_v= m *vm, size_t num, * protected memory, as the majority of memory for such VMs is * protected, i.e. using shared memory is effectively opt-in. */ - return __vm_phy_pages_alloc(vm, num, min_gpa, memslot, + return __vm_phy_pages_alloc(vm, num, 1, min_gpa, memslot, vm_arch_has_protected_memory(vm)); } =20 +static inline gpa_t vm_phy_pages_alloc_align(struct kvm_vm *vm, size_t num, + size_t align, gpa_t min_gpa, + u32 memslot) +{ + /* + * By default, allocate memory as protected for VMs that support + * protected memory, as the majority of memory for such VMs is + * protected, i.e. using shared memory is effectively opt-in. + */ + return __vm_phy_pages_alloc(vm, num, align, min_gpa, memslot, + vm_arch_has_protected_memory(vm)); +} + + /* * ____vm_create() does KVM_CREATE_VM and little else. __vm_create() also * loads the test binary into guest memory and creates an IRQ chip (x86 on= ly). diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/sel= ftests/kvm/lib/kvm_util.c index 2a76eca7029d..cdb004c9ba56 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1442,7 +1442,7 @@ static gva_t ____vm_alloc(struct kvm_vm *vm, size_t s= z, gva_t min_gva, u64 pages =3D (sz >> vm->page_shift) + ((sz % vm->page_size) !=3D 0); =20 virt_pgd_alloc(vm); - gpa_t gpa =3D __vm_phy_pages_alloc(vm, pages, + gpa_t gpa =3D __vm_phy_pages_alloc(vm, pages, 1, KVM_UTIL_MIN_PFN * vm->page_size, vm->memslots[type], protected); =20 @@ -2021,7 +2021,7 @@ const char *exit_reason_str(unsigned int exit_reason) * and their base address is returned. A TEST_ASSERT failure occurs if * not enough pages are available at or above min_gpa. */ -gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, +gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, size_t align, gpa_t min_gpa, u32 memslot, bool protected) { @@ -2039,23 +2039,22 @@ gpa_t __vm_phy_pages_alloc(struct kvm_vm *vm, size_= t num, TEST_ASSERT(!protected || region->protected_phy_pages, "Region doesn't support protected memory"); =20 - base =3D pg =3D min_gpa >> vm->page_shift; - do { - for (; pg < base + num; ++pg) { - if (!sparsebit_is_set(region->unused_phy_pages, pg)) { - base =3D pg =3D sparsebit_next_set(region->unused_phy_pages, pg); - break; + base =3D min_gpa >> vm->page_shift; +again: + base =3D (base + align - 1) & ~(align - 1); + for (pg =3D base; pg < base + num; ++pg) { + if (!sparsebit_is_set(region->unused_phy_pages, pg)) { + base =3D sparsebit_next_set(region->unused_phy_pages, pg); + if (!base) { + fprintf(stderr, "No guest physical page available, " + "min_gpa: 0x%lx page_size: 0x%x memslot: %u\n", + min_gpa, vm->page_size, memslot); + fputs("---- vm dump ----\n", stderr); + vm_dump(stderr, vm, 2); + abort(); } + goto again; } - } while (pg && pg !=3D base + num); - - if (pg =3D=3D 0) { - fprintf(stderr, "No guest physical page available, " - "min_gpa: 0x%lx page_size: 0x%x memslot: %u\n", - min_gpa, vm->page_size, memslot); - fputs("---- vm dump ----\n", stderr); - vm_dump(stderr, vm, 2); - abort(); } =20 for (pg =3D base; pg < base + num; ++pg) { --=20 2.39.5 From nobody Mon May 25 08:10:54 2026 Received: from mail-pf1-f179.google.com (mail-pf1-f179.google.com [209.85.210.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3F6043FBB41 for ; Fri, 15 May 2026 16:04:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.179 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778861093; cv=none; b=FYP6cCv5kNWo26xcjhnK/PewuQXtarnBz9qUIdzUCNriR/R4MS4klIq1Wmm56ky9LGMjE/z4oE9fed4FMJA5DKRj7HgxUxG9aOo5NO6skK7EH3gPJ+6LfAF0HTx9p/VumcJGUGo5EcTvkNmjeTmXLkb+s4M6txkCqDvzHX/tdqE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778861093; c=relaxed/simple; bh=/61JLfOfez1v08pldDmyGCGZgO3FEgH6LleMQz/rkR4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Wf19jJTulKyIO3SYuoKYS4YCuwbXYeJE20jVZNR8CSWO1I/Z+uBJi3Ajx0xhV3qvQbU84LrZcM15KiobfQvfFj9JqUwqLc0deXz6G7zEwR4N1fFIIjt2KR8FVIo75yv6u3hpsYNaSd+5QHoHuX8yDM+YYFiV5FnntOA2GiKgfbs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=IeKfU+N7; arc=none smtp.client-ip=209.85.210.179 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="IeKfU+N7" Received: by mail-pf1-f179.google.com with SMTP id d2e1a72fcca58-82f8b60e54dso7646808b3a.2 for ; Fri, 15 May 2026 09:04:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778861090; x=1779465890; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=8KPbKQ0XXO4UpDmWtvuBXzFoonMrUVhhxnM6fBWiCZE=; b=IeKfU+N712uAYMI/rnbOllnDlXBOybdSlJQDJ/WEZCqCgBJbB87mtCOeOHHjqxi9F4 4207yxwj8hWh+epquz91UueZqxB+gqVibsEnia/srnN2t7TT4z9BlolunO/v3DyNc1HA Hv4BzsHkXPCMFpBN65pp8VuXRFGqFX6JZNmB9xK9h3HcbFowSwHVPJhkNk7NDcF8JRoB nmEg8Y2ytonI+jLvbcSDop0OuMVPIU5Vp3yAlhlrdA2Ails2N5FRknBf9MveTlqHftN2 vQgELCcPE3LeUMJLUeWKcaRkYVAp3NgUoAhh3lFh0mmlRdXWEa92aG3aKcX2abb2aBfw slSg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778861090; x=1779465890; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=8KPbKQ0XXO4UpDmWtvuBXzFoonMrUVhhxnM6fBWiCZE=; b=drTOm15/J5zhVtRcSj6iXdVVfkt9aSeWct7fJf+pRTSbwSSJkTDDE3bs8pi0j5ck3T YXX9z0KirDOLylo7/l8oqSf2KJ9yWrmP/wUMCqayIPktVown01cL63vY7vhEixuBRwPd hKqKOr1jNMoWvrrNGQccgNleJDnGx2aqc7Nvp5tZT3OozbfYe27i/JCrCxCBaNP29oIM 7ZXIZsKS+YWMGgozbqk8XQ8ZRqUZUHcaDlblJZ9JUlUP9JB+toiYuCKZxKv0QeO316HH J4JcC/HaYxsMp4fZ/QW4Ai8fZ4DkynkTrRRfLvF6V5E7a4nzFC9tnzmY/geKCYB14URv BK9Q== X-Forwarded-Encrypted: i=1; AFNElJ8Tu8Mcc+yCZrgNz6CgtN0panww/WCKtda0psyLRhACeYwexcX0c5peLEypfaLmRS1iKHDaGwR5mtiLGqs=@vger.kernel.org X-Gm-Message-State: AOJu0Yz+qpEE5qEg8yfl6TaCNUsHk0erLnwkNvG8MNQ49mDeclZca4bs I0JLP+KansPMZMiTd8QQpO2E2KMklW4psBjz2LgizB2Vi/e0Y9s0ECOE X-Gm-Gg: Acq92OG9WF8CbeVeZ27Vy/QWLLVQagAwtQG7ROnAnohXsG9WhiAfhkvWUon4jBIN+Qq fQXWQh95XYfbT0HpJrH0SRZbmjzLZ0bsOGN2F2l7AfV5eDsxOwIbksuOcOKseegdn4U+EXohGH8 EpnYMkmrCmeJhrMUVnuodfIfHNpKJkCThQpi9uwxYr4INMyyKOEZ91SnfO9UE/wKKW8MYzUQPZN 196TrrKWt5k8cRJqnBS0AltxVFrx9Nd95ppofglvWSBRAo5l70pHg1OJ9LRtS9caQ3nqgkT43rg BRbNkkjTfvVbSZomIVj0JVezrNca5obSh9pCnxJEA88n5gJvmN4mX+uZViMMJWLnIwNezDQWPnk zNW4vMKmSiaXNUUZg8bKAMpCn3ifogmZusW/Ox/x6y1yaLTCHEMrOqIuCPliKuNL8INi8E0BAF2 zo0tjCYD8RI1sbPiDDbktMkJU+O5eGlpeRNx0yrTtpuy6vFuDuCnjecMHipVe4iZo= X-Received: by 2002:a05:6a00:2e08:b0:82a:17b6:53ca with SMTP id d2e1a72fcca58-83f33decf92mr5275586b3a.38.1778861090229; Fri, 15 May 2026 09:04:50 -0700 (PDT) Received: from localhost.localdomain ([171.76.86.174]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-83f19c7c74fsm7920262b3a.49.2026.05.15.09.04.45 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Fri, 15 May 2026 09:04:49 -0700 (PDT) From: "Ritesh Harjani (IBM)" To: kvm@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org, Madhavan Srinivasan , Harsh Prateek Bora , Christophe Leroy , Venkat Rao Bagalkote , Nicholas Piggin , linux-kernel@vger.kernel.org, "Ritesh Harjani (IBM)" Subject: [RFC 3/4] KVM: PPC: selftests: add support for powerpc Date: Fri, 15 May 2026 21:34:22 +0530 Message-ID: <77f14ffafce407dc042e78a6a02cfaa8710a645a.1778857539.git.ritesh.list@gmail.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Nicholas Piggin 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. Signed-off-by: Nicholas Piggin [Rebased to latest mainline tree] Signed-off-by: Ritesh Harjani (IBM) --- 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 | 38 ++ .../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 | 481 ++++++++++++++++++ .../testing/selftests/kvm/lib/powerpc/ucall.c | 22 + 15 files changed, 819 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_ar= ch.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 6aa3fe2ee1bb..9d0a0cb32811 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14115,6 +14115,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/ =20 KERNEL VIRTUAL MACHINE FOR RISC-V (KVM/riscv) M: Anup Patel 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 =3D ../../../.. include $(top_srcdir)/scripts/subarch.include ARCH ?=3D $(SUBARCH) =20 -ifeq ($(ARCH),$(filter $(ARCH),arm64 s390 riscv x86 x86_64 loongarch)) +ifeq ($(ARCH),$(filter $(ARCH),arm64 s390 riscv x86 x86_64 loongarch power= pc)) # Top-level selftests allows ARCH=3Dx86_64 :-( ifeq ($(ARCH),x86_64) override ARCH :=3D x86 diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selft= ests/kvm/Makefile.kvm index 9118a5a51b89..825bea7f851d 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -52,6 +52,11 @@ LIBKVM_loongarch +=3D lib/loongarch/processor.c LIBKVM_loongarch +=3D lib/loongarch/ucall.c LIBKVM_loongarch +=3D lib/loongarch/exception.S =20 +LIBKVM_powerpc +=3D lib/powerpc/handlers.S +LIBKVM_powerpc +=3D lib/powerpc/processor.c +LIBKVM_powerpc +=3D lib/powerpc/ucall.c +LIBKVM_powerpc +=3D lib/powerpc/hcall.c + # Non-compiled test targets TEST_PROGS_x86 +=3D x86/nx_huge_pages_test.sh =20 @@ -239,6 +244,11 @@ TEST_GEN_PROGS_loongarch +=3D memslot_perf_test TEST_GEN_PROGS_loongarch +=3D set_memory_region_test TEST_GEN_PROGS_loongarch +=3D steal_time =20 +TEST_GEN_PROGS_powerpc =3D $(TEST_GEN_PROGS_COMMON) +TEST_GEN_PROGS_powerpc +=3D access_tracking_perf_test +TEST_GEN_PROGS_powerpc +=3D dirty_log_perf_test +TEST_GEN_PROGS_powerpc +=3D hardware_disable_test + SPLIT_TESTS +=3D arch_timer SPLIT_TESTS +=3D get-reg-list =20 diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing= /selftests/kvm/include/kvm_util.h index c515c918c2c9..10f03a182c8b 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -209,6 +209,9 @@ enum vm_guest_mode { VM_MODE_P41V48_4K, VM_MODE_P41V39_4K, =20 + VM_MODE_P52V52_4K, /* For powerpc64 */ + VM_MODE_P52V52_64K, + NUM_VM_MODES, }; =20 @@ -268,6 +271,12 @@ extern enum vm_guest_mode vm_mode_default; #define MIN_PAGE_SHIFT 12U #define ptes_per_page(page_size) ((page_size) / 8) =20 +#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 =20 #define VM_SHAPE_DEFAULT VM_SHAPE(VM_MODE_DEFAULT) diff --git a/tools/testing/selftests/kvm/include/powerpc/hcall.h b/tools/te= sting/selftests/kvm/include/powerpc/hcall.h new file mode 100644 index 000000000000..4028baa6c5d8 --- /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 + +/* Ucalls use unimplemented PAPR hcall 0 which exits KVM */ +#define H_UCALL 0 + +int64_t hcall0(uint64_t token); +int64_t hcall1(uint64_t token, uint64_t arg1); +int64_t hcall2(uint64_t token, uint64_t arg1, uint64_t 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 + +#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/tool= s/testing/selftests/kvm/include/powerpc/processor.h new file mode 100644 index 000000000000..cb75b77c33bb --- /dev/null +++ b/tools/testing/selftests/kvm/include/powerpc/processor.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * powerpc processor specific defines + */ +#ifndef SELFTEST_KVM_PROCESSOR_H +#define SELFTEST_KVM_PROCESSOR_H + +#include +#include "ppc_asm.h" + +extern unsigned char __interrupts_start[]; +extern unsigned char __interrupts_end[]; + +struct kvm_vm; +struct kvm_vcpu; + +struct ex_regs { + uint64_t gprs[32]; + uint64_t nia; + uint64_t msr; + uint64_t cfar; + uint64_t lr; + uint64_t ctr; + uint64_t xer; + uint32_t cr; + uint32_t trap; + uint64_t vaddr; /* vaddr 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/te= sting/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" =20 -#if defined(__aarch64__) || defined(__riscv) +#if defined(__aarch64__) || defined(__riscv) || defined(__powerpc64__) #include "processor.h" enum vm_guest_mode vm_mode_default; #endif =20 +#if defined(__powerpc64__) +#include +#endif + struct guest_mode guest_modes[NUM_VM_MODES]; =20 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 =20 @@ -108,6 +112,18 @@ void guest_modes_append_default(void) TEST_ASSERT(vm_mode_default !=3D 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) =3D=3D 4096) + vm_mode_default =3D VM_MODE_P52V52_4K; + else + vm_mode_default =3D VM_MODE_P52V52_64K; + guest_mode_append(VM_MODE_P52V52_4K, true); + guest_mode_append(VM_MODE_P52V52_64K, true); + } +#endif } =20 void for_each_guest_mode(void (*func)(enum vm_guest_mode, void *), void *a= rg) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/sel= ftests/kvm/lib/kvm_util.c index cdb004c9ba56..0dc67c1502cf 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -218,6 +218,8 @@ const char *vm_guest_mode_string(u32 i) [VM_MODE_P41V57_4K] =3D "PA-bits:41, VA-bits:57, 4K pages", [VM_MODE_P41V48_4K] =3D "PA-bits:41, VA-bits:48, 4K pages", [VM_MODE_P41V39_4K] =3D "PA-bits:41, VA-bits:39, 4K pages", + [VM_MODE_P52V52_4K] =3D "PA-bits:52, VA-bits:52, 4K pages", + [VM_MODE_P52V52_64K] =3D "PA-bits:52, VA-bits:52, 64K pages", }; _Static_assert(sizeof(strings)/sizeof(char *) =3D=3D NUM_VM_MODES, "Missing new mode strings?"); @@ -254,6 +256,8 @@ const struct vm_guest_mode_params vm_guest_mode_params[= ] =3D { [VM_MODE_P41V57_4K] =3D { 41, 57, 0x1000, 12 }, [VM_MODE_P41V48_4K] =3D { 41, 48, 0x1000, 12 }, [VM_MODE_P41V39_4K] =3D { 41, 39, 0x1000, 12 }, + [VM_MODE_P52V52_4K] =3D { 52, 52, 0x1000, 12 }, + [VM_MODE_P52V52_64K] =3D { 52, 52, 0x10000, 16 }, }; _Static_assert(sizeof(vm_guest_mode_params)/sizeof(struct vm_guest_mode_pa= rams) =3D=3D NUM_VM_MODES, "Missing new mode params?"); @@ -371,6 +375,10 @@ struct kvm_vm *____vm_create(struct vm_shape shape) case VM_MODE_P41V39_4K: vm->mmu.pgtable_levels =3D 3; break; + case VM_MODE_P52V52_4K: + case VM_MODE_P52V52_64K: + vm->mmu.pgtable_levels =3D 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/tes= ting/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 + +.macro INTERRUPT vec +. =3D __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=3D4 + ld %r0,(0*8)(%r31) + ld %r3,(3*8)(%r31) +.rept 28 + ld reg,(reg*8)(%r31) + reg=3Dreg+1 +.endr + addi %r1,%r1,INT_FRAME_SIZE + rfid + +virt_handle_interrupt_p: + .llong virt_handle_interrupt + +handle_interrupt: +reg=3D4 +.rept 28 + std reg,(reg*8)(%r13) + reg=3Dreg+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/testin= g/selftests/kvm/lib/powerpc/hcall.c new file mode 100644 index 000000000000..23a56aabad42 --- /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" + +int64_t hcall0(uint64_t token) +{ + register uintptr_t r3 asm ("r3") =3D token; + + asm volatile("sc 1" : "+r"(r3) : + : "r0", "r4", "r5", "r6", "r7", "r8", "r9", + "r10","r11", "r12", "ctr", "xer", + "memory"); + + return r3; +} + +int64_t hcall1(uint64_t token, uint64_t arg1) +{ + register uintptr_t r3 asm ("r3") =3D token; + register uintptr_t r4 asm ("r4") =3D arg1; + + asm volatile("sc 1" : "+r"(r3), "+r"(r4) : + : "r0", "r5", "r6", "r7", "r8", "r9", + "r10","r11", "r12", "ctr", "xer", + "memory"); + + return r3; +} + +int64_t hcall2(uint64_t token, uint64_t arg1, uint64_t arg2) +{ + register uintptr_t r3 asm ("r3") =3D token; + register uintptr_t r4 asm ("r4") =3D arg1; + register uintptr_t r5 asm ("r5") =3D arg2; + + asm volatile("sc 1" : "+r"(r3), "+r"(r4), "+r"(r5) : + : "r0", "r6", "r7", "r8", "r9", + "r10","r11", "r12", "ctr", "xer", + "memory"); + + return r3; +} diff --git a/tools/testing/selftests/kvm/lib/powerpc/processor.c b/tools/te= sting/selftests/kvm/lib/powerpc/processor.c new file mode 100644 index 000000000000..a345844cf941 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/powerpc/processor.c @@ -0,0 +1,481 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * KVM selftest powerpc library code - CPU-related functions (page tables.= ..) + */ + +#include + +#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 + +static void set_proc_table(struct kvm_vm *vm, int pid, uint64_t dw0, uint6= 4_t dw1) +{ + uint64_t *proc_table; + + proc_table =3D addr_gpa2hva(vm, vm->arch.prtb); + proc_table[pid * 2 + 0] =3D cpu_to_be64(dw0); + proc_table[pid * 2 + 1] =3D 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 =3D=3D VM_MODE_P52V52_4K) || + (vm->mode =3D=3D VM_MODE_P52V52_64K), + "Unsupported guest mode, mode: 0x%x", vm->mode); + + prtb =3D vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR, + vm->memslots[MEM_REGION_PT]); + vm->arch.prtb =3D prtb; + + pgd_pages =3D (1UL << (RADIX_PGD_INDEX_SIZE + 3)) >> vm->page_shift; + if (!pgd_pages) + pgd_pages =3D 1; + pgtb =3D vm_phy_pages_alloc_align(vm, pgd_pages, pgd_pages, + KVM_GUEST_PAGE_TABLE_MIN_PADDR, + vm->memslots[MEM_REGION_PT]); + vm->mmu.pgd =3D pgtb; + + /* Set the base page directory in the proc table */ + set_radix_proc_table(vm, 0, pgtb); + + if (vm->mode =3D=3D VM_MODE_P52V52_4K) + mmu_cfg.process_table =3D prtb | 0x8000000000000000UL | 0x0; /* 4K size = */ + else /* vm->mode =3D=3D VM_MODE_P52V52_64K */ + mmu_cfg.process_table =3D prtb | 0x8000000000000000UL | 0x4; /* 64K size= */ + mmu_cfg.flags =3D KVM_PPC_MMUV3_RADIX | KVM_PPC_MMUV3_GTSE; + + vm_ioctl(vm, KVM_PPC_CONFIGURE_V3_MMU, &mmu_cfg); +} + +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 =3D=3D VM_MODE_P52V52_4K) + return 9; + else /* vm->mode =3D=3D VM_MODE_P52V52_64K */ + return 5; + default: + TEST_ASSERT(false, "Invalid page table level %d\n", level); + return 0; + } +} + +static uint64_t pt_entry_coverage(struct kvm_vm *vm, int level) +{ + uint64_t size =3D vm->page_size; + + if (level =3D=3D 4) + return size; + size <<=3D pt_shift(vm, 4); + if (level =3D=3D 3) + return size; + size <<=3D pt_shift(vm, 3); + if (level =3D=3D 2) + return size; + size <<=3D pt_shift(vm, 2); + return size; +} + +static int pt_idx(struct kvm_vm *vm, uint64_t vaddr, int level, uint64_t *= nls) +{ + switch (level) { + case 1: + if (nls) + *nls =3D 0x9; + return (vaddr >> 39) & 0x1fff; + case 2: + if (nls) + *nls =3D 0x9; + return (vaddr >> 30) & 0x1ff; + case 3: + if (vm->mode =3D=3D VM_MODE_P52V52_4K) { + if (nls) + *nls =3D 0x9; + } else { /* vm->mode =3D=3D VM_MODE_P52V52_64K */ + if (nls) + *nls =3D 0x5; + } + return (vaddr >> 21) & 0x1ff; + case 4: + if (vm->mode =3D=3D VM_MODE_P52V52_4K) + return (vaddr >> 12) & 0x1ff; + else /* vm->mode =3D=3D VM_MODE_P52V52_64K */ + return (vaddr >> 16) & 0x1f; + default: + TEST_ASSERT(false, "Invalid page table level %d\n", level); + return 0; + } +} + +static uint64_t *virt_get_pte(struct kvm_vm *vm, gpa_t pt, + uint64_t vaddr, int level, uint64_t *nls) +{ + int idx =3D pt_idx(vm, vaddr, level, nls); + uint64_t *ptep =3D 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, uint64_t pt_shift) +{ + gpa_t pt; + + if (pt_shift >=3D vm->page_shift) { + size_t pt_pages =3D 1ULL << (pt_shift - vm->page_shift); + + pt =3D vm_phy_pages_alloc_align(vm, pt_pages, pt_pages, + KVM_GUEST_PAGE_TABLE_MIN_PADDR, + vm->memslots[MEM_REGION_PT]); + } else { + struct vm_pt_frag_cache *pt_frag_cache; + + if (pt_shift =3D=3D 8) { + pt_frag_cache =3D &vm->arch.pt_frag_cache[0]; + } else if (pt_shift =3D=3D 12) { + pt_frag_cache =3D &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 =3D vm_phy_pages_alloc_align(vm, 1, 1, + KVM_GUEST_PAGE_TABLE_MIN_PADDR, + vm->memslots[MEM_REGION_PT]); + } + pt =3D pt_frag_cache->page + pt_frag_cache->page_nr_used; + pt_frag_cache->page_nr_used +=3D (1 << pt_shift); + if (pt_frag_cache->page_nr_used =3D=3D vm->page_size) { + pt_frag_cache->page =3D 0; + pt_frag_cache->page_nr_used =3D 0; + } + } + + return pt; +} + +void virt_arch_pg_map(struct kvm_vm *vm, uint64_t gva, uint64_t gpa) +{ + gpa_t pt =3D vm->mmu.pgd; + uint64_t *ptep, pte; + int level; + + for (level =3D 1; level <=3D 3; level++) { + uint64_t nls; + uint64_t *pdep =3D virt_get_pte(vm, pt, gva, level, &nls); + uint64_t pde =3D 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 =3D pde & PDE_PT_MASK; + continue; + } + + pt =3D __vm_alloc_pt(vm, nls + 3); + pde =3D PDE_VALID | nls | pt; + *pdep =3D cpu_to_be64(pde); + } + + ptep =3D virt_get_pte(vm, pt, gva, level, NULL); + pte =3D be64_to_cpu(*ptep); + + TEST_ASSERT(!pte, "PTE already present at level: %u gva: 0x%lx pte:0x%lx\= n", + level, gva, pte); + + pte =3D PTE_VALID | PTE_LEAF | PTE_REFERENCED | PTE_CHANGED | PTE_PRIV | + PTE_READ | PTE_RW | PTE_EXEC | (gpa & PTE_PAGE_MASK); + *ptep =3D cpu_to_be64(pte); +} + +gpa_t addr_arch_gva2gpa(struct kvm_vm *vm, gva_t gva) +{ + gpa_t pt =3D vm->mmu.pgd; + uint64_t *ptep, pte; + int level; + + for (level =3D 1; level <=3D 3; level++) { + uint64_t nls; + uint64_t *pdep =3D virt_get_pte(vm, pt, gva, level, &nls); + uint64_t pde =3D 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 =3D pde & PDE_PT_MASK; + } + + ptep =3D virt_get_pte(vm, pt, gva, level, NULL); + pte =3D 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 & PTE_READ) && (pte & PTE_RW) && (pte & PTE_EXEC), + "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, uint8_t indent) +{ + int size, idx; + + size =3D 1U << (pt_shift(vm, level) + 3); + + for (idx =3D 0; idx < size; idx +=3D 8, va +=3D pt_entry_coverage(vm, lev= el)) { + uint64_t *page_table =3D addr_gpa2hva(vm, pt + idx); + uint64_t pte =3D 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, uint8_t indent) +{ + gpa_t pt =3D 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" : "=3Dr"(r2)); + + return r2; +} + +void vcpu_arch_set_entry_point(struct kvm_vcpu *vcpu, void *guest_code) +{ + struct kvm_regs regs; + + vcpu_regs_get(vcpu, ®s); + regs.pc =3D (uintptr_t)guest_code; + regs.gpr[12] =3D (uintptr_t)guest_code; + vcpu_regs_set(vcpu, ®s); +} + +struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id) +{ + const size_t stack_size =3D 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; + uint64_t lpcr; + + stack_vaddr =3D __vm_alloc(vm, stack_size, + DEFAULT_GUEST_STACK_VADDR_MIN, + MEM_REGION_DATA); + + ex_regs_vaddr =3D __vm_alloc(vm, stack_size, + DEFAULT_GUEST_STACK_VADDR_MIN, + MEM_REGION_DATA); + ex_regs_paddr =3D addr_gva2gpa(vm, ex_regs_vaddr); + ex_regs =3D addr_gpa2hva(vm, ex_regs_paddr); + ex_regs->vaddr =3D ex_regs_vaddr; + + vcpu =3D __vm_vcpu_add(vm, vcpu_id); + + vcpu_enable_cap(vcpu, KVM_CAP_PPC_PAPR, 1); + + /* Setup guest registers */ + vcpu_regs_get(vcpu, ®s); + lpcr =3D vcpu_get_reg(vcpu, KVM_REG_PPC_LPCR_64); + + regs.gpr[1] =3D stack_vaddr + stack_size - 256; + regs.gpr[2] =3D (uintptr_t)get_r2(); + regs.gpr[13] =3D (uintptr_t)ex_regs_paddr; + + regs.msr =3D MSR_SF | MSR_VEC | MSR_VSX | MSR_FP | + MSR_ME | MSR_IR | MSR_DR | MSR_RI; + + if (BYTE_ORDER =3D=3D LITTLE_ENDIAN) { + regs.msr |=3D MSR_LE; + lpcr |=3D LPCR_ILE; + } else { + lpcr &=3D ~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 >=3D 1 && num <=3D 5, "Unsupported number of args: %u\n", + num); + + va_start(ap, num); + vcpu_regs_get(vcpu, ®s); + + for (i =3D 0; i < num; i++) + regs.gpr[i + 3] =3D va_arg(ap, uint64_t); + + vcpu_regs_set(vcpu, ®s); + va_end(ap); +} + +void vcpu_arch_dump(FILE *stream, struct kvm_vcpu *vcpu, uint8_t 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) +{ + gpa_t excp_paddr; + void *mem; + + excp_paddr =3D vm_phy_page_alloc(vm, 0, vm->memslots[MEM_REGION_DATA]); + + TEST_ASSERT(excp_paddr =3D=3D 0, + "Interrupt vectors not allocated at gPA address 0: (0x%lx)", + excp_paddr); + + mem =3D addr_gpa2hva(vm, excp_paddr); + memcpy(mem, __interrupts_start, __interrupts_end - __interrupts_start); +} + +void assert_on_unhandled_exception(struct kvm_vcpu *vcpu) +{ + struct ucall uc; + + if (get_ucall(vcpu, &uc) =3D=3D UCALL_UNHANDLED) { + gpa_t ex_regs_paddr; + struct ex_regs *ex_regs; + struct kvm_regs regs; + + vcpu_regs_get(vcpu, ®s); + ex_regs_paddr =3D (gpa_t)regs.gpr[13]; + ex_regs =3D 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 =3D 0; i < NR_HANDLERS; i++) { + if (handlers[i].trap =3D=3D 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 =3D 0; i < NR_HANDLERS; i++) { + if (!handlers[i].trap || handlers[i].trap =3D=3D trap) { + if (fn =3D=3D NULL) + trap =3D 0; /* Clear handler */ + handlers[i].trap =3D trap; + handlers[i].fn =3D 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/testin= g/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 =3D vcpu->run; + + if (run->exit_reason =3D=3D UCALL_EXIT_REASON && + run->papr_hcall.nr =3D=3D H_UCALL) { + struct kvm_regs regs; + + vcpu_regs_get(vcpu, ®s); + if (regs.gpr[4] =3D=3D UCALL_R4_UCALL) + return (void *)regs.gpr[5]; + } + return NULL; +} --=20 2.39.5 From nobody Mon May 25 08:10:54 2026 Received: from mail-pf1-f177.google.com (mail-pf1-f177.google.com [209.85.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4ED993FBB46 for ; Fri, 15 May 2026 16:04:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.177 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778861096; cv=none; b=blJLgrQsA49kKge2bza4EUasT2XVrP4K/Ts5LOy0RGG8IBZ1jOJ/3Df00BplyRRmuY+UlqFFGj9NQw4jii3FlgVTq4r0XqHP0Eu53tY+10bL/hDFg2Us9exYQfLblHoSym9cIa8+En4ykHJ6LPKaFWoX3vh7qZYc8YVckvL/PLo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778861096; c=relaxed/simple; bh=hGVAQIOSZVX+OOxyi3w8w+qe9kLA9gh1RSXqVgqXZ5c=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=m+5vkCxRZ6fmhbEbPtGmVOH1VedoAwrazJWstbqTvx2lzd8ER8BdfAo7yZ8l+VZkjb2fQj3ffyglusAU7b0seSXjJb2qkyM+9hU9orIlVsCse158g9baQ3uk7Fff9JxuXn3pJqbVML3n/kb/kySqvRn4k6cXga3Ucnoy0VyqLpc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=irnabj42; arc=none smtp.client-ip=209.85.210.177 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="irnabj42" Received: by mail-pf1-f177.google.com with SMTP id d2e1a72fcca58-8353ca0f1f1so617261b3a.1 for ; Fri, 15 May 2026 09:04:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1778861094; x=1779465894; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=CWSTcJ0lUIenOrMKgCBsi4dMZXBhfxtLdXUWtU/7JTQ=; b=irnabj42CBvDID/L/gPzZTgciPwcTWIx7P8ttBvZ15A/z8mCjq1hAkeGPE54d7E8mm 3BWSg+esELXlw+ilIYOD+vXqM/62cxjt9cyo+Y+AdFOHgpGQj3kMvt49i93uZnCjXdfH mNx6YppHT2ElZqjdXZzWNcr7Av3hdcVThU8kDyHBgy6W4TaxtWvYrqKkXDj//rnud3p6 GTQhlQzTdxEkSzUkcbn959QbjD5uAR9UuQGLH2xGBPqIU9oBmdYndXB7ZT+u/SbPPEDj 4KcVRI7/Iz3hEe6j9RWT4dRFuXisVpf3LQ0bJhXELOns62XTdv58D8/U0RtV4RjI5fcy J3kQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778861094; x=1779465894; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=CWSTcJ0lUIenOrMKgCBsi4dMZXBhfxtLdXUWtU/7JTQ=; b=R7fV09Ay4uGFfanDMZWe4sfOVa4W4ejV/aoKOc+4N6FG6Q1RT1gvrlc88rYM9GLAfE n8ETmNIu+vr+UQynmQwlPZ+47fwoPkqqi48oubBjMT0kk21+oHdZAAJyk7GNZ6DD0eb8 GD5b5hYAmv26SXlez+eZhZ95m6TrISZpLL2ysV3VtIa7vtp5xIZiokk/JQlzOQ0+b2xx 7UXZ+pqgylI7omjQfWAgCONzSHUfujWNnJ+8cqFGkkX7XByKOx+KHfrEMw+ntdeJz3+G JQCBbJLuA9KyA4MsJ3EN6OCqK0JnT9ST6TziNWwySgyH6W8LJOoJq4tg25ljT5cgqJaL EA1A== X-Forwarded-Encrypted: i=1; AFNElJ+YIgCBL/dtQH/Ya/eEVyfrjDrgIoSPhsQy8K/L/DHCJYvykRPNBat/QX6XlRxNDfMmcCdJwf90guKIS3o=@vger.kernel.org X-Gm-Message-State: AOJu0Yyt4r4+84FQYQKy2hVVcEZf3/lxAr0q7uHZLq9Hb45+kDXnHwBg Lhc8fzl8Rg51HK8+TMJk4dywl0sbsFUvY1k/DZ2HgBgACS7P//PNWtFo X-Gm-Gg: Acq92OH5+cN1o1A5f3WPK+znWz9ibtcjbCD9VGaWHpGdhqHgob/yqg+fcL9B0uM06b6 D+x3fb3fDVyzDOweyoCA6d964YRYkyd4is9xo9lBdWkcGHUQR7w+4HKWLuhHHy8d+X81etRzpFS GspHJvPTGMR5CEEz1Vd7Tc0QK8jTzsUIaFsbuhPpWuCXUrTfljV9DoMXnmKaQTWlSHULUOgl+7u QZraX1V/upkLmUu/UtjLemwPDpbC8RGMN5MhdlhsTGI6a0tiJDrT4SKx+krTImbZ6XyZ3UJhnLr D6WMzwKIfOe3ZqS70Z4ojWJQGMLEO0/5zL5DxI2p3s8PvU8jWYT1Hk4Vg84DK4LToH3bkOomj9Y JOy4CsCAZ15DL3BSPXHTU6pUx6MuWhxLe+9KEquiPEJq15h27WxtAN528jkr2qhWNWYgZzRCCI8 tK9SaTqpULqyNWzYALC4RAZD1WKtSLUpCO5asDH8zj7XwNZC1QbTan X-Received: by 2002:a05:6a00:39a0:b0:829:8083:472b with SMTP id d2e1a72fcca58-83f33ada10cmr4070840b3a.4.1778861094440; Fri, 15 May 2026 09:04:54 -0700 (PDT) Received: from localhost.localdomain ([171.76.86.174]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-83f19c7c74fsm7920262b3a.49.2026.05.15.09.04.50 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Fri, 15 May 2026 09:04:53 -0700 (PDT) From: "Ritesh Harjani (IBM)" To: kvm@vger.kernel.org Cc: linuxppc-dev@lists.ozlabs.org, Madhavan Srinivasan , Harsh Prateek Bora , Christophe Leroy , Venkat Rao Bagalkote , Nicholas Piggin , linux-kernel@vger.kernel.org, "Ritesh Harjani (IBM)" Subject: [RFC 4/4] KVM: PPC: selftests: powerpc enable kvm_create_max_vcpus test Date: Fri, 15 May 2026 21:34:23 +0530 Message-ID: <0050c451633ae8e22ac80368587aca70e96457d0.1778857539.git.ritesh.list@gmail.com> X-Mailer: git-send-email 2.50.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Nicholas Piggin 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. Signed-off-by: Nicholas Piggin [Rebased to laest mainline tree] Signed-off-by: Ritesh Harjani (IBM) --- tools/testing/selftests/kvm/kvm_create_max_vcpus.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c b/tools/tes= ting/selftests/kvm/kvm_create_max_vcpus.c index c5310736ed06..a82c13d6cdf5 100644 --- a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c +++ b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c @@ -56,6 +56,15 @@ int main(int argc, char *argv[]) "KVM_MAX_VCPU_IDS (%d) must be at least as large as KVM_MAX_VCPUS (%= d).", kvm_max_vcpu_id, kvm_max_vcpus); =20 +#ifdef __powerpc64__ + /* + * powerpc has a particular format for the vcpu ID that depends on + * the guest SMT mode, and the max ID cap is too large for non-SMT + * modes, where the maximum ID is the same as the maximum vCPUs. + */ + kvm_max_vcpu_id =3D kvm_max_vcpus; +#endif + test_vcpu_creation(0, kvm_max_vcpus); =20 if (kvm_max_vcpu_id > kvm_max_vcpus) --=20 2.39.5