On 12/13/24 08:30, Adrian Hunter wrote: > On 13/12/24 18:16, Dave Hansen wrote: >> On 12/11/24 10:43, Adrian Hunter wrote: >> ... >>> - size = tdvmcall_a0_read(vcpu); >>> - write = tdvmcall_a1_read(vcpu); >>> - port = tdvmcall_a2_read(vcpu); >>> + size = tdx->vp_enter_out.io_size; >>> + write = tdx->vp_enter_out.io_direction == TDX_WRITE; >>> + port = tdx->vp_enter_out.io_port; >> ...> + case TDVMCALL_IO: >>> + out->io_size = args.r12; >>> + out->io_direction = args.r13 ? TDX_WRITE : TDX_READ; >>> + out->io_port = args.r14; >>> + out->io_value = args.r15; >>> + break; >> >> I honestly don't understand the need for the abstracted structure to sit >> in the middle. It doesn't get stored or serialized or anything, right? >> So why have _another_ structure? >> >> Why can't this just be (for instance): >> >> size = tdx->foo.r12; >> >> ? >> >> Basically, you hand around the raw arguments until you need to use them. > > That sounds like what we have at present? That is: > > u64 tdh_vp_enter(u64 tdvpr, struct tdx_module_args *args) > { > args->rcx = tdvpr; > > return __seamcall_saved_ret(TDH_VP_ENTER, args); > } > > And then either add Rick's struct tdx_vp? Like so: > > u64 tdh_vp_enter(struct tdx_vp *vp, struct tdx_module_args *args) > { > args->rcx = tdx_tdvpr_pa(vp); > > return __seamcall_saved_ret(TDH_VP_ENTER, args); > } > > Or leave it to the caller: > > u64 tdh_vp_enter(struct tdx_module_args *args) > { > return __seamcall_saved_ret(TDH_VP_ENTER, args); > } > > Or forget the wrapper altogether, and let KVM call > __seamcall_saved_ret() ? Rick's version, please. I don't want __seamcall_saved_ret() exported to modules. I want to at least have a clean boundary beyond which __seamcall_saved_ret() is not exposed. My nit with the "u64 tdvpr" version was that there's zero type safety. The tdvp-less tdh_vp_enter() is even *less* safe of a calling convention and also requires that each caller do tdx_tdvpr_pa() or equivalent. But I feel like I'm repeating myself a bit at this point.