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() ?