Re: [PATCH v5 08/22] x86/virt/tdx: Shut down TDX module in case of error

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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






[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux