[PATCH v3 2/2] x86/tdx: Fix zero-extension for 32-bit port I/O

From: Kiryl Shutsemau (Meta)

Date: Wed May 27 2026 - 08:15:25 EST


According to x86 architecture rules, 32-bit operations zero-extend the
result to 64 bits. The current implementation of handle_in() only masks
the lower 32 bits, which preserves the upper 32 bits of RAX when a
32-bit port IN instruction is emulated.

Update handle_in() to zero out the entire RAX register when the I/O size
is 4 bytes to ensure correct zero-extension. For smaller sizes (1 or 2
bytes), continue to preserve the unaffected upper bits.

Fixes: 03149948832a ("x86/tdx: Port I/O: Add runtime hypercalls")
Reported-by: Borys Tsyrulnikov <tsyrulnikov.borys@xxxxxxxxx>
Link: https://lore.kernel.org/all/CAKw_Dz96rfSQc6Rn+9QBcUFHhmkK+9zu+P=bxowfZwxrATCBRg@xxxxxxxxxxxxxx/
Signed-off-by: Kiryl Shutsemau (Meta) <kas@xxxxxxxxxx>
Reviewed-by: Kai Huang <kai.huang@xxxxxxxxx>
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@xxxxxxxxxxxxxxx>
Cc: stable@xxxxxxxxxxxxxxx
---
arch/x86/coco/tdx/tdx.c | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c
index 65119362f9a2..58feca419326 100644
--- a/arch/x86/coco/tdx/tdx.c
+++ b/arch/x86/coco/tdx/tdx.c
@@ -703,8 +703,25 @@ static bool handle_in(struct pt_regs *regs, int size, int port)
*/
success = !__tdx_hypercall(&args);

- /* Update part of the register affected by the emulated instruction */
- regs->ax &= ~mask;
+ /*
+ * IN writes the result into a sub-register of RAX. Only the
+ * 32-bit form zero-extends; the smaller forms leave the upper
+ * bits untouched:
+ *
+ * insn dest size bits written bits preserved
+ * inb AL 1 RAX[ 7: 0] RAX[63: 8]
+ * inw AX 2 RAX[15: 0] RAX[63:16]
+ * inl EAX 4 RAX[63: 0] (none, zero-extended)
+ *
+ * 'mask' only covers the low 'size' bytes, which is exactly the
+ * range affected for size 1 and 2. For size 4 the write also
+ * clears RAX[63:32], so widen the clear-mask.
+ */
+ if (size == 4)
+ regs->ax = 0;
+ else
+ regs->ax &= ~mask;
+
if (success)
regs->ax |= args.r11 & mask;

--
2.54.0