Re: [PATCH v3 2/2] x86/tdx: Fix zero-extension for 32-bit port I/O
From: Dave Hansen
Date: Wed May 27 2026 - 13:49:20 EST
On 5/27/26 05:05, Kiryl Shutsemau (Meta) wrote:
...
> - /* 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;
> +
Is there any way we could do this with fewer comments and more code?
I mean, there's only three cases. Why have;
u64 mask = GENMASK(BITS_PER_BYTE * size - 1, 0);
When there are only 3 possible cases:
1 => 0xf
2 => 0xff
4 => 0xffff
and one of those cases needs a special case on top of it.
Maybe something like this?
/* Clear out part of RAX so part of args.r11 can be OR'd in: */
switch (size) {
case 1:
/* inb consumes lower 8 bits of r11: */
regs->ax &= ~GENMASK_ULL(7, 0);
args.r11 &= GENMASK_ULL(7, 0);
break;
case 2:
/* inw consumes lower 16 bits of r11: */
regs->ax &= ~GENMASK_ULL(15, 0);
args.r11 &= GENMASK_ULL(15, 0);
break;
case 4:
/* inl is weird and zeros the whole register: */
regs->ax &= ~GENMASK_ULL(63, 0);
/* But only consumes 32-bits from r11: */
args.r11 &= GENMASK_ULL(31, 0);
break;
default:
/* Probable TDX module bug. Illegal in[bwl] size: */
WARN_ON_ONCE(1);
success = 0;
}
if (success)
regs->ax |= args.r11;
It might need a temporary variable for args.r11, but you get the point.
That's basically the data from the comment but written as code. tdx.c | 29 ++++++++++++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)