• Kai Huang's avatar
    x86/virt/tdx: Add skeleton to enable TDX on demand · 6162b310
    Kai Huang authored
    There are essentially two steps to get the TDX module ready:
    1) Get each CPU ready to run TDX
    2) Set up the shared TDX module data structures
    
    Introduce and export (to KVM) the infrastructure to do both of these
    pieces at runtime.
    
    == Per-CPU TDX Initialization ==
    
    Track the initialization status of each CPU with a per-cpu variable.
    This avoids failures in the case of KVM module reloads and handles cases
    where CPUs come online later.
    
    Generally, the per-cpu SEAMCALLs happen first.  But there's actually one
    global call that has to happen before _any_ others (TDH_SYS_INIT).  It's
    analogous to the boot CPU having to do a bit of extra work just because
    it happens to be the first one.  Track if _any_ CPU has done this call
    and then only actually do it during the first per-cpu init.
    
    == Shared TDX Initialization ==
    
    Create the global state function (tdx_enable()) as a simple placeholder.
    The TODO list will be pared down as functionality is added.
    
    Use a state machine protected by mutex to make sure the work in
    tdx_enable() will only be done once.  This avoids failures if the KVM
    module is reloaded.
    
    A CPU must be made ready to run TDX before it can participate in
    initializing the shared parts of the module.  Any caller of tdx_enable()
    need to ensure that it can never run on a CPU which is not ready to
    run TDX.  It needs to be wary of CPU hotplug, preemption and the
    VMX enabling state of any CPU on which it might run.
    
    == Why runtime instead of boot time? ==
    
    The TDX module can be initialized only once in its lifetime.  Instead
    of always initializing it at boot time, this implementation chooses an
    "on demand" approach to initialize TDX until there is a real need (e.g
    when requested by KVM).  This approach has below pros:
    
    1) It avoids consuming the memory that must be allocated by kernel and
    given to the TDX module as metadata (~1/256th of the TDX-usable memory),
    and also saves the CPU cycles of initializing the TDX module (and the
    metadata) when TDX is not used at all.
    
    2) The TDX module design allows it to be updated while the system is
    running.  The update procedure shares quite a few steps with this "on
    demand" initialization mechanism.  The hope is that much of "on demand"
    mechanism can be shared with a future "update" mechanism.  A boot-time
    TDX module implementation would not be able to share much code with the
    update mechanism.
    
    3) Making SEAMCALL requires VMX to be enabled.  Currently, only the KVM
    code mucks with VMX enabling.  If the TDX module were to be initialized
    separately from KVM (like at boot), the boot code would need to be
    taught how to muck with VMX enabling and KVM would need to be taught how
    to cope with that.  Making KVM itself responsible for TDX initialization
    lets the rest of the kernel stay blissfully unaware of VMX.
    
    [ dhansen: completely reorder/rewrite changelog ]
    Signed-off-by: default avatarKai Huang <kai.huang@intel.com>
    Signed-off-by: default avatarDave Hansen <dave.hansen@linux.intel.com>
    Reviewed-by: default avatarKirill A. Shutemov <kirill.shutemov@linux.intel.com>
    Reviewed-by: default avatarNikolay Borisov <nik.borisov@suse.com>
    Reviewed-by: default avatarDave Hansen <dave.hansen@linux.intel.com>
    Link: https://lore.kernel.org/all/20231208170740.53979-6-dave.hansen%40intel.com
    6162b310
tdx.c 6.84 KB