Received: by 2002:a05:6a10:d5a5:0:0:0:0 with SMTP id gn37csp4936746pxb; Tue, 5 Oct 2021 13:43:14 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwHWOO63l+g5iIB07ZfNRN8O4juEpUHTz74muqS2Qt9Lr9kEI9e8s7cEiMugHF18dLHf2FN X-Received: by 2002:a17:90b:1993:: with SMTP id mv19mr6169090pjb.76.1633466594688; Tue, 05 Oct 2021 13:43:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1633466594; cv=none; d=google.com; s=arc-20160816; b=L3nnRNrbFj86nbXJmkat44E96DM/Lmq83bC/TYM6lQO2eIHD2wzzIGDyKbvN0j13Rs zf4B0jOLCyqZkbHOq/E1SpbEiTFd0zW1cAPlvJBfarDIUhIc3FthLnOVyBCr4cIykkdj vTzCeYlD/pSudlDGlvl6wRUjyCQM5yC3eoTijhdhO2QWNwUx2MwQTii9PjvYxR6LRfRz QIonfBQmv5fs+e0SrqGVr+g8ntTQ7hSGb6dsqxvB4dbuRdR6VM1ac8KWRt5qaz+DDNPE +54oMfK8JiD00rGN2kyFbcyDehFiKs+mgqnvkeja+VUavVBy1TANKuqrZzGk3F09waHY do2Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=XF1aB3LTmpm1I4tq//VmHQYze+duKbvVx8+hRB2aChU=; b=p2O6u29/77R/E9xhecXOnU3w+z634sftE/mqD20kgVtt9O9fJx8bqWetLAj/9456+i RsxVdVn3IIzImX/FSqQwSE6/tpzv2GhH6xJ+2psbXVP4II7fqfcJLM7bN/hewoPHl5tE hcdbUAGGAxogSH9VrsG6FkOUhrsw9cHW2LVkCkE4HdjVt3yM9DitXTf1w7C2rDHfj4XF thkrZK5KU+yHoJ/LHQkMkwIc/vnxpcILIJvSoh+0sRi45JkKcVNAdEdbCUjTzQVPDICj /26H0a7PzC17JBPhI7oLjV0TVmjWzjgdpDNcaSy4Vg0TdErHmRDz6AO/8IYCUCuV3avb ZZGA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id 35si6189946pgq.480.2021.10.05.13.43.01; Tue, 05 Oct 2021 13:43:14 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236063AbhJEUn7 (ORCPT + 99 others); Tue, 5 Oct 2021 16:43:59 -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 S235673AbhJEUnv (ORCPT ); Tue, 5 Oct 2021 16:43:51 -0400 X-IronPort-AV: E=McAfee;i="6200,9189,10128"; a="289354598" X-IronPort-AV: E=Sophos;i="5.85,349,1624345200"; d="scan'208";a="289354598" 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:42:00 -0700 X-IronPort-AV: E=Sophos;i="5.85,349,1624345200"; d="scan'208";a="523979531" 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:59 -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 04/10] x86/tdx: Handle early IO operations Date: Tue, 5 Oct 2021 13:41:30 -0700 Message-Id: <20211005204136.1812078-5-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 From: Andi Kleen Add an early #VE handler to convert early port IOs into TDCALLs. 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 TDCALLs to call the host. To support port IO in early boot code, add a minimal support in early exception handlers. This is similar to what AMD SEV does. This is mainly to support early_printk's serial driver, as well as potentially the VGA driver (although it is expected not to be used). The early handler only does IO calls and nothing else, and anything that goes wrong results in a normal early exception panic. It cannot share the code paths with the normal #VE handler because it needs to avoid using trace calls or printk. This early handler allows us to use the normal in*/out* macros without patching them for every driver. Since, there is no expectation that early port IO is performance critical, the #VE emulation cost is worth the simplicity benefit of not patching out port IO usage in early code. There are also no concerns with nesting, since there should be no NMIs this early. Signed-off-by: Andi Kleen Reviewed-by: Dan Williams Reviewed-by: Andi Kleen Signed-off-by: Kuppuswamy Sathyanarayanan --- Changes since v6: * None Changes since v5: * None Changes since v4: * Changed order of variable declaration in tdx_early_io() Changes since v3: * None Changes since v2: * None Changes since v1: * Renamed tdx_early_io() to tdg_early_io(). arch/x86/include/asm/tdx.h | 4 +++ arch/x86/kernel/head64.c | 3 ++ arch/x86/kernel/tdx.c | 60 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index 02f6036ef85f..e8ddc7c5bbab 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -74,6 +74,8 @@ unsigned long tdx_get_ve_info(struct ve_info *ve); int tdx_handle_virtualization_exception(struct pt_regs *regs, struct ve_info *ve); +bool tdx_early_handle_ve(struct pt_regs *regs); + /* * To support I/O port access in decompressor or early kernel init * code, since #VE exception handler cannot be used, use paravirt @@ -137,6 +139,8 @@ do { \ #define is_tdx_guest 0ULL static inline void tdx_early_init(void) { }; +static inline bool tdx_early_handle_ve(struct pt_regs *regs) { return false; } + #endif /* CONFIG_INTEL_TDX_GUEST */ #if defined(CONFIG_KVM_GUEST) && defined(CONFIG_INTEL_TDX_GUEST) diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index 97ce0d037387..281d360e9ca4 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c @@ -410,6 +410,9 @@ void __init do_early_exception(struct pt_regs *regs, int trapnr) trapnr == X86_TRAP_VC && handle_vc_boot_ghcb(regs)) return; + if (trapnr == X86_TRAP_VE && tdx_early_handle_ve(regs)) + return; + early_fixup_exception(regs, trapnr); } diff --git a/arch/x86/kernel/tdx.c b/arch/x86/kernel/tdx.c index 11e367228e96..4cbffcb737d9 100644 --- a/arch/x86/kernel/tdx.c +++ b/arch/x86/kernel/tdx.c @@ -10,6 +10,11 @@ /* TDX Module call Leaf IDs */ #define TDGETVEINFO 3 +#define VE_IS_IO_OUT(exit_qual) (((exit_qual) & 8) ? 0 : 1) +#define VE_GET_IO_SIZE(exit_qual) (((exit_qual) & 7) + 1) +#define VE_GET_PORT_NUM(exit_qual) ((exit_qual) >> 16) +#define VE_IS_IO_STRING(exit_qual) ((exit_qual) & 16 ? 1 : 0) + /* * Allocate it in the data region to avoid zeroing it during * BSS initialization. It is mainly used in cc_platform_has() @@ -228,6 +233,61 @@ int tdx_handle_virtualization_exception(struct pt_regs *regs, return ret; } +/* + * Handle early IO, mainly for early printks serial output. + * This avoids anything that doesn't work early on, like tracing + * or printks, by calling the low level functions directly. Any + * problems are handled by falling back to a standard early exception. + * + * Assumes the IO instruction was using ax, which is enforced + * by the standard io.h macros. + */ +static __init bool tdx_early_io(struct pt_regs *regs, u32 exit_qual) +{ + struct tdx_hypercall_output outh; + int out, size, port, ret; + bool string; + u64 mask; + + string = VE_IS_IO_STRING(exit_qual); + + /* I/O strings ops are unrolled at build time. */ + if (string) + return 0; + + out = VE_IS_IO_OUT(exit_qual); + size = VE_GET_IO_SIZE(exit_qual); + port = VE_GET_PORT_NUM(exit_qual); + mask = GENMASK(8 * size, 0); + + ret = _tdx_hypercall(EXIT_REASON_IO_INSTRUCTION, size, out, port, + regs->ax, &outh); + if (!out && !ret) { + regs->ax &= ~mask; + regs->ax |= outh.r11 & mask; + } + + return !ret; +} + +/* + * Early #VE exception handler. Just used to handle port IOs + * for early_printk. If anything goes wrong handle it like + * a normal early exception. + */ +__init bool tdx_early_handle_ve(struct pt_regs *regs) +{ + struct ve_info ve; + + if (tdx_get_ve_info(&ve)) + return false; + + if (ve.exit_reason == EXIT_REASON_IO_INSTRUCTION) + return tdx_early_io(regs, ve.exit_qual); + + return false; +} + void __init tdx_early_init(void) { is_tdx_guest_init(); -- 2.25.1