On Fri, 2022-06-24 at 11:50 -0700, Dave Hansen wrote: > So, the last patch was called: > > Implement SEAMCALL function > > and yet, in this patch, we have a "seamcall()" function. That's a bit > confusing and not covered at *all* in this subject. > > Further, seamcall() is the *ONLY* caller of __seamcall() that I see in > this series. That makes its presence here even more odd. > > The seamcall() bits should either be in their own patch, or mashed in > with __seamcall(). Right. The reason I didn't put the seamcall() into previous patch was it is only used in this tdx.c, so it should be static. But adding a static function w/o using it in previous patch will trigger a compile warning. So I introduced here where it is first used. One option is I can introduce seamcall() as a static inline function in tdx.h in previous patch so there won't be a warning. I'll change to use this way. Please let me know if you have any comments. > > > +/* > > + * Wrapper of __seamcall(). It additionally prints out the error > > + * informationi if __seamcall() fails normally. It is useful during > > + * the module initialization by providing more information to the user. > > + */ > > +static u64 seamcall(u64 fn, u64 rcx, u64 rdx, u64 r8, u64 r9, > > + struct tdx_module_output *out) > > +{ > > + u64 ret; > > + > > + ret = __seamcall(fn, rcx, rdx, r8, r9, out); > > + if (ret == TDX_SEAMCALL_VMFAILINVALID || !ret) > > + return ret; > > + > > + pr_err("SEAMCALL failed: leaf: 0x%llx, error: 0x%llx\n", fn, ret); > > + if (out) > > + pr_err("SEAMCALL additional output: rcx 0x%llx, rdx 0x%llx, r8 0x%llx, r9 0x%llx, r10 0x%llx, r11 0x%llx.\n", > > + out->rcx, out->rdx, out->r8, out->r9, out->r10, out->r11); > > + > > + return ret; > > +} > > + > > +static void seamcall_smp_call_function(void *data) > > +{ > > + struct seamcall_ctx *sc = data; > > + struct tdx_module_output out; > > + u64 ret; > > + > > + ret = seamcall(sc->fn, sc->rcx, sc->rdx, sc->r8, sc->r9, &out); > > + if (ret) > > + atomic_set(&sc->err, -EFAULT); > > +} > > + > > +/* > > + * Call the SEAMCALL on all online CPUs concurrently. Caller to check > > + * @sc->err to determine whether any SEAMCALL failed on any cpu. > > + */ > > +static void seamcall_on_each_cpu(struct seamcall_ctx *sc) > > +{ > > + on_each_cpu(seamcall_smp_call_function, sc, true); > > +} > > You can get away with this three-liner seamcall_on_each_cpu() being in > this patch, but seamcall() itself doesn't belong here. Right. Please see above reply. > > > /* > > * Detect and initialize the TDX module. > > * > > @@ -138,7 +195,10 @@ static int init_tdx_module(void) > > > > static void shutdown_tdx_module(void) > > { > > - /* TODO: Shut down the TDX module */ > > + struct seamcall_ctx sc = { .fn = TDH_SYS_LP_SHUTDOWN }; > > + > > + seamcall_on_each_cpu(&sc); > > + > > tdx_module_status = TDX_MODULE_SHUTDOWN; > > } > > > > @@ -221,6 +281,9 @@ bool platform_tdx_enabled(void) > > * CPU hotplug is temporarily disabled internally to prevent any cpu > > * from going offline. > > * > > + * Caller also needs to guarantee all CPUs are in VMX operation during > > + * this function, otherwise Oops may be triggered. > > I would *MUCH* rather have this be a: > > if (!cpu_feature_enabled(X86_FEATURE_VMX)) > WARN_ONCE("VMX should be on blah blah\n"); > > than just plain oops. Even a pr_err() that preceded the oops would be > nicer than an oops that someone has to go decode and then grumble when > their binutils is too old that it can't disassemble the TDCALL. I can add this to seamcall(): /* * SEAMCALL requires CPU being in VMX operation otherwise it causes #UD. * Sanity check and return early to avoid Oops. Note cpu_vmx_enabled() * actually only checks whether VMX is enabled but doesn't check whether * CPU is in VMX operation (VMXON is done). There's no way to check * whether VMXON has been done, but currently enabling VMX and doing * VMXON are always done together. */ if (!cpu_vmx_enabled()) { WARN_ONCE("CPU is not in VMX operation before making SEAMCALL"); return -EINVAL; } The reason I didn't do is I'd like to make seamcall() simple, that it only returns TDX_SEAMCALL_VMFAILINVALID or the actual SEAMCALL leaf error. With above, this function also returns kernel error code, which isn't good. Alternatively, we can always add EXTABLE to TDX_MODULE_CALL macro to handle #UD and #GP by returning dedicated error codes (please also see my reply to previous patch for the code needed to handle), in which case we don't need such check here. Always handling #UD in TDX_MODULE_CALL macro also has another advantage: there will be no Oops for #UD regardless the issue that "there's no way to check whether VMXON has been done" in the above comment. What's your opinion? -- Thanks, -Kai