* Re: [PATCH v2 09/19] PCI/TSM: Support creating encrypted MMIO descriptors via TDISP Report
From: Xu Yilun @ 2026-03-13 10:23 UTC (permalink / raw)
To: Aneesh Kumar K.V
Cc: Dan Williams, linux-coco, linux-pci, gregkh, aik, bhelgaas,
alistair23, lukas, jgg, Arnd Bergmann
In-Reply-To: <yq5a4imuanoa.fsf@kernel.org>
> > + if (last_bar < bar) {
> > + /* transition to a new bar */
> > + last_bar = bar;
> > + /*
> > + * The tsm_offset for the first range of the BAR
> > + * corresponds to the BAR base.
> > + */
> > + reporting_bar_base = tsm_offset;
> > + } else if (tsm_offset < last_reporting_end) {
> > + pci_dbg(pdev, "Reporting ranges within BAR not in ascending order\n");
> > + return NULL;
> > + }
> >
> ....
> > + range_off = tsm_offset - reporting_bar_base;
> >
> range_off will always be zero? Should we do
tsm_offset comes from Device Interface Report, MMIO RANGE, First 4k
Page. How do you interpret the exact meaning of this field?
My understanding is, it is the obfuscated host start pfn of this range,
if this range has offset to the BAR start, this field should also be
offsetted.
But if the first range in the BAR should be aligned to BAR, otherwise
there is no way for guest to position the range in the BAR.
So the logic here is:
reporting_bar_base: the first obfuscated pfn for the BAR, the BAR pfn
tsm_offset: the current obfucated pfn for the BAR.
tsm_offset - reporting_bar_base: the offset to the BAR.
>
> range_off = tsm_offset & (pci_resource_len(pdev, bar) - 1);
>
>
> So that we correctly handle if the interface report is reporting a range
> within a bar. The only requirement here is bar address should be aligned
> to its size and mmio_reporting_offset should not add offsets in that range.
^ permalink raw reply
* Re: [PATCH v2 10/19] x86, swiotlb: Teach swiotlb to skip "accepted" devices
From: Xu Yilun @ 2026-03-13 10:26 UTC (permalink / raw)
To: Aneesh Kumar K.V
Cc: Dan Williams, linux-coco, linux-pci, gregkh, aik, bhelgaas,
alistair23, lukas, jgg, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
Marek Szyprowski, Robin Murphy
In-Reply-To: <yq5ah5qx9t77.fsf@kernel.org>
> > @@ -365,6 +365,7 @@ void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags,
> >
> > io_tlb_default_mem.force_bounce =
> > swiotlb_force_bounce || (flags & SWIOTLB_FORCE);
> > + io_tlb_default_mem.bounce_unaccepted = flags & SWIOTLB_UNACCEPTED;
> >
>
> This should be.
>
> @@ -373,7 +373,7 @@ void __init swiotlb_init_remap(bool addressing_limit, unsigned int flags,
>
> io_tlb_default_mem.force_bounce =
> swiotlb_force_bounce || (flags & SWIOTLB_FORCE);
> - io_tlb_default_mem.bounce_unaccepted = flags & SWIOTLB_UNACCEPTED;
> + io_tlb_default_mem.bounce_unaccepted = !!(flags & SWIOTLB_UNACCEPTED);
Ah yes, I just realized assigning to a 1-bit field would truncate the
assigned value to its LSB...
^ permalink raw reply
* Re: SVSM Development Call March 11, 2026
From: Jörg Rödel @ 2026-03-13 10:49 UTC (permalink / raw)
To: coconut-svsm, linux-coco
In-Reply-To: <ete4u42tzmawocptkhibgkv6tgg7rlqcpncdutnk36qtpdejcz@cxhur5ib7dzz>
Meeting minutes are now posted here:
https://github.com/coconut-svsm/governance/pull/99
-Joerg
^ permalink raw reply
* Re: [PATCH v4 11/24] x86/virt/seamldr: Introduce skeleton for TDX Module updates
From: Chao Gao @ 2026-03-13 12:15 UTC (permalink / raw)
To: Dave Hansen
Cc: linux-coco, linux-kernel, kvm, x86, reinette.chatre, ira.weiny,
kai.huang, dan.j.williams, yilun.xu, sagis, vannapurve, paulmck,
nik.borisov, zhenzhong.duan, seanjc, rick.p.edgecombe, kas,
dave.hansen, vishal.l.verma, binbin.wu, tony.lindgren,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin
In-Reply-To: <31936a20-929f-489a-9dc6-0f8fcb9307f1@intel.com>
On Thu, Mar 12, 2026 at 01:40:44PM -0700, Dave Hansen wrote:
>On 2/12/26 06:35, Chao Gao wrote:
>> +static void set_target_state(enum tdp_state state)
>> +{
>> + /* Reset ack counter. */
>> + atomic_set(&tdp_data.thread_ack, num_online_cpus());
>> + /* Ensure thread_ack is updated before the new state */
>> + smp_wmb();
>> + WRITE_ONCE(tdp_data.state, state);
>> +}
>
>This looks overly complicated.
>
>If it doesn't need to be scalable, just make it stupid and simple. Why
>not just protect the whole thing with a spinlock and be done with it?
Good suggestion. I copied this from multi_cpu_stop() without considering
whether it could be simplified.
Regarding scalability, I compared the update time and didn't see a
meaningful difference on a system with 240 CPUs.
I will make changes like this:
(Note: I'm also renaming tdp_data/tdp_state to update_data and
module_update_state for clarity, since "tdp" isn't obvious as Kai pointed
out.)
static struct {
enum module_update_state state;
- atomic_t thread_ack;
- atomic_t failed;
+ int thread_ack;
+ int failed;
+ raw_spinlock_t lock;
} update_data;
static void set_target_state(enum module_update_state state)
{
/* Reset ack counter. */
- atomic_set(&update_data.thread_ack, num_online_cpus());
- /*
- * Ensure thread_ack is updated before the new state.
- * Otherwise, other CPUs may see the new state and ack
- * it before thread_ack is reset. An ack before reset
- * is effectively lost, causing the system to wait
- * forever for thread_ack to become zero.
- */
- smp_wmb();
- WRITE_ONCE(update_data.state, state);
+ update_data.thread_ack = num_online_cpus();
+ update_data.state = state;
}
/* Last one to ack a state moves to the next state. */
static void ack_state(void)
{
- if (atomic_dec_and_test(&update_data.thread_ack))
+ guard(raw_spinlock)(&update_data.lock);
+ update_data.thread_ack--;
+ if (!update_data.thread_ack)
set_target_state(update_data.state + 1);
}
^ permalink raw reply
* Re: [PATCH v4 10/24] x86/virt/seamldr: Allocate and populate a module update request
From: Chao Gao @ 2026-03-13 12:16 UTC (permalink / raw)
To: Edgecombe, Rick P
Cc: Zhao, Yan Y, kvm@vger.kernel.org, linux-coco@lists.linux.dev,
Huang, Kai, dave.hansen@linux.intel.com, kas@kernel.org,
Chatre, Reinette, seanjc@google.com, linux-kernel@vger.kernel.org,
binbin.wu@linux.intel.com, Weiny, Ira, nik.borisov@suse.com,
mingo@redhat.com, Verma, Vishal L, tony.lindgren@linux.intel.com,
Annapurve, Vishal, sagis@google.com, Duan, Zhenzhong,
tglx@kernel.org, paulmck@kernel.org, hpa@zytor.com, bp@alien8.de,
yilun.xu@linux.intel.com, x86@kernel.org, Williams, Dan J
In-Reply-To: <89d69e852d3d822b51d3623d02ef6637239ccad5.camel@intel.com>
On Fri, Mar 13, 2026 at 12:56:19AM +0800, Edgecombe, Rick P wrote:
>On Thu, 2026-03-12 at 22:36 +0800, Chao Gao wrote:
>> > > + if (blob->version != 0x100) {
>> > Do we need a macro for this 0x100?
>>
>> Maybe not, as this is a one-off check (i.e., the version/macro won't be used
>> anywhere else). If someone has a strong opinion on this, I can add one.
>
>Seems like kind of a magic number as it is. What would the macro name be, and
>would it make the code more understandable?
Yes. Adding a macro can improve readability. So, will do.
Thanks, Yan and Rick.
^ permalink raw reply
* Re: [PATCH v2 03/19] device core: Introduce confidential device acceptance
From: Greg KH @ 2026-03-13 12:18 UTC (permalink / raw)
To: Dan Williams
Cc: linux-coco, linux-pci, aik, aneesh.kumar, yilun.xu, bhelgaas,
alistair23, lukas, jgg, Christoph Hellwig, Jason Gunthorpe,
Marek Szyprowski, Robin Murphy, Roman Kisel, Samuel Ortiz,
Rafael J. Wysocki, Danilo Krummrich
In-Reply-To: <69b38e7427a61_b2b610073@dwillia2-mobl4.notmuch>
On Thu, Mar 12, 2026 at 09:11:32PM -0700, Dan Williams wrote:
> Greg KH wrote:
> > On Mon, Mar 02, 2026 at 04:01:51PM -0800, Dan Williams wrote:
> > > An "accepted" device is one that is allowed to access private memory within
> > > a Trusted Computing Boundary (TCB). The concept of "acceptance" is distinct
> > > from other device properties like usb_device::authorized, or
> > > tb_switch::authorized. The entry to the accepted state is a violent
> > > operation in which the device will reject MMIO requests that are not
> > > encrypted, and the device enters a new IOMMU protection domain to allow it
> > > to access addresses that were previously off-limits.
> >
> > Trying to mix/match "acceptance" with "authorized" is going to be a
> > nightmare, what's the combination that can happen here over time?
>
> I do think Linux needs to mix/match these concepts. "Authorization" is a
> kernel policy to operate a device at all. "Acceptance" is a mechanism
> to operate a device within a hardware TCB boundary.
>
> So, the truth table of combinations would be:
>
> accepted authorized result
> 0 0 logically and physically disconnected device
>
> 0 1 connected device, DMA is bounce buffered
> and loses confidentiality, integrity,
> and performance
>
> 1 0 logically disconnected device, but a
> relying party trusts that the device is
> not spoofing authorization.
>
> 1 1 connected device, DMA is direct and gains
> confidentiality, integrity and performance
>
> To say it another way, when the above distinguishes "logically" vs
> "physically" disconnected it is whether the device interface can be
> verified to not be under adversarial control. An unaccepted device can
> do limited damage, but still can bounce buffer secrets out of the TCB if
> so directed.
I really don't agree with this, but I can't think of why at the moment.
I feel like you are looking at this purely in the TCB point of view,
while I don't feel that is something that should be considered "special"
at all here. Linux has, for the most part, always trusted the hardware,
and now you are wanting to not trust the hardware for some things and
parts of the kernel. Which is great, it's something that I have wanted
to change for a very long time now, but let's do it right if at all
possible.
Give me a few days to come up with a better reply, let me think about
this some more...
> > We need to either "trust" or "not trust" the device, and the bus can
> > decide what to do with that value (if anything). The DMA layer can then
> > use that value to do:
>
> Trust is separate. For example, there are deployed use cases today where
> the device is trusted, but unaccepted. Acceptance support for those
> cases is mostly a performance optimization to be able to stop performing
> software encryption on top of DMA bounce buffering.
If "acceptance" is just a performance issue, I think you all need to go
back to the marketing people as that's probably not what they intended
to have happen here. For some reason I thought they were selling this
as "security", not "speed" :)
> > > Subsystems like the DMA mapping layer, that need to modify their behavior
> > > based on the accept state, may only have access to the base 'struct
> > > device'.
> >
> > ^this.
>
> The DMA layer is not operating on a trust concept it is effectively
> being told to select an IOMMU.
Ok, then that's independent of "acceptance", that is "use this IOMMU vs.
that one" type of thing which is just a "basic configuration for speed"
type of thing as you mention above :)
Let's not confuse that with anything else like "acceptance" please.
> > > It is also likely that the concept of TCB acceptance grows beyond
> > > PCI devices over time. For these reasons, introduce the concept of
> > > acceptance in 'struct device_private' which is device common, but only
> > > suitable for buses and built-in infrastructure to consume.
> >
> > Busses are what can control this, but please, let's not make this a
> > cc-only type thing. We have the idea of trust starting to propagate
> > through a number of different busses, let's get it right here, so we
> > don't have to have all of these different bus-specific hacks like we do
> > today.
>
> The conflation of "trust" and "acceptance" has been the main stumbling
> block of past proposals. As you have said before "kernel drivers trust
> their devices". That precedent is not being touched in this proposal.
Ah, but I WANT to touch that. Let's FINALLY solve that! Or at the very
least, provide the infrastructure in the driver core to allow busses
that want to do that, to be able to do so.
> Instead, give userspace all the tools it needs to deploy policy about
> when to operate a device. When it does decide to operate the device give
> it the mechanism to add confidentiality, integrity and performance to
> that operation.
Yes, this is a policy decision, and if you are only saying this is about
"which IOMMU should we select", then that's a dma layer configuration
option. Let's not call that "acceptance" please.
> This is a "CC-only type thing" because only CC partitions the system
> into two device domains. One where "trusted unaccepted" devices can
> operate without CC protections and "trusted accepted" devices can
> operate with CC protections and direct DMA.
In other words, it's an IOMMU switch, so why not use the switch
infrastructure? </me runs away...>
anyway, let me think about this some more...
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH v2 03/19] device core: Introduce confidential device acceptance
From: Jason Gunthorpe @ 2026-03-13 13:32 UTC (permalink / raw)
To: Dan Williams
Cc: Greg KH, linux-coco, linux-pci, aik, aneesh.kumar, yilun.xu,
bhelgaas, alistair23, lukas, Christoph Hellwig, Marek Szyprowski,
Robin Murphy, Roman Kisel, Samuel Ortiz, Rafael J. Wysocki,
Danilo Krummrich
In-Reply-To: <69b38e7427a61_b2b610073@dwillia2-mobl4.notmuch>
On Thu, Mar 12, 2026 at 09:11:32PM -0700, Dan Williams wrote:
> Greg KH wrote:
> > On Mon, Mar 02, 2026 at 04:01:51PM -0800, Dan Williams wrote:
> > > An "accepted" device is one that is allowed to access private memory within
> > > a Trusted Computing Boundary (TCB). The concept of "acceptance" is distinct
> > > from other device properties like usb_device::authorized, or
> > > tb_switch::authorized. The entry to the accepted state is a violent
> > > operation in which the device will reject MMIO requests that are not
> > > encrypted, and the device enters a new IOMMU protection domain to allow it
> > > to access addresses that were previously off-limits.
> >
> > Trying to mix/match "acceptance" with "authorized" is going to be a
> > nightmare, what's the combination that can happen here over time?
>
> I do think Linux needs to mix/match these concepts. "Authorization" is a
> kernel policy to operate a device at all. "Acceptance" is a mechanism
> to operate a device within a hardware TCB boundary.
I'm not sure about these words either, I would revise your table to be
more OS centric, the device can be in one of four security levels:
0 Blocked and disabled
The device cannot attack the system, enforced by the OS not loading a
driver or mapping the MMIO and IOMMU fully blocking everything from it.
1 In use, attacks from a hostile device are possible
A driver can operate the device and is expected to defend against
attacks from the device itself. The IOMMU restricts the device to only
access driver approved data (no ATS, DMA strict only, CC shared
only, interrupt remapping security, bounce partial DMA mappings, etc)
2 In use, no attacks from the device
The device does what the driver says and is not hostile. The driver
does not have to defend itself, the IOMMU can run in faster & lower
security modes (ATS on, DMA-FQ, Identity, still CC shared only)
* Basically our default security level today
3 In use, no attacks, and access to CC private memory
Like #2 and now the IOMMU allows access to CC private memory too.
[*] I'm inclunding all attacks with "hostile device", including MIM on
the PCIe link, compromised/fake device, attacks from a VMM through a
virtual device, etc.
From a CC VM perspective 0 is at boot, 1 is an out of TCB device, 2
doesn't exist (without TDISP there is no way to keep the
hypervisor from attacking?), and 3 is a full accepted TDSIP device.
#2 can happen in bare metal where a OS may activate link encryption
and attest the device, but doesn't have CC private/shared memory.
From a uAPI perspective I'm not sold on having two bools, I think a
level string would be more flexible. TSM and CC properties are
orthogonal, except you can't select #3 without the TSM saying it is in
RUN.
Internally we'd probably turn that dev->trusted thing into an
enum and teach the iommu layer to treat it more dynamically.
Jason
^ permalink raw reply
* Re: [PATCH v2 09/19] PCI/TSM: Support creating encrypted MMIO descriptors via TDISP Report
From: Jason Gunthorpe @ 2026-03-13 13:36 UTC (permalink / raw)
To: Xu Yilun
Cc: Aneesh Kumar K.V, Dan Williams, linux-coco, linux-pci, gregkh,
aik, bhelgaas, alistair23, lukas, Arnd Bergmann
In-Reply-To: <abPlt8oNUOqGvbA3@yilunxu-OptiPlex-7050>
On Fri, Mar 13, 2026 at 06:23:51PM +0800, Xu Yilun wrote:
> My understanding is, it is the obfuscated host start pfn of this range,
> if this range has offset to the BAR start, this field should also be
> offsetted.
The OS must get an idea of the bar layout out of the report, so there
have to be restrictions on how it is formed otherwise it is
unparsible. IMHO the PCI spec created this very general mechanism but
the CPU CC specs need to constrain it to be usable by an OS.
> > range_off = tsm_offset & (pci_resource_len(pdev, bar) - 1);
> >
> > So that we correctly handle if the interface report is reporting a range
> > within a bar. The only requirement here is bar address should be aligned
> > to its size and mmio_reporting_offset should not add offsets in that range.
Right.
Jason
^ permalink raw reply
* Re: [PATCH v4 11/24] x86/virt/seamldr: Introduce skeleton for TDX Module updates
From: Chao Gao @ 2026-03-13 13:54 UTC (permalink / raw)
To: Edgecombe, Rick P
Cc: kvm@vger.kernel.org, linux-coco@lists.linux.dev, Huang, Kai,
Williams, Dan J, dave.hansen@linux.intel.com, kas@kernel.org,
Chatre, Reinette, Weiny, Ira, linux-kernel@vger.kernel.org,
mingo@redhat.com, Verma, Vishal L, nik.borisov@suse.com,
seanjc@google.com, tony.lindgren@linux.intel.com,
binbin.wu@linux.intel.com, Annapurve, Vishal, Duan, Zhenzhong,
sagis@google.com, paulmck@kernel.org, hpa@zytor.com,
tglx@kernel.org, yilun.xu@linux.intel.com, x86@kernel.org,
bp@alien8.de
In-Reply-To: <aa798a36216fb44969a6abedf96ecf1c7d4e95fe.camel@intel.com>
>> > >
>> > > The TDX Module update process consists of several steps as described in
>> > > Intel® Trust Domain Extensions (Intel® TDX) Module Base Architecture
>> > > Specification, Revision 348549-007, Chapter 4.5 "TD-Preserving TDX Module
>> > > Update"
>> > >
>> > > - shut down the old module
>> > > - install the new module
>> > > - global and per-CPU initialization
>> > > - restore state information
>> > >
>> > > Some steps must execute on a single CPU, others must run serially across
>> > > all CPUs, and some can run concurrently on all CPUs. There are also
>> > > ordering requirements between steps, so all CPUs must work in a step-locked
>> > > manner.
>> >
>> > Does the fact that they can run on other CPUs add any synchronization
>> > requirements? If not I'd leave it off.
>>
>> I'm not sure I understand the concern.
>>
>> Lockstep synchronization is needed specifically because we have both multiple
>> CPUs and multiple steps.
>>
>> If updates only required a single CPU, stop_machine() would be sufficient.
>
>The last part "some can run concurrently on all CPUs", how does it affect the
>design? They can run concurrently, but don't have to... So it's a non-
>requirement?
>
>It seems the main argument here is, this thing has lots of complex ordering
>requirements. So we do it lockstep as a simple pattern to bring sanity. It's a
>fine fuzzy argument I think. The way you list the types of requirements all
>specifically has me trying to find the connection between each requirement and
>lockstep. That is where I get lost. If the reader doesn't need to do the work of
>understanding, don't ask them. And if they do, it probably needs to be clearer.
Got it. I'll keep it simple:
The TDX Module update process consists of several steps as described in
Intel® Trust Domain Extensions (Intel® TDX) Module Base Architecture
Specification, Revision 348549-007, Chapter 4.5 "TD-Preserving TDX Module
Update"
- shut down the old module
- install the new module
- global and per-CPU initialization
- restore state information
There are ordering requirements between steps which mandate lockstep
synchronization across all CPUs.
Or the step details might be irrelevant. Perhaps:
TDX module update consists of several steps. Ordering requirements between
steps mandate lockstep synchronization across all CPUs.
>> > > 1. The entire update process must use stop_machine() to synchronize with
>> > > other TDX workloads
>> > > 2. Update steps must be performed in a step-locked manner
>> > >
>> > > To prepare for implementing concrete TDX Module update steps, establish
>> > > the framework by mimicking multi_cpu_stop(), which is a good example of
>> > > performing a multi-step task in step-locked manner.
>> > >
>> >
>> > Offline Chao pointed that Paul suggested this after considering refactoring out
>> > the common code. I think it might still be worth mentioning why you can't use
>> > multi_cpu_stop() directly. I guess there are some differences. what are they.
>>
>> To be clear, Paul didn't actually suggest this approach. His feedback indicated
>> he wasn't concerned about duplicating some of multi_cpu_stop()'s code, i.e., no
>> need to refactor out some common code.
>
>Right, sorry for oversimplifying.
>
>>
>> https://lore.kernel.org/all/a7affba9-0cea-4493-b868-392158b59d83@paulmck-laptop/#t
>>
>> We can't use multi_cpu_stop() directly because it only provides lockstep
>> execution for its own infrastructure, not for the function it runs. If we
>> passed a function that performs steps A, B, and C to multi_cpu_stop(), there's
>> no guarantee that all CPUs complete step A before any CPU begins step B.
>
>If it could be said more concisely, it seems relevant.
How about:
multi_cpu_stop() executes in lockstep but doesn't synchronize steps within the
callback function it takes. So, implement one based on its pattern.
^ permalink raw reply
* Re: [PATCH 1/1] firmware: smccc: add support for Live Firmware Activation (LFA)
From: Andre Przywara @ 2026-03-13 14:39 UTC (permalink / raw)
To: Nirmoy Das, Salman Nabi, vvidwans, sudeep.holla, mark.rutland,
lpieralisi
Cc: ardb, chao.gao, linux-arm-kernel, linux-coco, linux-kernel,
sdonthineni, vsethi, vwadekar
In-Reply-To: <19aeb934-7e36-4f30-8f7f-a8ae74a797f5@nvidia.com>
Hi Nirmoy,
On 3/13/26 10:46, Nirmoy Das wrote:
> Hi Salman and Andre,
>
>
> We found an bug while testing LFA. See below:
>
> On 19.01.26 14:27, Salman Nabi wrote:
>> The Arm Live Firmware Activation (LFA) is a specification [1] to describe
>> activating firmware components without a reboot. Those components
>> (like TF-A's BL31, EDK-II, TF-RMM, secure paylods) would be updated the
>> usual way: via fwupd, FF-A or other secure storage methods, or via some
>> IMPDEF Out-Of-Bound method. The user can then activate this new firmware,
>> at system runtime, without requiring a reboot.
>> The specification covers the SMCCC interface to list and query available
>> components and eventually trigger the activation.
[ .... ]
>> +
>> + update_fw_images_tree();
>> +
>> + /*
>> + * Removing non-valid image directories at the end of an activation.
>> + * We can't remove the sysfs attributes while in the respective
>> + * _store() handler, so have to postpone the list removal to a
>> + * workqueue.
>> + */
>> + INIT_WORK(&fw_images_update_work, remove_invalid_fw_images);
>
>
> This can get invoke multiple times so re-initializing a work item that
> may already be queued or running
>
> is unsafe. This should be moved to lfa_init() so it is only called once.
> I suggest:
Ah, good point, thanks for spotting and reporting. Will fold this into
the next post!
Cheers,
Andre
>
> diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/
> lfa_fw.c
> index 90727a66e49a5..135358113104c 100644
> --- a/drivers/firmware/smccc/lfa_fw.c
> +++ b/drivers/firmware/smccc/lfa_fw.c
> @@ -653,7 +653,6 @@ static int update_fw_images_tree(void)
> * _store() handler, so have to postpone the list removal to a
> * workqueue.
> */
> - INIT_WORK(&fw_images_update_work, remove_invalid_fw_images);
> queue_work(fw_images_update_wq, &fw_images_update_work);
>
> return 0;
> @@ -680,7 +679,7 @@ static void lfa_notify_handler(acpi_handle handle,
> u32 event, void *data)
> * of all activable and pending images.
> */
> do {
> - /* Reset activable image flag */
> + flush_workqueue(fw_images_update_wq);
> found_activable_image = false;
> list_for_each_entry(attrs, &lfa_fw_images, image_node) {
> if (attrs->fw_seq_id == -1)
> @@ -782,6 +781,8 @@ static int __init lfa_init(void)
> return -ENOMEM;
> }
>
> + INIT_WORK(&fw_images_update_work, remove_invalid_fw_images);
> +
> pr_info("Live Firmware Activation: detected v%ld.%ld\n",
> reg.a0 >> 16, reg.a0 & 0xffff);
>
>
> Regards,
>
> Nirmoy
>
>> + queue_work(fw_images_update_wq, &fw_images_update_work);
>> + mutex_unlock(&lfa_lock);
>> +
>> + return ret;
>> +}
>> +
^ permalink raw reply
* Re: [PATCH v2 3/3] KVM: SEV: Add support for SNP BTB Isolation
From: Tom Lendacky @ 2026-03-13 16:50 UTC (permalink / raw)
To: Kim Phillips, linux-kernel, kvm, linux-coco, x86
Cc: Sean Christopherson, Paolo Bonzini, K Prateek Nayak,
Nikunj A Dadhania, Michael Roth, Borislav Petkov, Borislav Petkov,
Naveen Rao, David Kaplan, Pawan Gupta
In-Reply-To: <20260311130611.2201214-4-kim.phillips@amd.com>
On 3/11/26 08:06, Kim Phillips wrote:
> This feature ensures SNP guest Branch Target Buffers (BTBs) are not
> affected by context outside that guest. CPU hardware tracks each
> guest's BTB entries and can flush the BTB if it has been determined
> to be contaminated with any prediction information originating outside
> the particular guest's context.
>
> To mitigate possible performance penalties incurred by these flushes,
> it is recommended that the hypervisor run with SPEC_CTRL[IBRS] set.
> Note that using Automatic IBRS is not an equivalent option here, since
> it behaves differently when SEV-SNP is active. See commit acaa4b5c4c85
> ("x86/speculation: Do not enable Automatic IBRS if SEV-SNP is enabled")
> for more details.
>
> Indicate support for BTB Isolation in sev_supported_vmsa_features,
> bit 7.
>
> SNP-active guests can enable (BTB) Isolation through SEV_Status
> bit 9 (SNPBTBIsolation).
>
> For more info, refer to page 615, Section 15.36.17 "Side-Channel
> Protection", AMD64 Architecture Programmer's Manual Volume 2: System
> Programming Part 2, Pub. 24593 Rev. 3.42 - March 2024 (see Link).
>
> Link: https://bugzilla.kernel.org/attachment.cgi?id=306250
> Signed-off-by: Kim Phillips <kim.phillips@amd.com>
> ---
> v2: No changes
> v1: https://lore.kernel.org/kvm/20260224180157.725159-4-kim.phillips@amd.com/
>
> arch/x86/include/asm/svm.h | 1 +
> arch/x86/kvm/svm/sev.c | 3 +++
> 2 files changed, 4 insertions(+)
>
> diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
> index edde36097ddc..2038461c1316 100644
> --- a/arch/x86/include/asm/svm.h
> +++ b/arch/x86/include/asm/svm.h
> @@ -305,6 +305,7 @@ static_assert((X2AVIC_4K_MAX_PHYSICAL_ID & AVIC_PHYSICAL_MAX_INDEX_MASK) == X2AV
> #define SVM_SEV_FEAT_RESTRICTED_INJECTION BIT(3)
> #define SVM_SEV_FEAT_ALTERNATE_INJECTION BIT(4)
> #define SVM_SEV_FEAT_DEBUG_SWAP BIT(5)
> +#define SVM_SEV_FEAT_BTB_ISOLATION BIT(7)
> #define SVM_SEV_FEAT_SECURE_TSC BIT(9)
>
> #define VMCB_ALLOWED_SEV_FEATURES_VALID BIT_ULL(63)
> diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
> index 3f9c1aa39a0a..ac29cf47dd08 100644
> --- a/arch/x86/kvm/svm/sev.c
> +++ b/arch/x86/kvm/svm/sev.c
> @@ -3167,6 +3167,9 @@ void __init sev_hardware_setup(void)
>
> if (sev_snp_enabled && tsc_khz && cpu_feature_enabled(X86_FEATURE_SNP_SECURE_TSC))
> sev_supported_vmsa_features |= SVM_SEV_FEAT_SECURE_TSC;
> +
> + if (sev_snp_enabled)
> + sev_supported_vmsa_features |= SVM_SEV_FEAT_BTB_ISOLATION;
This would also need to update the SVM_SEV_FEAT_SNP_ONLY_MASK that Sean
suggested/created in the IBPB-On-Entry series.
Thanks,
Tom
> }
>
> void sev_hardware_unsetup(void)
^ permalink raw reply
* Re: [PATCH v4 11/24] x86/virt/seamldr: Introduce skeleton for TDX Module updates
From: Edgecombe, Rick P @ 2026-03-13 17:43 UTC (permalink / raw)
To: Gao, Chao
Cc: kvm@vger.kernel.org, linux-coco@lists.linux.dev, Huang, Kai,
x86@kernel.org, dave.hansen@linux.intel.com, kas@kernel.org,
binbin.wu@linux.intel.com, Weiny, Ira,
tony.lindgren@linux.intel.com, mingo@redhat.com, Verma, Vishal L,
nik.borisov@suse.com, seanjc@google.com,
linux-kernel@vger.kernel.org, Annapurve, Vishal, sagis@google.com,
Duan, Zhenzhong, tglx@kernel.org, paulmck@kernel.org,
Chatre, Reinette, bp@alien8.de, yilun.xu@linux.intel.com,
Williams, Dan J, hpa@zytor.com
In-Reply-To: <abQW/1Cfxl9TdJ8D@intel.com>
On Fri, 2026-03-13 at 21:54 +0800, Chao Gao wrote:
> Or the step details might be irrelevant. Perhaps:
>
> TDX module update consists of several steps. Ordering requirements between
> steps mandate lockstep synchronization across all CPUs.
It seems like enough to understand this patch. Then would you put a little blurb
about the ordering of each step in the later patches?
>
> > > > > 1. The entire update process must use stop_machine() to synchronize with
> > > > > other TDX workloads
> > > > > 2. Update steps must be performed in a step-locked manner
> > > > >
> > > > > To prepare for implementing concrete TDX Module update steps, establish
> > > > > the framework by mimicking multi_cpu_stop(), which is a good example of
> > > > > performing a multi-step task in step-locked manner.
> > > > >
> > > >
> > > > Offline Chao pointed that Paul suggested this after considering refactoring out
> > > > the common code. I think it might still be worth mentioning why you can't use
> > > > multi_cpu_stop() directly. I guess there are some differences. what are they.
> > >
> > > To be clear, Paul didn't actually suggest this approach. His feedback indicated
> > > he wasn't concerned about duplicating some of multi_cpu_stop()'s code, i.e., no
> > > need to refactor out some common code.
> >
> > Right, sorry for oversimplifying.
> >
> > >
> > > https://lore.kernel.org/all/a7affba9-0cea-4493-b868-392158b59d83@paulmck-laptop/#t
> > >
> > > We can't use multi_cpu_stop() directly because it only provides lockstep
> > > execution for its own infrastructure, not for the function it runs. If we
> > > passed a function that performs steps A, B, and C to multi_cpu_stop(), there's
> > > no guarantee that all CPUs complete step A before any CPU begins step B.
> >
> > If it could be said more concisely, it seems relevant.
>
> How about:
>
> multi_cpu_stop() executes in lockstep but doesn't synchronize steps within the
> callback function it takes. So, implement one based on its pattern.
Yea.
^ permalink raw reply
* Re: [PATCH v2 08/19] PCI/TSM: Add "evidence" support
From: Dan Williams @ 2026-03-13 18:06 UTC (permalink / raw)
To: Xu Yilun, Dan Williams
Cc: linux-coco, linux-pci, gregkh, aik, aneesh.kumar, bhelgaas,
alistair23, lukas, jgg, Donald Hunter, Jakub Kicinski
In-Reply-To: <abPh3d4+opAkot3p@yilunxu-OptiPlex-7050>
Xu Yilun wrote:
> > +void pci_tsm_init_evidence(struct pci_tsm_evidence *evidence, int slot,
> > + enum hash_algo digest_algo)
> > +{
> > + evidence->slot = slot;
> > + evidence->generation = 1;
> > + evidence->digest_algo = digest_algo;
> > + init_rwsem(&evidence->lock);
>
> IIUC, this function is for link tsm driver, is it?
It is meant to be generic for both, and an "optional" support
library for the low-level TSM drivers.
- Host PCI/TSM evidence interface collects the blobs
- Guest PCI/TSM evidence interface retrieves the digests via private TSM
GHCI
- Some infrastructure (either arch specific GHCI or new common GHCI)
pushes the blobs from Host to Guest so that guest PCI/TSM evidence
gathering can also get the blobs.
> But in the following patch, devsec tsm would consume
> pci_tsm_mmio_alloc() which uses evidence->lock. So my solution is to
> initialize the lock on tsm construction.
So I did flub the "->evidence == 0" check, and yes initializing the lock
by default looks like the right answer to that problem.
^ permalink raw reply
* Re: [PATCH v2 03/19] device core: Introduce confidential device acceptance
From: Dan Williams @ 2026-03-13 18:53 UTC (permalink / raw)
To: Greg KH, Dan Williams
Cc: linux-coco, linux-pci, aik, aneesh.kumar, yilun.xu, bhelgaas,
alistair23, lukas, jgg, Christoph Hellwig, Jason Gunthorpe,
Marek Szyprowski, Robin Murphy, Roman Kisel, Samuel Ortiz,
Rafael J. Wysocki, Danilo Krummrich
In-Reply-To: <2026031319-payee-photo-bdd9@gregkh>
Greg KH wrote:
> On Thu, Mar 12, 2026 at 09:11:32PM -0700, Dan Williams wrote:
> > Greg KH wrote:
> > > On Mon, Mar 02, 2026 at 04:01:51PM -0800, Dan Williams wrote:
> > > > An "accepted" device is one that is allowed to access private memory within
> > > > a Trusted Computing Boundary (TCB). The concept of "acceptance" is distinct
> > > > from other device properties like usb_device::authorized, or
> > > > tb_switch::authorized. The entry to the accepted state is a violent
> > > > operation in which the device will reject MMIO requests that are not
> > > > encrypted, and the device enters a new IOMMU protection domain to allow it
> > > > to access addresses that were previously off-limits.
> > >
> > > Trying to mix/match "acceptance" with "authorized" is going to be a
> > > nightmare, what's the combination that can happen here over time?
> >
> > I do think Linux needs to mix/match these concepts. "Authorization" is a
> > kernel policy to operate a device at all. "Acceptance" is a mechanism
> > to operate a device within a hardware TCB boundary.
> >
> > So, the truth table of combinations would be:
> >
> > accepted authorized result
> > 0 0 logically and physically disconnected device
> >
> > 0 1 connected device, DMA is bounce buffered
> > and loses confidentiality, integrity,
> > and performance
> >
> > 1 0 logically disconnected device, but a
> > relying party trusts that the device is
> > not spoofing authorization.
> >
> > 1 1 connected device, DMA is direct and gains
> > confidentiality, integrity and performance
> >
> > To say it another way, when the above distinguishes "logically" vs
> > "physically" disconnected it is whether the device interface can be
> > verified to not be under adversarial control. An unaccepted device can
> > do limited damage, but still can bounce buffer secrets out of the TCB if
> > so directed.
>
> I really don't agree with this, but I can't think of why at the moment.
> I feel like you are looking at this purely in the TCB point of view,
> while I don't feel that is something that should be considered "special"
> at all here. Linux has, for the most part, always trusted the hardware,
> and now you are wanting to not trust the hardware.
I think framing "trust" as an enum rather than a boolean better
addresses this problem.
> for some things and parts of the kernel. Which is great, it's
> something that I have wanted to change for a very long time now, but
> let's do it right if at all possible.
>
> Give me a few days to come up with a better reply, let me think about
> this some more...
Sure, but I also think we might already be converging, more below...
> > > We need to either "trust" or "not trust" the device, and the bus can
> > > decide what to do with that value (if anything). The DMA layer can then
> > > use that value to do:
> >
> > Trust is separate. For example, there are deployed use cases today where
> > the device is trusted, but unaccepted. Acceptance support for those
> > cases is mostly a performance optimization to be able to stop performing
> > software encryption on top of DMA bounce buffering.
>
> If "acceptance" is just a performance issue, I think you all need to go
> back to the marketing people as that's probably not what they intended
> to have happen here. For some reason I thought they were selling this
> as "security", not "speed" :)
Do not get me wrong there are several threat models mitigated by having
hardware assurance that all communications with the device are
confidentiality and integrity protected. Hardware assurances that
attempts to subvert those protections result in hardware error states is
part of the value. However, you can approximate a subset of those
protections with high overhead workarounds.
> > > > Subsystems like the DMA mapping layer, that need to modify their behavior
> > > > based on the accept state, may only have access to the base 'struct
> > > > device'.
> > >
> > > ^this.
> >
> > The DMA layer is not operating on a trust concept it is effectively
> > being told to select an IOMMU.
>
> Ok, then that's independent of "acceptance", that is "use this IOMMU vs.
> that one" type of thing which is just a "basic configuration for speed"
> type of thing as you mention above :)
>
> Let's not confuse that with anything else like "acceptance" please.
That is fine, and I think you and Jason may be hitting on the same
concern.
>
> > > > It is also likely that the concept of TCB acceptance grows beyond
> > > > PCI devices over time. For these reasons, introduce the concept of
> > > > acceptance in 'struct device_private' which is device common, but only
> > > > suitable for buses and built-in infrastructure to consume.
> > >
> > > Busses are what can control this, but please, let's not make this a
> > > cc-only type thing. We have the idea of trust starting to propagate
> > > through a number of different busses, let's get it right here, so we
> > > don't have to have all of these different bus-specific hacks like we do
> > > today.
> >
> > The conflation of "trust" and "acceptance" has been the main stumbling
> > block of past proposals. As you have said before "kernel drivers trust
> > their devices". That precedent is not being touched in this proposal.
>
> Ah, but I WANT to touch that. Let's FINALLY solve that! Or at the very
> least, provide the infrastructure in the driver core to allow busses
> that want to do that, to be able to do so.
Jason's framing of an enum rather than a boolean for "trust" seems
workable to me and melds "authorization" and "CC acceptance" into one
concept.
> > Instead, give userspace all the tools it needs to deploy policy about
> > when to operate a device. When it does decide to operate the device give
> > it the mechanism to add confidentiality, integrity and performance to
> > that operation.
>
> Yes, this is a policy decision, and if you are only saying this is about
> "which IOMMU should we select", then that's a dma layer configuration
> option. Let's not call that "acceptance" please.
Done.
...and there is precedent for a "trust" enum, lockdown levels. In that
case as well there are a menu of priveleges that can be incrementally
enabled by a policy.
> > This is a "CC-only type thing" because only CC partitions the system
> > into two device domains. One where "trusted unaccepted" devices can
> > operate without CC protections and "trusted accepted" devices can
> > operate with CC protections and direct DMA.
>
> In other words, it's an IOMMU switch, so why not use the switch
> infrastructure? </me runs away...>
>
> anyway, let me think about this some more...
Will do, however in the meantime I am going to speculate that this "trust
as enum" idea is workable and start drafting some patches towards that.
^ permalink raw reply
* Re: [PATCH v2 03/19] device core: Introduce confidential device acceptance
From: Jason Gunthorpe @ 2026-03-13 19:07 UTC (permalink / raw)
To: Dan Williams
Cc: Greg KH, linux-coco, linux-pci, aik, aneesh.kumar, yilun.xu,
bhelgaas, alistair23, lukas, Christoph Hellwig, Marek Szyprowski,
Robin Murphy, Roman Kisel, Samuel Ortiz, Rafael J. Wysocki,
Danilo Krummrich
In-Reply-To: <69b45d178ae17_b2b6100f2@dwillia2-mobl4.notmuch>
On Fri, Mar 13, 2026 at 11:53:11AM -0700, Dan Williams wrote:
> Jason's framing of an enum rather than a boolean for "trust" seems
> workable to me and melds "authorization" and "CC acceptance" into one
> concept.
I think you can also fold the auto-probe into this as well.
The kernel would have some default policy for what enum value to set
upon discovery and instead of 'disable auto probe' you'd arrange to
set trust level 0 which would block driver binding and probing
inherently.
Policy in userspace then has to increase the trust level which could
trigger an auto-bind.
> > > Instead, give userspace all the tools it needs to deploy policy about
> > > when to operate a device. When it does decide to operate the device give
> > > it the mechanism to add confidentiality, integrity and performance to
> > > that operation.
> >
> > Yes, this is a policy decision, and if you are only saying this is about
> > "which IOMMU should we select", then that's a dma layer configuration
> > option. Let's not call that "acceptance" please.
>
> Done.
AFAICT "which IOMMU should we select" should entirely be driven by the
TDISP state being in RUN
Jason
^ permalink raw reply
* Re: [PATCH v2 03/19] device core: Introduce confidential device acceptance
From: Dan Williams @ 2026-03-13 19:56 UTC (permalink / raw)
To: Jason Gunthorpe, Dan Williams
Cc: Greg KH, linux-coco, linux-pci, aik, aneesh.kumar, yilun.xu,
bhelgaas, alistair23, lukas, Christoph Hellwig, Marek Szyprowski,
Robin Murphy, Roman Kisel, Samuel Ortiz, Rafael J. Wysocki,
Danilo Krummrich
In-Reply-To: <20260313133235.GC1586734@nvidia.com>
Jason Gunthorpe wrote:
> On Thu, Mar 12, 2026 at 09:11:32PM -0700, Dan Williams wrote:
> > Greg KH wrote:
> > > On Mon, Mar 02, 2026 at 04:01:51PM -0800, Dan Williams wrote:
> > > > An "accepted" device is one that is allowed to access private memory within
> > > > a Trusted Computing Boundary (TCB). The concept of "acceptance" is distinct
> > > > from other device properties like usb_device::authorized, or
> > > > tb_switch::authorized. The entry to the accepted state is a violent
> > > > operation in which the device will reject MMIO requests that are not
> > > > encrypted, and the device enters a new IOMMU protection domain to allow it
> > > > to access addresses that were previously off-limits.
> > >
> > > Trying to mix/match "acceptance" with "authorized" is going to be a
> > > nightmare, what's the combination that can happen here over time?
> >
> > I do think Linux needs to mix/match these concepts. "Authorization" is a
> > kernel policy to operate a device at all. "Acceptance" is a mechanism
> > to operate a device within a hardware TCB boundary.
>
> I'm not sure about these words either, I would revise your table to be
> more OS centric, the device can be in one of four security levels:
I like this framing.
> 0 Blocked and disabled
> The device cannot attack the system, enforced by the OS not loading a
> driver or mapping the MMIO and IOMMU fully blocking everything from it.
In terms of details I am trying to think through whether the device
actually changes its ->trust level in reaction to a driver attaching, or
whether the block and disabled state is implicit in not being driver
bound.
It does strike me that this value could be used to convey whether a
given arch's IOMMU driver indeed arranges for devices to be IOMMU
blocked while driver detached. In that case you could see, "oh, devices
are not DMA blocked by default" as we talked about in the ATS-always-on
thread [1].
[1]: http://lore.kernel.org/20260128130520.GV1134360@nvidia.com
> 1 In use, attacks from a hostile device are possible
> A driver can operate the device and is expected to defend against
> attacks from the device itself. The IOMMU restricts the device to only
> access driver approved data (no ATS, DMA strict only, CC shared
> only, interrupt remapping security, bounce partial DMA mappings, etc)
This is a better way to convey the current "force_swiotlb" settings that
TVMs deploy in their arch code.
> 2 In use, no attacks from the device
> The device does what the driver says and is not hostile. The driver
> does not have to defend itself, the IOMMU can run in faster & lower
> security modes (ATS on, DMA-FQ, Identity, still CC shared only)
> * Basically our default security level today
>
> 3 In use, no attacks, and access to CC private memory
> Like #2 and now the IOMMU allows access to CC private memory too.
I am assuming that each bus implementation may have a different way to
get the device to the various trust levels.
For example, the uAPI for PCI TDISP requires associating a device with a
TSM and asking the TSM to push the device to trust level 3. Another bus
like thunderbolt may want to imply that "authorized" that uses challenge
response (tb_domain_challenge_switch_key) enables trust level 2, but
otherwise only enables trust level 1.
> [*] I'm inclunding all attacks with "hostile device", including MIM on
> the PCIe link, compromised/fake device, attacks from a VMM through a
> virtual device, etc.
>
> From a CC VM perspective 0 is at boot, 1 is an out of TCB device, 2
> doesn't exist (without TDISP there is no way to keep the
> hypervisor from attacking?),
Yes, no mitigations against spoofing the device interface without TDISP.
However, I would also assume that level 2 is the ATS-on trust level
outside of TDISP cases.
> and 3 is a full accepted TDSIP device.
>
> #2 can happen in bare metal where a OS may activate link encryption
> and attest the device, but doesn't have CC private/shared memory.
Bare metal would still need to figure out how to send T=1 MMIO cycles
and check with some boot attestation that it can trust its MMIO mappings
are indeed targeting the device. So let's say trust level 2 is
everything but private MMIO and private DMA.
> From a uAPI perspective I'm not sold on having two bools, I think a
> level string would be more flexible. TSM and CC properties are
> orthogonal, except you can't select #3 without the TSM saying it is in
> RUN.
Perhaps the concern is less 2 bools in the uAPI and more the concern
that 'struct pci_dev::untrusted', 'struct tb_switch::authorized',
'struct usb_dev::authorized' and this new 'struct
device_private::cc_accepted' are getting convoluted.
> Internally we'd probably turn that dev->trusted thing into an
> enum and teach the iommu layer to treat it more dynamically.
I will take a stab at some patches in this direction and at least
demonstrate how 'struct pci_dev::untrusted' can be merged with what CC
wants to add on top.
^ permalink raw reply
* Re: [PATCH v2 1/3] cpu/bugs: Allow forcing Automatic IBRS with SNP enabled using spectre_v2=eibrs
From: Pawan Gupta @ 2026-03-13 20:04 UTC (permalink / raw)
To: Kim Phillips
Cc: linux-kernel, kvm, linux-coco, x86, Sean Christopherson,
Paolo Bonzini, K Prateek Nayak, Nikunj A Dadhania, Tom Lendacky,
Michael Roth, Borislav Petkov, Borislav Petkov, Naveen Rao,
David Kaplan, stable
In-Reply-To: <20260311130611.2201214-2-kim.phillips@amd.com>
On Wed, Mar 11, 2026 at 08:06:09AM -0500, Kim Phillips wrote:
> To allow this, do the SNP check in spectre_v2_select_mitigation()
> processing instead of the original commit's implementation in
> cpu_set_bug_bits().
>
> Since SPECTRE_V2_CMD_AUTO logic falls through to SPECTRE_V2_CMD_FORCE,
> double-check if SPECTRE_V2_CMD_FORCE is used before allowing
> SPECTRE_V2_EIBRS with SNP enabled.
>
> Also mute SPECTRE_V2_IBRS_PERF_MSG if SNP is enabled on an AutoIBRS
> capable machine, since, in that case, the message doesn't apply.
>
> Fixes: acaa4b5c4c85 ("x86/speculation: Do not enable Automatic IBRS if SEV-SNP is enabled")
> Reported-by: Tom Lendacky <thomas.lendacky@amd.com>
> Cc: Borislav Petkov (AMD) <bp@alien8.de>
> Cc: stable@kernel.org
> Signed-off-by: Kim Phillips <kim.phillips@amd.com>
> ---
> v2:
> - Address Dave Hansen's comment to adhere to using the IBRS_ENHANCED
> Intel feature flag also for AutoIBRS.
>
> v1:
> https://lore.kernel.org/kvm/20260224180157.725159-2-kim.phillips@amd.com/
>
> arch/x86/kernel/cpu/bugs.c | 12 ++++++++++--
> arch/x86/kernel/cpu/common.c | 6 +-----
> 2 files changed, 11 insertions(+), 7 deletions(-)
>
> diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
> index 83f51cab0b1e..957e0df38d90 100644
> --- a/arch/x86/kernel/cpu/bugs.c
> +++ b/arch/x86/kernel/cpu/bugs.c
> @@ -2181,7 +2181,14 @@ static void __init spectre_v2_select_mitigation(void)
> break;
> fallthrough;
> case SPECTRE_V2_CMD_FORCE:
> - if (boot_cpu_has(X86_FEATURE_IBRS_ENHANCED)) {
> + /*
> + * Unless forced, don't use AutoIBRS when SNP is enabled
> + * because it degrades host userspace indirect branch performance.
> + */
> + if (boot_cpu_has(X86_FEATURE_IBRS_ENHANCED) &&
> + (!boot_cpu_has(X86_FEATURE_SEV_SNP) ||
> + (boot_cpu_has(X86_FEATURE_SEV_SNP) &&
> + spectre_v2_cmd == SPECTRE_V2_CMD_FORCE))) {
This is forcing AutoIBRS when spectre_v2=on (meaning force), but the
subject says to allow forcing with spectre_v2=eibrs, which one is it?
^ permalink raw reply
* Re: [PATCH v2 03/19] device core: Introduce confidential device acceptance
From: Jason Gunthorpe @ 2026-03-13 20:24 UTC (permalink / raw)
To: Dan Williams
Cc: Greg KH, linux-coco, linux-pci, aik, aneesh.kumar, yilun.xu,
bhelgaas, alistair23, lukas, Christoph Hellwig, Marek Szyprowski,
Robin Murphy, Roman Kisel, Samuel Ortiz, Rafael J. Wysocki,
Danilo Krummrich
In-Reply-To: <69b46bd7935d9_b2b6100b7@dwillia2-mobl4.notmuch>
On Fri, Mar 13, 2026 at 12:56:07PM -0700, Dan Williams wrote:
> > 0 Blocked and disabled
> > The device cannot attack the system, enforced by the OS not loading a
> > driver or mapping the MMIO and IOMMU fully blocking everything from it.
>
> In terms of details I am trying to think through whether the device
> actually changes its ->trust level in reaction to a driver attaching, or
> whether the block and disabled state is implicit in not being driver
> bound.
I am thinking of it as an independent property. When the device is
first discovered it gets a level by default, userspace can change the
level but only when not bound. The level restricts what the kernel
will do with the device, 0 would mean "do not allow a driver to bind"
> > 1 In use, attacks from a hostile device are possible
> > A driver can operate the device and is expected to defend against
> > attacks from the device itself. The IOMMU restricts the device to only
> > access driver approved data (no ATS, DMA strict only, CC shared
> > only, interrupt remapping security, bounce partial DMA mappings, etc)
>
> This is a better way to convey the current "force_swiotlb" settings that
> TVMs deploy in their arch code.
SWIOTLB that is needed to make the DMA API work because the device
cannot reach CC private memory is orthogonal - the TDISP state (or
lack of) should directly drive that in the DMA API.
The DMA API just wants a flag in the struct device that says if the
device can access encrypted memory or only decrypted.
> I am assuming that each bus implementation may have a different way to
> get the device to the various trust levels.
I was actually thinking no, it is just a generic orthogonal driver
core property.
> For example, the uAPI for PCI TDISP requires associating a device with a
> TSM and asking the TSM to push the device to trust level 3.
The other way, you can't get to level 3 unless the TSM subsystem ACK's
it. So TSM independently does its bit then userspace can set the level
to 3.
If it sets RUN and 2 that should work and have some kind of meaning,
just not be super useful.
> Another bus like thunderbolt may want to imply that "authorized"
> that uses challenge response (tb_domain_challenge_switch_key)
> enables trust level 2, but otherwise only enables trust level 1.
For thunderbolt/hot plug I imagine the kernel would default all
devices to level 0. Userspace would do its thing, using whatever other
uAPIs, and then set the level to 1 or 2. Then the driver starts.
This way nothing is coupled and the kernel can offer all kinds of
different uAPI for device verification. Userspaces picks the
appropriate one and acks it with the level change.
> Yes, no mitigations against spoofing the device interface without TDISP.
> However, I would also assume that level 2 is the ATS-on trust level
> outside of TDISP cases.
Yes, level 2 would be the break where the device is required to not do
wild PCIe packets to maintain kernel integrity.
> > #2 can happen in bare metal where a OS may activate link encryption
> > and attest the device, but doesn't have CC private/shared memory.
>
> Bare metal would still need to figure out how to send T=1 MMIO cycles
> and check with some boot attestation that it can trust its MMIO mappings
> are indeed targeting the device. So let's say trust level 2 is
> everything but private MMIO and private DMA.
bare metal has no T=1 and no "private" at all. It just sets up link
encryption, excludes a MIM, attests the peer, then opens the iommu.
Jason
^ permalink raw reply
* Re: [PATCH v2 03/19] device core: Introduce confidential device acceptance
From: Dan Williams @ 2026-03-14 1:32 UTC (permalink / raw)
To: Jason Gunthorpe, Dan Williams
Cc: Greg KH, linux-coco, linux-pci, aik, aneesh.kumar, yilun.xu,
bhelgaas, alistair23, lukas, Christoph Hellwig, Marek Szyprowski,
Robin Murphy, Roman Kisel, Samuel Ortiz, Rafael J. Wysocki,
Danilo Krummrich
In-Reply-To: <20260313202421.GG1586734@nvidia.com>
Jason Gunthorpe wrote:
> On Fri, Mar 13, 2026 at 12:56:07PM -0700, Dan Williams wrote:
> > > 0 Blocked and disabled
> > > The device cannot attack the system, enforced by the OS not loading a
> > > driver or mapping the MMIO and IOMMU fully blocking everything from it.
> >
> > In terms of details I am trying to think through whether the device
> > actually changes its ->trust level in reaction to a driver attaching, or
> > whether the block and disabled state is implicit in not being driver
> > bound.
>
> I am thinking of it as an independent property. When the device is
> first discovered it gets a level by default, userspace can change the
> level but only when not bound. The level restricts what the kernel
> will do with the device, 0 would mean "do not allow a driver to bind"
The problem is that for all the buses that do not currently have a
"device authorization" concept only userspace can decide that a device
should skip bind by default. For that, I propose module autoprobe policy
[1]. Not yet convinced the kernel needs its own per-device "no bind"
policy.
However, I do think userspace would like to know if the IOMMU subsystem
has blocked device DMA while unbound.
[1]: http://lore.kernel.org/20260303000207.1836586-6-dan.j.williams@intel.com
> > > 1 In use, attacks from a hostile device are possible
> > > A driver can operate the device and is expected to defend against
> > > attacks from the device itself. The IOMMU restricts the device to only
> > > access driver approved data (no ATS, DMA strict only, CC shared
> > > only, interrupt remapping security, bounce partial DMA mappings, etc)
> >
> > This is a better way to convey the current "force_swiotlb" settings that
> > TVMs deploy in their arch code.
>
> SWIOTLB that is needed to make the DMA API work because the device
> cannot reach CC private memory is orthogonal - the TDISP state (or
> lack of) should directly drive that in the DMA API.
>
> The DMA API just wants a flag in the struct device that says if the
> device can access encrypted memory or only decrypted.
You mean separate "trusted to access private" and "currently enabled to
access private" properties? I am trying to think of a situation where
"dev->trust >= 3" and a flag saying "disable bouncing for encrypted
memory" would ever disagree.
> > I am assuming that each bus implementation may have a different way to
> > get the device to the various trust levels.
>
> I was actually thinking no, it is just a generic orthogonal driver
> core property.
Property? Agreed. uAPI? Not so sure...
> > For example, the uAPI for PCI TDISP requires associating a device with a
> > TSM and asking the TSM to push the device to trust level 3.
>
> The other way, you can't get to level 3 unless the TSM subsystem ACK's
> it. So TSM independently does its bit then userspace can set the level
> to 3.
That bit though has lock-to-run consistency expectations. So if the
kernel does not yet fully trust the device by time the relying party is
satisfied, and the uAPI to transition the device into the TCB (level 3)
is driver-core generic it raises TOCTOU issues in my mind. The
driver-core would need to ask the bus "user now trusts this device, do
you?".
Aneesh and I are currently debating on Discord whether the kernel needs
to protect against guest userspace confusing itself. Part of me says no,
especially with sysfs, if multiple threads are racing "unlock,
update/re-measure, lock, accept", then userspace gets to keep the
pieces.
However, to Aneesh's point we could protect against that with a
transactional uAPI like netlink that can express "trust if and only if
the device has not been relocked before final accept" by passing a
cookie obtained at lock to accept. That would be awkward to coordinate
with driver-core generic uAPI for trust.
> If it sets RUN and 2 that should work and have some kind of meaning,
> just not be super useful.
>
> > Another bus like thunderbolt may want to imply that "authorized"
> > that uses challenge response (tb_domain_challenge_switch_key)
> > enables trust level 2, but otherwise only enables trust level 1.
>
> For thunderbolt/hot plug I imagine the kernel would default all
> devices to level 0. Userspace would do its thing, using whatever other
> uAPIs, and then set the level to 1 or 2. Then the driver starts.
>
> This way nothing is coupled and the kernel can offer all kinds of
> different uAPI for device verification. Userspaces picks the
> appropriate one and acks it with the level change.
Thunderbolt already has authorized uAPI. I expect adding dev->trust
support to thunderbolt is more related to ATS privilege and private
memory privilege.
> > Yes, no mitigations against spoofing the device interface without TDISP.
> > However, I would also assume that level 2 is the ATS-on trust level
> > outside of TDISP cases.
>
> Yes, level 2 would be the break where the device is required to not do
> wild PCIe packets to maintain kernel integrity.
>
> > > #2 can happen in bare metal where a OS may activate link encryption
> > > and attest the device, but doesn't have CC private/shared memory.
> >
> > Bare metal would still need to figure out how to send T=1 MMIO cycles
> > and check with some boot attestation that it can trust its MMIO mappings
> > are indeed targeting the device. So let's say trust level 2 is
> > everything but private MMIO and private DMA.
>
> bare metal has no T=1 and no "private" at all. It just sets up link
> encryption, excludes a MIM, attests the peer, then opens the iommu.
Ok, we are on the same page as to what a theoretical level 2 would mean.
^ permalink raw reply
* Re: [PATCH v2 08/19] PCI/TSM: Add "evidence" support
From: Jakub Kicinski @ 2026-03-14 18:12 UTC (permalink / raw)
To: Dan Williams
Cc: linux-coco, linux-pci, gregkh, aik, aneesh.kumar, yilun.xu,
bhelgaas, alistair23, lukas, jgg, Donald Hunter
In-Reply-To: <20260303000207.1836586-9-dan.j.williams@intel.com>
On Mon, 2 Mar 2026 16:01:56 -0800 Dan Williams wrote:
> The implementation adheres to the guideline from:
> Documentation/userspace-api/netlink/genetlink-legacy.rst
>
> New Netlink families should never respond to a DO operation with
> multiple replies, with ``NLM_F_MULTI`` set. Use a filtered dump
> instead.
My understanding of F_MULTI is that deserializer is supposed to
continue deserializing into current object. IOW if we have:
struct does_this {
int really;
int have_to;
int be_netlink;
};
You can send "really" and "be_netlink" in one message and "have_to"
in the next, and receiver should reconstruct them into a single struct.
If F_MULTI is not set - receiver assumes that the next message is a new
struct. And the whole dump returns a list of structs.
So IOW I think what you're doing is a bit too.. inventive.
Do you have plans to add more commands?
The read-only stuff feels like it could be a sysfs API?
The main strength of Netlink is "do" commands with multiple optional
attrs.
^ permalink raw reply
* Re: [PATCH v2 08/19] PCI/TSM: Add "evidence" support
From: Lukas Wunner @ 2026-03-14 18:37 UTC (permalink / raw)
To: Dan Williams
Cc: linux-coco, linux-pci, gregkh, aik, aneesh.kumar, yilun.xu,
bhelgaas, alistair23, jgg, Donald Hunter, Jakub Kicinski
In-Reply-To: <20260303000207.1836586-9-dan.j.williams@intel.com>
On Mon, Mar 02, 2026 at 04:01:56PM -0800, Dan Williams wrote:
> +definitions:
> + -
> + type: const
> + name: max-object-size
> + value: 0x01000000
[...]
> + -
> + name: val
> + type: binary
> + checks:
> + max-len: max-obj-size
The length of a netlink attribute is a 16-bit value, so a 16 MByte value
(0x01000000) won't fit.
Moreover you're referencing max-obj-size but are defining max-object-size.
This doesn't look like it's ever been tested, so at the very least
it should be marked RFC in the subject to convey that it's not yet
in a cut-and-dried state.
The two top-most commits on my development branch have solved the
size problem and may serve as a template:
https://github.com/l1k/linux/commits/doe
Thanks,
Lukas
^ permalink raw reply
* Re: [PATCH] coco/guest: Remove unneeded selection of CRYPTO
From: Eric Biggers @ 2026-03-14 20:55 UTC (permalink / raw)
To: Dan Williams, linux-coco
In-Reply-To: <20260109022620.GB2790@sol>
On Thu, Jan 08, 2026 at 06:26:22PM -0800, Eric Biggers wrote:
> On Wed, Dec 03, 2025 at 09:55:12PM -0800, Eric Biggers wrote:
> > All that's needed here is CRYPTO_HASH_INFO. It used to be the case that
> > CRYPTO_HASH_INFO was visible only when CRYPTO, but that was fixed by
> > commit aacb37f597d0 ("lib/crypto: hash_info: Move hash_info.c into
> > lib/crypto/"). Now CRYPTO_HASH_INFO can be selected directly.
> >
> > Signed-off-by: Eric Biggers <ebiggers@kernel.org>
> > ---
> > drivers/virt/coco/guest/Kconfig | 1 -
> > 1 file changed, 1 deletion(-)
> >
> > diff --git a/drivers/virt/coco/guest/Kconfig b/drivers/virt/coco/guest/Kconfig
> > index 3d5e1d05bf34..da570dc4bd48 100644
> > --- a/drivers/virt/coco/guest/Kconfig
> > +++ b/drivers/virt/coco/guest/Kconfig
> > @@ -11,7 +11,6 @@ config TSM_REPORTS
> > tristate
> >
> > config TSM_MEASUREMENTS
> > select TSM_GUEST
> > select CRYPTO_HASH_INFO
> > - select CRYPTO
> > bool
> >
>
> Any interest in applying this patch?
Ping.
If there continues to be no response, I'll take this patch via
libcrypto-next.
- Eric
^ permalink raw reply
* Re: [PATCH] coco/guest: Remove unneeded selection of CRYPTO
From: Dan Williams @ 2026-03-14 22:04 UTC (permalink / raw)
To: Eric Biggers, Dan Williams, linux-coco
In-Reply-To: <20260314205533.GA45660@quark>
Eric Biggers wrote:
> On Thu, Jan 08, 2026 at 06:26:22PM -0800, Eric Biggers wrote:
> > On Wed, Dec 03, 2025 at 09:55:12PM -0800, Eric Biggers wrote:
> > > All that's needed here is CRYPTO_HASH_INFO. It used to be the case that
> > > CRYPTO_HASH_INFO was visible only when CRYPTO, but that was fixed by
> > > commit aacb37f597d0 ("lib/crypto: hash_info: Move hash_info.c into
> > > lib/crypto/"). Now CRYPTO_HASH_INFO can be selected directly.
> > >
> > > Signed-off-by: Eric Biggers <ebiggers@kernel.org>
> > > ---
> > > drivers/virt/coco/guest/Kconfig | 1 -
> > > 1 file changed, 1 deletion(-)
> > >
> > > diff --git a/drivers/virt/coco/guest/Kconfig b/drivers/virt/coco/guest/Kconfig
> > > index 3d5e1d05bf34..da570dc4bd48 100644
> > > --- a/drivers/virt/coco/guest/Kconfig
> > > +++ b/drivers/virt/coco/guest/Kconfig
> > > @@ -11,7 +11,6 @@ config TSM_REPORTS
> > > tristate
> > >
> > > config TSM_MEASUREMENTS
> > > select TSM_GUEST
> > > select CRYPTO_HASH_INFO
> > > - select CRYPTO
> > > bool
> > >
> >
> > Any interest in applying this patch?
>
> Ping.
>
> If there continues to be no response, I'll take this patch via
> libcrypto-next.
Apologies, not sure how I missed this.
Acked-by: Dan Williams <dan.j.williams@intel.com>
...and yes, fine for this to go through libcrypto-next.
^ permalink raw reply
* [PATCH v5 00/22] Runtime TDX module update support
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
To: kvm, linux-coco, linux-doc, linux-kernel, x86
Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
yilun.xu, Chao Gao, Borislav Petkov, H. Peter Anvin, Ingo Molnar,
Jonathan Corbet, Shuah Khan, Thomas Gleixner
Hi Reviewers,
With this posting, I'm hoping to collect more Reviewed-by or Acked-by tags.
Please note these changes:
Patch 18 handles a CPU erratum that clears the active VMCS after
P-SEAMLDR calls. Because of this erratum, patch 6 now exposes seamldr
attributes during device probe rather than creation as unconditional
exposure would be unsafe.
Patch 22 adds error logging for update failures. It's kind of
nice-to-have, so it is placed last for easy removal if necessary.
For transparency, I should note that I used an Intel-operated AI tool to
help proofread this cover-letter and commit messages.
Changelog:
v4->v5:
- s/TDX Module/TDX module/g [Binbin/Dave]
- drop is_vmalloc_addr() checking [Dave/Rick]
- protect lockstep control data with a lock [Dave]
- clarify why raw_spinlock is used [Dave/Kai]
- drop patches that check all CPUs are online and updates are not exhausted [Dave]
- register seamldr attributes in device probe
- use devm_add_action_or_reset for seamldr deinit [Yilun]
- remove global tdx_fw [Yilun]
- clarify request_firmware() doesn't take filename from userspace [Rick]
- drop unnecessary checks when populating an update request [Rick]
- rewrite the commit message for the skeleton patch
- rewrite the commit message for the "update-sensitive operations" handling patch
- other minor code changes, changelog improvements and typo fixes [Binbin/Yan etc]
- collect review tags from Yilun/Rick/Kai/Binbin
- v4: https://lore.kernel.org/kvm/20260212143606.534586-1-chao.gao@intel.com/
This series adds support for runtime TDX module updates that preserve
running TDX guests. It is also available at:
https://github.com/gaochaointel/linux-dev/commits/tdx-module-updates-v5/
== Background ==
Intel TDX isolates Trusted Domains (TDs), or confidential guests, from the
host. A key component of Intel TDX is the TDX module, which enforces
security policies to protect the memory and CPU states of TDs from the
host. However, the TDX module is software that requires updates.
== Problems ==
Currently, the TDX module is loaded by the BIOS at boot time, and the only
way to update it is through a reboot, which results in significant system
downtime. Users expect the TDX module to be updatable at runtime without
disrupting TDX guests.
== Solution ==
On TDX platforms, P-SEAMLDR[1] is a component within the protected SEAM
range. It is loaded by the BIOS and provides the host with functions to
install a TDX module at runtime.
Implement a TDX module update facility via the fw_upload mechanism. Given
that there is variability in which module update to load based on features,
fix levels, and potentially reloading the same version for error recovery
scenarios, the explicit userspace chosen payload flexibility of fw_upload
is attractive.
This design allows the kernel to accept a bitstream instead of loading a
named file from the filesystem, as the module selection and policy
enforcement for TDX modules are quite complex (see patch "coco/tdx-host:
Implement firmware upload sysfs ABI for TDX module updates"). By doing
so, much of this complexity is shifted out of the kernel. The kernel
needs to expose information, such as the TDX module version, to
userspace. Userspace must understand the TDX module versioning scheme
and update policy to select the appropriate TDX module (see "TDX module
Versioning" below).
In the unlikely event the update fails, for example userspace picks an
incompatible update image, or the image is otherwise corrupted, all TDs
will experience SEAMCALL failures and be killed. The recovery of TD
operation from that event requires a reboot.
Given there is no mechanism to quiesce SEAMCALLs, the TDs themselves must
pause execution over an update. The most straightforward way to meet the
'pause TDs while update executes' constraint is to run the update in
stop_machine() context. All other evaluated solutions export more
complexity to KVM, or exports more fragility to userspace.
== How to test this series ==
First, load kvm-intel.ko and tdx-host.ko if they haven't been loaded:
# modprobe -r kvm_intel
# modprobe kvm_intel tdx=1
# modprobe tdx-host
Then, use the userspace tool below to select the appropriate TDX module and
install it via the interfaces exposed by this series:
# git clone https://github.com/intel/tdx-module-binaries
# cd tdx-module-binaries
# python version_select_and_load.py --update
this version changes the firmware directory name from seamldr_upload to
tdx_module, so, below change should be applied to version_select_and_load.py:
diff --git a/version_select_and_load.py b/version_select_and_load.py
index 2193bd8..6a3b604 100644
--- a/version_select_and_load.py
+++ b/version_select_and_load.py
@@ -38,7 +38,7 @@ except ImportError:
print("Error: cpuid module is not installed. Please install it using 'pip install cpuid'")
sys.exit(1)
-FIRMWARE_PATH = "/sys/class/firmware/seamldr_upload"
+FIRMWARE_PATH = "/sys/class/firmware/tdx_module"
MODULE_PATH = "/sys/devices/faux/tdx_host"
SEAMLDR_PATH = "/sys/devices/faux/tdx_host/seamldr"
allow_debug = False
== Other information relevant to Runtime TDX module updates ==
=== TDX module versioning ===
Each TDX module is assigned a version number x.y.z, where x represents the
"major" version, y the "minor" version, and z the "update" version.
Runtime TDX module updates are restricted to Z-stream releases.
Note that Z-stream releases do not necessarily guarantee compatibility. A
new release may not be compatible with all previous versions. To address this,
Intel provides a separate file containing compatibility information, which
specifies the minimum module version required for a particular update. This
information is referenced by the tool to determine if two modules are
compatible.
=== TCB Stability ===
Updates change the TCB as viewed by attestation reports. In TDX there is
a distinction between launch-time version and current version where
runtime TDX module updates cause that latter version number to change,
subject to Z-stream constraints.
The concern that a malicious host may attack confidential VMs by loading
insecure updates was addressed by Alex in [3]. Similarly, the scenario
where some "theoretical paranoid tenant" in the cloud wants to audit
updates and stop trusting the host after updates until audit completion
was also addressed in [4]. Users not in the cloud control the host machine
and can manage updates themselves, so they don't have these concerns.
See more about the implications of current TCB version changes in
attestation as summarized by Dave in [5].
=== TDX module Distribution Model ===
At a high level, Intel publishes all TDX modules on the github [2], along
with a mapping_file.json which documents the compatibility information
about each TDX module and a userspace tool to install the TDX module. OS
vendors can package these modules and distribute them. Administrators
install the package and use the tool to select the appropriate TDX module
and install it via the interfaces exposed by this series.
[1]: https://cdrdv2.intel.com/v1/dl/getContent/733584
[2]: https://github.com/intel/tdx-module-binaries
[3]: https://lore.kernel.org/all/665c5ae0-4b7c-4852-8995-255adf7b3a2f@amazon.com/
[4]: https://lore.kernel.org/all/5d1da767-491b-4077-b472-2cc3d73246d6@amazon.com/
[5]: https://lore.kernel.org/all/94d6047e-3b7c-4bc1-819c-85c16ff85abf@intel.com/
Chao Gao (21):
coco/tdx-host: Introduce a "tdx_host" device
coco/tdx-host: Expose TDX module version
x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs
x86/virt/seamldr: Retrieve P-SEAMLDR information
coco/tdx-host: Expose P-SEAMLDR information via sysfs
coco/tdx-host: Implement firmware upload sysfs ABI for TDX module
updates
x86/virt/seamldr: Allocate and populate a module update request
x86/virt/seamldr: Introduce skeleton for TDX module updates
x86/virt/seamldr: Abort updates if errors occurred midway
x86/virt/seamldr: Shut down the current TDX module
x86/virt/tdx: Reset software states during TDX module shutdown
x86/virt/seamldr: Install a new TDX module
x86/virt/seamldr: Do TDX per-CPU initialization after updates
x86/virt/tdx: Restore TDX module state
x86/virt/tdx: Update tdx_sysinfo and check features post-update
x86/virt/tdx: Avoid updates during update-sensitive operations
coco/tdx-host: Don't expose P-SEAMLDR features on CPUs with erratum
x86/virt/tdx: Enable TDX module runtime updates
coco/tdx-host: Document TDX module update compatibility criteria
x86/virt/tdx: Document TDX module update
x86/virt/seamldr: Log TDX module update failures
Kai Huang (1):
x86/virt/tdx: Move low level SEAMCALL helpers out of <asm/tdx.h>
.../ABI/testing/sysfs-devices-faux-tdx-host | 75 ++++
Documentation/arch/x86/tdx.rst | 36 ++
arch/x86/include/asm/cpufeatures.h | 1 +
arch/x86/include/asm/seamldr.h | 37 ++
arch/x86/include/asm/tdx.h | 65 +---
arch/x86/include/asm/tdx_global_metadata.h | 5 +
arch/x86/include/asm/vmx.h | 1 +
arch/x86/kvm/vmx/tdx_errno.h | 2 -
arch/x86/virt/vmx/tdx/Makefile | 2 +-
arch/x86/virt/vmx/tdx/seamcall_internal.h | 109 ++++++
arch/x86/virt/vmx/tdx/seamldr.c | 325 ++++++++++++++++++
arch/x86/virt/vmx/tdx/tdx.c | 165 ++++++---
arch/x86/virt/vmx/tdx/tdx.h | 11 +-
arch/x86/virt/vmx/tdx/tdx_global_metadata.c | 18 +
drivers/virt/coco/Kconfig | 2 +
drivers/virt/coco/Makefile | 1 +
drivers/virt/coco/tdx-host/Kconfig | 12 +
drivers/virt/coco/tdx-host/Makefile | 1 +
drivers/virt/coco/tdx-host/tdx-host.c | 228 ++++++++++++
19 files changed, 995 insertions(+), 101 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-devices-faux-tdx-host
create mode 100644 arch/x86/include/asm/seamldr.h
create mode 100644 arch/x86/virt/vmx/tdx/seamcall_internal.h
create mode 100644 arch/x86/virt/vmx/tdx/seamldr.c
create mode 100644 drivers/virt/coco/tdx-host/Kconfig
create mode 100644 drivers/virt/coco/tdx-host/Makefile
create mode 100644 drivers/virt/coco/tdx-host/tdx-host.c
--
2.47.3
^ permalink raw reply related
* [PATCH v5 01/22] x86/virt/tdx: Move low level SEAMCALL helpers out of <asm/tdx.h>
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
To: linux-kernel, linux-coco, kvm
Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
yilun.xu, Chao Gao, Zhenzhong Duan, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, x86, H. Peter Anvin
In-Reply-To: <20260315135920.354657-1-chao.gao@intel.com>
From: Kai Huang <kai.huang@intel.com>
TDX host core code implements three seamcall*() helpers to make SEAMCALL
to the TDX module. Currently, they are implemented in <asm/tdx.h> and
are exposed to other kernel code which includes <asm/tdx.h>.
However, other than the TDX host core, seamcall*() are not expected to
be used by other kernel code directly. For instance, for all SEAMCALLs
that are used by KVM, the TDX host core exports a wrapper function for
each of them.
Move seamcall*() and related code out of <asm/tdx.h> and make them only
visible to TDX host core.
Since TDX host core tdx.c is already very heavy, don't put low level
seamcall*() code there but to a new dedicated "seamcall_internal.h". Also,
currently tdx.c has seamcall_prerr*() helpers which additionally print
error message when calling seamcall*() fails. Move them to
"seamcall_internal.h" as well. In such way all low level SEAMCALL helpers
are in a dedicated place, which is much more readable.
Copy the copyright notice from the original files and consolidate the
date ranges to:
Copyright (C) 2021-2023 Intel Corporation
Signed-off-by: Kai Huang <kai.huang@intel.com>
Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
---
v5:
- s/seamcall.h/seamcall_internal.h [Binbin]
- Fix an unintentional change to sc_retry() during code movement.
v4:
- Collect reviews
- add "internal" to the new header file [Dave]
- document the scope of the new header file [Dave]
- correct the copyright notice [Dave]
v2:
- new
---
arch/x86/include/asm/tdx.h | 47 ----------
arch/x86/virt/vmx/tdx/seamcall_internal.h | 109 ++++++++++++++++++++++
arch/x86/virt/vmx/tdx/tdx.c | 47 +---------
3 files changed, 111 insertions(+), 92 deletions(-)
create mode 100644 arch/x86/virt/vmx/tdx/seamcall_internal.h
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index 6b338d7f01b7..cb2219302dfc 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -97,54 +97,7 @@ static inline long tdx_kvm_hypercall(unsigned int nr, unsigned long p1,
#endif /* CONFIG_INTEL_TDX_GUEST && CONFIG_KVM_GUEST */
#ifdef CONFIG_INTEL_TDX_HOST
-u64 __seamcall(u64 fn, struct tdx_module_args *args);
-u64 __seamcall_ret(u64 fn, struct tdx_module_args *args);
-u64 __seamcall_saved_ret(u64 fn, struct tdx_module_args *args);
void tdx_init(void);
-
-#include <linux/preempt.h>
-#include <asm/archrandom.h>
-#include <asm/processor.h>
-
-typedef u64 (*sc_func_t)(u64 fn, struct tdx_module_args *args);
-
-static __always_inline u64 __seamcall_dirty_cache(sc_func_t func, u64 fn,
- struct tdx_module_args *args)
-{
- lockdep_assert_preemption_disabled();
-
- /*
- * SEAMCALLs are made to the TDX module and can generate dirty
- * cachelines of TDX private memory. Mark cache state incoherent
- * so that the cache can be flushed during kexec.
- *
- * This needs to be done before actually making the SEAMCALL,
- * because kexec-ing CPU could send NMI to stop remote CPUs,
- * in which case even disabling IRQ won't help here.
- */
- this_cpu_write(cache_state_incoherent, true);
-
- return func(fn, args);
-}
-
-static __always_inline u64 sc_retry(sc_func_t func, u64 fn,
- struct tdx_module_args *args)
-{
- int retry = RDRAND_RETRY_LOOPS;
- u64 ret;
-
- do {
- preempt_disable();
- ret = __seamcall_dirty_cache(func, fn, args);
- preempt_enable();
- } while (ret == TDX_RND_NO_ENTROPY && --retry);
-
- return ret;
-}
-
-#define seamcall(_fn, _args) sc_retry(__seamcall, (_fn), (_args))
-#define seamcall_ret(_fn, _args) sc_retry(__seamcall_ret, (_fn), (_args))
-#define seamcall_saved_ret(_fn, _args) sc_retry(__seamcall_saved_ret, (_fn), (_args))
int tdx_cpu_enable(void);
int tdx_enable(void);
const char *tdx_dump_mce_info(struct mce *m);
diff --git a/arch/x86/virt/vmx/tdx/seamcall_internal.h b/arch/x86/virt/vmx/tdx/seamcall_internal.h
new file mode 100644
index 000000000000..be5f446467df
--- /dev/null
+++ b/arch/x86/virt/vmx/tdx/seamcall_internal.h
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * SEAMCALL utilities for TDX host-side operations.
+ *
+ * Provides convenient wrappers around SEAMCALL assembly with retry logic,
+ * error reporting and cache coherency tracking.
+ *
+ * Copyright (C) 2021-2023 Intel Corporation
+ */
+
+#ifndef _X86_VIRT_SEAMCALL_INTERNAL_H
+#define _X86_VIRT_SEAMCALL_INTERNAL_H
+
+#include <linux/printk.h>
+#include <linux/types.h>
+#include <asm/archrandom.h>
+#include <asm/processor.h>
+#include <asm/tdx.h>
+
+u64 __seamcall(u64 fn, struct tdx_module_args *args);
+u64 __seamcall_ret(u64 fn, struct tdx_module_args *args);
+u64 __seamcall_saved_ret(u64 fn, struct tdx_module_args *args);
+
+typedef u64 (*sc_func_t)(u64 fn, struct tdx_module_args *args);
+
+static __always_inline u64 __seamcall_dirty_cache(sc_func_t func, u64 fn,
+ struct tdx_module_args *args)
+{
+ lockdep_assert_preemption_disabled();
+
+ /*
+ * SEAMCALLs are made to the TDX module and can generate dirty
+ * cachelines of TDX private memory. Mark cache state incoherent
+ * so that the cache can be flushed during kexec.
+ *
+ * This needs to be done before actually making the SEAMCALL,
+ * because kexec-ing CPU could send NMI to stop remote CPUs,
+ * in which case even disabling IRQ won't help here.
+ */
+ this_cpu_write(cache_state_incoherent, true);
+
+ return func(fn, args);
+}
+
+static __always_inline u64 sc_retry(sc_func_t func, u64 fn,
+ struct tdx_module_args *args)
+{
+ int retry = RDRAND_RETRY_LOOPS;
+ u64 ret;
+
+ do {
+ preempt_disable();
+ ret = __seamcall_dirty_cache(func, fn, args);
+ preempt_enable();
+ } while (ret == TDX_RND_NO_ENTROPY && --retry);
+
+ return ret;
+}
+
+#define seamcall(_fn, _args) sc_retry(__seamcall, (_fn), (_args))
+#define seamcall_ret(_fn, _args) sc_retry(__seamcall_ret, (_fn), (_args))
+#define seamcall_saved_ret(_fn, _args) sc_retry(__seamcall_saved_ret, (_fn), (_args))
+
+typedef void (*sc_err_func_t)(u64 fn, u64 err, struct tdx_module_args *args);
+
+static inline void seamcall_err(u64 fn, u64 err, struct tdx_module_args *args)
+{
+ pr_err("SEAMCALL (0x%016llx) failed: 0x%016llx\n", fn, err);
+}
+
+static inline void seamcall_err_ret(u64 fn, u64 err,
+ struct tdx_module_args *args)
+{
+ seamcall_err(fn, err, args);
+ pr_err("RCX 0x%016llx RDX 0x%016llx R08 0x%016llx\n",
+ args->rcx, args->rdx, args->r8);
+ pr_err("R09 0x%016llx R10 0x%016llx R11 0x%016llx\n",
+ args->r9, args->r10, args->r11);
+}
+
+static __always_inline int sc_retry_prerr(sc_func_t func,
+ sc_err_func_t err_func,
+ u64 fn, struct tdx_module_args *args)
+{
+ u64 sret = sc_retry(func, fn, args);
+
+ if (sret == TDX_SUCCESS)
+ return 0;
+
+ if (sret == TDX_SEAMCALL_VMFAILINVALID)
+ return -ENODEV;
+
+ if (sret == TDX_SEAMCALL_GP)
+ return -EOPNOTSUPP;
+
+ if (sret == TDX_SEAMCALL_UD)
+ return -EACCES;
+
+ err_func(fn, sret, args);
+ return -EIO;
+}
+
+#define seamcall_prerr(__fn, __args) \
+ sc_retry_prerr(__seamcall, seamcall_err, (__fn), (__args))
+
+#define seamcall_prerr_ret(__fn, __args) \
+ sc_retry_prerr(__seamcall_ret, seamcall_err_ret, (__fn), (__args))
+
+#endif /* _X86_VIRT_SEAMCALL_INTERNAL_H */
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 8b8e165a2001..06d9709ade85 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -39,6 +39,8 @@
#include <asm/cpu_device_id.h>
#include <asm/processor.h>
#include <asm/mce.h>
+
+#include "seamcall_internal.h"
#include "tdx.h"
static u32 tdx_global_keyid __ro_after_init;
@@ -59,51 +61,6 @@ static LIST_HEAD(tdx_memlist);
static struct tdx_sys_info tdx_sysinfo;
-typedef void (*sc_err_func_t)(u64 fn, u64 err, struct tdx_module_args *args);
-
-static inline void seamcall_err(u64 fn, u64 err, struct tdx_module_args *args)
-{
- pr_err("SEAMCALL (0x%016llx) failed: 0x%016llx\n", fn, err);
-}
-
-static inline void seamcall_err_ret(u64 fn, u64 err,
- struct tdx_module_args *args)
-{
- seamcall_err(fn, err, args);
- pr_err("RCX 0x%016llx RDX 0x%016llx R08 0x%016llx\n",
- args->rcx, args->rdx, args->r8);
- pr_err("R09 0x%016llx R10 0x%016llx R11 0x%016llx\n",
- args->r9, args->r10, args->r11);
-}
-
-static __always_inline int sc_retry_prerr(sc_func_t func,
- sc_err_func_t err_func,
- u64 fn, struct tdx_module_args *args)
-{
- u64 sret = sc_retry(func, fn, args);
-
- if (sret == TDX_SUCCESS)
- return 0;
-
- if (sret == TDX_SEAMCALL_VMFAILINVALID)
- return -ENODEV;
-
- if (sret == TDX_SEAMCALL_GP)
- return -EOPNOTSUPP;
-
- if (sret == TDX_SEAMCALL_UD)
- return -EACCES;
-
- err_func(fn, sret, args);
- return -EIO;
-}
-
-#define seamcall_prerr(__fn, __args) \
- sc_retry_prerr(__seamcall, seamcall_err, (__fn), (__args))
-
-#define seamcall_prerr_ret(__fn, __args) \
- sc_retry_prerr(__seamcall_ret, seamcall_err_ret, (__fn), (__args))
-
/*
* Do the module global initialization once and return its result.
* It can be done on any cpu. It's always called with interrupts
--
2.47.3
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox