Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/tdx: Port I/O: Add early boot support

TDX guests cannot do port I/O directly. The TDX module triggers a #VE
exception to let the guest kernel emulate port I/O by converting them
into TDCALLs to call the host.

But before IDT handlers are set up, port I/O cannot be emulated using
normal kernel #VE handlers. To support the #VE-based emulation during
this boot window, add a minimal early #VE handler support in early
exception handlers. This is similar to what AMD SEV does. This is
mainly to support earlyprintk's serial driver, as well as potentially
the VGA driver.

The early handler only supports I/O-related #VE exceptions. Unhandled or
failed exceptions will be handled via early_fixup_exceptions() (like
normal exception failures). At runtime I/O-related #VE exceptions (along
with other types) handled by virt_exception_kernel().

Signed-off-by: Andi Kleen <ak@linux.intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com>
Link: https://lkml.kernel.org/r/20220405232939.73860-19-kirill.shutemov@linux.intel.com

authored by

Andi Kleen and committed by
Dave Hansen
32e72854 03149948

+23
+16
arch/x86/coco/tdx/tdx.c
··· 418 418 return handle_out(regs, size, port); 419 419 } 420 420 421 + /* 422 + * Early #VE exception handler. Only handles a subset of port I/O. 423 + * Intended only for earlyprintk. If failed, return false. 424 + */ 425 + __init bool tdx_early_handle_ve(struct pt_regs *regs) 426 + { 427 + struct ve_info ve; 428 + 429 + tdx_get_ve_info(&ve); 430 + 431 + if (ve.exit_reason != EXIT_REASON_IO_INSTRUCTION) 432 + return false; 433 + 434 + return handle_io(regs, ve.exit_qual); 435 + } 436 + 421 437 void tdx_get_ve_info(struct ve_info *ve) 422 438 { 423 439 struct tdx_module_output out;
+4
arch/x86/include/asm/tdx.h
··· 65 65 66 66 void tdx_safe_halt(void); 67 67 68 + bool tdx_early_handle_ve(struct pt_regs *regs); 69 + 68 70 #else 69 71 70 72 static inline void tdx_early_init(void) { }; 71 73 static inline void tdx_safe_halt(void) { }; 74 + 75 + static inline bool tdx_early_handle_ve(struct pt_regs *regs) { return false; } 72 76 73 77 #endif /* CONFIG_INTEL_TDX_GUEST */ 74 78
+3
arch/x86/kernel/head64.c
··· 417 417 trapnr == X86_TRAP_VC && handle_vc_boot_ghcb(regs)) 418 418 return; 419 419 420 + if (trapnr == X86_TRAP_VE && tdx_early_handle_ve(regs)) 421 + return; 422 + 420 423 early_fixup_exception(regs, trapnr); 421 424 } 422 425