From nobody Fri Sep 25 15:16:45 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.14]) (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 D665C3546C2; Thu, 10 Sep 2026 22:34:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.14 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789079668; cv=none; b=s3nO4L9hMeOs/HjEuX9YuCduoIIXTQ15DSBPGgPvEVAftSS1RuJVZUw9T1H2b4WRrUsSRomTQ83rFiZfFx4bm8o0ZBTp4n5F5hxIP9LubTA3kBKYH/3VeK6yKu4ECkMsZCe8lUyVRrZqXMVlfp12t82355DBPVuGTIoqFcWRCQ8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789079668; c=relaxed/simple; bh=AaborA1YqhltsyazAzMXTF21qWXPXv//Ui1djDJE8Fs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=puPAUOG1+z3AdVPAyNtSDRZJPIWmWbHgtdFboCf3mSYMfxu//GDI253o5SH821aESgmMk+Uwg1e0DVpr6vKe1iG9BKRkmSZopUkASNjvS6htNc4hiDC5eU/xLrNbnpyAOi15H84/SWtlKRr8Gll+UPqr1LmK1zX7C5w1Nhycr3o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=U+I7yEMo; arc=none smtp.client-ip=198.175.65.14 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="U+I7yEMo" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1789079667; x=1820615667; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=AaborA1YqhltsyazAzMXTF21qWXPXv//Ui1djDJE8Fs=; b=U+I7yEMo015r0WtQpaS0ZvvxWjYDXcP3dkx0xVu+U7p9O7EVvJCduFFj SBFHCFaNWRIuGutFm3/eIkYOEndD6gDk3igGabApptb+LALOBpr4YQp6Z djbHVt/dodrZQ9hM/b+kAtBurC5hLxk2UqGujrtYNd5lo8zqCGvQ33tsH chpR4ICPuVoIcY6FfkNhxtx1u5pjYYDgmC/fnJ7SIUEGEUHg6CH9fJS5l rRy4iZBc9glOTsXX1IEXJp5p0gTIrHX9JameJm+duKohgIpE+6iaMlXFw eB5yM0tHeVsg0tnh8if9aJfWi0a8vGnMeI1+Bfgr9LRqJIuyhRTk05rkV w==; X-CSE-ConnectionGUID: ea5X0oBTTDGnQ2sTa6FHAw== X-CSE-MsgGUID: WuEcCHSkRGO/HjbApo664g== X-IronPort-AV: E=McAfee;i="6800,10657,11901"; a="93407824" X-IronPort-AV: E=Sophos;i="6.27,96,1787036400"; d="scan'208";a="93407824" Received: from orviesa002.jf.intel.com ([10.64.159.142]) by orvoesa106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Sep 2026 15:34:25 -0700 X-CSE-ConnectionGUID: m46k88v2T020yUiLz3uBLg== X-CSE-MsgGUID: Wt5imkNhRoW5I82HZ+WggQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.27,96,1787036400"; d="scan'208";a="301647428" Received: from vverma7-desk1.amr.corp.intel.com (HELO [192.168.1.200]) ([10.125.111.227]) by orviesa002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Sep 2026 15:34:25 -0700 From: Vishal Verma Date: Thu, 10 Sep 2026 16:34:08 -0600 Subject: [PATCH 1/2] x86/tdx: Move port I/O definitions to a shared header Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260910-b4-tdx_earlyprintk_tdcalls-v1-1-4b2b1bf9001b@intel.com> References: <20260910-b4-tdx_earlyprintk_tdcalls-v1-0-4b2b1bf9001b@intel.com> In-Reply-To: <20260910-b4-tdx_earlyprintk_tdcalls-v1-0-4b2b1bf9001b@intel.com> To: x86@kernel.org, Dave Hansen , Kiryl Shutsemau , Rick Edgecombe Cc: linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev, kvm@vger.kernel.org, Vishal Verma X-Mailer: b4 0.16-dev-62088 X-Developer-Signature: v=1; a=openpgp-sha256; l=3016; i=vishal.l.verma@intel.com; h=from:subject:message-id; bh=AaborA1YqhltsyazAzMXTF21qWXPXv//Ui1djDJE8Fs=; b=owGbwMvMwCXGf25diOft7jLG02pJDFmLDfL9t0zLSRDlZVBOLAgXmlQlUCTLPk/huN6TqIuTv XTWC/p2lLIwiHExyIopsvzd85HxmNz2fJ7ABEeYOaxMIEMYuDgFYCKRNowMHx2+fD18NHV7gsSH yN3L/boe8R8TeD05qH/eXpPSda6yaxj++0y1Y1Ffofv9UMJSd43zBd+8bKcFfNy5XDJ9xq89OtG HWQE= X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF In preparation for switching early_printk to use direct TDVMCALLs for I/O, factor out the PORT_READ and PORT_WRITE definitions from arch/x86/coco/tdx/tdx.c into arch/x86/include/asm/shared/tdx.h, and namespace them with 'TDVMCALL_'. The decompressor also used 0/1 literals in its tdx_io_{in,out} helpers - switch those to use the new definitions. Signed-off-by: Vishal Verma Cc: Rick Edgecombe Reviewed-by: Kiryl Shutsemau (Meta) --- arch/x86/include/asm/shared/tdx.h | 4 ++++ arch/x86/boot/compressed/tdx.c | 4 ++-- arch/x86/coco/tdx/tdx.c | 8 ++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/x86/include/asm/shared/tdx.h b/arch/x86/include/asm/share= d/tdx.h index f20e91d7ac35..25429d515cc5 100644 --- a/arch/x86/include/asm/shared/tdx.h +++ b/arch/x86/include/asm/shared/tdx.h @@ -84,6 +84,10 @@ #define TDVMCALL_STATUS_ALIGN_ERROR 0x8000000000000002ULL #define TDVMCALL_STATUS_SUBFUNC_UNSUPPORTED 0x8000000000000003ULL =20 +/* TDG.VP.VMCALL direction, passed in R13 */ +#define TDVMCALL_PORT_READ 0 +#define TDVMCALL_PORT_WRITE 1 + /* * Bitmasks of exposed registers (with VMM). */ diff --git a/arch/x86/boot/compressed/tdx.c b/arch/x86/boot/compressed/tdx.c index 8451d6a1030c..ed278bac3c93 100644 --- a/arch/x86/boot/compressed/tdx.c +++ b/arch/x86/boot/compressed/tdx.c @@ -22,7 +22,7 @@ static inline unsigned int tdx_io_in(int size, u16 port) .r10 =3D TDX_HYPERCALL_STANDARD, .r11 =3D hcall_func(EXIT_REASON_IO_INSTRUCTION), .r12 =3D size, - .r13 =3D 0, + .r13 =3D TDVMCALL_PORT_READ, .r14 =3D port, }; =20 @@ -38,7 +38,7 @@ static inline void tdx_io_out(int size, u16 port, u32 val= ue) .r10 =3D TDX_HYPERCALL_STANDARD, .r11 =3D hcall_func(EXIT_REASON_IO_INSTRUCTION), .r12 =3D size, - .r13 =3D 1, + .r13 =3D TDVMCALL_PORT_WRITE, .r14 =3D port, .r15 =3D value, }; diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index f904a636d449..7d1a93ee2534 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -24,10 +24,6 @@ #define EPT_READ 0 #define EPT_WRITE 1 =20 -/* Port I/O direction */ -#define PORT_READ 0 -#define PORT_WRITE 1 - /* See Exit Qualification for I/O Instructions in VMX documentation */ #define VE_IS_IO_IN(e) ((e) & BIT(3)) #define VE_GET_IO_SIZE(e) (((e) & GENMASK(2, 0)) + 1) @@ -691,7 +687,7 @@ static bool handle_in(struct pt_regs *regs, int size, i= nt port) .r10 =3D TDX_HYPERCALL_STANDARD, .r11 =3D hcall_func(EXIT_REASON_IO_INSTRUCTION), .r12 =3D size, - .r13 =3D PORT_READ, + .r13 =3D TDVMCALL_PORT_READ, .r14 =3D port, }; bool success; @@ -720,7 +716,7 @@ static bool handle_out(struct pt_regs *regs, int size, = int port) * "TDG.VP.VMCALL". */ return !_tdx_hypercall(hcall_func(EXIT_REASON_IO_INSTRUCTION), size, - PORT_WRITE, port, regs->ax & mask); + TDVMCALL_PORT_WRITE, port, regs->ax & mask); } =20 /* --=20 2.55.0 From nobody Fri Sep 25 15:16:45 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.14]) (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 21CCC355055; Thu, 10 Sep 2026 22:34:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.14 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789079669; cv=none; b=nlHBCiLvfScFzKIiu4R4CAtRtg/QiJpF71igvy1t+87cqKQLvMr4Q5AMgFtNo2V8YbEOPchUaXOX0T96AIgNXvgPv/vCFkrd4qBprlwJLwXe2+e+50UEw3Ank/rK7rCpgwQAYZtJmmXoJAeXtLGn/aDK29XAWjbvEWez1rirqMk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789079669; c=relaxed/simple; bh=iDQI1L4c2kG8qVvCvgA+Osxg0WS1jnZM/F8nmdFfJnY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=ffmwVabEvivC/+TSmZ7iTMU3b9ZBGA0HlkriXDxzYPQ22cD8+d9RszlB+VXNcWUdeiVJ+WrTDYGfuzlZr9HQIgRmHnglu2IkxWC+faSChaO5toDQ/RpCEUpUzCtCSD/KIV3RihYNVZUCjhNUfZv56LuSGpauaXLnFVU4NpA7/vs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com; spf=pass smtp.mailfrom=intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=lVxaM8O/; arc=none smtp.client-ip=198.175.65.14 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="lVxaM8O/" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1789079667; x=1820615667; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=iDQI1L4c2kG8qVvCvgA+Osxg0WS1jnZM/F8nmdFfJnY=; b=lVxaM8O/ie4gcZFD5hbEhxv1G+9GDnkGeh3AJYc1S9Hp7twrN1dt31/v 3bS8Di7VBnNaPjcWZ/DZLfafizzHCn1jPedVFWI7myHNvs28PJdFeRdk9 WHD0ALLFPfvo/sWC7LSNkw2hZvi/NDQNmgJutBQetEdZZJCEwR7OM+se4 QUa4An0YBgbl9p600/eg73r/m1jMAXAze+BpbeOCpvBBt9hm0pT2YK2P7 A1N+LM9qFWHNJ1zdVUKM1uz8ZTloyxiEMjL3ir75s+AK5fiXKIkvrWmr6 u7Eys1ySE4FF50UfJYuwYu/jlEthxABmLbirbWlfmtdrixSiQW+PDHFn7 w==; X-CSE-ConnectionGUID: TyYa11YtSZ6lEmXzzcmtKw== X-CSE-MsgGUID: EEolN1lLT6S5ENkS7FpKyw== X-IronPort-AV: E=McAfee;i="6800,10657,11901"; a="93407827" X-IronPort-AV: E=Sophos;i="6.27,96,1787036400"; d="scan'208";a="93407827" Received: from orviesa002.jf.intel.com ([10.64.159.142]) by orvoesa106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Sep 2026 15:34:25 -0700 X-CSE-ConnectionGUID: iLufNV7XQ++i3myguPqdYg== X-CSE-MsgGUID: w0xWTo24RUq7/p19f9CV3Q== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.27,96,1787036400"; d="scan'208";a="301647431" Received: from vverma7-desk1.amr.corp.intel.com (HELO [192.168.1.200]) ([10.125.111.227]) by orviesa002-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Sep 2026 15:34:25 -0700 From: Vishal Verma Date: Thu, 10 Sep 2026 16:34:09 -0600 Subject: [PATCH 2/2] x86/early_printk: Avoid #VE emulation for TDX guest serial output Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260910-b4-tdx_earlyprintk_tdcalls-v1-2-4b2b1bf9001b@intel.com> References: <20260910-b4-tdx_earlyprintk_tdcalls-v1-0-4b2b1bf9001b@intel.com> In-Reply-To: <20260910-b4-tdx_earlyprintk_tdcalls-v1-0-4b2b1bf9001b@intel.com> To: x86@kernel.org, Dave Hansen , Kiryl Shutsemau , Rick Edgecombe Cc: linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev, kvm@vger.kernel.org, Vishal Verma X-Mailer: b4 0.16-dev-62088 X-Developer-Signature: v=1; a=openpgp-sha256; l=4064; i=vishal.l.verma@intel.com; h=from:subject:message-id; bh=iDQI1L4c2kG8qVvCvgA+Osxg0WS1jnZM/F8nmdFfJnY=; b=owGbwMvMwCXGf25diOft7jLG02pJDFmLDQoyrjxcdOeqneHNnMyeO5FvjR6u06ydGV74NtjG6 MHti4vjO0pZGMS4GGTFFFn+7vnIeExuez5PYIIjzBxWJpAhDFycAjARw0OMDOsL167hU1M+Nm9B ao/v0WmRYfsu7PFYvziT9UyrQ9b6p6aMDJOTDh3s7Xv/+sotwQ7ReVOrLA0LrrClH3334HRL8VL 181wA X-Developer-Key: i=vishal.l.verma@intel.com; a=openpgp; fpr=F8682BE134C67A12332A2ED07AFA61BEA3B84DFF A TDX guest cannot execute port I/O instructions directly, but earlyprintk's serial console still issues plain inb()/outb() and lets each one fault into the #VE handler to be emulated as a TDVMCALL. While that works, it is a roundabout way to get a character out. early_serial_putc() polls the LSR, and then writes a byte, but since the TDX guest can't directly do port I/O, a #VE exception is raised. The #VE handler must call TDG.VP.VEINFO.GET to find out what faulted, and then it can issue the TDVMCALL that does the actual work. This makes #VE a functional mechanism for doing I/O, which is not desirable, is unnecessarily complicated and fragile, and results in twice the number of calls into the TDX module. Instead, issue the TDVMCALL directly. In early_printk.c, port access is routed through static calls so the MMIO console can substitute its own accessors. Add a TDX pair and swap them in the same way. Note that the output does not appear any earlier - "earlyprintk=3D" is an early_param(), so the console is still registered from parse_early_param(). This only changes how the bytes leave the guest once it is up. LLMs were used under supervision to create this patch, to help understand the scope and mechanisms, create testing instrumentation (throwaway) to count #VEs before/after the change, and to drive lab machines to do this testing. Signed-off-by: Vishal Verma --- arch/x86/kernel/early_printk.c | 48 ++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 48 insertions(+) diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c index cba75306e5b6..4a70799cd80a 100644 --- a/arch/x86/kernel/early_printk.c +++ b/arch/x86/kernel/early_printk.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include =20 /* Simple VGA output */ #define VGABASE (__ISA_IO_base + 0xb8000) @@ -111,6 +113,48 @@ ANNOTATE_NOENDBR_SYM(io_serial_out); DEFINE_STATIC_CALL(serial_in, io_serial_in); DEFINE_STATIC_CALL(serial_out, io_serial_out); =20 +#ifdef CONFIG_INTEL_TDX_GUEST +/* + * A TDX guest cannot execute port I/O instructions, so ask the VMM to do = it. + */ +static __noendbr unsigned int tdx_serial_in(unsigned long addr, int offset) +{ + struct tdx_module_args args =3D { + .r10 =3D TDX_HYPERCALL_STANDARD, + .r11 =3D hcall_func(EXIT_REASON_IO_INSTRUCTION), + .r12 =3D 1, /* One byte */ + .r13 =3D TDVMCALL_PORT_READ, + .r14 =3D addr + offset, + }; + + if (__tdx_hypercall(&args)) + return UINT_MAX; + + return args.r11; +} +ANNOTATE_NOENDBR_SYM(tdx_serial_in); + +static __noendbr void tdx_serial_out(unsigned long addr, int offset, int v= alue) +{ + /* One byte */ + _tdx_hypercall(hcall_func(EXIT_REASON_IO_INSTRUCTION), 1, + TDVMCALL_PORT_WRITE, addr + offset, value); +} +ANNOTATE_NOENDBR_SYM(tdx_serial_out); + +/* Substitute the hypercall accessors, but only in an actual TDX guest */ +static __init void early_serial_tdx_init(void) +{ + if (!cpu_feature_enabled(X86_FEATURE_TDX_GUEST)) + return; + + static_call_update(serial_in, tdx_serial_in); + static_call_update(serial_out, tdx_serial_out); +} +#else +static inline void early_serial_tdx_init(void) { } +#endif /* CONFIG_INTEL_TDX_GUEST */ + static int early_serial_putc(unsigned char ch) { unsigned timeout =3D 0xffff; @@ -160,6 +204,9 @@ static __init void early_serial_init(char *s) unsigned long baud =3D DEFAULT_BAUD; char *e; =20 + /* Must be before early_serial_hw_init(), which does port I/O */ + early_serial_tdx_init(); + if (*s =3D=3D ',') ++s; =20 @@ -323,6 +370,7 @@ static __init void early_pci_serial_init(char *s) */ if ((bar0 & PCI_BASE_ADDRESS_SPACE) =3D=3D PCI_BASE_ADDRESS_SPACE_IO) { /* it is IO mapped */ + early_serial_tdx_init(); early_serial_base =3D bar0 & PCI_BASE_ADDRESS_IO_MASK; write_pci_config(bus, slot, func, PCI_COMMAND, cmdreg|PCI_COMMAND_IO); --=20 2.55.0