From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id BDDF1C433F5 for ; Tue, 5 Oct 2021 20:42:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9D922613D5 for ; Tue, 5 Oct 2021 20:42:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235999AbhJEUn6 (ORCPT ); Tue, 5 Oct 2021 16:43:58 -0400 Received: from mga07.intel.com ([134.134.136.100]:11157 "EHLO mga07.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229920AbhJEUnu (ORCPT ); Tue, 5 Oct 2021 16:43:50 -0400 X-IronPort-AV: E=McAfee;i="6200,9189,10128"; a="289354596" X-IronPort-AV: E=Sophos;i="5.85,349,1624345200"; d="scan'208";a="289354596" Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Oct 2021 13:41:59 -0700 X-IronPort-AV: E=Sophos;i="5.85,349,1624345200"; d="scan'208";a="523979490" Received: from alyee-mobl.amr.corp.intel.com (HELO skuppusw-desk1.amr.corp.intel.com) ([10.254.5.222]) by fmsmga008-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 Oct 2021 13:41:58 -0700 From: Kuppuswamy Sathyanarayanan To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , x86@kernel.org, Paolo Bonzini , David Hildenbrand , Andrea Arcangeli , Josh Poimboeuf , "H . Peter Anvin" Cc: Dave Hansen , Tony Luck , Dan Williams , Andi Kleen , Kirill Shutemov , Sean Christopherson , Kuppuswamy Sathyanarayanan , linux-kernel@vger.kernel.org Subject: [PATCH v7 03/10] x86/tdx: Handle port I/O in decompression code Date: Tue, 5 Oct 2021 13:41:29 -0700 Message-Id: <20211005204136.1812078-4-sathyanarayanan.kuppuswamy@linux.intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20211005204136.1812078-1-sathyanarayanan.kuppuswamy@linux.intel.com> References: <20211005204136.1812078-1-sathyanarayanan.kuppuswamy@linux.intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add support to replace IN/OUT instructions in decompression code with TDX IO hypercalls. TDX cannot do port IO directly. The TDX module triggers a #VE exception to let the guest kernel to emulate port I/O, by converting them into TDX hypercalls to call the host. But for the really early code in the decompressor, #VE cannot be used because the IDT needed for handling the exception is not set-up, and some other infrastructure needed by the handler is missing. So to support port IO in decompressor code, directly replace IN/OUT instructions with TDX IO hypercalls. This can be easily achieved by modifying __in/__out macros. Also, since TDX IO hypercall requires an IO size parameter, modify __in/__out macros to accept size as input parameter. Reviewed-by: Andi Kleen Reviewed-by: Dan Williams Signed-off-by: Kuppuswamy Sathyanarayanan --- Changes since v6: * None Changes since v5: * None Changes since v4: * Replaced in/out with IN/OUT. * Fixed typo in commit log and comments. * Renamed tdg_* prefix with tdx_* Changes since v3: * None Changes since v2: * None Changes since v1: * Modified tdg_{in/out} to adapt to API changes of __tdx_hypercall(). * Removed !CONFIG_INTEL_TDX_GUEST comment in #if else case. arch/x86/boot/compressed/Makefile | 1 + arch/x86/boot/compressed/tdcall.S | 3 ++ arch/x86/include/asm/io.h | 9 ++--- arch/x86/include/asm/tdx.h | 60 +++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 arch/x86/boot/compressed/tdcall.S diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 22a2a6cc2ab4..1bfe30ebadbe 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -99,6 +99,7 @@ endif vmlinux-objs-$(CONFIG_ACPI) += $(obj)/acpi.o vmlinux-objs-$(CONFIG_INTEL_TDX_GUEST) += $(obj)/tdx.o +vmlinux-objs-$(CONFIG_INTEL_TDX_GUEST) += $(obj)/tdcall.o vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o efi-obj-$(CONFIG_EFI_STUB) = $(objtree)/drivers/firmware/efi/libstub/lib.a diff --git a/arch/x86/boot/compressed/tdcall.S b/arch/x86/boot/compressed/tdcall.S new file mode 100644 index 000000000000..aafadc136c88 --- /dev/null +++ b/arch/x86/boot/compressed/tdcall.S @@ -0,0 +1,3 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include "../../kernel/tdcall.S" diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h index 3647a96238a9..fa6aa43e5dc3 100644 --- a/arch/x86/include/asm/io.h +++ b/arch/x86/include/asm/io.h @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -272,25 +273,25 @@ static inline bool sev_key_active(void) { return false; } #endif /* CONFIG_AMD_MEM_ENCRYPT */ #ifndef __out -#define __out(bwl, bw) \ +#define __out(bwl, bw, sz) \ asm volatile("out" #bwl " %" #bw "0, %w1" : : "a"(value), "Nd"(port)) #endif #ifndef __in -#define __in(bwl, bw) \ +#define __in(bwl, bw, sz) \ asm volatile("in" #bwl " %w1, %" #bw "0" : "=a"(value) : "Nd"(port)) #endif #define BUILDIO(bwl, bw, type) \ static inline void out##bwl(unsigned type value, int port) \ { \ - __out(bwl, bw); \ + __out(bwl, bw, sizeof(type)); \ } \ \ static inline unsigned type in##bwl(int port) \ { \ unsigned type value; \ - __in(bwl, bw); \ + __in(bwl, bw, sizeof(type)); \ return value; \ } \ \ diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index ebb97e082376..02f6036ef85f 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -5,6 +5,8 @@ #include #include +#include +#include #define TDX_CPUID_LEAF_ID 0x21 #define TDX_HYPERCALL_STANDARD 0 @@ -72,6 +74,64 @@ unsigned long tdx_get_ve_info(struct ve_info *ve); int tdx_handle_virtualization_exception(struct pt_regs *regs, struct ve_info *ve); +/* + * To support I/O port access in decompressor or early kernel init + * code, since #VE exception handler cannot be used, use paravirt + * model to implement __in/__out macros which will in turn be used + * by in{b,w,l}()/out{b,w,l} I/O helper macros used in kernel. Details + * about __in/__out macro usage can be found in arch/x86/include/asm/io.h + */ +#ifdef BOOT_COMPRESSED_MISC_H + +bool early_is_tdx_guest(void); + +/* + * Helper function used for making hypercall for "in" + * instruction. It will be called from __in IO macro + * If IO is failed, it will return all 1s. + */ +static inline unsigned int tdx_io_in(int size, int port) +{ + struct tdx_hypercall_output out = {0}; + + __tdx_hypercall(TDX_HYPERCALL_STANDARD, EXIT_REASON_IO_INSTRUCTION, + size, 0, port, 0, &out); + + return out.r10 ? UINT_MAX : out.r11; +} + +/* + * Helper function used for making hypercall for "out" + * instruction. It will be called from __out IO macro + */ +static inline void tdx_io_out(int size, int port, u64 value) +{ + struct tdx_hypercall_output out = {0}; + + __tdx_hypercall(TDX_HYPERCALL_STANDARD, EXIT_REASON_IO_INSTRUCTION, + size, 1, port, value, &out); +} + +#define __out(bwl, bw, sz) \ +do { \ + if (early_is_tdx_guest()) { \ + tdx_io_out(sz, port, value); \ + } else { \ + asm volatile("out" #bwl " %" #bw "0, %w1" : : \ + "a"(value), "Nd"(port)); \ + } \ +} while (0) +#define __in(bwl, bw, sz) \ +do { \ + if (early_is_tdx_guest()) { \ + value = tdx_io_in(sz, port); \ + } else { \ + asm volatile("in" #bwl " %w1, %" #bw "0" : \ + "=a"(value) : "Nd"(port)); \ + } \ +} while (0) +#endif + #else #define is_tdx_guest 0ULL -- 2.25.1