• Kai Huang's avatar
    x86/virt/tdx: Configure global KeyID on all packages · e56d28df
    Kai Huang authored
    After the list of TDMRs and the global KeyID are configured to the TDX
    module, the kernel needs to configure the key of the global KeyID on all
    packages using TDH.SYS.KEY.CONFIG.
    
    This SEAMCALL cannot run parallel on different cpus.  Loop all online
    cpus and use smp_call_on_cpu() to call this SEAMCALL on the first cpu of
    each package.
    
    To keep things simple, this implementation takes no affirmative steps to
    online cpus to make sure there's at least one cpu for each package.  The
    callers (aka. KVM) can ensure success by ensuring sufficient CPUs are
    online for this to succeed.
    
    Intel hardware doesn't guarantee cache coherency across different
    KeyIDs.  The PAMTs are transitioning from being used by the kernel
    mapping (KeyId 0) to the TDX module's "global KeyID" mapping.
    
    This means that the kernel must flush any dirty KeyID-0 PAMT cachelines
    before the TDX module uses the global KeyID to access the PAMTs.
    Otherwise, if those dirty cachelines were written back, they would
    corrupt the TDX module's metadata.  Aside: This corruption would be
    detected by the memory integrity hardware on the next read of the memory
    with the global KeyID.  The result would likely be fatal to the system
    but would not impact TDX security.
    
    Following the TDX module specification, flush cache before configuring
    the global KeyID on all packages.  Given the PAMT size can be large
    (~1/256th of system RAM), just use WBINVD on all CPUs to flush.
    
    If TDH.SYS.KEY.CONFIG fails, the TDX module may already have "converted"
    some memory for TDX module use.  Convert the memory back so that it can
    be safely used by the kernel again.  Note that this is slower than it
    should be because of the "partial write machine check" erratum which
    affects TDX-capable hardware.
    
    Also refactor and introduce a new helper: tdmr_do_pamt_func().  This
    takes a TDMR and runs a function on its PAMT.  It looks a _bit_ odd to
    pass a function pointer around like this, but its use is pretty narrow
    and it does eliminate what would otherwise be some copying and pasting.
    
    [ dhansen: * munge changelog as usual
    	   * remove weird (*pamd_func)() syntax ]
    Signed-off-by: default avatarKai Huang <kai.huang@intel.com>
    Signed-off-by: default avatarDave Hansen <dave.hansen@linux.intel.com>
    Reviewed-by: default avatarIsaku Yamahata <isaku.yamahata@intel.com>
    Reviewed-by: default avatarKirill A. Shutemov <kirill.shutemov@linux.intel.com>
    Reviewed-by: default avatarYuan Yao <yuan.yao@intel.com>
    Reviewed-by: default avatarDave Hansen <dave.hansen@linux.intel.com>
    Link: https://lore.kernel.org/all/20231208170740.53979-14-dave.hansen%40intel.com
    e56d28df
tdx.c 32.5 KB