* [PATCH] x86/tdx: Remove the early #VE handler
@ 2026-09-10 18:28 Vishal Verma
2026-09-10 20:39 ` Edgecombe, Rick P
0 siblings, 1 reply; 7+ messages in thread
From: Vishal Verma @ 2026-09-10 18:28 UTC (permalink / raw)
To: x86, Dave Hansen, Rick Edgecombe, Kiryl Shutsemau
Cc: linux-kernel, linux-coco, kvm, Vishal Verma, Andi Kleen
tdx_early_handle_ve() emulates port I/O for #VEs taken before
idt_setup_early_traps() installs the real #VE gate. Per commit
32e72854fa5f ("x86/tdx: Port I/O: Add early boot support"), it exists to
support earlyprintk's serial driver.
"earlyprintk=" and "earlycon=" are both early_param() handlers, so no
console can be registered before parse_early_param(), which runs from
setup_arch(), after idt_setup_early_traps() has replaced the early IDT.
Nothing in the window between idt_setup_early_handler() and
idt_setup_early_traps() does port I/O, so this emulation doesn't ever
get called.
Remove the handler. Any #VE in the early window now falls through to
early_fixup_exception(), as it previously did for #VEs that were not I/O
instructions.
Found with the help of an LLM observing that the real IDT is installed
before parse_early_param(). LLMs were also used to verify this. On a TDX
guest booted with earlyprintk, a counter added to tdx_early_handle_ve()
for testing remained 0 after boot.
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Rick Edgecombe <rick.p.edgecombe@intel.com>
---
arch/x86/include/asm/tdx.h | 4 ----
arch/x86/coco/tdx/tdx.c | 22 ----------------------
arch/x86/kernel/head64.c | 3 ---
3 files changed, 29 deletions(-)
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index 89e97d5761d8..495154a7d77d 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -75,8 +75,6 @@ bool tdx_handle_virt_exception(struct pt_regs *regs, struct ve_info *ve);
void tdx_halt(void);
-bool tdx_early_handle_ve(struct pt_regs *regs);
-
int tdx_mcall_get_report0(u8 *reportdata, u8 *tdreport);
int tdx_mcall_extend_rtmr(u8 index, u8 *data);
@@ -91,8 +89,6 @@ void __init tdx_dump_td_ctls(u64 td_ctls);
static inline void tdx_early_init(void) { };
static inline void tdx_halt(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/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c
index f904a636d449..9bc78cb28710 100644
--- a/arch/x86/coco/tdx/tdx.c
+++ b/arch/x86/coco/tdx/tdx.c
@@ -755,28 +755,6 @@ static int handle_io(struct pt_regs *regs, struct ve_info *ve)
return ve_instr_len(ve);
}
-/*
- * Early #VE exception handler. Only handles a subset of port I/O.
- * Intended only for earlyprintk. If failed, return false.
- */
-__init bool tdx_early_handle_ve(struct pt_regs *regs)
-{
- struct ve_info ve;
- int insn_len;
-
- tdx_get_ve_info(&ve);
-
- if (ve.exit_reason != EXIT_REASON_IO_INSTRUCTION)
- return false;
-
- insn_len = handle_io(regs, &ve);
- if (insn_len < 0)
- return false;
-
- regs->ip += insn_len;
- return true;
-}
-
void tdx_get_ve_info(struct ve_info *ve)
{
struct tdx_module_args args = {};
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index fd28b53dbac5..7b8b13f45454 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -166,9 +166,6 @@ 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);
}
---
base-commit: df2908090cda368b01ff43709f51890076c56157
change-id: 20260828-b4-tdx_remove_early_ve_handler-7c1463cf0f63
Best regards,
--
Vishal Verma <vishal.l.verma@intel.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] x86/tdx: Remove the early #VE handler
2026-09-10 18:28 [PATCH] x86/tdx: Remove the early #VE handler Vishal Verma
@ 2026-09-10 20:39 ` Edgecombe, Rick P
2026-09-11 0:15 ` Verma, Vishal L
2026-09-11 10:37 ` Kiryl Shutsemau
0 siblings, 2 replies; 7+ messages in thread
From: Edgecombe, Rick P @ 2026-09-10 20:39 UTC (permalink / raw)
To: Verma, Vishal L, kas, x86, dave.hansen; +Cc: kvm, linux-coco, linux-kernel, ak
On Thu, 2026-09-10 at 12:28 -0600, Vishal Verma wrote:
> tdx_early_handle_ve() emulates port I/O for #VEs taken before
> idt_setup_early_traps() installs the real #VE gate. Per commit
> 32e72854fa5f ("x86/tdx: Port I/O: Add early boot support"), it exists to
> support earlyprintk's serial driver.
>
> "earlyprintk=" and "earlycon=" are both early_param() handlers, so no
> console can be registered before parse_early_param(), which runs from
> setup_arch(), after idt_setup_early_traps() has replaced the early IDT.
> Nothing in the window between idt_setup_early_handler() and
> idt_setup_early_traps() does port I/O, so this emulation doesn't ever
> get called.
>
> Remove the handler. Any #VE in the early window now falls through to
> early_fixup_exception(), as it previously did for #VEs that were not I/O
> instructions.
>
> Found with the help of an LLM observing that the real IDT is installed
> before parse_early_param(). LLMs were also used to verify this. On a TDX
> guest booted with earlyprintk, a counter added to tdx_early_handle_ve()
> for testing remained 0 after boot.
The logic and history makes sense to me. I'm surprised early printk is not
useful this early.
Reviewed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
I see do_early_exception() -> handle_vc_boot_ghcb() has some early_printks().
Presumably these don't work for the same reason?
>
> Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
> Cc: Andi Kleen <ak@linux.intel.com>
> Cc: Rick Edgecombe <rick.p.edgecombe@intel.com>
> ---
> arch/x86/include/asm/tdx.h | 4 ----
> arch/x86/coco/tdx/tdx.c | 22 ----------------------
> arch/x86/kernel/head64.c | 3 ---
> 3 files changed, 29 deletions(-)
>
> diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
> index 89e97d5761d8..495154a7d77d 100644
> --- a/arch/x86/include/asm/tdx.h
> +++ b/arch/x86/include/asm/tdx.h
> @@ -75,8 +75,6 @@ bool tdx_handle_virt_exception(struct pt_regs *regs, struct ve_info *ve);
>
> void tdx_halt(void);
>
> -bool tdx_early_handle_ve(struct pt_regs *regs);
> -
> int tdx_mcall_get_report0(u8 *reportdata, u8 *tdreport);
>
> int tdx_mcall_extend_rtmr(u8 index, u8 *data);
> @@ -91,8 +89,6 @@ void __init tdx_dump_td_ctls(u64 td_ctls);
> static inline void tdx_early_init(void) { };
> static inline void tdx_halt(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/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c
> index f904a636d449..9bc78cb28710 100644
> --- a/arch/x86/coco/tdx/tdx.c
> +++ b/arch/x86/coco/tdx/tdx.c
> @@ -755,28 +755,6 @@ static int handle_io(struct pt_regs *regs, struct ve_info *ve)
> return ve_instr_len(ve);
> }
>
> -/*
> - * Early #VE exception handler. Only handles a subset of port I/O.
> - * Intended only for earlyprintk. If failed, return false.
> - */
> -__init bool tdx_early_handle_ve(struct pt_regs *regs)
> -{
> - struct ve_info ve;
> - int insn_len;
> -
> - tdx_get_ve_info(&ve);
> -
> - if (ve.exit_reason != EXIT_REASON_IO_INSTRUCTION)
> - return false;
> -
> - insn_len = handle_io(regs, &ve);
> - if (insn_len < 0)
> - return false;
> -
> - regs->ip += insn_len;
> - return true;
> -}
> -
> void tdx_get_ve_info(struct ve_info *ve)
> {
> struct tdx_module_args args = {};
> diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
> index fd28b53dbac5..7b8b13f45454 100644
> --- a/arch/x86/kernel/head64.c
> +++ b/arch/x86/kernel/head64.c
> @@ -166,9 +166,6 @@ 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);
> }
>
>
> ---
> base-commit: df2908090cda368b01ff43709f51890076c56157
> change-id: 20260828-b4-tdx_remove_early_ve_handler-7c1463cf0f63
>
> Best regards,
> --
> Vishal Verma <vishal.l.verma@intel.com>
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] x86/tdx: Remove the early #VE handler
2026-09-10 20:39 ` Edgecombe, Rick P
@ 2026-09-11 0:15 ` Verma, Vishal L
2026-09-11 10:37 ` Kiryl Shutsemau
1 sibling, 0 replies; 7+ messages in thread
From: Verma, Vishal L @ 2026-09-11 0:15 UTC (permalink / raw)
To: kas, Edgecombe, Rick P, x86, dave.hansen
Cc: kvm, linux-coco, linux-kernel, ak
On Thu, 2026-09-10 at 20:39 +0000, Edgecombe, Rick P wrote:
> On Thu, 2026-09-10 at 12:28 -0600, Vishal Verma wrote:
> > tdx_early_handle_ve() emulates port I/O for #VEs taken before
> > idt_setup_early_traps() installs the real #VE gate. Per commit
> > 32e72854fa5f ("x86/tdx: Port I/O: Add early boot support"), it exists to
> > support earlyprintk's serial driver.
> >
> > "earlyprintk=" and "earlycon=" are both early_param() handlers, so no
> > console can be registered before parse_early_param(), which runs from
> > setup_arch(), after idt_setup_early_traps() has replaced the early IDT.
> > Nothing in the window between idt_setup_early_handler() and
> > idt_setup_early_traps() does port I/O, so this emulation doesn't ever
> > get called.
> >
> > Remove the handler. Any #VE in the early window now falls through to
> > early_fixup_exception(), as it previously did for #VEs that were not I/O
> > instructions.
> >
> > Found with the help of an LLM observing that the real IDT is installed
> > before parse_early_param(). LLMs were also used to verify this. On a TDX
> > guest booted with earlyprintk, a counter added to tdx_early_handle_ve()
> > for testing remained 0 after boot.
>
> The logic and history makes sense to me. I'm surprised early printk is not
> useful this early.
>
> Reviewed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
>
> I see do_early_exception() -> handle_vc_boot_ghcb() has some early_printks().
> Presumably these don't work for the same reason?
>
>
Thanks for the review!
For handle_vc_boot_ghcb() - that's a #VC handler. #VE gets patched into
the idt_table via early_idts[], but #VC doesn't until later - in
trap_init(). So early #VCs still need to be handled here.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] x86/tdx: Remove the early #VE handler
2026-09-10 20:39 ` Edgecombe, Rick P
2026-09-11 0:15 ` Verma, Vishal L
@ 2026-09-11 10:37 ` Kiryl Shutsemau
2026-09-11 15:24 ` Edgecombe, Rick P
1 sibling, 1 reply; 7+ messages in thread
From: Kiryl Shutsemau @ 2026-09-11 10:37 UTC (permalink / raw)
To: Edgecombe, Rick P
Cc: Verma, Vishal L, x86, dave.hansen, kvm, linux-coco, linux-kernel, ak
On Thu, Sep 10, 2026 at 08:39:47PM +0000, Edgecombe, Rick P wrote:
> On Thu, 2026-09-10 at 12:28 -0600, Vishal Verma wrote:
> > tdx_early_handle_ve() emulates port I/O for #VEs taken before
> > idt_setup_early_traps() installs the real #VE gate. Per commit
> > 32e72854fa5f ("x86/tdx: Port I/O: Add early boot support"), it exists to
> > support earlyprintk's serial driver.
> >
> > "earlyprintk=" and "earlycon=" are both early_param() handlers, so no
> > console can be registered before parse_early_param(), which runs from
> > setup_arch(), after idt_setup_early_traps() has replaced the early IDT.
> > Nothing in the window between idt_setup_early_handler() and
> > idt_setup_early_traps() does port I/O, so this emulation doesn't ever
> > get called.
> >
> > Remove the handler. Any #VE in the early window now falls through to
> > early_fixup_exception(), as it previously did for #VEs that were not I/O
> > instructions.
> >
> > Found with the help of an LLM observing that the real IDT is installed
> > before parse_early_param(). LLMs were also used to verify this. On a TDX
> > guest booted with earlyprintk, a counter added to tdx_early_handle_ve()
> > for testing remained 0 after boot.
>
> The logic and history makes sense to me. I'm surprised early printk is not
> useful this early.
>
> Reviewed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
Rick, could you actually test it?
Are we sure there's no other port I/O in before idt_setup_early_traps()?
I don't see anything direct, but exception path is different story.
native_machine_emergency_restart() does port I/O for BOOT_KBD which
seems to be reachable and leads to #VE with the patch:
machine_emergency_restart()
__machine_emergency_restart(1)
machine_ops.emergency_restart()
native_machine_emergency_restart()
reboot_type == BOOT_ACPI (default)
acpi_reboot()
reboot_type = BOOT_KBD
kb_wait()
inb(0x64) --> #VE
Could you check if the patch changes panic() behaviour in the window
before idt_setup_early_traps()?
--
Kiryl Shutsemau / Kirill A. Shutemov
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] x86/tdx: Remove the early #VE handler
2026-09-11 10:37 ` Kiryl Shutsemau
@ 2026-09-11 15:24 ` Edgecombe, Rick P
2026-09-11 16:07 ` Kiryl Shutsemau
0 siblings, 1 reply; 7+ messages in thread
From: Edgecombe, Rick P @ 2026-09-11 15:24 UTC (permalink / raw)
To: kas; +Cc: kvm, linux-coco, Verma, Vishal L, linux-kernel, ak, x86, dave.hansen
On Fri, 2026-09-11 at 11:37 +0100, Kiryl Shutsemau wrote:
> > Reviewed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
>
> Rick, could you actually test it?
I didn't test it myself, but discussed with Vishal his testing.
>
> Are we sure there's no other port I/O in before idt_setup_early_traps()?
It was a concern that some other feature besides early printk might use port io.
But none were found. Andi's recollection was that he hit something that needed
this, but this may have been with some older changed early printk behavior.
>
> I don't see anything direct, but exception path is different story.
>
> native_machine_emergency_restart() does port I/O for BOOT_KBD which
> seems to be reachable and leads to #VE with the patch:
>
> machine_emergency_restart()
> __machine_emergency_restart(1)
> machine_ops.emergency_restart()
> native_machine_emergency_restart()
> reboot_type == BOOT_ACPI (default)
> acpi_reboot()
> reboot_type = BOOT_KBD
> kb_wait()
> inb(0x64) --> #VE
Is BOOT_KBD something that you think could be hit from a TDX guest?
>
> Could you check if the patch changes panic() behaviour in the window
> before idt_setup_early_traps()?
Can you describe more what you are imagining? panic() doing early printk or some
other port io? Wondering if you have some more specific hunch.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] x86/tdx: Remove the early #VE handler
2026-09-11 15:24 ` Edgecombe, Rick P
@ 2026-09-11 16:07 ` Kiryl Shutsemau
2026-09-11 17:51 ` Edgecombe, Rick P
0 siblings, 1 reply; 7+ messages in thread
From: Kiryl Shutsemau @ 2026-09-11 16:07 UTC (permalink / raw)
To: Edgecombe, Rick P
Cc: kvm, linux-coco, Verma, Vishal L, linux-kernel, ak, x86, dave.hansen
On Fri, Sep 11, 2026 at 03:24:34PM +0000, Edgecombe, Rick P wrote:
> On Fri, 2026-09-11 at 11:37 +0100, Kiryl Shutsemau wrote:
> > > Reviewed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
> >
> > Rick, could you actually test it?
>
> I didn't test it myself, but discussed with Vishal his testing.
>
> >
> > Are we sure there's no other port I/O in before idt_setup_early_traps()?
>
> It was a concern that some other feature besides early printk might use port io.
> But none were found. Andi's recollection was that he hit something that needed
> this, but this may have been with some older changed early printk behavior.
>
> >
> > I don't see anything direct, but exception path is different story.
> >
> > native_machine_emergency_restart() does port I/O for BOOT_KBD which
> > seems to be reachable and leads to #VE with the patch:
> >
> > machine_emergency_restart()
> > __machine_emergency_restart(1)
> > machine_ops.emergency_restart()
> > native_machine_emergency_restart()
> > reboot_type == BOOT_ACPI (default)
> > acpi_reboot()
> > reboot_type = BOOT_KBD
> > kb_wait()
> > inb(0x64) --> #VE
>
> Is BOOT_KBD something that you think could be hit from a TDX guest?
It is the first fallback from default BOOT_ACPI failure. But it is just
an example of port I/O I found.
> > Could you check if the patch changes panic() behaviour in the window
> > before idt_setup_early_traps()?
>
> Can you describe more what you are imagining? panic() doing early printk or some
> other port io? Wondering if you have some more specific hunch.
I don't see panic() triggering early printk, but I see potential path to
other port I/O as pointed above.
I have vague recollection that I tried to remove it before, but
something stopped me.
--
Kiryl Shutsemau / Kirill A. Shutemov
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] x86/tdx: Remove the early #VE handler
2026-09-11 16:07 ` Kiryl Shutsemau
@ 2026-09-11 17:51 ` Edgecombe, Rick P
0 siblings, 0 replies; 7+ messages in thread
From: Edgecombe, Rick P @ 2026-09-11 17:51 UTC (permalink / raw)
To: kas; +Cc: kvm, linux-coco, Verma, Vishal L, linux-kernel, ak, x86, dave.hansen
On Fri, 2026-09-11 at 17:07 +0100, Kiryl Shutsemau wrote:
> > Is BOOT_KBD something that you think could be hit from a TDX guest?
>
> It is the first fallback from default BOOT_ACPI failure. But it is just
> an example of port I/O I found.
>
> > > Could you check if the patch changes panic() behaviour in the window
> > > before idt_setup_early_traps()?
> >
> > Can you describe more what you are imagining? panic() doing early printk or
> > some other port io? Wondering if you have some more specific hunch.
>
> I don't see panic() triggering early printk, but I see potential path to
> other port I/O as pointed above.
>
> I have vague recollection that I tried to remove it before, but
> something stopped me.
Yea, the risk is that some other usage is relying on this, even though the
comment in the handler says "Intended only for earlyprintk".
When doing the initial TDX guest work, did you guys consider trying to use some
alternatives magic to redirect #VE causing things to the tdvmcall helpers? I
guess it doesn't help the early boot case.
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-09-11 17:51 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-10 18:28 [PATCH] x86/tdx: Remove the early #VE handler Vishal Verma
2026-09-10 20:39 ` Edgecombe, Rick P
2026-09-11 0:15 ` Verma, Vishal L
2026-09-11 10:37 ` Kiryl Shutsemau
2026-09-11 15:24 ` Edgecombe, Rick P
2026-09-11 16:07 ` Kiryl Shutsemau
2026-09-11 17:51 ` Edgecombe, Rick P
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®