From patchwork Tue Sep 10 15:21:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nikolas Wipper X-Patchwork-Id: 827222 Received: from smtp-fw-52004.amazon.com (smtp-fw-52004.amazon.com [52.119.213.154]) (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 C5B4819ABB6; Tue, 10 Sep 2024 15:22:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=52.119.213.154 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725981758; cv=none; b=SD/N8Jo+8sf+4HmrB23QBwO/WLbUbKWmz7eU314EOZ/9zE8YPNrUKLQL5L+es8zPCjwbfDs8HprMiez/9hUKyvzLuIwerflpzHf1ZQaVohuVaoQ3mcGROglirozDDRHFAAFVwj/zp5ASZPHcHVgVVQ8uqcAuFLOJZtsful2Ts4M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725981758; c=relaxed/simple; bh=B/K2QUnoSkS4ZvGZwey8z+/mNvJkvwtcoAo//x+7GQk=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=b22ptN2yPgFW2DaX+/ty6xrKgrUmloCnRdNji1zUmSqdo6pYgQBNNvKgDt7p60nOZBWF+muQBiP3y2n6v2hjXbyFbo3g2mJ+BkuTbkmaWS1ZzOCMZMMjy0bzgkSXBJnIJoof5/FZTGWigVYFJxTrfzFd5WZID8ZHh600f3VWUGc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amazon.de; spf=pass smtp.mailfrom=amazon.de; dkim=pass (1024-bit key) header.d=amazon.de header.i=@amazon.de header.b=R5vVlrEn; arc=none smtp.client-ip=52.119.213.154 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amazon.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=amazon.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amazon.de header.i=@amazon.de header.b="R5vVlrEn" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1725981756; x=1757517756; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=NC1az9/hAILYnJFLiqNcORpyqC2hQx+wOpC0bECqtHU=; b=R5vVlrEn453Ei4Y5fhEsyz3AEMyiFQg5oo9Bl8vpN2zvo+EJKj/gaiZF yUmAhTMdZA2jGNJM1OFZFfXw2PjE1qR2uYW104UEYOBhEPc3eSMDt/XdP /fxRr0X4zCsqVeW54Jx7EaZCLqSf2fF3NjonaUfJOKEgU799xI31VMeWO U=; X-IronPort-AV: E=Sophos;i="6.10,217,1719878400"; d="scan'208";a="230917179" Received: from iad12-co-svc-p1-lb1-vlan2.amazon.com (HELO smtpout.prod.us-west-2.prod.farcaster.email.amazon.dev) ([10.43.8.2]) by smtp-border-fw-52004.iad7.amazon.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Sep 2024 15:22:32 +0000 Received: from EX19MTAEUA001.ant.amazon.com [10.0.43.254:48425] by smtpin.naws.eu-west-1.prod.farcaster.email.amazon.dev [10.0.1.162:2525] with esmtp (Farcaster) id 56079a0b-55b2-49ad-8775-ef55f4079c09; Tue, 10 Sep 2024 15:22:30 +0000 (UTC) X-Farcaster-Flow-ID: 56079a0b-55b2-49ad-8775-ef55f4079c09 Received: from EX19D041EUB004.ant.amazon.com (10.252.61.113) by EX19MTAEUA001.ant.amazon.com (10.252.50.223) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34; Tue, 10 Sep 2024 15:22:29 +0000 Received: from EX19MTAUEA001.ant.amazon.com (10.252.134.203) by EX19D041EUB004.ant.amazon.com (10.252.61.113) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34; Tue, 10 Sep 2024 15:22:28 +0000 Received: from dev-dsk-nikwip-1b-bc9ec026.eu-west-1.amazon.com (10.253.74.52) by mail-relay.amazon.com (10.252.134.102) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34 via Frontend Transport; Tue, 10 Sep 2024 15:22:27 +0000 From: Nikolas Wipper To: Paolo Bonzini , Sean Christopherson , Vitaly Kuznetsov CC: Nicolas Saenz Julienne , Alexander Graf , James Gowans , , Thomas Gleixner , "Ingo Molnar" , Borislav Petkov , Dave Hansen , , , , , , , , Nikolas Wipper Subject: [PATCH 01/15] KVM: Add API documentation for KVM_TRANSLATE2 Date: Tue, 10 Sep 2024 15:21:53 +0000 Message-ID: <20240910152207.38974-2-nikwip@amazon.de> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20240910152207.38974-1-nikwip@amazon.de> References: <20240910152207.38974-1-nikwip@amazon.de> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add API documentation for the new KVM_TRANSLATE2 ioctl. Signed-off-by: Nikolas Wipper --- Documentation/virt/kvm/api.rst | 131 +++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index a4b7dc4a9dda..632dc591badf 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -6442,6 +6442,137 @@ the capability to be present. `flags` must currently be zero. +4.144 KVM_TRANSLATE2 +-------------------- + +:Capability: KVM_CAP_TRANSLATE2 +:Architectures: x86 +:Type: vcpu ioctl +:Parameters: struct kvm_translation2 (in/out) +:Returns: 0 on success, <0 on error + +KVM_TRANSLATE2 translates a guest virtual address into a guest physical one +while probing for requested access permissions and allowing for control over +whether accessed and dirty bits are set in each of the page map levels +structure. If the page walk fails, it provides detailed information explaining +the reason for the failure. + +:: + + /* for KVM_TRANSLATE2 */ + struct kvm_translation2 { + /* in */ + __u64 linear_address; + #define KVM_TRANSLATE_FLAGS_SET_ACCESSED (1 << 0) + #define KVM_TRANSLATE_FLAGS_SET_DIRTY (1 << 1) + #define KVM_TRANSLATE_FLAGS_FORCE_SET_ACCESSED (1 << 2) + __u16 flags; + #define KVM_TRANSLATE_ACCESS_WRITE (1 << 0) + #define KVM_TRANSLATE_ACCESS_USER (1 << 1) + #define KVM_TRANSLATE_ACCESS_EXEC (1 << 2) + #define KVM_TRANSLATE_ACCESS_ALL \ + (KVM_TRANSLATE_ACCESS_WRITE | \ + KVM_TRANSLATE_ACCESS_USER | \ + KVM_TRANSLATE_ACCESS_EXEC) + __u16 access; + __u8 padding[4]; + + /* out */ + __u64 physical_address; + __u8 valid; + #define KVM_TRANSLATE_FAULT_NOT_PRESENT 1 + #define KVM_TRANSLATE_FAULT_PRIVILEGE_VIOLATION 2 + #define KVM_TRANSLATE_FAULT_RESERVED_BITS 3 + #define KVM_TRANSLATE_FAULT_INVALID_GVA 4 + #define KVM_TRANSLATE_FAULT_INVALID_GPA 5 + __u16 error_code; + __u8 set_bits_succeeded; + __u8 padding2[4]; + }; + +If the page walk succeeds, `physical_address` will contain the result of the +page walk, `valid` will be set to 1 and `error_code` will not contain any +meaningful value. + +If the page walk fails, `valid` will be set to 0 and `error_code` will contain +the reason of the walk failure. `physical_address` may contain the physical +address of the page table where the page walk was aborted, depending on the +returned error code: + +.. csv-table:: + :header: "`error_code`", "`physical_address`" + + "KVM_TRANSLATE_FAULT_NOT_PRESENT", "Physical address of the page table entry without the present bit" + "KVM_TRANSLATE_FAULT_PRIVILEGE_VIOLATION", "Physical address of the page table entry where access checks failed" + "KVM_TRANSLATE_FAULT_RESERVED_BITS", "Physical address of the page table entry with reserved bits set" + "KVM_TRANSLATE_FAULT_INVALID_GPA", "Physical address that wasn't backed by host memory" + "KVM_TRANSLATE_FAULT_INVALID_GVA", "empty", + +The `flags` field can take each of these flags: + +KVM_TRANSLATE_FLAGS_SET_ACCESSED + Sets the accessed bit on each page table level on a successful page walk. + +KVM_TRANSLATE_FLAGS_SET_DIRTY + Sets the dirty bit on each page table level on a successful page walk. + +KVM_TRANSLATE_FLAGS_FORCE_SET_ACCESSED + Forces setting the accessed bit on every page table level that was walked + successfully on failed page walks. + +.. warning:: + + Setting these flags and then using the translated address may lead to a + race, if another vCPU remotely flushes the local vCPUs TLB while the + address is still in use. This can be mitigated by stalling such TLB flushes + until the memory operation is finished. + +The `access` field can take each of these flags: + +KVM_TRANSLATE_ACCESS_WRITE + The page walker will check for write access on every page table. + +KVM_TRANSLATE_ACCESS_USER + The page walker will check for user mode access on every page table. + +KVM_TRANSLATE_ACCESS_EXEC + The page walker will check for executable/fetch access on every page table. + +If none of these flags are set, read access and kernel mode permissions are +implied. + +The `error_code` field can take one of these values: + +KVM_TRANSLATE_FAULT_NOT_PRESENT + The virtual address is not mapped to any physical address. + +KVM_TRANSLATE_FAULT_PRIVILEGE_VIOLATION + One of the access checks failed during the page walk. + +KVM_TRANSLATE_FAULT_RESERVED_BITS + Reserved bits were set in a page table. + +KVM_TRANSLATE_FAULT_INVALID_GPA + One of the guest page table entries' addresses along the page walk was not + backed by a host memory. + +KVM_TRANSLATE_FAULT_INVALID_GVA + The GVA provided is not valid in the current vCPU state. For example, if on + 32-bit systems, the virtual address provided was larger than 32-bits, or on + 64-bit x86 systems, the virtual address was non-canonical. + +Regardless of the success of the page walk, `set_bits_succeeded` will contain a +boolean value indicating whether the accessed/dirty bits were set. It may be +false, if the bits were not set, because the page walk failed and +KVM_TRANSLATE_FLAGS_FORCE_SET_ACCESSED was not passed, or if there was an error +setting the bits, for example, the host memory backing the page table entry was +marked read-only. + +KVM_TRANSLATE_FLAGS_FORCE_SET_ACCESSED and KVM_TRANSLATE_FLAGS_SET_DIRTY must +never be passed without KVM_TRANSLATE_FLAGS_SET_ACCESSED. +KVM_TRANSLATE_FLAGS_SET_DIRTY must never be passed without +KVM_TRANSLATE_ACCESS_WRITE. Doing either will cause the ioctl to fail with exit +code -EINVAL. 5. The kvm_run structure ======================== From patchwork Tue Sep 10 15:21:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nikolas Wipper X-Patchwork-Id: 827221 Received: from smtp-fw-80009.amazon.com (smtp-fw-80009.amazon.com [99.78.197.220]) (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 E43BD1A0B1E; Tue, 10 Sep 2024 15:23:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=99.78.197.220 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725981790; cv=none; b=jlh9WN4hQrZZ6wFGMRlBn2UMCx8rwGFkAqJH+CNapTtF7BuKZjLTC0iln1yCwNTu2W1X9tYrU+Y/lYWjcLxUuyHY3vAAUm1vcRZXtiEQtrQH0EECO7PLbFoZTonPKkfyoDxwutOL42hHrit0MEJ8evXUf5GPoMSMKq3LvpsDBS4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725981790; c=relaxed/simple; bh=itnc9gRgJy+e6+5K0E7HXZ5B4JuLftNx3P5bSoOBP7Y=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=MUYLTETpHqkoFnj6eHUlp2D/PI6f9E7Iy6/AJHQSVW6EbRGtbsLKVKVYSRf5mslJpAlH6QHqqu5bNDVsnQ2wTazpJMkloRWRn5lPgIMdhbBz+kV07evj/9f2vHVxdfk7gQyNveBZD8k3q1isIa1wOl44mSddR+dVydvydAdJw1s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amazon.de; spf=pass smtp.mailfrom=amazon.de; dkim=pass (1024-bit key) header.d=amazon.de header.i=@amazon.de header.b=lqhhk/nq; arc=none smtp.client-ip=99.78.197.220 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amazon.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=amazon.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amazon.de header.i=@amazon.de header.b="lqhhk/nq" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1725981789; x=1757517789; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Km2TrPXosr7uX6oYzMA+218QoXlL+9LaKCD4YvBno24=; b=lqhhk/nqiulfoDQJzCvbQHRjNTyIF7c9TfclsnWTEjph5b35oxkuKBVa al1AeL2UoZ+v9/6UPaDddgEE6w7kTPHlnV9M8OF5s+2AnKLOh2QZN6zTg L03kZYXuYHLtqW37vs8c5JxHAkn6WDN3ixLivfNtceFm2Kh1lQNDyJVyv U=; X-IronPort-AV: E=Sophos;i="6.10,217,1719878400"; d="scan'208";a="124219001" Received: from pdx4-co-svc-p1-lb2-vlan2.amazon.com (HELO smtpout.prod.us-west-2.prod.farcaster.email.amazon.dev) ([10.25.36.210]) by smtp-border-fw-80009.pdx80.corp.amazon.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Sep 2024 15:23:06 +0000 Received: from EX19MTAUWA001.ant.amazon.com [10.0.21.151:55695] by smtpin.naws.us-west-2.prod.farcaster.email.amazon.dev [10.0.52.222:2525] with esmtp (Farcaster) id 418f5ccd-c6c8-424b-bda0-10b12e0c347f; Tue, 10 Sep 2024 15:23:06 +0000 (UTC) X-Farcaster-Flow-ID: 418f5ccd-c6c8-424b-bda0-10b12e0c347f Received: from EX19D020UWA003.ant.amazon.com (10.13.138.254) by EX19MTAUWA001.ant.amazon.com (10.250.64.218) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34; Tue, 10 Sep 2024 15:23:05 +0000 Received: from EX19MTAUWA001.ant.amazon.com (10.250.64.204) by EX19D020UWA003.ant.amazon.com (10.13.138.254) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34; Tue, 10 Sep 2024 15:23:05 +0000 Received: from dev-dsk-nikwip-1b-bc9ec026.eu-west-1.amazon.com (10.253.74.52) by mail-relay.amazon.com (10.250.64.204) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34 via Frontend Transport; Tue, 10 Sep 2024 15:23:02 +0000 From: Nikolas Wipper To: Paolo Bonzini , Sean Christopherson , Vitaly Kuznetsov CC: Nicolas Saenz Julienne , Alexander Graf , James Gowans , , Thomas Gleixner , "Ingo Molnar" , Borislav Petkov , Dave Hansen , , , , , , , , Nikolas Wipper Subject: [PATCH 03/15] KVM: x86/mmu: Introduce exception flag for unmapped GPAs Date: Tue, 10 Sep 2024 15:21:55 +0000 Message-ID: <20240910152207.38974-4-nikwip@amazon.de> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20240910152207.38974-1-nikwip@amazon.de> References: <20240910152207.38974-1-nikwip@amazon.de> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Introduce a flag in x86_exception which signals that a page walk failed because a page table GPA wasn't backed by a memslot. This only applies to page tables; the final physical address is not checked. This extra flag is needed, because the normal page fault error code does not contain a bit to signal this kind of fault. Used in subsequent patches to give userspace information about translation failure. Signed-off-by: Nikolas Wipper --- arch/x86/kvm/kvm_emulate.h | 2 ++ arch/x86/kvm/mmu/paging_tmpl.h | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h index 55a18e2f2dcd..afd8e86bc6af 100644 --- a/arch/x86/kvm/kvm_emulate.h +++ b/arch/x86/kvm/kvm_emulate.h @@ -27,6 +27,8 @@ struct x86_exception { u64 address; /* cr2 or nested page fault gpa */ u8 async_page_fault; unsigned long exit_qualification; +#define KVM_X86_UNMAPPED_PTE_GPA BIT(0) + u16 flags; }; /* diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index d9c3c78b3c14..f6a78b7cfca1 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -339,6 +339,8 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, #endif walker->max_level = walker->level; + walker->fault.flags = 0; + /* * FIXME: on Intel processors, loads of the PDPTE registers for PAE paging * by the MOV to CR instruction are treated as reads and do not cause the @@ -393,8 +395,10 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, return 0; slot = kvm_vcpu_gfn_to_memslot(vcpu, gpa_to_gfn(real_gpa)); - if (!kvm_is_visible_memslot(slot)) + if (!kvm_is_visible_memslot(slot)) { + walker->fault.flags = KVM_X86_UNMAPPED_PTE_GPA; goto error; + } host_addr = gfn_to_hva_memslot_prot(slot, gpa_to_gfn(real_gpa), &walker->pte_writable[walker->level - 1]); From patchwork Tue Sep 10 15:21:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nikolas Wipper X-Patchwork-Id: 827220 Received: from smtp-fw-9106.amazon.com (smtp-fw-9106.amazon.com [207.171.188.206]) (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 D17E219D88C; Tue, 10 Sep 2024 15:23:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=207.171.188.206 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725981833; cv=none; b=XxoYi5BTFmzaEOypDPOeeXRXO1OSEDWTDlY8G+ViTrQP+viBZmGTilSa1J8IonTT+5tFNosOk7pssA7OEwB5zx4i23Pl2UoF6YA1bhkflfRrswCHTBK++lhiBA3xIcl4XeMnsK4HX4ckOjrDjEFgOz2nmqRY5mnkXWerXlE/LIM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725981833; c=relaxed/simple; bh=BVepAbkOeEU3slbtp/jqhBcz5M3ofT+FBHaVmTXzrPo=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=QVXWc1LH5P6w9BW1WkWvTFpXqZ2BT9agDzNqqEy8Mmy3SokPK2hRWmdw9XU9b83329QKboF8PSMQJ/5JK3aSWkQ/BJUPoqdtZ1OOW83MHwQ6MOrU+UwAbBibscPSYds4JR+NDxgbH6We8LkSCShgDppMkTG9qHWj5pQfkazDAWo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amazon.de; spf=pass smtp.mailfrom=amazon.de; dkim=pass (1024-bit key) header.d=amazon.de header.i=@amazon.de header.b=VAb69RGB; arc=none smtp.client-ip=207.171.188.206 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amazon.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=amazon.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amazon.de header.i=@amazon.de header.b="VAb69RGB" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1725981829; x=1757517829; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=eR/aj8npvoNsBgWmleE4bomhd/6jXremotPxYL2Sd6Y=; b=VAb69RGBgV8VUNYVnWkUuzwL2f7jAl+Mrvpq5UtBwy6n6U5oR88bnM+Z s3VRveyC1kmcZdthhBYH9qyHooorNvb94sRWzUjAqK4srtkUhVWtOQuLW Iy0pLZcuZoVDKNrGQTwwTaoZb26ew4s8LX2Mp4bQGw0MoH+e0yaUQvZRl U=; X-IronPort-AV: E=Sophos;i="6.10,217,1719878400"; d="scan'208";a="758470499" Received: from pdx4-co-svc-p1-lb2-vlan2.amazon.com (HELO smtpout.prod.us-east-1.prod.farcaster.email.amazon.dev) ([10.25.36.210]) by smtp-border-fw-9106.sea19.amazon.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Sep 2024 15:23:47 +0000 Received: from EX19MTAEUB001.ant.amazon.com [10.0.17.79:2418] by smtpin.naws.eu-west-1.prod.farcaster.email.amazon.dev [10.0.38.136:2525] with esmtp (Farcaster) id d4f45114-c17c-419b-9541-f2fc8de2c3fd; Tue, 10 Sep 2024 15:23:45 +0000 (UTC) X-Farcaster-Flow-ID: d4f45114-c17c-419b-9541-f2fc8de2c3fd Received: from EX19D014EUC002.ant.amazon.com (10.252.51.161) by EX19MTAEUB001.ant.amazon.com (10.252.51.26) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34; Tue, 10 Sep 2024 15:23:40 +0000 Received: from EX19MTAUEC001.ant.amazon.com (10.252.135.222) by EX19D014EUC002.ant.amazon.com (10.252.51.161) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34; Tue, 10 Sep 2024 15:23:40 +0000 Received: from dev-dsk-nikwip-1b-bc9ec026.eu-west-1.amazon.com (10.253.74.52) by mail-relay.amazon.com (10.252.135.200) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34 via Frontend Transport; Tue, 10 Sep 2024 15:23:38 +0000 From: Nikolas Wipper To: Paolo Bonzini , Sean Christopherson , Vitaly Kuznetsov CC: Nicolas Saenz Julienne , Alexander Graf , James Gowans , , Thomas Gleixner , "Ingo Molnar" , Borislav Petkov , Dave Hansen , , , , , , , , Nikolas Wipper Subject: [PATCH 05/15] KVM: x86/mmu: Introduce flags parameter to page walker Date: Tue, 10 Sep 2024 15:21:57 +0000 Message-ID: <20240910152207.38974-6-nikwip@amazon.de> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20240910152207.38974-1-nikwip@amazon.de> References: <20240910152207.38974-1-nikwip@amazon.de> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Introduce the flags parameter to walk_addr_generic() which is needed to introduce fine grained control over the accessed/dirty bits. Also forward the parameter to several of the page walker's helper functions, so it can be used in an ioctl. Setting both PWALK_SET_ACCESSED and PWALK_SET_DIRTY will continue to maintain the previous behaviour, that is, both bits are only set after a successful walk and the dirty bit is only set when write access is enabled. No functional change intended. Signed-off-by: Nikolas Wipper --- arch/x86/include/asm/kvm_host.h | 10 +++++++++- arch/x86/kvm/hyperv.c | 3 ++- arch/x86/kvm/mmu.h | 6 +++--- arch/x86/kvm/mmu/mmu.c | 4 ++-- arch/x86/kvm/mmu/paging_tmpl.h | 25 ++++++++++++++----------- arch/x86/kvm/x86.c | 33 ++++++++++++++++++++------------- 6 files changed, 50 insertions(+), 31 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 46e0a466d7fb..3acf0b069693 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -281,6 +281,14 @@ enum x86_intercept_stage; #define PFERR_PRIVATE_ACCESS BIT_ULL(49) #define PFERR_SYNTHETIC_MASK (PFERR_IMPLICIT_ACCESS | PFERR_PRIVATE_ACCESS) +#define PFERR_NESTED_GUEST_PAGE (PFERR_GUEST_PAGE_MASK | \ + PFERR_WRITE_MASK | \ + PFERR_PRESENT_MASK) + +#define PWALK_SET_ACCESSED BIT(0) +#define PWALK_SET_DIRTY BIT(1) +#define PWALK_SET_ALL (PWALK_SET_ACCESSED | PWALK_SET_DIRTY) + /* apic attention bits */ #define KVM_APIC_CHECK_VAPIC 0 /* @@ -450,7 +458,7 @@ struct kvm_mmu { void (*inject_page_fault)(struct kvm_vcpu *vcpu, struct x86_exception *fault); gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, - gpa_t gva_or_gpa, u64 access, + gpa_t gva_or_gpa, u64 access, u64 flags, struct x86_exception *exception); int (*sync_spte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, int i); diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 4f0a94346d00..b237231ace61 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -2036,7 +2036,8 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc) * read with kvm_read_guest(). */ if (!hc->fast && is_guest_mode(vcpu)) { - hc->ingpa = translate_nested_gpa(vcpu, hc->ingpa, 0, NULL); + hc->ingpa = translate_nested_gpa(vcpu, hc->ingpa, 0, + PWALK_SET_ALL, NULL); if (unlikely(hc->ingpa == INVALID_GPA)) return HV_STATUS_INVALID_HYPERCALL_INPUT; } diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index 9dc5dd43ae7f..35030f6466b5 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -275,15 +275,15 @@ static inline void kvm_update_page_stats(struct kvm *kvm, int level, int count) } gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u64 access, - struct x86_exception *exception); + u64 flags, struct x86_exception *exception); static inline gpa_t kvm_translate_gpa(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, - gpa_t gpa, u64 access, + gpa_t gpa, u64 access, u64 flags, struct x86_exception *exception) { if (mmu != &vcpu->arch.nested_mmu) return gpa; - return translate_nested_gpa(vcpu, gpa, access, exception); + return translate_nested_gpa(vcpu, gpa, access, flags, exception); } #endif diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 0d94354bb2f8..50c635142bf7 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -4102,12 +4102,12 @@ void kvm_mmu_sync_prev_roots(struct kvm_vcpu *vcpu) } static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, - gpa_t vaddr, u64 access, + gpa_t vaddr, u64 access, u64 flags, struct x86_exception *exception) { if (exception) exception->error_code = 0; - return kvm_translate_gpa(vcpu, mmu, vaddr, access, exception); + return kvm_translate_gpa(vcpu, mmu, vaddr, access, flags, exception); } static bool mmio_info_in_cache(struct kvm_vcpu *vcpu, u64 addr, bool direct) diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index 74651b097fa0..c278b83b023f 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -301,7 +301,7 @@ static inline bool FNAME(is_last_gpte)(struct kvm_mmu *mmu, */ static int FNAME(walk_addr_generic)(struct guest_walker *walker, struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, - gpa_t addr, u64 access) + gpa_t addr, u64 access, u64 flags) { int ret; pt_element_t pte; @@ -379,7 +379,8 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, walker->pte_gpa[walker->level - 1] = pte_gpa; real_gpa = kvm_translate_gpa(vcpu, mmu, gfn_to_gpa(table_gfn), - nested_access, &walker->fault); + nested_access, flags, + &walker->fault); /* * FIXME: This can happen if emulation (for of an INS/OUTS @@ -449,7 +450,8 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, gfn += pse36_gfn_delta(pte); #endif - real_gpa = kvm_translate_gpa(vcpu, mmu, gfn_to_gpa(gfn), access, &walker->fault); + real_gpa = kvm_translate_gpa(vcpu, mmu, gfn_to_gpa(gfn), access, + flags, &walker->fault); if (real_gpa == INVALID_GPA) return 0; @@ -467,8 +469,8 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, (PT_GUEST_DIRTY_SHIFT - PT_GUEST_ACCESSED_SHIFT); if (unlikely(!accessed_dirty)) { - ret = FNAME(update_accessed_dirty_bits)(vcpu, mmu, walker, - addr, write_fault); + ret = FNAME(update_accessed_dirty_bits)(vcpu, mmu, walker, addr, + write_fault); if (unlikely(ret < 0)) goto error; else if (ret) @@ -527,11 +529,11 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, return 0; } -static int FNAME(walk_addr)(struct guest_walker *walker, - struct kvm_vcpu *vcpu, gpa_t addr, u64 access) +static int FNAME(walk_addr)(struct guest_walker *walker, struct kvm_vcpu *vcpu, + gpa_t addr, u64 access, u64 flags) { return FNAME(walk_addr_generic)(walker, vcpu, vcpu->arch.mmu, addr, - access); + access, flags); } static bool @@ -793,7 +795,8 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault * The bit needs to be cleared before walking guest page tables. */ r = FNAME(walk_addr)(&walker, vcpu, fault->addr, - fault->error_code & ~PFERR_RSVD_MASK); + fault->error_code & ~PFERR_RSVD_MASK, + PWALK_SET_ALL); /* * The page is not mapped by the guest. Let the guest handle it. @@ -872,7 +875,7 @@ static gpa_t FNAME(get_level1_sp_gpa)(struct kvm_mmu_page *sp) /* Note, @addr is a GPA when gva_to_gpa() translates an L2 GPA to an L1 GPA. */ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, - gpa_t addr, u64 access, + gpa_t addr, u64 access, u64 flags, struct x86_exception *exception) { struct guest_walker walker; @@ -884,7 +887,7 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, WARN_ON_ONCE((addr >> 32) && mmu == vcpu->arch.walk_mmu); #endif - r = FNAME(walk_addr_generic)(&walker, vcpu, mmu, addr, access); + r = FNAME(walk_addr_generic)(&walker, vcpu, mmu, addr, access, flags); if (r) { gpa = gfn_to_gpa(walker.gfn); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 15080385b8fe..32e81cd502ee 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1067,7 +1067,8 @@ int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3) * to an L1 GPA. */ real_gpa = kvm_translate_gpa(vcpu, mmu, gfn_to_gpa(pdpt_gfn), - PFERR_USER_MASK | PFERR_WRITE_MASK, NULL); + PFERR_USER_MASK | PFERR_WRITE_MASK, + PWALK_SET_ALL, NULL); if (real_gpa == INVALID_GPA) return 0; @@ -7560,7 +7561,7 @@ void kvm_get_segment(struct kvm_vcpu *vcpu, } gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u64 access, - struct x86_exception *exception) + u64 flags, struct x86_exception *exception) { struct kvm_mmu *mmu = vcpu->arch.mmu; gpa_t t_gpa; @@ -7569,7 +7570,7 @@ gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u64 access, /* NPT walks are always user-walks */ access |= PFERR_USER_MASK; - t_gpa = mmu->gva_to_gpa(vcpu, mmu, gpa, access, exception); + t_gpa = mmu->gva_to_gpa(vcpu, mmu, gpa, access, flags, exception); return t_gpa; } @@ -7580,7 +7581,8 @@ gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva, struct kvm_mmu *mmu = vcpu->arch.walk_mmu; u64 access = (kvm_x86_call(get_cpl)(vcpu) == 3) ? PFERR_USER_MASK : 0; - return mmu->gva_to_gpa(vcpu, mmu, gva, access, exception); + return mmu->gva_to_gpa(vcpu, mmu, gva, access, PWALK_SET_ALL, + exception); } EXPORT_SYMBOL_GPL(kvm_mmu_gva_to_gpa_read); @@ -7591,7 +7593,8 @@ gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva, u64 access = (kvm_x86_call(get_cpl)(vcpu) == 3) ? PFERR_USER_MASK : 0; access |= PFERR_WRITE_MASK; - return mmu->gva_to_gpa(vcpu, mmu, gva, access, exception); + return mmu->gva_to_gpa(vcpu, mmu, gva, access, PWALK_SET_ALL, + exception); } EXPORT_SYMBOL_GPL(kvm_mmu_gva_to_gpa_write); @@ -7601,7 +7604,7 @@ gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva, { struct kvm_mmu *mmu = vcpu->arch.walk_mmu; - return mmu->gva_to_gpa(vcpu, mmu, gva, 0, exception); + return mmu->gva_to_gpa(vcpu, mmu, gva, 0, PWALK_SET_ALL, exception); } static int kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes, @@ -7613,7 +7616,8 @@ static int kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes, int r = X86EMUL_CONTINUE; while (bytes) { - gpa_t gpa = mmu->gva_to_gpa(vcpu, mmu, addr, access, exception); + gpa_t gpa = mmu->gva_to_gpa(vcpu, mmu, addr, access, + PWALK_SET_ALL, exception); unsigned offset = addr & (PAGE_SIZE-1); unsigned toread = min(bytes, (unsigned)PAGE_SIZE - offset); int ret; @@ -7647,8 +7651,8 @@ static int kvm_fetch_guest_virt(struct x86_emulate_ctxt *ctxt, int ret; /* Inline kvm_read_guest_virt_helper for speed. */ - gpa_t gpa = mmu->gva_to_gpa(vcpu, mmu, addr, access|PFERR_FETCH_MASK, - exception); + gpa_t gpa = mmu->gva_to_gpa(vcpu, mmu, addr, access | PFERR_FETCH_MASK, + PWALK_SET_ALL, exception); if (unlikely(gpa == INVALID_GPA)) return X86EMUL_PROPAGATE_FAULT; @@ -7705,7 +7709,8 @@ static int kvm_write_guest_virt_helper(gva_t addr, void *val, unsigned int bytes int r = X86EMUL_CONTINUE; while (bytes) { - gpa_t gpa = mmu->gva_to_gpa(vcpu, mmu, addr, access, exception); + gpa_t gpa = mmu->gva_to_gpa(vcpu, mmu, addr, access, + PWALK_SET_ALL, exception); unsigned offset = addr & (PAGE_SIZE-1); unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset); int ret; @@ -7817,14 +7822,15 @@ static int vcpu_mmio_gva_to_gpa(struct kvm_vcpu *vcpu, unsigned long gva, */ if (vcpu_match_mmio_gva(vcpu, gva) && (!is_paging(vcpu) || !permission_fault(vcpu, vcpu->arch.walk_mmu, - vcpu->arch.mmio_access, 0, access))) { + vcpu->arch.mmio_access, + PWALK_SET_ALL, access))) { *gpa = vcpu->arch.mmio_gfn << PAGE_SHIFT | (gva & (PAGE_SIZE - 1)); trace_vcpu_match_mmio(gva, *gpa, write, false); return 1; } - *gpa = mmu->gva_to_gpa(vcpu, mmu, gva, access, exception); + *gpa = mmu->gva_to_gpa(vcpu, mmu, gva, access, PWALK_SET_ALL, exception); if (*gpa == INVALID_GPA) return -1; @@ -13644,7 +13650,8 @@ void kvm_fixup_and_inject_pf_error(struct kvm_vcpu *vcpu, gva_t gva, u16 error_c (PFERR_WRITE_MASK | PFERR_FETCH_MASK | PFERR_USER_MASK); if (!(error_code & PFERR_PRESENT_MASK) || - mmu->gva_to_gpa(vcpu, mmu, gva, access, &fault) != INVALID_GPA) { + mmu->gva_to_gpa(vcpu, mmu, gva, access, PWALK_SET_ALL, + &fault) != INVALID_GPA) { /* * If vcpu->arch.walk_mmu->gva_to_gpa succeeded, the page * tables probably do not match the TLB. Just proceed From patchwork Tue Sep 10 15:21:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nikolas Wipper X-Patchwork-Id: 827219 Received: from smtp-fw-6002.amazon.com (smtp-fw-6002.amazon.com [52.95.49.90]) (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 08D1119923A; Tue, 10 Sep 2024 15:24:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=52.95.49.90 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725981863; cv=none; b=Mv3vxo+W2NM6jl1SF7pBZGaboRPnTL9IZWKtZ/WQLT1QcirWTODkUzFsh2YHtVG51s7Cdz59WcWdBxq/+5z7y5tuvGKTX6vefQDbgW+8U0GJGy8YtuysPZgoYAt1IhtJY1RHyds385B7zW2uAuDt7kCE5pxd3aARkbQeAMhRsmc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725981863; c=relaxed/simple; bh=POQ8kozreKNtgbjSembbt5PYvEATBNIM8q9Rfx3n8fY=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=LHXSbcQkbxcsdwYarqCf0l7E9W4dGX5XL656bFj43ffPMRUdyLqcVyLQU4B5aETSpmtXmhlslUgNk6GWm5KYQK5v25uGokru+NV5Px+YRDfe9fNzr2+XY7PokxjcRV/rsK36ZN1Ab8OALjkwQg6Gf3SlIFvn/dWcYETtCMWVKm4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amazon.de; spf=pass smtp.mailfrom=amazon.de; dkim=pass (1024-bit key) header.d=amazon.de header.i=@amazon.de header.b=McST4tjY; arc=none smtp.client-ip=52.95.49.90 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amazon.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=amazon.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amazon.de header.i=@amazon.de header.b="McST4tjY" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1725981862; x=1757517862; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=3HArsw7M4ipywp4YAC24VV8yFEbuXaMw9heDyfTkF5M=; b=McST4tjY70U7io27HNx5d7mYs+NDWjmHR8ThlOB4cNENgRfYmN15laco EMNUxNfRYyqGq+oPwagw8dmGMusJB9LfJ7jec9+q4y4BGy2waBUZoe27j B3pWxIcDp6xZXIFAqu+BJbDBsOmTNWsbSp1bZtUbBf101q0EE5ooiGJGE s=; X-IronPort-AV: E=Sophos;i="6.10,217,1719878400"; d="scan'208";a="432460269" Received: from iad12-co-svc-p1-lb1-vlan3.amazon.com (HELO smtpout.prod.us-west-2.prod.farcaster.email.amazon.dev) ([10.43.8.6]) by smtp-border-fw-6002.iad6.amazon.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Sep 2024 15:24:17 +0000 Received: from EX19MTAUWC002.ant.amazon.com [10.0.21.151:47925] by smtpin.naws.us-west-2.prod.farcaster.email.amazon.dev [10.0.52.222:2525] with esmtp (Farcaster) id be656b80-426d-46ed-a1f5-9204a4d60b53; Tue, 10 Sep 2024 15:24:16 +0000 (UTC) X-Farcaster-Flow-ID: be656b80-426d-46ed-a1f5-9204a4d60b53 Received: from EX19D020UWC001.ant.amazon.com (10.13.138.157) by EX19MTAUWC002.ant.amazon.com (10.250.64.143) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34; Tue, 10 Sep 2024 15:24:16 +0000 Received: from EX19MTAUEA001.ant.amazon.com (10.252.134.203) by EX19D020UWC001.ant.amazon.com (10.13.138.157) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34; Tue, 10 Sep 2024 15:24:15 +0000 Received: from dev-dsk-nikwip-1b-bc9ec026.eu-west-1.amazon.com (10.253.74.52) by mail-relay.amazon.com (10.252.134.102) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34 via Frontend Transport; Tue, 10 Sep 2024 15:24:14 +0000 From: Nikolas Wipper To: Paolo Bonzini , Sean Christopherson , Vitaly Kuznetsov CC: Nicolas Saenz Julienne , Alexander Graf , James Gowans , , Thomas Gleixner , "Ingo Molnar" , Borislav Petkov , Dave Hansen , , , , , , , , Nikolas Wipper Subject: [PATCH 07/15] KVM: x86/mmu: Implement PWALK_SET_DIRTY in page walker Date: Tue, 10 Sep 2024 15:21:59 +0000 Message-ID: <20240910152207.38974-8-nikwip@amazon.de> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20240910152207.38974-1-nikwip@amazon.de> References: <20240910152207.38974-1-nikwip@amazon.de> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Implement PWALK_SET_DIRTY in the page walker. This flag allows controlling, whether the page walker will set the dirty bit after a successful page walk. If the page walk fails for any reason, the dirty flag is not set. Signed-off-by: Nikolas Wipper --- arch/x86/kvm/mmu/paging_tmpl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index eed6e2c653ba..b6897f7fbf52 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -318,6 +318,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, const int user_fault = access & PFERR_USER_MASK; const int fetch_fault = access & PFERR_FETCH_MASK; const int set_accessed = flags & PWALK_SET_ACCESSED; + const int set_dirty = flags & PWALK_SET_DIRTY; u16 errcode = 0; gpa_t real_gpa; gfn_t gfn; @@ -471,7 +472,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, if (unlikely(set_accessed && !accessed_dirty)) { ret = FNAME(update_accessed_dirty_bits)(vcpu, mmu, walker, addr, - write_fault); + write_fault && set_dirty); if (unlikely(ret < 0)) goto error; else if (ret) From patchwork Tue Sep 10 15:22:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nikolas Wipper X-Patchwork-Id: 827218 Received: from smtp-fw-9106.amazon.com (smtp-fw-9106.amazon.com [207.171.188.206]) (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 5CC641A2551; Tue, 10 Sep 2024 15:24:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=207.171.188.206 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725981897; cv=none; b=Mc7GeDe0FAqLOE7po5aAl4G05hNy8yahtmN/QwUEHWeYGTbLa6xORVx0m+6ZwUTbfpkNYuU8zO1Q44UVsF+rynIEso1feMn7GPBSgtJHehzXW7iwC9IiVQ2CAZAxRBeuS+B5yAcx164tC+RSoj73sHPZ8kJ6pLHmtWZTmd64w98= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725981897; c=relaxed/simple; bh=DKOkjI+c3qUYMLTmRQMPPaIYgXbxgKRzFDlLxE4acjM=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Nh3DlUJuEvRuhpHjNXk9ikFbr45MLor2WUJh4lrZtLBYkjAMUzDhKtwYYTwLBZs1E3LvnWKe88n+6Mm3NiVybjNcRYvGVguNctySoEm32ORCrRbkS7sTnBO84JqlRjsrAf3KDqf1lByTTNnMxfCBi+i39fqEVBr5TPbWviIz6aA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amazon.de; spf=pass smtp.mailfrom=amazon.de; dkim=pass (1024-bit key) header.d=amazon.de header.i=@amazon.de header.b=pRCWkV56; arc=none smtp.client-ip=207.171.188.206 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amazon.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=amazon.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amazon.de header.i=@amazon.de header.b="pRCWkV56" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1725981896; x=1757517896; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=8a5R4qdiyvNyIJoumEfbzn9XD7EbuO1bJFlMEMd4SNM=; b=pRCWkV56kCmDsRJsTsbHl4dtrHE++IqdY/ac5yNNtDxpwkDdlkj3b0N9 Ry5FvDOuE2nkMhOqglV0Jxvil0Cm36qKUQpump/k6jFwbfPSfNPFX3sIJ JMKNDT/LG2mfZMX19OFGgZuHR6l7j7Tv6/4WwfKinKz5Q6crV8uBHq08Y o=; X-IronPort-AV: E=Sophos;i="6.10,217,1719878400"; d="scan'208";a="758470951" Received: from pdx4-co-svc-p1-lb2-vlan2.amazon.com (HELO smtpout.prod.us-east-1.prod.farcaster.email.amazon.dev) ([10.25.36.210]) by smtp-border-fw-9106.sea19.amazon.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Sep 2024 15:24:54 +0000 Received: from EX19MTAEUC001.ant.amazon.com [10.0.17.79:12094] by smtpin.naws.eu-west-1.prod.farcaster.email.amazon.dev [10.0.13.80:2525] with esmtp (Farcaster) id 38291df8-0ba6-4211-80b0-303256e1086f; Tue, 10 Sep 2024 15:24:52 +0000 (UTC) X-Farcaster-Flow-ID: 38291df8-0ba6-4211-80b0-303256e1086f Received: from EX19D004EUA001.ant.amazon.com (10.252.50.27) by EX19MTAEUC001.ant.amazon.com (10.252.51.193) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34; Tue, 10 Sep 2024 15:24:52 +0000 Received: from EX19MTAUEA001.ant.amazon.com (10.252.134.203) by EX19D004EUA001.ant.amazon.com (10.252.50.27) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34; Tue, 10 Sep 2024 15:24:52 +0000 Received: from dev-dsk-nikwip-1b-bc9ec026.eu-west-1.amazon.com (10.253.74.52) by mail-relay.amazon.com (10.252.134.102) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34 via Frontend Transport; Tue, 10 Sep 2024 15:24:50 +0000 From: Nikolas Wipper To: Paolo Bonzini , Sean Christopherson , Vitaly Kuznetsov CC: Nicolas Saenz Julienne , Alexander Graf , James Gowans , , Thomas Gleixner , "Ingo Molnar" , Borislav Petkov , Dave Hansen , , , , , , , , Nikolas Wipper Subject: [PATCH 09/15] KVM: x86/mmu: Introduce status parameter to page walker Date: Tue, 10 Sep 2024 15:22:01 +0000 Message-ID: <20240910152207.38974-10-nikwip@amazon.de> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20240910152207.38974-1-nikwip@amazon.de> References: <20240910152207.38974-1-nikwip@amazon.de> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Introduce the status parameter to walk_addr_generic() which is used in later patches to provide the caller with information on whether setting the accessed/dirty bits succeeded. No functional change intended. Signed-off-by: Nikolas Wipper --- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/hyperv.c | 2 +- arch/x86/kvm/mmu.h | 8 +++++--- arch/x86/kvm/mmu/mmu.c | 5 +++-- arch/x86/kvm/mmu/paging_tmpl.h | 26 ++++++++++++++++---------- arch/x86/kvm/x86.c | 25 ++++++++++++++----------- 6 files changed, 40 insertions(+), 28 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index cd2c391d6a24..1c5aaf55c683 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -460,7 +460,7 @@ struct kvm_mmu { struct x86_exception *fault); gpa_t (*gva_to_gpa)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, gpa_t gva_or_gpa, u64 access, u64 flags, - struct x86_exception *exception); + struct x86_exception *exception, u16 *status); int (*sync_spte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, int i); struct kvm_mmu_root_info root; diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index b237231ace61..30d5b86bc306 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -2037,7 +2037,7 @@ static u64 kvm_hv_flush_tlb(struct kvm_vcpu *vcpu, struct kvm_hv_hcall *hc) */ if (!hc->fast && is_guest_mode(vcpu)) { hc->ingpa = translate_nested_gpa(vcpu, hc->ingpa, 0, - PWALK_SET_ALL, NULL); + PWALK_SET_ALL, NULL, NULL); if (unlikely(hc->ingpa == INVALID_GPA)) return HV_STATUS_INVALID_HYPERCALL_INPUT; } diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index 35030f6466b5..272ce93f855f 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -275,15 +275,17 @@ static inline void kvm_update_page_stats(struct kvm *kvm, int level, int count) } gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u64 access, - u64 flags, struct x86_exception *exception); + u64 flags, struct x86_exception *exception, + u16 *status); static inline gpa_t kvm_translate_gpa(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, gpa_t gpa, u64 access, u64 flags, - struct x86_exception *exception) + struct x86_exception *exception, + u16 *status) { if (mmu != &vcpu->arch.nested_mmu) return gpa; - return translate_nested_gpa(vcpu, gpa, access, flags, exception); + return translate_nested_gpa(vcpu, gpa, access, flags, exception, status); } #endif diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 50c635142bf7..2ab0437edf54 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -4103,11 +4103,12 @@ void kvm_mmu_sync_prev_roots(struct kvm_vcpu *vcpu) static gpa_t nonpaging_gva_to_gpa(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, gpa_t vaddr, u64 access, u64 flags, - struct x86_exception *exception) + struct x86_exception *exception, u16 *status) { if (exception) exception->error_code = 0; - return kvm_translate_gpa(vcpu, mmu, vaddr, access, flags, exception); + return kvm_translate_gpa(vcpu, mmu, vaddr, access, flags, exception, + status); } static bool mmio_info_in_cache(struct kvm_vcpu *vcpu, u64 addr, bool direct) diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index 2cc40fd17f53..985a19dda603 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -197,7 +197,8 @@ static inline unsigned FNAME(gpte_access)(u64 gpte) static int FNAME(update_accessed_dirty_bits)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, struct guest_walker *walker, - gpa_t addr, int write_fault) + gpa_t addr, int write_fault, + u16 *status) { unsigned level, index; pt_element_t pte, orig_pte; @@ -301,7 +302,8 @@ static inline bool FNAME(is_last_gpte)(struct kvm_mmu *mmu, */ static int FNAME(walk_addr_generic)(struct guest_walker *walker, struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, - gpa_t addr, u64 access, u64 flags) + gpa_t addr, u64 access, u64 flags, + u16 *status) { int ret; pt_element_t pte; @@ -344,6 +346,9 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, walker->fault.flags = 0; + if (status) + *status = 0; + /* * FIXME: on Intel processors, loads of the PDPTE registers for PAE paging * by the MOV to CR instruction are treated as reads and do not cause the @@ -383,7 +388,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, real_gpa = kvm_translate_gpa(vcpu, mmu, gfn_to_gpa(table_gfn), nested_access, flags, - &walker->fault); + &walker->fault, status); /* * FIXME: This can happen if emulation (for of an INS/OUTS @@ -453,8 +458,8 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, gfn += pse36_gfn_delta(pte); #endif - real_gpa = kvm_translate_gpa(vcpu, mmu, gfn_to_gpa(gfn), access, - flags, &walker->fault); + real_gpa = kvm_translate_gpa(vcpu, mmu, gfn_to_gpa(gfn), access, flags, + &walker->fault, status); if (real_gpa == INVALID_GPA) goto late_exit; @@ -473,7 +478,8 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, if (unlikely(set_accessed && !accessed_dirty)) { ret = FNAME(update_accessed_dirty_bits)(vcpu, mmu, walker, addr, - write_fault && set_dirty); + write_fault && set_dirty, + status); if (unlikely(ret < 0)) goto error; else if (ret) @@ -538,7 +544,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, */ ++walker->level; FNAME(update_accessed_dirty_bits)(vcpu, mmu, walker, addr, - false); + false, status); --walker->level; } return 0; @@ -548,7 +554,7 @@ static int FNAME(walk_addr)(struct guest_walker *walker, struct kvm_vcpu *vcpu, gpa_t addr, u64 access, u64 flags) { return FNAME(walk_addr_generic)(walker, vcpu, vcpu->arch.mmu, addr, - access, flags); + access, flags, NULL); } static bool @@ -891,7 +897,7 @@ static gpa_t FNAME(get_level1_sp_gpa)(struct kvm_mmu_page *sp) /* Note, @addr is a GPA when gva_to_gpa() translates an L2 GPA to an L1 GPA. */ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, gpa_t addr, u64 access, u64 flags, - struct x86_exception *exception) + struct x86_exception *exception, u16 *status) { struct guest_walker walker; gpa_t gpa = INVALID_GPA; @@ -902,7 +908,7 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, WARN_ON_ONCE((addr >> 32) && mmu == vcpu->arch.walk_mmu); #endif - r = FNAME(walk_addr_generic)(&walker, vcpu, mmu, addr, access, flags); + r = FNAME(walk_addr_generic)(&walker, vcpu, mmu, addr, access, flags, status); if (r) { gpa = gfn_to_gpa(walker.gfn); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 32e81cd502ee..be696b60aba6 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1068,7 +1068,7 @@ int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3) */ real_gpa = kvm_translate_gpa(vcpu, mmu, gfn_to_gpa(pdpt_gfn), PFERR_USER_MASK | PFERR_WRITE_MASK, - PWALK_SET_ALL, NULL); + PWALK_SET_ALL, NULL, NULL); if (real_gpa == INVALID_GPA) return 0; @@ -7561,7 +7561,8 @@ void kvm_get_segment(struct kvm_vcpu *vcpu, } gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u64 access, - u64 flags, struct x86_exception *exception) + u64 flags, struct x86_exception *exception, + u16 *status) { struct kvm_mmu *mmu = vcpu->arch.mmu; gpa_t t_gpa; @@ -7570,7 +7571,8 @@ gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u64 access, /* NPT walks are always user-walks */ access |= PFERR_USER_MASK; - t_gpa = mmu->gva_to_gpa(vcpu, mmu, gpa, access, flags, exception); + t_gpa = mmu->gva_to_gpa(vcpu, mmu, gpa, access, flags, exception, + status); return t_gpa; } @@ -7582,7 +7584,7 @@ gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva, u64 access = (kvm_x86_call(get_cpl)(vcpu) == 3) ? PFERR_USER_MASK : 0; return mmu->gva_to_gpa(vcpu, mmu, gva, access, PWALK_SET_ALL, - exception); + exception, NULL); } EXPORT_SYMBOL_GPL(kvm_mmu_gva_to_gpa_read); @@ -7594,7 +7596,7 @@ gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva, u64 access = (kvm_x86_call(get_cpl)(vcpu) == 3) ? PFERR_USER_MASK : 0; access |= PFERR_WRITE_MASK; return mmu->gva_to_gpa(vcpu, mmu, gva, access, PWALK_SET_ALL, - exception); + exception, NULL); } EXPORT_SYMBOL_GPL(kvm_mmu_gva_to_gpa_write); @@ -7604,7 +7606,7 @@ gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva, { struct kvm_mmu *mmu = vcpu->arch.walk_mmu; - return mmu->gva_to_gpa(vcpu, mmu, gva, 0, PWALK_SET_ALL, exception); + return mmu->gva_to_gpa(vcpu, mmu, gva, 0, PWALK_SET_ALL, exception, NULL); } static int kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes, @@ -7617,7 +7619,7 @@ static int kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes, while (bytes) { gpa_t gpa = mmu->gva_to_gpa(vcpu, mmu, addr, access, - PWALK_SET_ALL, exception); + PWALK_SET_ALL, exception, NULL); unsigned offset = addr & (PAGE_SIZE-1); unsigned toread = min(bytes, (unsigned)PAGE_SIZE - offset); int ret; @@ -7652,7 +7654,8 @@ static int kvm_fetch_guest_virt(struct x86_emulate_ctxt *ctxt, /* Inline kvm_read_guest_virt_helper for speed. */ gpa_t gpa = mmu->gva_to_gpa(vcpu, mmu, addr, access | PFERR_FETCH_MASK, - PWALK_SET_ALL, exception); + PWALK_SET_ALL, + exception, NULL); if (unlikely(gpa == INVALID_GPA)) return X86EMUL_PROPAGATE_FAULT; @@ -7710,7 +7713,7 @@ static int kvm_write_guest_virt_helper(gva_t addr, void *val, unsigned int bytes while (bytes) { gpa_t gpa = mmu->gva_to_gpa(vcpu, mmu, addr, access, - PWALK_SET_ALL, exception); + PWALK_SET_ALL, exception, NULL); unsigned offset = addr & (PAGE_SIZE-1); unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset); int ret; @@ -7830,7 +7833,7 @@ static int vcpu_mmio_gva_to_gpa(struct kvm_vcpu *vcpu, unsigned long gva, return 1; } - *gpa = mmu->gva_to_gpa(vcpu, mmu, gva, access, PWALK_SET_ALL, exception); + *gpa = mmu->gva_to_gpa(vcpu, mmu, gva, access, PWALK_SET_ALL, exception, NULL); if (*gpa == INVALID_GPA) return -1; @@ -13651,7 +13654,7 @@ void kvm_fixup_and_inject_pf_error(struct kvm_vcpu *vcpu, gva_t gva, u16 error_c if (!(error_code & PFERR_PRESENT_MASK) || mmu->gva_to_gpa(vcpu, mmu, gva, access, PWALK_SET_ALL, - &fault) != INVALID_GPA) { + &fault, NULL) != INVALID_GPA) { /* * If vcpu->arch.walk_mmu->gva_to_gpa succeeded, the page * tables probably do not match the TLB. Just proceed From patchwork Tue Sep 10 15:22:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nikolas Wipper X-Patchwork-Id: 827217 Received: from smtp-fw-52003.amazon.com (smtp-fw-52003.amazon.com [52.119.213.152]) (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 E5FF11925B4; Tue, 10 Sep 2024 15:25:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=52.119.213.152 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725981934; cv=none; b=vCC43e28ex+AABykKcG6mk+f/kftcu7In1HWqEQkFarFADOcxGsSoSqKue5YI54xrEVXgtigMuV8hj5Zcq5sQJZjwvcqSEncHs6HiCxGj2UZPIOShYlR6KWnTbDpICXQQLVretiA2b7pfUGheTiwdXzmuHc7l0jtVOXMXyErGBo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725981934; c=relaxed/simple; bh=lwh5M10z4RNM2Da7RQPLG2d6B6aeiw/t0tqiRaPr1iw=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Aq7nhpgnKEqgaz9dbP+CtD4fyJCyiMT4azBAyukoiW+bjCz1hiLLIdWWByEUFsW2EYgYCoiupiSRcJYxoRetbi9UMnBdZREfFO6WnqhdYUqrfbcWfpWz6MefUfNxGqFScMRJkVQvROWUTDg07F5t3ErFxEG4s7+Xi6/CvTX5M/8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amazon.de; spf=pass smtp.mailfrom=amazon.de; dkim=pass (1024-bit key) header.d=amazon.de header.i=@amazon.de header.b=fmyPc+Sv; arc=none smtp.client-ip=52.119.213.152 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amazon.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=amazon.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amazon.de header.i=@amazon.de header.b="fmyPc+Sv" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1725981934; x=1757517934; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=LBFZ6gE4Eg8idRjndx3TROKSBGwrVfkZ4QZJ3iCcd00=; b=fmyPc+Sv42ljvz10vLDEpb99oxVcMkXNxj8slfOFAbfhiBAm6RBiu3sb Si/OOdCqj18Jt0xs1/j7x3cWfSQquVF3QcIdpuw0xkzUc/j9dy7ymU50J ZsLEcihw6TMOJduL3YJ7Xj3E9kbPyEWsgWEAebfZPeBcr/Uw304cc4cKr 8=; X-IronPort-AV: E=Sophos;i="6.10,217,1719878400"; d="scan'208";a="24631299" Received: from iad12-co-svc-p1-lb1-vlan3.amazon.com (HELO smtpout.prod.us-west-2.prod.farcaster.email.amazon.dev) ([10.43.8.6]) by smtp-border-fw-52003.iad7.amazon.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Sep 2024 15:25:30 +0000 Received: from EX19MTAUWB002.ant.amazon.com [10.0.38.20:1552] by smtpin.naws.us-west-2.prod.farcaster.email.amazon.dev [10.0.40.54:2525] with esmtp (Farcaster) id a5951997-5357-4874-bf9e-57a899457c9a; Tue, 10 Sep 2024 15:25:29 +0000 (UTC) X-Farcaster-Flow-ID: a5951997-5357-4874-bf9e-57a899457c9a Received: from EX19D020UWC002.ant.amazon.com (10.13.138.147) by EX19MTAUWB002.ant.amazon.com (10.250.64.231) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34; Tue, 10 Sep 2024 15:25:28 +0000 Received: from EX19MTAUWB001.ant.amazon.com (10.250.64.248) by EX19D020UWC002.ant.amazon.com (10.13.138.147) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34; Tue, 10 Sep 2024 15:25:28 +0000 Received: from dev-dsk-nikwip-1b-bc9ec026.eu-west-1.amazon.com (10.253.74.52) by mail-relay.amazon.com (10.250.64.254) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34 via Frontend Transport; Tue, 10 Sep 2024 15:25:26 +0000 From: Nikolas Wipper To: Paolo Bonzini , Sean Christopherson , Vitaly Kuznetsov CC: Nicolas Saenz Julienne , Alexander Graf , James Gowans , , Thomas Gleixner , "Ingo Molnar" , Borislav Petkov , Dave Hansen , , , , , , , , Nikolas Wipper Subject: [PATCH 11/15] KVM: x86: Introduce generic gva to gpa translation function Date: Tue, 10 Sep 2024 15:22:03 +0000 Message-ID: <20240910152207.38974-12-nikwip@amazon.de> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20240910152207.38974-1-nikwip@amazon.de> References: <20240910152207.38974-1-nikwip@amazon.de> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Introduce a function to translate gvas to gpas with the ability to control set_bit_mode, access mode and flags, as well as receive status codes. Signed-off-by: Nikolas Wipper --- arch/x86/include/asm/kvm_host.h | 3 +++ arch/x86/kvm/x86.c | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 7ac1956f6f9b..ae05e917d7ea 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -2160,6 +2160,9 @@ static inline bool kvm_mmu_unprotect_gfn_and_retry(struct kvm_vcpu *vcpu, void kvm_mmu_free_roots(struct kvm *kvm, struct kvm_mmu *mmu, ulong roots_to_free); void kvm_mmu_free_guest_mode_roots(struct kvm *kvm, struct kvm_mmu *mmu); +gpa_t kvm_mmu_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t gva, u64 access, + u64 flags, struct x86_exception *exception, + u16 *status); gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva, struct x86_exception *exception); gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva, diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index be696b60aba6..27fc71aaa1e4 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -7577,6 +7577,17 @@ gpa_t translate_nested_gpa(struct kvm_vcpu *vcpu, gpa_t gpa, u64 access, return t_gpa; } +gpa_t kvm_mmu_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t gva, u64 access, + u64 flags, struct x86_exception *exception, + u16 *status) +{ + struct kvm_mmu *mmu = vcpu->arch.walk_mmu; + + return mmu->gva_to_gpa(vcpu, mmu, gva, access, flags, exception, + status); +} +EXPORT_SYMBOL_GPL(kvm_mmu_gva_to_gpa); + gpa_t kvm_mmu_gva_to_gpa_read(struct kvm_vcpu *vcpu, gva_t gva, struct x86_exception *exception) { From patchwork Tue Sep 10 15:22:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nikolas Wipper X-Patchwork-Id: 827216 Received: from smtp-fw-6002.amazon.com (smtp-fw-6002.amazon.com [52.95.49.90]) (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 0962819AD81; Tue, 10 Sep 2024 15:26:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=52.95.49.90 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725981972; cv=none; b=YyjULrgjz0s/rJrzFfkJTWA5wuBYNTbGUWpzp+hr3JPkVLQPmgjE6vgFHJt8X34+0pzclWABiI9b8XgP07Wl1EZrrUxiTjfIM8Emfjc9rGVRHdxl04+Gwit9GjPitXU7h8Wux2oFUZKkUflVGjhqzITHrlnzI7qT+gZvc27Go/Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725981972; c=relaxed/simple; bh=++HidJlPLgLwaU/8+cLxxidpjLOQ5iKZF0hGZox10tc=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=NpBRFKmYfv9Vy67Rv/IPZgL7G9DyXMkGugBWovm8+WI8WYiIjN6j6a0VeEMqEHQCIgirTPrlGIFhc9pVuLzFJAZ7Re97Y2lHYVATK/5y2/lzQjr2C4vnOUyoUromjhbkF40eINAl1OKZesv/pEQx2wf+wYl4W+Nk4hwhMbNgTp0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amazon.de; spf=pass smtp.mailfrom=amazon.de; dkim=pass (1024-bit key) header.d=amazon.de header.i=@amazon.de header.b=u9duiKmX; arc=none smtp.client-ip=52.95.49.90 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amazon.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=amazon.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amazon.de header.i=@amazon.de header.b="u9duiKmX" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1725981971; x=1757517971; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=qyhv+EAHgrh/iCvCQUdCsSUgOa9xa1Wd76nhgoQDloY=; b=u9duiKmX9pqi7g76xsw1uex/8eLRjCIQExkQ61YVv10C8vPtLateKtV7 JzDr5Y5pj/EqIYyJ4fXbysWZJwEMgKKKyXBwgityWjWtHoSJG5rhpllgw M6oal1X7MYuwXeZHg4YT+XCtOjAZhPZEMc/ErDv3nswmSeM/GEE4WvHTA 0=; X-IronPort-AV: E=Sophos;i="6.10,217,1719878400"; d="scan'208";a="432460735" Received: from iad12-co-svc-p1-lb1-vlan3.amazon.com (HELO smtpout.prod.us-west-2.prod.farcaster.email.amazon.dev) ([10.43.8.6]) by smtp-border-fw-6002.iad6.amazon.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Sep 2024 15:26:08 +0000 Received: from EX19MTAUWB001.ant.amazon.com [10.0.21.151:10936] by smtpin.naws.us-west-2.prod.farcaster.email.amazon.dev [10.0.38.253:2525] with esmtp (Farcaster) id c98c2613-8b3f-4de2-87d9-65fcddd7723f; Tue, 10 Sep 2024 15:26:06 +0000 (UTC) X-Farcaster-Flow-ID: c98c2613-8b3f-4de2-87d9-65fcddd7723f Received: from EX19D020UWC004.ant.amazon.com (10.13.138.149) by EX19MTAUWB001.ant.amazon.com (10.250.64.248) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34; Tue, 10 Sep 2024 15:26:06 +0000 Received: from EX19MTAUWA001.ant.amazon.com (10.250.64.204) by EX19D020UWC004.ant.amazon.com (10.13.138.149) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34; Tue, 10 Sep 2024 15:26:06 +0000 Received: from dev-dsk-nikwip-1b-bc9ec026.eu-west-1.amazon.com (10.253.74.52) by mail-relay.amazon.com (10.250.64.204) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34 via Frontend Transport; Tue, 10 Sep 2024 15:26:03 +0000 From: Nikolas Wipper To: Paolo Bonzini , Sean Christopherson , Vitaly Kuznetsov CC: Nicolas Saenz Julienne , Alexander Graf , James Gowans , , Thomas Gleixner , "Ingo Molnar" , Borislav Petkov , Dave Hansen , , , , , , , , Nikolas Wipper Subject: [PATCH 13/15] KVM: Add KVM_TRANSLATE2 stub Date: Tue, 10 Sep 2024 15:22:05 +0000 Message-ID: <20240910152207.38974-14-nikwip@amazon.de> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20240910152207.38974-1-nikwip@amazon.de> References: <20240910152207.38974-1-nikwip@amazon.de> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add stub function for the KVM_TRANSLATE2 ioctl, as well as generic parameter verification. In a later commit, the ioctl will be properly implemented for x86. Signed-off-by: Nikolas Wipper --- include/linux/kvm_host.h | 2 ++ virt/kvm/kvm_main.c | 41 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index c78017fd2907..de6557794735 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1492,6 +1492,8 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu); int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, struct kvm_translation *tr); +int kvm_arch_vcpu_ioctl_translate2(struct kvm_vcpu *vcpu, + struct kvm_translation2 *tr); int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs); int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index d51357fd28d7..c129dc0b0485 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -4442,6 +4442,32 @@ static int kvm_vcpu_pre_fault_memory(struct kvm_vcpu *vcpu, } #endif +int __weak kvm_arch_vcpu_ioctl_translate2(struct kvm_vcpu *vcpu, + struct kvm_translation2 *tr) +{ + return -EINVAL; +} + +static int kvm_vcpu_ioctl_translate2(struct kvm_vcpu *vcpu, + struct kvm_translation2 *tr) +{ + /* Don't allow FORCE_SET_ACCESSED and SET_BITS without SET_ACCESSED */ + if (!(tr->flags & KVM_TRANSLATE_FLAGS_SET_ACCESSED) && + (tr->flags & KVM_TRANSLATE_FLAGS_FORCE_SET_ACCESSED || + tr->flags & KVM_TRANSLATE_FLAGS_SET_DIRTY)) + return -EINVAL; + + if (tr->flags & KVM_TRANSLATE_FLAGS_SET_DIRTY && + !(tr->access & KVM_TRANSLATE_ACCESS_WRITE)) + return -EINVAL; + + if (tr->flags & ~KVM_TRANSLATE_FLAGS_ALL || + tr->access & ~KVM_TRANSLATE_ACCESS_ALL) + return -EINVAL; + + return kvm_arch_vcpu_ioctl_translate2(vcpu, tr); +} + static long kvm_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -4585,6 +4611,21 @@ static long kvm_vcpu_ioctl(struct file *filp, r = 0; break; } + case KVM_TRANSLATE2: { + struct kvm_translation2 tr; + + r = -EFAULT; + if (copy_from_user(&tr, argp, sizeof(tr))) + goto out; + r = kvm_vcpu_ioctl_translate2(vcpu, &tr); + if (r) + goto out; + r = -EFAULT; + if (copy_to_user(argp, &tr, sizeof(tr))) + goto out; + r = 0; + break; + } case KVM_SET_GUEST_DEBUG: { struct kvm_guest_debug dbg; From patchwork Tue Sep 10 15:22:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Nikolas Wipper X-Patchwork-Id: 827215 Received: from smtp-fw-6001.amazon.com (smtp-fw-6001.amazon.com [52.95.48.154]) (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 D54E919ABB6; Tue, 10 Sep 2024 15:26:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=52.95.48.154 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725982022; cv=none; b=R3wbnWUL81BwAY3jvGgAeamhSHYmjR2HIyM8LgBmt32zOl0YOAyjURN2YKv0oNg9Eus7AH6OXLM19pQVjOx8gP6M6oBAo1SCLyethY3fXEz9vJf987I8UiOd/FFeM6DNtAlwKtFHGFgd56KK3KwhPAELbxw/owL7kDr9aAu/W9Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725982022; c=relaxed/simple; bh=9cKjl9ygprSgUGbTu9ou8VxGIYHVdp/M2hZ72Ih7JLQ=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=hH0tXPNdOeB85+ywSiEdjWVOvAyL2eqSLPkBu8yAJM8AYqMfn3uFBhoogQ0JC6fxlnT+qNkJKlKPurXHP64HSG3aWUd2YxU8gXaHdt3rdVCZp2+rFAkcyH7/BmUcoEREkQqWopfLtUSASABrwiEaf/TLSRJ/EcdzCIf8EVszeqQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amazon.de; spf=pass smtp.mailfrom=amazon.de; dkim=pass (1024-bit key) header.d=amazon.de header.i=@amazon.de header.b=TJV73I0G; arc=none smtp.client-ip=52.95.48.154 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=amazon.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=amazon.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=amazon.de header.i=@amazon.de header.b="TJV73I0G" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amazon.de; i=@amazon.de; q=dns/txt; s=amazon201209; t=1725982021; x=1757518021; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=9cKjl9ygprSgUGbTu9ou8VxGIYHVdp/M2hZ72Ih7JLQ=; b=TJV73I0GBfGkLuPTE4hHaboHrbBDasOLYNmBzZEqMMC86wJF0RZ9+Q/N rNYY23kAbr57xHORC4RsIBNwQsmydXYVNfMgKSr7Xd6c3OMekvas8ZDt5 5KVR0JmDt013iL/GMN3fYy3S7+upHHRa24GM7X0sr57D9ZRFcbmiO2p3n U=; X-IronPort-AV: E=Sophos;i="6.10,217,1719878400"; d="scan'208";a="422886989" Received: from iad12-co-svc-p1-lb1-vlan2.amazon.com (HELO smtpout.prod.us-west-2.prod.farcaster.email.amazon.dev) ([10.43.8.2]) by smtp-border-fw-6001.iad6.amazon.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Sep 2024 15:26:50 +0000 Received: from EX19MTAUWA002.ant.amazon.com [10.0.38.20:61190] by smtpin.naws.us-west-2.prod.farcaster.email.amazon.dev [10.0.23.84:2525] with esmtp (Farcaster) id dd07028c-4466-4584-b915-58f08c541f19; Tue, 10 Sep 2024 15:26:49 +0000 (UTC) X-Farcaster-Flow-ID: dd07028c-4466-4584-b915-58f08c541f19 Received: from EX19D020UWA002.ant.amazon.com (10.13.138.222) by EX19MTAUWA002.ant.amazon.com (10.250.64.202) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34; Tue, 10 Sep 2024 15:26:41 +0000 Received: from EX19MTAUEA001.ant.amazon.com (10.252.134.203) by EX19D020UWA002.ant.amazon.com (10.13.138.222) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34; Tue, 10 Sep 2024 15:26:41 +0000 Received: from dev-dsk-nikwip-1b-bc9ec026.eu-west-1.amazon.com (10.253.74.52) by mail-relay.amazon.com (10.252.134.102) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) id 15.2.1258.34 via Frontend Transport; Tue, 10 Sep 2024 15:26:39 +0000 From: Nikolas Wipper To: Paolo Bonzini , Sean Christopherson , Vitaly Kuznetsov CC: Nicolas Saenz Julienne , Alexander Graf , James Gowans , , Thomas Gleixner , "Ingo Molnar" , Borislav Petkov , Dave Hansen , , , , , , , , Nikolas Wipper Subject: [PATCH 15/15] KVM: selftests: Add test for KVM_TRANSLATE2 Date: Tue, 10 Sep 2024 15:22:07 +0000 Message-ID: <20240910152207.38974-16-nikwip@amazon.de> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20240910152207.38974-1-nikwip@amazon.de> References: <20240910152207.38974-1-nikwip@amazon.de> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Add selftest for KVM_TRANSLATE2. There are four different subtests. A basic translate test that checks whether access permissions are handled correctly. A set bits test, that checks whether the accessed and dirty bits are set correctly. An errors test, that checks negative cases of the flags. And a fuzzy test on random guest page tables. The tests currently use x86 specific paging code, so generalising them for more platforms is hard. Once other architectures implement KVM_TRANSLATE2 they need to be split into arch specific and agnostic parts. Signed-off-by: Nikolas Wipper --- tools/testing/selftests/kvm/Makefile | 1 + .../selftests/kvm/x86_64/kvm_translate2.c | 310 ++++++++++++++++++ 2 files changed, 311 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86_64/kvm_translate2.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 45cb70c048bb..5bb2db679658 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -81,6 +81,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/hyperv_svm_test TEST_GEN_PROGS_x86_64 += x86_64/hyperv_tlb_flush TEST_GEN_PROGS_x86_64 += x86_64/kvm_clock_test TEST_GEN_PROGS_x86_64 += x86_64/kvm_pv_test +TEST_GEN_PROGS_x86_64 += x86_64/kvm_translate2 TEST_GEN_PROGS_x86_64 += x86_64/monitor_mwait_test TEST_GEN_PROGS_x86_64 += x86_64/nested_exceptions_test TEST_GEN_PROGS_x86_64 += x86_64/platform_info_test diff --git a/tools/testing/selftests/kvm/x86_64/kvm_translate2.c b/tools/testing/selftests/kvm/x86_64/kvm_translate2.c new file mode 100644 index 000000000000..607af6376243 --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/kvm_translate2.c @@ -0,0 +1,310 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test for x86 KVM_TRANSLATE2 + * + * Copyright © 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * This work is licensed under the terms of the GNU GPL, version 2. + * + */ +#include +#include +#include +#include +#include + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" + +#define CHECK_ACCESSED_BIT(pte, set, start) \ + ({ \ + for (int _i = start; _i <= PG_LEVEL_512G; _i++) { \ + if (set) \ + TEST_ASSERT( \ + (*pte[_i] & PTE_ACCESSED_MASK) != 0, \ + "Page not marked accessed on level %i", \ + _i); \ + else \ + TEST_ASSERT( \ + (*pte[_i] & PTE_ACCESSED_MASK) == 0, \ + "Page marked accessed on level %i", \ + _i); \ + } \ + }) + +#define CHECK_DIRTY_BIT(pte, set) \ + ({ \ + if (set) \ + TEST_ASSERT((*pte[PG_LEVEL_4K] & PTE_DIRTY_MASK) != 0, \ + "Page not marked dirty"); \ + else \ + TEST_ASSERT((*pte[PG_LEVEL_4K] & PTE_DIRTY_MASK) == 0, \ + "Page marked dirty"); \ + }) + +enum point_of_failure { + pof_none, + pof_ioctl, + pof_page_walk, + pof_no_failure, +}; + +struct kvm_translation2 kvm_translate2(struct kvm_vcpu *vcpu, uint64_t vaddr, + int flags, int access, + enum point_of_failure pof) +{ + struct kvm_translation2 tr = { .linear_address = vaddr, + .flags = flags, + .access = access }; + + int res = ioctl(vcpu->fd, KVM_TRANSLATE2, &tr); + + if (pof == pof_none) + return tr; + + if (pof == pof_ioctl) { + TEST_ASSERT(res == -1, "ioctl didn't fail"); + return tr; + } + + TEST_ASSERT(res != -1, "ioctl failed"); + TEST_ASSERT((pof != pof_page_walk) == tr.valid, + "Page walk fail with code %u", tr.error_code); + + return tr; +} + +void test_translate(struct kvm_vm *vm, struct kvm_vcpu *vcpu, int index, + uint64_t *pte[PG_LEVEL_NUM], vm_vaddr_t vaddr) +{ + struct kvm_translation2 translation; + int access = index; + + printf("%s - write: %u, user: %u, exec: %u ...\t", + __func__, + (access & KVM_TRANSLATE_ACCESS_WRITE) >> 0, + (access & KVM_TRANSLATE_ACCESS_USER) >> 1, + (access & KVM_TRANSLATE_ACCESS_EXEC) >> 2); + + uint64_t mask = PTE_WRITABLE_MASK | PTE_USER_MASK | PTE_NX_MASK; + uint64_t new_value = 0; + + if (access & KVM_TRANSLATE_ACCESS_WRITE) + new_value |= PTE_WRITABLE_MASK; + if (access & KVM_TRANSLATE_ACCESS_USER) + new_value |= PTE_USER_MASK; + if (!(access & KVM_TRANSLATE_ACCESS_EXEC)) + new_value |= PTE_NX_MASK; + + for (int i = PG_LEVEL_4K; i <= PG_LEVEL_512G; i++) + *pte[i] = (*pte[i] & ~mask) | new_value; + + translation = kvm_translate2(vcpu, vaddr, 0, access, pof_no_failure); + + TEST_ASSERT_EQ(*pte[PG_LEVEL_4K] & GENMASK(51, 12), + translation.physical_address); + + /* Check configurations that have extra access requirements */ + for (int i = 0; i < 8; i++) { + int case_access = i; + + if ((case_access | access) <= access) + continue; + + translation = kvm_translate2(vcpu, vaddr, 0, case_access, + pof_page_walk); + TEST_ASSERT_EQ(translation.error_code, + KVM_TRANSLATE_FAULT_PRIVILEGE_VIOLATION); + } + + /* Clear accessed bits */ + for (int i = PG_LEVEL_4K; i <= PG_LEVEL_512G; i++) + *pte[i] &= ~PTE_ACCESSED_MASK; + + printf("[ok]\n"); +} + +void test_set_bits(struct kvm_vm *vm, struct kvm_vcpu *vcpu, + uint64_t *pte[PG_LEVEL_NUM], vm_vaddr_t vaddr) +{ + printf("%s ...\t", __func__); + + /* Sanity checks */ + CHECK_ACCESSED_BIT(pte, false, PG_LEVEL_4K); + CHECK_DIRTY_BIT(pte, false); + + kvm_translate2(vcpu, vaddr, 0, 0, pof_no_failure); + + CHECK_ACCESSED_BIT(pte, false, PG_LEVEL_4K); + CHECK_DIRTY_BIT(pte, false); + + kvm_translate2(vcpu, vaddr, KVM_TRANSLATE_FLAGS_SET_ACCESSED, 0, + pof_no_failure); + + CHECK_ACCESSED_BIT(pte, true, PG_LEVEL_4K); + CHECK_DIRTY_BIT(pte, false); + + kvm_translate2(vcpu, vaddr, + KVM_TRANSLATE_FLAGS_SET_ACCESSED | KVM_TRANSLATE_FLAGS_SET_DIRTY, + KVM_TRANSLATE_ACCESS_WRITE, pof_no_failure); + + CHECK_ACCESSED_BIT(pte, true, PG_LEVEL_4K); + CHECK_DIRTY_BIT(pte, true); + + printf("[ok]\n"); +} + +void test_errors(struct kvm_vm *vm, struct kvm_vcpu *vcpu, + uint64_t *pte[PG_LEVEL_NUM], vm_vaddr_t vaddr) +{ + struct kvm_translation2 tr; + + printf("%s ...\t", __func__); + + /* Set an unsupported access bit */ + kvm_translate2(vcpu, vaddr, 0, (1 << 3), pof_ioctl); + kvm_translate2(vcpu, vaddr, KVM_TRANSLATE_FLAGS_SET_DIRTY, 0, pof_ioctl); + kvm_translate2(vcpu, vaddr, KVM_TRANSLATE_FLAGS_FORCE_SET_ACCESSED, 0, + pof_ioctl); + + /* Try to translate a non-canonical address */ + tr = kvm_translate2(vcpu, 0b101ull << 60, 0, 0, pof_page_walk); + TEST_ASSERT_EQ(tr.error_code, KVM_TRANSLATE_FAULT_INVALID_GVA); + + uint64_t old_pte = *pte[PG_LEVEL_2M]; + + *pte[PG_LEVEL_2M] |= (1ull << 51); /* Set a reserved bit */ + + tr = kvm_translate2(vcpu, vaddr, 0, 0, pof_page_walk); + TEST_ASSERT_EQ(tr.error_code, KVM_TRANSLATE_FAULT_RESERVED_BITS); + + *pte[PG_LEVEL_2M] &= ~(1ull << 51); + + /* Create a GPA that's definitely not mapped */ + *pte[PG_LEVEL_2M] |= GENMASK(35, 13); + + tr = kvm_translate2(vcpu, vaddr, 0, 0, pof_page_walk); + TEST_ASSERT_EQ(tr.error_code, KVM_TRANSLATE_FAULT_INVALID_GPA); + + *pte[PG_LEVEL_2M] = old_pte; + + /* Clear accessed bits */ + for (int i = PG_LEVEL_4K; i <= PG_LEVEL_512G; i++) + *pte[i] &= ~PTE_ACCESSED_MASK; + + /* Try translating a non-present page */ + *pte[PG_LEVEL_4K] &= ~PTE_PRESENT_MASK; + + tr = kvm_translate2( + vcpu, vaddr, + KVM_TRANSLATE_FLAGS_SET_ACCESSED | + KVM_TRANSLATE_FLAGS_FORCE_SET_ACCESSED, 0, + pof_page_walk); + TEST_ASSERT_EQ(tr.error_code, KVM_TRANSLATE_FAULT_NOT_PRESENT); + CHECK_ACCESSED_BIT(pte, true, PG_LEVEL_2M); + + *pte[PG_LEVEL_4K] |= PTE_PRESENT_MASK; + + /* + * Try setting accessed/dirty bits on a PTE that is in read-only memory + */ + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, 0x80000000, 1, 4, + KVM_MEM_READONLY); + + uint64_t *addr = addr_gpa2hva(vm, 0x80000000); + uint64_t *base = addr_gpa2hva(vm, *pte[PG_LEVEL_2M] & GENMASK(51, 12)); + + /* Copy the entire page table */ + for (int i = 0; i < 0x200; i += 1) + addr[i] = (base[i] & ~PTE_ACCESSED_MASK) | PTE_PRESENT_MASK; + + uint64_t old_2m = *pte[PG_LEVEL_2M]; + *pte[PG_LEVEL_2M] &= ~GENMASK(51, 12); + *pte[PG_LEVEL_2M] |= 0x80000000; + + tr = kvm_translate2(vcpu, vaddr, + KVM_TRANSLATE_FLAGS_SET_ACCESSED | + KVM_TRANSLATE_FLAGS_SET_DIRTY | + KVM_TRANSLATE_FLAGS_FORCE_SET_ACCESSED, + KVM_TRANSLATE_ACCESS_WRITE, pof_no_failure); + + TEST_ASSERT(!tr.set_bits_succeeded, "Page not read-only"); + + *pte[PG_LEVEL_2M] = old_2m; + + printf("[ok]\n"); +} + +/* Test page walker stability, by trying to translate with garbage PTEs */ +void test_fuzz(struct kvm_vm *vm, struct kvm_vcpu *vcpu, + uint64_t *pte[PG_LEVEL_NUM], vm_vaddr_t vaddr) +{ + printf("%s ...\t", __func__); + + /* Test gPTEs that point to random addresses */ + for (int level = PG_LEVEL_4K; level < PG_LEVEL_NUM; level++) { + for (int i = 0; i < 10000; i++) { + uint64_t random_address = random() % GENMASK(29, 0) << 12; + *pte[level] = (*pte[level] & ~GENMASK(51, 12)) | random_address; + + kvm_translate2(vcpu, vaddr, + KVM_TRANSLATE_FLAGS_SET_ACCESSED | + KVM_TRANSLATE_FLAGS_SET_DIRTY | + KVM_TRANSLATE_FLAGS_FORCE_SET_ACCESSED, + 0, pof_none); + } + } + + /* Test gPTEs with completely random values */ + for (int level = PG_LEVEL_4K; level < PG_LEVEL_NUM; level++) { + for (int i = 0; i < 10000; i++) { + *pte[level] = random(); + + kvm_translate2(vcpu, vaddr, + KVM_TRANSLATE_FLAGS_SET_ACCESSED | + KVM_TRANSLATE_FLAGS_SET_DIRTY | + KVM_TRANSLATE_FLAGS_FORCE_SET_ACCESSED, + 0, pof_none); + } + } + + printf("[ok]\n"); +} + +int main(int argc, char *argv[]) +{ + uint64_t *pte[PG_LEVEL_NUM]; + struct kvm_vcpu *vcpu; + struct kvm_sregs regs; + struct kvm_vm *vm; + vm_vaddr_t vaddr; + int page_level; + + TEST_REQUIRE(kvm_has_cap(KVM_CAP_TRANSLATE2)); + + vm = vm_create_with_one_vcpu(&vcpu, NULL); + + vaddr = __vm_vaddr_alloc_page(vm, MEM_REGION_TEST_DATA); + + for (page_level = PG_LEVEL_512G; page_level > PG_LEVEL_NONE; + page_level--) { + pte[page_level] = __vm_get_page_table_entry(vm, vaddr, &page_level); + } + + /* Enable WP bit in cr0, so kernel accesses uphold write protection */ + vcpu_ioctl(vcpu, KVM_GET_SREGS, ®s); + regs.cr0 |= 1 << 16; + vcpu_ioctl(vcpu, KVM_SET_SREGS, ®s); + + for (int index = 0; index < 8; index++) + test_translate(vm, vcpu, index, pte, vaddr); + + test_set_bits(vm, vcpu, pte, vaddr); + test_errors(vm, vcpu, pte, vaddr); + test_fuzz(vm, vcpu, pte, vaddr); + + kvm_vm_free(vm); + + return 0; +}