* [PATCH 0/2] Arm LFA: timeout and ACPI platform driver support
From: Vedashree Vidwans @ 2026-02-10 22:40 UTC (permalink / raw)
To: salman.nabi, sudeep.holla, andre.przywara, lpieralisi,
mark.rutland, trilokkumar.soni
Cc: ardb, chao.gao, linux-arm-kernel, linux-coco, linux-kernel,
sdonthineni, vsethi, vwadekar, Vedashree Vidwans
Hello,
(This is an updated version of the [RFC PATCH 0/5] Arm LFA: Improvements
and interrupt support [1], which builds on top of the latest [PATCH 0/1]
Arm Live Firmware activation (LFA) support [2].)
The latest LFA specification [3] updates the interface requirements for
ACPI-based platforms to use the ACPI Notify() signal, and
device-tree-based interface is unspecified. This series focuses on
reworking the LFA driver as an ACPI-backed platform driver, using ACPI
Notify() instead of a dedicated interrupt handler. The LFA core behavior
and sysfs layout remain as implemented by the base driver.
This series contains two incremental changes:
1. Add a timeout and watchdog touch during LFA operations, to make the
driver more robust in cases where firmware-side prime/activation phases
take longer than expected.
2. Register the LFA implementation as a platform driver, layering a
platform driver interface on top of the existing LFA core logic so the
functionality can be instantiated via a platform device.
Note:
This posting focuses on architectural and implementation improvements
for the LFA driver itself. It assumes that the bugs and issues raised
during review of the original "[PATCH 0/1] Arm Live Firmware activation
(LFA) support” [2] will be addressed directly by the author in that base
series. Once those fixes are in place, this series is intended to layer
on top cleanly.
Testing:
The final integrated driver (base LFA + these additions) has been tested
on Nvidia server platform with Linux kernel v6.16. The sysfs interface
was not exercised as part of this testing.
Regards,
Veda
[1] https://lore.kernel.org/linux-arm-kernel/20251208221319.1524888-1-vvidwans@nvidia.com/
[2] https://lore.kernel.org/linux-arm-kernel/20260119122729.287522-2-salman.nabi@arm.com/
[3] https://developer.arm.com/documentation/den0147/latest/
Vedashree Vidwans (2):
firmware: smccc: add timeout, touch wdt
firmware: smccc: register as platform driver
drivers/firmware/smccc/lfa_fw.c | 193 ++++++++++++++++++++++++++++----
1 file changed, 174 insertions(+), 19 deletions(-)
--
2.43.0
^ permalink raw reply
* [PATCH 1/2] firmware: smccc: add timeout, touch wdt
From: Vedashree Vidwans @ 2026-02-10 22:40 UTC (permalink / raw)
To: salman.nabi, sudeep.holla, andre.przywara, lpieralisi,
mark.rutland, trilokkumar.soni
Cc: ardb, chao.gao, linux-arm-kernel, linux-coco, linux-kernel,
sdonthineni, vsethi, vwadekar, Vedashree Vidwans
In-Reply-To: <20260210224023.2341728-1-vvidwans@nvidia.com>
Enhance PRIME/ACTIVATION functions to touch watchdog and implement
timeout mechanism. This update ensures that any potential hangs are
detected promptly and that the LFA process is allocated sufficient
execution time before the watchdog timer expires. These changes improve
overall system reliability by reducing the risk of undetected process
stalls and unexpected watchdog resets.
Signed-off-by: Vedashree Vidwans <vvidwans@nvidia.com>
---
drivers/firmware/smccc/lfa_fw.c | 40 +++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
index da6b54fe1685..b0ace6fc8dac 100644
--- a/drivers/firmware/smccc/lfa_fw.c
+++ b/drivers/firmware/smccc/lfa_fw.c
@@ -17,6 +17,9 @@
#include <linux/array_size.h>
#include <linux/list.h>
#include <linux/mutex.h>
+#include <linux/nmi.h>
+#include <linux/ktime.h>
+#include <linux/delay.h>
#undef pr_fmt
#define pr_fmt(fmt) "Arm LFA: " fmt
@@ -37,6 +40,14 @@
#define LFA_PRIME_CALL_AGAIN BIT(0)
#define LFA_ACTIVATE_CALL_AGAIN BIT(0)
+/* Prime loop limits, TODO: tune after testing */
+#define LFA_PRIME_BUDGET_US 30000000 /* 30s cap */
+#define LFA_PRIME_POLL_DELAY_US 10 /* 10us between polls */
+
+/* Activation loop limits, TODO: tune after testing */
+#define LFA_ACTIVATE_BUDGET_US 20000000 /* 20s cap */
+#define LFA_ACTIVATE_POLL_DELAY_US 10 /* 10us between polls */
+
/* LFA return values */
#define LFA_SUCCESS 0
#define LFA_NOT_SUPPORTED 1
@@ -219,6 +230,7 @@ static int call_lfa_activate(void *data)
struct image_props *attrs = data;
struct arm_smccc_1_2_regs args = { 0 };
struct arm_smccc_1_2_regs res = { 0 };
+ ktime_t end = ktime_add_us(ktime_get(), LFA_ACTIVATE_BUDGET_US);
args.a0 = LFA_1_0_FN_ACTIVATE;
args.a1 = attrs->fw_seq_id; /* fw_seq_id under consideration */
@@ -232,6 +244,8 @@ static int call_lfa_activate(void *data)
args.a2 = !(attrs->cpu_rendezvous_forced || attrs->cpu_rendezvous);
for (;;) {
+ /* Touch watchdog, ACTIVATE shouldn't take longer than watchdog_thresh */
+ touch_nmi_watchdog();
arm_smccc_1_2_invoke(&args, &res);
if ((long)res.a0 < 0) {
@@ -241,6 +255,15 @@ static int call_lfa_activate(void *data)
}
if (!(res.a1 & LFA_ACTIVATE_CALL_AGAIN))
break; /* ACTIVATE successful */
+
+ /* SMC returned with call_again flag set */
+ if (ktime_before(ktime_get(), end)) {
+ udelay(LFA_ACTIVATE_POLL_DELAY_US);
+ continue;
+ }
+
+ pr_err("ACTIVATE for image %s timed out", attrs->image_name);
+ return -ETIMEDOUT;
}
return res.a0;
@@ -290,6 +313,7 @@ static int prime_fw_image(struct image_props *attrs)
{
struct arm_smccc_1_2_regs args = { 0 };
struct arm_smccc_1_2_regs res = { 0 };
+ ktime_t end = ktime_add_us(ktime_get(), LFA_PRIME_BUDGET_US);
int ret;
mutex_lock(&lfa_lock);
@@ -317,6 +341,8 @@ static int prime_fw_image(struct image_props *attrs)
args.a0 = LFA_1_0_FN_PRIME;
args.a1 = attrs->fw_seq_id; /* fw_seq_id under consideration */
for (;;) {
+ /* Touch watchdog, PRIME shouldn't take longer than watchdog_thresh */
+ touch_nmi_watchdog();
arm_smccc_1_2_invoke(&args, &res);
if ((long)res.a0 < 0) {
@@ -328,6 +354,20 @@ static int prime_fw_image(struct image_props *attrs)
}
if (!(res.a1 & LFA_PRIME_CALL_AGAIN))
break; /* PRIME successful */
+
+ /* SMC returned with call_again flag set */
+ if (ktime_before(ktime_get(), end)) {
+ udelay(LFA_PRIME_POLL_DELAY_US);
+ continue;
+ }
+
+ pr_err("LFA_PRIME for image %s timed out", attrs->image_name);
+ mutex_unlock(&lfa_lock);
+
+ ret = lfa_cancel(attrs);
+ if (ret != 0)
+ return ret;
+ return -ETIMEDOUT;
}
mutex_unlock(&lfa_lock);
--
2.43.0
^ permalink raw reply related
* [PATCH 2/2] firmware: smccc: register as platform driver
From: Vedashree Vidwans @ 2026-02-10 22:40 UTC (permalink / raw)
To: salman.nabi, sudeep.holla, andre.przywara, lpieralisi,
mark.rutland, trilokkumar.soni
Cc: ardb, chao.gao, linux-arm-kernel, linux-coco, linux-kernel,
sdonthineni, vsethi, vwadekar, Vedashree Vidwans
In-Reply-To: <20260210224023.2341728-1-vvidwans@nvidia.com>
- Register the LFA driver as a platform driver corresponding to
'arml0003' ACPI device. The driver will be invoked when the device is
detected on a platform. NOTE: current functionality only available for
ACPI configuration.
- Add functionality to register ACPI notify handler for LFA in the
driver probe().
- When notify handler is invoked, driver will query latest FW component
details and trigger activation of capable and pending FW component in a
loop until all FWs are activated.
ACPI node snippet from LFA spec[1]:
Device (LFA0) {
Name (_HID, "ARML0003")
Name (_UID, 0)
}
[1] https://developer.arm.com/documentation/den0147/latest/
Signed-off-by: Vedashree Vidwans <vvidwans@nvidia.com>
---
drivers/firmware/smccc/lfa_fw.c | 153 ++++++++++++++++++++++++++++----
1 file changed, 134 insertions(+), 19 deletions(-)
diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
index b0ace6fc8dac..042de937bf83 100644
--- a/drivers/firmware/smccc/lfa_fw.c
+++ b/drivers/firmware/smccc/lfa_fw.c
@@ -20,7 +20,10 @@
#include <linux/nmi.h>
#include <linux/ktime.h>
#include <linux/delay.h>
+#include <linux/acpi.h>
+#include <linux/platform_device.h>
+#define DRIVER_NAME "ARM_LFA"
#undef pr_fmt
#define pr_fmt(fmt) "Arm LFA: " fmt
@@ -284,26 +287,7 @@ static int activate_fw_image(struct image_props *attrs)
return lfa_cancel(attrs);
}
- /*
- * Invalidate fw_seq_ids (-1) for all images as the seq_ids and the
- * number of firmware images in the LFA agent may change after a
- * successful activation attempt. Negate all image flags as well.
- */
- attrs = NULL;
- list_for_each_entry(attrs, &lfa_fw_images, image_node) {
- set_image_flags(attrs, -1, 0b1000, 0, 0);
- }
-
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);
- queue_work(fw_images_update_wq, &fw_images_update_work);
mutex_unlock(&lfa_lock);
return ret;
@@ -627,6 +611,7 @@ static int update_fw_images_tree(void)
{
struct arm_smccc_1_2_regs reg = { 0 };
struct uuid_regs image_uuid;
+ struct image_props *attrs;
char image_id_str[40];
int ret, num_of_components;
@@ -636,6 +621,15 @@ static int update_fw_images_tree(void)
return -ENODEV;
}
+ /*
+ * Invalidate fw_seq_ids (-1) for all images as the seq_ids and the
+ * number of firmware images in the LFA agent may change after a
+ * successful activation attempt. Negate all image flags as well.
+ */
+ list_for_each_entry(attrs, &lfa_fw_images, image_node) {
+ set_image_flags(attrs, -1, 0b1000, 0, 0);
+ }
+
for (int i = 0; i < num_of_components; i++) {
reg.a0 = LFA_1_0_FN_GET_INVENTORY;
reg.a1 = i; /* fw_seq_id under consideration */
@@ -653,9 +647,121 @@ static int update_fw_images_tree(void)
}
}
+ /*
+ * 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);
+ queue_work(fw_images_update_wq, &fw_images_update_work);
+
+ return 0;
+}
+
+#if defined(CONFIG_ACPI)
+static void lfa_notify_handler(acpi_handle handle, u32 event, void *data)
+{
+ struct image_props *attrs = NULL;
+ int ret;
+ bool found_activable_image = false;
+
+ /* Get latest FW inventory */
+ mutex_lock(&lfa_lock);
+ ret = update_fw_images_tree();
+ mutex_unlock(&lfa_lock);
+ if (ret != 0) {
+ pr_err("FW images tree update failed");
+ return;
+ }
+
+ /*
+ * Go through all FW images in a loop and trigger activation
+ * of all activable and pending images.
+ */
+ do {
+ /* Reset activable image flag */
+ found_activable_image = false;
+ list_for_each_entry(attrs, &lfa_fw_images, image_node) {
+ if (attrs->fw_seq_id == -1)
+ continue; /* Invalid FW component */
+
+ if ((!attrs->activation_capable) || (!attrs->activation_pending))
+ continue; /* FW component is not activable */
+
+ /*
+ * Found an image that is activable.
+ * As the FW images tree is revised after activation, it is
+ * not ideal to invoke activation from inside
+ * list_for_each_entry() loop.
+ * So, set the flasg and exit loop.
+ */
+ found_activable_image = true;
+ break;
+ }
+
+ if (found_activable_image) {
+ ret = prime_fw_image(attrs);
+ if (ret) {
+ pr_err("Firmware prime failed: %s\n",
+ lfa_error_strings[-ret]);
+ return;
+ }
+
+ ret = activate_fw_image(attrs);
+ if (ret) {
+ pr_err("Firmware activation failed: %s\n",
+ lfa_error_strings[-ret]);
+ return;
+ }
+
+ pr_info("Firmware %s activation succeeded", attrs->image_name);
+ }
+ } while (found_activable_image);
+}
+
+static int lfa_probe(struct platform_device *pdev)
+{
+ acpi_status status;
+ acpi_handle handle = ACPI_HANDLE(&pdev->dev);
+
+ if (!handle)
+ return -ENODEV;
+
+ /* Register notify handler that indicates if LFA updates are available */
+ status = acpi_install_notify_handler(handle,
+ ACPI_DEVICE_NOTIFY, lfa_notify_handler, pdev);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
return 0;
}
+static void lfa_remove(struct platform_device *pdev)
+{
+ acpi_handle handle = ACPI_HANDLE(&pdev->dev);
+
+ if (handle)
+ acpi_remove_notify_handler(handle,
+ ACPI_DEVICE_NOTIFY, lfa_notify_handler);
+}
+
+static const struct acpi_device_id lfa_acpi_ids[] = {
+ {"ARML0003"},
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, lfa_acpi_ids);
+
+static struct platform_driver lfa_driver = {
+ .probe = lfa_probe,
+ .remove = lfa_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .acpi_match_table = ACPI_PTR(lfa_acpi_ids),
+ },
+};
+#endif
+
static int __init lfa_init(void)
{
struct arm_smccc_1_2_regs reg = { 0 };
@@ -679,6 +785,12 @@ static int __init lfa_init(void)
pr_info("Live Firmware Activation: detected v%ld.%ld\n",
reg.a0 >> 16, reg.a0 & 0xffff);
+#if defined(CONFIG_ACPI)
+ err = platform_driver_register(&lfa_driver);
+ if (err < 0)
+ pr_err("Platform driver register failed");
+#endif
+
lfa_dir = kobject_create_and_add("lfa", firmware_kobj);
if (!lfa_dir)
return -ENOMEM;
@@ -703,6 +815,9 @@ static void __exit lfa_exit(void)
mutex_unlock(&lfa_lock);
kobject_put(lfa_dir);
+#if defined(CONFIG_ACPI)
+ platform_driver_unregister(&lfa_driver);
+#endif
}
module_exit(lfa_exit);
--
2.43.0
^ permalink raw reply related
* Re: [RFC PATCH v5 16/45] x86/virt/tdx: Add tdx_alloc/free_control_page() helpers
From: Huang, Kai @ 2026-02-10 22:46 UTC (permalink / raw)
To: Hansen, Dave, seanjc@google.com, bp@alien8.de, kas@kernel.org,
dave.hansen@linux.intel.com, mingo@redhat.com, x86@kernel.org,
tglx@kernel.org, Edgecombe, Rick P, pbonzini@redhat.com
Cc: ackerleytng@google.com, sagis@google.com, Li, Xiaoyao,
linux-kernel@vger.kernel.org, Zhao, Yan Y, kvm@vger.kernel.org,
linux-coco@lists.linux.dev, Yamahata, Isaku,
binbin.wu@linux.intel.com, Annapurve, Vishal
In-Reply-To: <4fe6121b-6fe3-4c97-b796-806533ed6806@intel.com>
On Tue, 2026-02-10 at 14:19 -0800, Dave Hansen wrote:
> On 2/10/26 14:15, Edgecombe, Rick P wrote:
> > I'm wasn't familiar with atomic_dec_and_lock(). I'm guess the atomic
> > part doesn't cover both decrementing *and* taking the lock?
>
> Right. Only 1=>0 is under the lock. All other decs are outside the lock.
>
> It doesn't do the atomic and the lock "atomically together" somehow.
Sorry I am a bit confused. But I think the "1=>0 and lock" are atomic
together?
If so, I think we can avoid the "race" mentioned by Rick, which is handled
by "x86/virt/tdx: Optimize tdx_alloc/free_control_page() helpers".
Kirill described the race [*]. Quote it here:
---
Consider the following scenario
CPU0 CPU1
tdx_pamt_put()
atomic_dec_and_test() == true
tdx_pamt_get()
atomic_inc_not_zero() == false
tdx_pamt_add()
<takes pamt_lock>
// CPU0 never removed PAMTmemory
tdh_phymem_pamt_add() ==
HPA_RANGE_NOT_FREE
atomic_set(1);
<drops pamt_lock>
<takes pamt_lock>
// Lost the race to CPU1
atomic_read() > 0
<drop pamt_lock>
---
But with atomic_dec_and_lock() (assuming "1=>0 and lock" is atomic), I think
this race won't happen. In tdx_pamt_put() on CPU0, the lock will always be
grabbed when refcount becomes 0, so PAMT pages are guaranteed to be freed.
Therefore tdx_pamt_get() on CPU1 should never meet "HPA_RANGE_NOT_FREE".
[*]
https://lore.kernel.org/kvm/bfaswqmlsyycr3alibn6f422cjtpd6ybssjekvrrz4zdwgwfcz@pxy25ra4sln2/
^ permalink raw reply
* Re: [RFC PATCH v5 16/45] x86/virt/tdx: Add tdx_alloc/free_control_page() helpers
From: Dave Hansen @ 2026-02-10 22:50 UTC (permalink / raw)
To: Huang, Kai, seanjc@google.com, bp@alien8.de, kas@kernel.org,
dave.hansen@linux.intel.com, mingo@redhat.com, x86@kernel.org,
tglx@kernel.org, Edgecombe, Rick P, pbonzini@redhat.com
Cc: ackerleytng@google.com, sagis@google.com, Li, Xiaoyao,
linux-kernel@vger.kernel.org, Zhao, Yan Y, kvm@vger.kernel.org,
linux-coco@lists.linux.dev, Yamahata, Isaku,
binbin.wu@linux.intel.com, Annapurve, Vishal
In-Reply-To: <b9b4b80a3818e9ebb3cb1aec76d1a1083fb91c7c.camel@intel.com>
On 2/10/26 14:46, Huang, Kai wrote:
> Sorry I am a bit confused. But I think the "1=>0 and lock" are atomic
> together?
Maybe I'm being pedantic. The 1=>0 happens under the lock, but the 1=>0
and the lock acquisition itself are not atomic. You can see them
happening at different times:
int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
{
/* Subtract 1 from counter unless that drops it to 0...
if (atomic_add_unless(atomic, -1, 1))
return 0;
/* Otherwise do it the slow way */
spin_lock(lock);
if (atomic_dec_and_test(atomic))
return 1;
spin_unlock(lock);
return 0;
}
tl;dr: Kirill was right, atomic_dec_and_test() doesn't work by itself here.
But I think atomic_dec_and_lock() will.
Does anyone disagree?
^ permalink raw reply
* Re: [RFC PATCH v5 16/45] x86/virt/tdx: Add tdx_alloc/free_control_page() helpers
From: Huang, Kai @ 2026-02-10 23:02 UTC (permalink / raw)
To: Hansen, Dave, seanjc@google.com, x86@kernel.org, kas@kernel.org,
dave.hansen@linux.intel.com, mingo@redhat.com, bp@alien8.de,
tglx@kernel.org, Edgecombe, Rick P, pbonzini@redhat.com
Cc: ackerleytng@google.com, sagis@google.com, Li, Xiaoyao,
linux-kernel@vger.kernel.org, Zhao, Yan Y, kvm@vger.kernel.org,
linux-coco@lists.linux.dev, Yamahata, Isaku,
binbin.wu@linux.intel.com, Annapurve, Vishal
In-Reply-To: <17d3ba24-7d58-4507-a5d7-43237974ba09@intel.com>
On Tue, 2026-02-10 at 14:50 -0800, Dave Hansen wrote:
> On 2/10/26 14:46, Huang, Kai wrote:
> > Sorry I am a bit confused. But I think the "1=>0 and lock" are atomic
> > together?
>
> Maybe I'm being pedantic. The 1=>0 happens under the lock, but the 1=>0
> and the lock acquisition itself are not atomic. You can see them
> happening at different times:
Oh I see. Thanks.
>
> int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
> {
> /* Subtract 1 from counter unless that drops it to 0...
> if (atomic_add_unless(atomic, -1, 1))
> return 0;
>
> /* Otherwise do it the slow way */
> spin_lock(lock);
> if (atomic_dec_and_test(atomic))
> return 1;
> spin_unlock(lock);
> return 0;
> }
>
> tl;dr: Kirill was right, atomic_dec_and_test() doesn't work by itself here.
>
> But I think atomic_dec_and_lock() will.
Agreed.
^ permalink raw reply
* Re: [PATCH 1/2] firmware: smccc: add timeout, touch wdt
From: Trilok Soni @ 2026-02-10 23:10 UTC (permalink / raw)
To: Vedashree Vidwans, salman.nabi, sudeep.holla, andre.przywara,
lpieralisi, mark.rutland
Cc: ardb, chao.gao, linux-arm-kernel, linux-coco, linux-kernel,
sdonthineni, vsethi, vwadekar
In-Reply-To: <20260210224023.2341728-2-vvidwans@nvidia.com>
On 2/10/2026 2:40 PM, Vedashree Vidwans wrote:
> Enhance PRIME/ACTIVATION functions to touch watchdog and implement
> timeout mechanism. This update ensures that any potential hangs are
> detected promptly and that the LFA process is allocated sufficient
> execution time before the watchdog timer expires. These changes improve
> overall system reliability by reducing the risk of undetected process
> stalls and unexpected watchdog resets.
>
> Signed-off-by: Vedashree Vidwans <vvidwans@nvidia.com>
> ---
> drivers/firmware/smccc/lfa_fw.c | 40 +++++++++++++++++++++++++++++++++
> 1 file changed, 40 insertions(+)
>
> diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
> index da6b54fe1685..b0ace6fc8dac 100644
> --- a/drivers/firmware/smccc/lfa_fw.c
> +++ b/drivers/firmware/smccc/lfa_fw.c
> @@ -17,6 +17,9 @@
> #include <linux/array_size.h>
> #include <linux/list.h>
> #include <linux/mutex.h>
> +#include <linux/nmi.h>
> +#include <linux/ktime.h>
> +#include <linux/delay.h>
>
> #undef pr_fmt
> #define pr_fmt(fmt) "Arm LFA: " fmt
> @@ -37,6 +40,14 @@
> #define LFA_PRIME_CALL_AGAIN BIT(0)
> #define LFA_ACTIVATE_CALL_AGAIN BIT(0)
>
> +/* Prime loop limits, TODO: tune after testing */
Do you want to keep this TODO? Your patches are not marked as RFC.
> +#define LFA_PRIME_BUDGET_US 30000000 /* 30s cap */
> +#define LFA_PRIME_POLL_DELAY_US 10 /* 10us between polls */
Are these values going to be tunable from the userspace or kernel module parameters?
> +
> +/* Activation loop limits, TODO: tune after testing */
Ditto.
> +#define LFA_ACTIVATE_BUDGET_US 20000000 /* 20s cap */
> +#define LFA_ACTIVATE_POLL_DELAY_US 10 /* 10us between polls */
...
---Trilok Soni
^ permalink raw reply
* Re: [PATCH 1/2] firmware: smccc: add timeout, touch wdt
From: Vedashree Vidwans @ 2026-02-10 23:46 UTC (permalink / raw)
To: Trilok Soni, salman.nabi, sudeep.holla, andre.przywara,
lpieralisi, mark.rutland
Cc: ardb, chao.gao, linux-arm-kernel, linux-coco, linux-kernel,
sdonthineni, vsethi, vwadekar
In-Reply-To: <cb7f90b5-6e13-4659-a448-1f621b89c71a@oss.qualcomm.com>
On 2/10/26 15:10, Trilok Soni wrote:
> On 2/10/2026 2:40 PM, Vedashree Vidwans wrote:
>> Enhance PRIME/ACTIVATION functions to touch watchdog and implement
>> timeout mechanism. This update ensures that any potential hangs are
>> detected promptly and that the LFA process is allocated sufficient
>> execution time before the watchdog timer expires. These changes improve
>> overall system reliability by reducing the risk of undetected process
>> stalls and unexpected watchdog resets.
>>
>> Signed-off-by: Vedashree Vidwans <vvidwans@nvidia.com>
>> ---
>> drivers/firmware/smccc/lfa_fw.c | 40 +++++++++++++++++++++++++++++++++
>> 1 file changed, 40 insertions(+)
>>
>> diff --git a/drivers/firmware/smccc/lfa_fw.c b/drivers/firmware/smccc/lfa_fw.c
>> index da6b54fe1685..b0ace6fc8dac 100644
>> --- a/drivers/firmware/smccc/lfa_fw.c
>> +++ b/drivers/firmware/smccc/lfa_fw.c
>> @@ -17,6 +17,9 @@
>> #include <linux/array_size.h>
>> #include <linux/list.h>
>> #include <linux/mutex.h>
>> +#include <linux/nmi.h>
>> +#include <linux/ktime.h>
>> +#include <linux/delay.h>
>>
>> #undef pr_fmt
>> #define pr_fmt(fmt) "Arm LFA: " fmt
>> @@ -37,6 +40,14 @@
>> #define LFA_PRIME_CALL_AGAIN BIT(0)
>> #define LFA_ACTIVATE_CALL_AGAIN BIT(0)
>>
>> +/* Prime loop limits, TODO: tune after testing */
>
> Do you want to keep this TODO? Your patches are not marked as RFC.
>
>> +#define LFA_PRIME_BUDGET_US 30000000 /* 30s cap */
>> +#define LFA_PRIME_POLL_DELAY_US 10 /* 10us between polls */
>
> Are these values going to be tunable from the userspace or kernel module parameters?
>
>> +
>> +/* Activation loop limits, TODO: tune after testing */
>
> Ditto.
>
>> +#define LFA_ACTIVATE_BUDGET_US 20000000 /* 20s cap */
>> +#define LFA_ACTIVATE_POLL_DELAY_US 10 /* 10us between polls */
> ...
>
> ---Trilok Soni
Thanks for pointing this out.
The "TODO: tune after testing" comment was left in by mistake; it should
not have been included in a non‑RFC posting.
Regarding tunability: the current series uses fixed values, but I agree
it would be useful to make these configurable. Adding module parameter
to adjust the timeout values would make it easier to tune them for
different platforms and workloads.
I’ll address both of these points in the next revision of the series.
Veda
^ permalink raw reply
* [PATCH v1 0/3] Increase CoCo attestation report buffer size
From: Kuppuswamy Sathyanarayanan @ 2026-02-11 0:17 UTC (permalink / raw)
To: Dan Williams, Kirill A . Shutemov
Cc: Dave Hansen, Rick Edgecombe, x86, linux-kernel, linux-coco
Hi All,
This patch series addresses buffer size limitations in the Confidential
Computing (CoCo) attestation stack. These changes are necessary to
support emerging security requirements such as DICE-based attestation
and Post-Quantum Cryptography (PQC).
DICE relies on layered evidence collected across multiple boot stages,
where each stage contributes to a cumulative certificate chain. This
process can increase the total report size to over 100KB. Furthermore,
with PQC support enabled, evidence size can reach several MB due to
larger cryptographic signatures and certificates.
Current Intel platforms use SGX-based attestation with Quote sizes
typically under 8KB. Newer Intel platforms will support DICE-based
attestation, requiring larger buffers.
This series extends the TSM framework to support reports up to 16MB,
providing sufficient headroom for these security standards. It also
increases the TDX Quote buffer size to 128KB to accommodate DICE-based
attestation.
Patch Details:
Patch 1/3 - Documents TSM binary blob size limits.
Patch 2/3 - Increases the generic TSM maximum output blob size from
32KB to 16MB.
Patch 3/3 - Increases the TDX-specific GET_QUOTE_BUF_SIZE from 8KB to
128KB to support DICE-based attestation.
Kuppuswamy Sathyanarayanan (3):
virt: tsm: Document size limits for outblob attributes
virt: tsm: Increase TSM_REPORT_OUTBLOB_MAX to 16MB
virt: tdx-guest: Increase Quote buffer size to 128KB
Documentation/ABI/testing/configfs-tsm-report | 16 ++++++++++++++++
drivers/virt/coco/tdx-guest/tdx-guest.c | 4 +++-
include/linux/tsm.h | 2 +-
3 files changed, 20 insertions(+), 2 deletions(-)
--
2.43.0
^ permalink raw reply
* [PATCH v1 1/3] virt: tsm: Document size limits for outblob attributes
From: Kuppuswamy Sathyanarayanan @ 2026-02-11 0:17 UTC (permalink / raw)
To: Dan Williams, Kirill A . Shutemov
Cc: Dave Hansen, Rick Edgecombe, x86, linux-kernel, linux-coco
In-Reply-To: <20260211001712.1531955-1-sathyanarayanan.kuppuswamy@linux.intel.com>
The configfs-tsm-report interface can fail with -EFBIG when the
attestation report generated by a TSM provider exceeds internal
maximums (TSM_REPORT_OUTBLOB_MAX). However, this error condition and
its handling are not currently documented in the ABI.
Userspace tools need to understand how to interpret various error
conditions when reading attestation reports.
Document that reads fail with -EFBIG when reports exceed size limits,
with guidance on how to resolve them.
Reviewed-by: Fang Peter <peter.fang@intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
Documentation/ABI/testing/configfs-tsm-report | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/Documentation/ABI/testing/configfs-tsm-report b/Documentation/ABI/testing/configfs-tsm-report
index 534408bc1408..ca3352cfd2f1 100644
--- a/Documentation/ABI/testing/configfs-tsm-report
+++ b/Documentation/ABI/testing/configfs-tsm-report
@@ -17,6 +17,12 @@ Description:
where the implementation is conveyed via the @provider
attribute.
+ This interface fails reads and sets errno to EFBIG when the
+ report generated by @provider exceeds the configfs-tsm-report
+ internal maximums. Contact the platform provider for the
+ compatible security module, driver, and attestation library
+ combination.
+
What: /sys/kernel/config/tsm/report/$name/auxblob
Date: October, 2023
KernelVersion: v6.7
@@ -31,6 +37,9 @@ Description:
Standardization v2.03 Section 4.1.8.1 MSG_REPORT_REQ.
https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/specifications/56421.pdf
+ See "EFBIG" comment in the @outblob description for potential
+ error conditions.
+
What: /sys/kernel/config/tsm/report/$name/manifestblob
Date: January, 2024
KernelVersion: v6.10
@@ -43,6 +52,9 @@ Description:
See 'service_provider' for information on the format of the
manifest blob.
+ See "EFBIG" comment in the @outblob description for potential
+ error conditions.
+
What: /sys/kernel/config/tsm/report/$name/provider
Date: September, 2023
KernelVersion: v6.7
--
2.43.0
^ permalink raw reply related
* [PATCH v1 2/3] virt: tsm: Increase TSM_REPORT_OUTBLOB_MAX to 16MB
From: Kuppuswamy Sathyanarayanan @ 2026-02-11 0:17 UTC (permalink / raw)
To: Dan Williams, Kirill A . Shutemov
Cc: Dave Hansen, Rick Edgecombe, x86, linux-kernel, linux-coco
In-Reply-To: <20260211001712.1531955-1-sathyanarayanan.kuppuswamy@linux.intel.com>
Confidential Computing (CoCo) attestation is evolving toward
standardized models such as DICE (Device Identifier Composition Engine)
and Post-Quantum Cryptography (PQC), which rely on layered certificate
chains and larger cryptographic signatures.
A typical PQC certificate can range from 5KB to 15KB, and DICE-based
architectures accumulate these certificates across multiple boot
stages. In such configurations, the total attestation evidence can
reach several megabytes, exceeding the current 32KB limit.
Increase TSM_REPORT_OUTBLOB_MAX to 16MB to accommodate these larger
certificate chains. This provides sufficient headroom to handle
evolving requirements without requiring frequent updates to the limit.
TSM_REPORT_OUTBLOB_MAX is used by the configfs read interface to cap
the maximum allowed binary blob size for outblob, auxblob and
manifestblob attributes. Hence, the per-open-file worst case memory
allocation increases from 32KB to 16MB. Multiple concurrent readers
multiply this cost (e.g., N readers of an M-byte blob incur NxM bytes
of vmalloc-backed memory). However, allocations are performed on demand
and remain proportional to the actual blob length, not the configured
maximum.
Reviewed-by: Fang Peter <peter.fang@intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
include/linux/tsm.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/linux/tsm.h b/include/linux/tsm.h
index a3b7ab668eff..7f72a154b6b2 100644
--- a/include/linux/tsm.h
+++ b/include/linux/tsm.h
@@ -8,7 +8,7 @@
#include <linux/device.h>
#define TSM_REPORT_INBLOB_MAX 64
-#define TSM_REPORT_OUTBLOB_MAX SZ_32K
+#define TSM_REPORT_OUTBLOB_MAX SZ_16M
/*
* Privilege level is a nested permission concept to allow confidential
--
2.43.0
^ permalink raw reply related
* [PATCH v1 3/3] virt: tdx-guest: Increase Quote buffer size to 128KB
From: Kuppuswamy Sathyanarayanan @ 2026-02-11 0:17 UTC (permalink / raw)
To: Dan Williams, Kirill A . Shutemov
Cc: Dave Hansen, Rick Edgecombe, x86, linux-kernel, linux-coco
In-Reply-To: <20260211001712.1531955-1-sathyanarayanan.kuppuswamy@linux.intel.com>
Intel platforms are transitioning from traditional SGX-based
attestation toward DICE-based attestation as part of a broader move
toward open and standardized attestation models. DICE enables layered
and extensible attestation, where evidence is accumulated across
multiple boot stages.
With SGX-based attestation, Quote sizes are typically under 8KB, as the
payload consists primarily of Quote data and a small certificate bundle.
Existing TDX guest code sizes the Quote buffer accordingly.
DICE-based attestation produces significantly larger Quotes due to the
inclusion of evidence (certificate chains) from multiple boot layers.
The cumulative Quote size can reach approximately 100KB.
Increase GET_QUOTE_BUF_SIZE to 128KB to ensure sufficient buffer
capacity for DICE-based Quote payloads.
Reviewed-by: Fang Peter <peter.fang@intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
---
Documentation/ABI/testing/configfs-tsm-report | 4 ++++
drivers/virt/coco/tdx-guest/tdx-guest.c | 4 +++-
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/Documentation/ABI/testing/configfs-tsm-report b/Documentation/ABI/testing/configfs-tsm-report
index ca3352cfd2f1..7a6a5045a7d5 100644
--- a/Documentation/ABI/testing/configfs-tsm-report
+++ b/Documentation/ABI/testing/configfs-tsm-report
@@ -73,6 +73,10 @@ Description:
Library Revision 0.8 Appendix 4,5
https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/Intel_TDX_DCAP_Quoting_Library_API.pdf
+ Intel TDX platforms with DICE-based attestation use CBOR Web Token
+ (CWT) format for the Quote payload. This is indicated by the Quote
+ size exceeding 8KB.
+
What: /sys/kernel/config/tsm/report/$name/generation
Date: September, 2023
KernelVersion: v6.7
diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/tdx-guest/tdx-guest.c
index 4e239ec960c9..4252b147593a 100644
--- a/drivers/virt/coco/tdx-guest/tdx-guest.c
+++ b/drivers/virt/coco/tdx-guest/tdx-guest.c
@@ -160,8 +160,10 @@ static void tdx_mr_deinit(const struct attribute_group *mr_grp)
/*
* Intel's SGX QE implementation generally uses Quote size less
* than 8K (2K Quote data + ~5K of certificate blob).
+ * DICE-based attestation uses layered evidence that requires
+ * larger Quote size (~100K).
*/
-#define GET_QUOTE_BUF_SIZE SZ_8K
+#define GET_QUOTE_BUF_SIZE SZ_128K
#define GET_QUOTE_CMD_VER 1
--
2.43.0
^ permalink raw reply related
* Re: [RFC PATCH v5 16/45] x86/virt/tdx: Add tdx_alloc/free_control_page() helpers
From: Edgecombe, Rick P @ 2026-02-11 0:50 UTC (permalink / raw)
To: Hansen, Dave, seanjc@google.com, x86@kernel.org,
dave.hansen@linux.intel.com, kas@kernel.org, bp@alien8.de,
mingo@redhat.com, tglx@kernel.org, pbonzini@redhat.com
Cc: Huang, Kai, ackerleytng@google.com, sagis@google.com,
Annapurve, Vishal, linux-kernel@vger.kernel.org, Zhao, Yan Y,
Li, Xiaoyao, kvm@vger.kernel.org, linux-coco@lists.linux.dev,
Yamahata, Isaku, binbin.wu@linux.intel.com
In-Reply-To: <655724f8-0098-40ee-a097-ce4c0249933d@intel.com>
On Tue, 2026-02-10 at 09:44 -0800, Dave Hansen wrote:
> slow_path = atomic_dec_and_lock(fine-grained-refcount,
> pamt_lock)
> if (!slow_path)
> goto out;
I guess if it returns 0, the lock is not held. So we can just return.
>
> // fine-grained-refcount==0 and must stay that way with
> // pamt_lock held. Remove the DPAMT pages:
> tdh_phymem_pamt_remove(page, pamt_pa_array)
> out:
> spin_unlock(pamt_lock)
>
> On the acquire side, you do:
>
> fast_path = atomic_inc_not_zero(fine-grained-refcount)
> if (fast_path)
> return;
>
> // slow path:
> spin_lock(pamt_lock)
>
> // Was the race lost with another 0=>1 increment?
> if (atomic_read(fine-grained-refcount) > 0)
> goto out_inc
>
> tdh_phymem_pamt_add(page, pamt_pa_array)
> // Inc after the TDCALL so another thread won't race ahead of us
> // and try to use a non-existent PAMT entry
> out_inc:
> atomic_inc(fine-grained-refcount)
> spin_unlock(pamt_lock)
>
> Then, at least only the 0=>1 and 1=>0 transitions need the global lock.
> The fast paths only touch the refcount which isn't shared nearly as much
> as the global lock.
>
> BTW, this probably still needs to be spin_lock_irq(), not what I wrote
> above, but that's not a big deal to add.
>
> I've stared at this for a bit and don't see any holes. Does anyone else
> see any?
I don't see any issues. It is largely similar to the version in the next patch
except we don't need to handle the HPA_RANGE_NOT_FREE case specially. It does
this without taking the lock in any more cases. So seems like a nice code
reduction.
It probably is still worth keeping the comment about the get/put race somewhere.
I'll see if I can slot it in somewhere.
^ permalink raw reply
* Re: [PATCH v1 1/3] virt: tsm: Document size limits for outblob attributes
From: dan.j.williams @ 2026-02-11 2:15 UTC (permalink / raw)
To: Kuppuswamy Sathyanarayanan, Dan Williams, Kirill A . Shutemov
Cc: Dave Hansen, Rick Edgecombe, x86, linux-kernel, linux-coco
In-Reply-To: <20260211001712.1531955-2-sathyanarayanan.kuppuswamy@linux.intel.com>
Kuppuswamy Sathyanarayanan wrote:
> The configfs-tsm-report interface can fail with -EFBIG when the
> attestation report generated by a TSM provider exceeds internal
> maximums (TSM_REPORT_OUTBLOB_MAX). However, this error condition and
> its handling are not currently documented in the ABI.
>
> Userspace tools need to understand how to interpret various error
> conditions when reading attestation reports.
>
> Document that reads fail with -EFBIG when reports exceed size limits,
> with guidance on how to resolve them.
>
> Reviewed-by: Fang Peter <peter.fang@intel.com>
> Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Looks good, I will change the subject to:
"configfs-tsm-report: Document size limits for outblob attributes"
^ permalink raw reply
* Re: [PATCH v1 2/3] virt: tsm: Increase TSM_REPORT_OUTBLOB_MAX to 16MB
From: dan.j.williams @ 2026-02-11 2:16 UTC (permalink / raw)
To: Kuppuswamy Sathyanarayanan, Dan Williams, Kirill A . Shutemov
Cc: Dave Hansen, Rick Edgecombe, x86, linux-kernel, linux-coco
In-Reply-To: <20260211001712.1531955-3-sathyanarayanan.kuppuswamy@linux.intel.com>
Kuppuswamy Sathyanarayanan wrote:
> Confidential Computing (CoCo) attestation is evolving toward
> standardized models such as DICE (Device Identifier Composition Engine)
> and Post-Quantum Cryptography (PQC), which rely on layered certificate
> chains and larger cryptographic signatures.
>
> A typical PQC certificate can range from 5KB to 15KB, and DICE-based
> architectures accumulate these certificates across multiple boot
> stages. In such configurations, the total attestation evidence can
> reach several megabytes, exceeding the current 32KB limit.
>
> Increase TSM_REPORT_OUTBLOB_MAX to 16MB to accommodate these larger
> certificate chains. This provides sufficient headroom to handle
> evolving requirements without requiring frequent updates to the limit.
>
> TSM_REPORT_OUTBLOB_MAX is used by the configfs read interface to cap
> the maximum allowed binary blob size for outblob, auxblob and
> manifestblob attributes. Hence, the per-open-file worst case memory
> allocation increases from 32KB to 16MB. Multiple concurrent readers
> multiply this cost (e.g., N readers of an M-byte blob incur NxM bytes
> of vmalloc-backed memory). However, allocations are performed on demand
> and remain proportional to the actual blob length, not the configured
> maximum.
Looks ok, again I will change the subject to:
"configfs-tsm-report: Increase TSM_REPORT_OUTBLOB_MAX to 16MB"
^ permalink raw reply
* Re: [PATCH v1 3/3] virt: tdx-guest: Increase Quote buffer size to 128KB
From: dan.j.williams @ 2026-02-11 2:19 UTC (permalink / raw)
To: Kuppuswamy Sathyanarayanan, Dan Williams, Kirill A . Shutemov
Cc: Dave Hansen, Rick Edgecombe, x86, linux-kernel, linux-coco
In-Reply-To: <20260211001712.1531955-4-sathyanarayanan.kuppuswamy@linux.intel.com>
Kuppuswamy Sathyanarayanan wrote:
> Intel platforms are transitioning from traditional SGX-based
> attestation toward DICE-based attestation as part of a broader move
> toward open and standardized attestation models. DICE enables layered
> and extensible attestation, where evidence is accumulated across
> multiple boot stages.
>
> With SGX-based attestation, Quote sizes are typically under 8KB, as the
> payload consists primarily of Quote data and a small certificate bundle.
> Existing TDX guest code sizes the Quote buffer accordingly.
>
> DICE-based attestation produces significantly larger Quotes due to the
> inclusion of evidence (certificate chains) from multiple boot layers.
> The cumulative Quote size can reach approximately 100KB.
>
> Increase GET_QUOTE_BUF_SIZE to 128KB to ensure sufficient buffer
> capacity for DICE-based Quote payloads.
>
> Reviewed-by: Fang Peter <peter.fang@intel.com>
> Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
> ---
> Documentation/ABI/testing/configfs-tsm-report | 4 ++++
> drivers/virt/coco/tdx-guest/tdx-guest.c | 4 +++-
> 2 files changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/ABI/testing/configfs-tsm-report b/Documentation/ABI/testing/configfs-tsm-report
> index ca3352cfd2f1..7a6a5045a7d5 100644
> --- a/Documentation/ABI/testing/configfs-tsm-report
> +++ b/Documentation/ABI/testing/configfs-tsm-report
> @@ -73,6 +73,10 @@ Description:
> Library Revision 0.8 Appendix 4,5
> https://download.01.org/intel-sgx/latest/dcap-latest/linux/docs/Intel_TDX_DCAP_Quoting_Library_API.pdf
>
> + Intel TDX platforms with DICE-based attestation use CBOR Web Token
> + (CWT) format for the Quote payload. This is indicated by the Quote
> + size exceeding 8KB.
Looks ok, please follow up with a link to the full format specification
when it is published.
I will change this subject to:
"configfs-tsm-report: tdx_guest: Increase Quote buffer size to 128KB"
^ permalink raw reply
* Re: [RFC PATCH v5 08/45] KVM: x86/mmu: Propagate mirror SPTE removal to S-EPT in handle_changed_spte()
From: Yan Zhao @ 2026-02-11 2:16 UTC (permalink / raw)
To: Sean Christopherson
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Kiryl Shutsemau, Paolo Bonzini, linux-kernel, linux-coco, kvm,
Kai Huang, Rick Edgecombe, Vishal Annapurve, Ackerley Tng,
Sagi Shahar, Binbin Wu, Xiaoyao Li, Isaku Yamahata
In-Reply-To: <aYuMaRbVQyUfYJTP@google.com>
On Tue, Feb 10, 2026 at 11:52:09AM -0800, Sean Christopherson wrote:
> > For TDX's future implementation of set_external_spte() for split splitting,
> > could we add a new param "bool shared" to op set_external_spte() in the
> > future? i.e.,
> > - when tdx_sept_split_private_spte() is invoked under write mmu_lock, it calls
> > tdh_do_no_vcpus() to retry BUSY error, and TDX_BUG_ON_2() then.
> > - when tdx_sept_split_private_spte() is invoked under read mmu_lock
> > (in the future when calling tdh_mem_range_block() in unnecessary), it could
> > directly return BUSY to TDP MMU on contention.
>
> Yeah, I have no objection to using @shared for things like that.
Great.
> > > + return 0;
> > > +}
> > > +
> > > +static void handle_changed_spte(struct kvm *kvm, int as_id, tdp_ptep_t sptep,
> > > + gfn_t gfn, u64 old_spte, u64 new_spte,
> > > + int level, bool shared)
> > > +{
> > Do we need "WARN_ON_ONCE(is_mirror_sptep(sptep) && shared)" here ?
>
> No, because I want to call this code for all paths, including the fault path.
Hmm. IIUC, handle_changed_spte() can't be invoked for mirror root under read
mmu_lock.
For read mmu_lock + mirror scenarios, they need to invoke
tdp_mmu_set_spte_atomic() --> __handle_changed_spte().
> > > @@ -663,14 +630,44 @@ static inline int __must_check tdp_mmu_set_spte_atomic(struct kvm *kvm,
> > >
> > > lockdep_assert_held_read(&kvm->mmu_lock);
> > >
> > > - ret = __tdp_mmu_set_spte_atomic(kvm, iter, new_spte);
> > >
> > > + /* KVM should never freeze SPTEs using higher level APIs. */
> > > + KVM_MMU_WARN_ON(is_frozen_spte(new_spte));
> > What about
> > KVM_MMU_WARN_ON(is_frozen_spte(new_spte) ||
> > is_frozen_spte(iter->old_spte) || iter->yielded);
> >
> > > + /*
> > > + * Temporarily freeze the SPTE until the external PTE operation has
> > > + * completed (unless the new SPTE itself will be frozen), e.g. so that
> > > + * concurrent faults don't attempt to install a child PTE in the
> > > + * external page table before the parent PTE has been written, or try
> > > + * to re-install a page table before the old one was removed.
> > > + */
> > > + if (is_mirror_sptep(iter->sptep))
> > > + ret = __tdp_mmu_set_spte_atomic(kvm, iter, FROZEN_SPTE);
> > > + else
> > > + ret = __tdp_mmu_set_spte_atomic(kvm, iter, new_spte);
> > and invoking open code try_cmpxchg64() directly?
>
> No, because __tdp_mmu_set_spte_atomic() is still used by kvm_tdp_mmu_age_spte(),
> and the yielded/frozen rules apply there as well.
I see.
> > > + /*
> > > + * Unfreeze the mirror SPTE. If updating the external SPTE failed,
> > > + * restore the old SPTE so that the SPTE isn't frozen in perpetuity,
> > > + * otherwise set the mirror SPTE to the new desired value.
> > > + */
> > > + if (is_mirror_sptep(iter->sptep)) {
> > > + if (ret)
> > > + __kvm_tdp_mmu_write_spte(iter->sptep, iter->old_spte);
> > > + else
> > > + __kvm_tdp_mmu_write_spte(iter->sptep, new_spte);
> > > + } else {
> > > + /*
> > > + * Bug the VM if handling the change failed, as failure is only
> > > + * allowed if KVM couldn't update the external SPTE.
> > > + */
> > > + KVM_BUG_ON(ret, kvm);
> > > + }
> > > + return ret;
> > > }
> > One concern for tdp_mmu_set_spte_atomic() to handle mirror SPTEs:
> > - Previously
> > 1. set *iter->sptep to FROZEN_SPTE.
> > 2. kvm_x86_call(set_external_spte)(old_spte, new_spte)
> > 3. set *iter->sptep to new_spte
> >
> > - Now with this diff
> > 1. set *iter->sptep to FROZEN_SPTE.
> > 2. __handle_changed_spte()
> > --> kvm_x86_call(set_external_spte)(iter->sptep, old_spte, new_spte)
>
> Note, iter->sptep isn't passed to set_external_spte(), the invocation for that is:
>
> return kvm_x86_call(set_external_spte)(kvm, gfn, old_spte,
> new_spte, level);
Oh, sorry. It should be
2. __handle_changed_spte(iter->sptep, old_spte, new_spte)
--> kvm_x86_call(set_external_spte)(old_spte, new_spte)
My concern is that what we pass to __handle_changed_spte() here are
"iter->sptep, iter->old_spte, new_spte".
ret = __handle_changed_spte(kvm, iter->as_id, iter->sptep, iter->gfn,
iter->old_spte, new_spte, iter->level, true);
i.e., new_spte is the target value which we haven't written it to iter->sptep
yet. We'll write the target value new_spte to iter->sptep after
__handle_changed_spte() succeeds. So, upon invoking __handle_changed_spte() in
tdp_mmu_set_spte_atomic(), iter->sptep just holds value FROZEN_SPTE.
So, re-reading iter->sptep will get a different value (which is FROZEN_SPTE)
from the new_spte passed to __handle_changed_spte().
Besides, __handle_changed_spte() contains code like
"kvm_update_page_stats(kvm, level, is_leaf ? 1 : -1);", which may have
incorrectly updated the stats even if kvm_x86_call(set_external_spte)() fails
later and the new_spte is never written to iter->sptep.
> > 3. set *iter->sptep to new_spte
> >
> > what if __handle_changed_spte() reads *iter->sptep in step 2?
>
> For the most part, "don't do that". There are an infinite number of "what ifs".
> I agree that re-reading iter->sptep is slightly more likely than other "what ifs",
> but then if we convert to a boolean it creates the "what if we swap the order of
> @as_id and @is_mirror_sp"? Given that @old_spte is provided, IMO re-reading the
> SPTE from memory will stand out.
As my above concern, re-reading SPTE in __handle_changed_spte() will just get
value FROZEN_SPTE instead of the value of new_spte.
> That said, I think we can have the best of both worlds. Rather than pass @as_id
> and @sptep, pass the @sp, i.e. the owning kvm_mmu_page. That would address your
> concern about re-reading the sptep, without needing another boolean.
Hmm, my intention of passing boolean is to avoid re-reading sptep, because
in step 2, we pass new_spte instead of the real value in sptep (which is
FROZEN_SPTE for mirror sp) to __handle_changed_spte().
So, passing @sp may not help?
^ permalink raw reply
* Re: [RFC PATCH v5 44/45] KVM: x86/mmu: Add support for splitting S-EPT hugepages on conversion
From: Yan Zhao @ 2026-02-11 8:43 UTC (permalink / raw)
To: Sean Christopherson
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Kiryl Shutsemau, Paolo Bonzini, linux-kernel, linux-coco, kvm,
Kai Huang, Rick Edgecombe, Vishal Annapurve, Ackerley Tng,
Sagi Shahar, Binbin Wu, Xiaoyao Li, Isaku Yamahata
In-Reply-To: <aXt_L6QKB9CSTZcW@google.com>
On Thu, Jan 29, 2026 at 07:39:27AM -0800, Sean Christopherson wrote:
> Compile tested only...
It passed my local tests with the fix [1].
[1] https://lore.kernel.org/all/aYX-RpxDYrI65XRC@google.com.
> @@ -1950,6 +1950,7 @@ struct kvm_x86_ops {
> void *(*alloc_apic_backing_page)(struct kvm_vcpu *vcpu);
> int (*gmem_prepare)(struct kvm *kvm, kvm_pfn_t pfn, gfn_t gfn, int max_order);
> void (*gmem_invalidate)(kvm_pfn_t start, kvm_pfn_t end);
> + int (*gmem_convert)(struct kvm *kvm, gfn_t start, gfn_t end, bool to_private);
> int (*gmem_max_mapping_level)(struct kvm *kvm, kvm_pfn_t pfn, bool is_private);
> };
Since tdx_gmem_convert() only performs S-EPT splitting on the specified range,
would it make sense to rename the op gmem_convert() to something like
gmem_split_private_mapping()?
(This would also involve renaming
kvm_gmem_convert() to kvm_gmem_split_private_mapping(), and
kvm_arch_gmem_convert() to kvm_arch_gmem_split_private_mapping()).
This way, it's natural for it to be called by kvm_gmem_set_attributes() for
private-to-shared conversions, kvm_gmem_punch_hole(), or kvm_gmem_error_folio().
> +static int tdx_gmem_convert(struct kvm *kvm, gfn_t start, gfn_t end,
> + bool to_private)
> +{
> + /*
> + * When converting from private=>shared, KVM must first split potential
> + * hugepages, as KVM mustn't overzap private mappings for TDX guests,
> + * i.e. must zap _exactly_ [start, end). Split potential hugepages at
> + * the head and tail of the to-be-converted (and thus zapped) range so
> + * that KVM doesn't overzap due to dropping a hugepage that doesn't
> + * fall wholly inside the range.
> + */
> + if (to_private || !kvm_has_mirrored_tdp(kvm))
> + return 0;
> +
> + /*
> + * Acquire the external cache lock, a.k.a. the Dynamic PAMT lock, to
> + * protect the per-VM cache of pre-allocate pages used to populate the
> + * Dynamic PAMT when splitting S-EPT huge pages.
> + */
> + guard(mutex)(&to_kvm_tdx(kvm)->pamt_cache_lock);
Thanks for the change from spinlock to mutex, which is a smart approach that
eliminates the need to release the lock for topup.
However, I have a question about kvm_tdp_mmu_try_split_huge_pages(), which is
called by dirty page tracking related functions. I'm not sure if we might want
to invoke them from a non-vCPU thread for mirror roots in the future. If that's
the case, would they need some way to acquire this lock?
> + guard(write_lock)(&kvm->mmu_lock);
> +
> + /*
> + * TODO: Also split from PG_LEVEL_1G => PG_LEVEL_2M when KVM supports
> + * 1GiB S-EPT pages.
> + */
> + return tdx_sept_split_huge_pages(kvm, start, end, PG_LEVEL_4K);
> +}
> +
> diff --git a/arch/x86/kvm/vmx/tdx.h b/arch/x86/kvm/vmx/tdx.h
> index f444fc84d93b..2bb4604a64ca 100644
> --- a/arch/x86/kvm/vmx/tdx.h
> +++ b/arch/x86/kvm/vmx/tdx.h
> @@ -48,6 +48,9 @@ struct kvm_tdx {
> * Set/unset is protected with kvm->mmu_lock.
> */
> bool wait_for_sept_zap;
> +
> + struct tdx_pamt_cache pamt_cache;
> + struct mutex pamt_cache_lock;
> };
>
> /* TDX module vCPU states */
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index c80cc60e7862..c3d71ba9a1dc 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -14061,7 +14061,7 @@ void kvm_arch_gmem_invalidate(kvm_pfn_t start, kvm_pfn_t end)
> int kvm_arch_gmem_convert(struct kvm *kvm, gfn_t start, gfn_t end,
> bool to_private)
> {
> - return 0;
> + return kvm_x86_call(gmem_convert)(kvm, start, end, to_private);
> }
> #endif
> #endif
>
> base-commit: b2791d61e9774d8575525816e864d2e09ee9090a
> --
^ permalink raw reply
* [PATCH 0/1] [Test Report] get qutoe time via tdvmcall
From: Jun Miao @ 2026-02-11 8:58 UTC (permalink / raw)
To: kas, dave.hansen, rick.p.edgecombe, sathyanarayanan.kuppuswamy
Cc: linux-coco, kvm, linux-kernel, jun.miao
[Background]
Currently, many mobile device vendors (such as OPPO and Xiaomi) use TDVM for security management.
Each mobile terminal must perform remote attestation before it can access the TDVM confidential container.
As a result, there are a large number of remote attestation get-quote requests, especially in cases
where vsock is not configured or misconfigured and cannot be used.
[Limitation]
Currently, the polling interval is set to 1 second, which allows at most one quote to be retrieved per second.
For workloads with frequent remote attestations, polling once per second severely limits performance.
Test like this:
[root@INTELTDX ~]# ./test_tdx_attest-thread
Start tdx_att_get_quote concurrent loop, duration: 1 s, threads: 1
Summary (tdx_att_get_quote)
Threads: 1
Mode: concurrent
Duration: requested 1 s, actual 1.036 s
Total: 1
Success: 1
Failure: 0
Avg total per 1s: 0.97
Avg success per 1s: 0.97
Avg total per 1s per thread: 0.97
Avg success per 1s per thread: 0.97
Min elapsed_time: 1025.95 ms
Max elapsed_time: 1025.95 ms
[Optimization Rationale]
But the actual trace the get quote time on GNR platform:
test_tdx_attest-598 [001] ..... 371.214611: tdx_report_new: [debug start wait]===: I am in function wait_for_quote_completion LINE=155===
test_tdx_attest-598 [001] ..... 371.220287: tdx_report_new: [debug end wait]===: I am in function wait_for_quote_completion LINE=162===
Cost time: 371.220287 - 371.215611 = 0.004676 = 4.6ms
The following test results were obtained on the GNR platform:
| msleep_interruptible(time) | 1ms | 5ms | 1s |
| ------------------------------ | -------- | -------- | ---------- |
| Duration | 1.004 s | 1.005 s | 1.036 s |
| Total(Get Quote) | 167 | 142 | 1 |
| Success: | 167 | 142 | 1 |
| Failure: | 0 | 0 | 0 |
| Avg total / 1s | 166.35 | 141.31 | 0.97 |
| Avg success / 1s | 166.35 | 141.31 | 0.97 |
| Avg total / 1s / thread | 166.35 | 141.31 | 0.97 |
| Avg success / 1s / thread | 166.35 | 141.31 | 0.97 |
| Min elapsed_time | 2.99 ms | 6.85 ms | 1025.95 ms |
| Max elapsed_time | 10.76 ms | 10.93 ms | 1025.95 ms |
Jun Miao (1):
virt: tdx-guest: Optimize the get-quote polling interval time
drivers/virt/coco/tdx-guest/tdx-guest.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
--
2.32.0
^ permalink raw reply
* [PATCH 1/1] virt: tdx-guest: Optimize the get-quote polling interval time
From: Jun Miao @ 2026-02-11 8:58 UTC (permalink / raw)
To: kas, dave.hansen, rick.p.edgecombe, sathyanarayanan.kuppuswamy
Cc: linux-coco, kvm, linux-kernel, jun.miao
In-Reply-To: <20260211085801.4036464-1-jun.miao@intel.com>
The TD guest sends TDREPORT to the TD Quoting Enclave via a vsock or
a tdvmcall. In general, vsock is indeed much faster than tdvmcall,
and Quote requests usually take a few millisecond to complete rather
than seconds based on actual measurements.
The following get quote time via tdvmcall were obtained on the GNR:
| msleep_interruptible(time) | 1s | 5ms | 1ms |
| ------------------------------ | -------- | -------- | ---------- |
| Duration | 1.004 s | 1.005 s | 1.036 s |
| Total(Get Quote) | 167 | 142 | 167 |
| Success: | 167 | 142 | 167 |
| Failure: | 0 | 0 | 0 |
| Avg total / 1s | 0.97 | 141.31 | 166.35 |
| Avg success / 1s | 0.97 | 141.31 | 166.35 |
| Avg total / 1s / thread | 0.97 | 141.31 | 166.35 |
| Avg success / 1s / thread | 0.97 | 141.31 | 166.35 |
| Min elapsed_time | 1025.95ms| 6.85 ms | 2.99 ms |
| Max elapsed_time | 1025.95ms| 10.93 ms | 10.76 ms |
According to trace analysis, the typical execution tdvmcall get the
quote time is 4 ms. Therefore, 5 ms is a reasonable balance between
performance efficiency and CPU overhead.
And compared to the previous throughput of one request per second,
the current 5ms can get 142 requests per second delivers a
142× performance improvement, which is critical for high-frequency
use cases without vsock.
So, change the 1s (MSEC_PER_SEC) -> 5ms (MSEC_PER_SEC / 200)
Signed-off-by: Jun Miao <jun.miao@intel.com>
---
drivers/virt/coco/tdx-guest/tdx-guest.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/tdx-guest/tdx-guest.c
index 4e239ec960c9..71d2d7304b1a 100644
--- a/drivers/virt/coco/tdx-guest/tdx-guest.c
+++ b/drivers/virt/coco/tdx-guest/tdx-guest.c
@@ -251,11 +251,11 @@ static int wait_for_quote_completion(struct tdx_quote_buf *quote_buf, u32 timeou
int i = 0;
/*
- * Quote requests usually take a few seconds to complete, so waking up
- * once per second to recheck the status is fine for this use case.
+ * Quote requests usually take a few milliseconds to complete, so waking up
+ * once per 5 milliseconds to recheck the status is fine for this use case.
*/
- while (quote_buf->status == GET_QUOTE_IN_FLIGHT && i++ < timeout) {
- if (msleep_interruptible(MSEC_PER_SEC))
+ while (quote_buf->status == GET_QUOTE_IN_FLIGHT && i++ < 200 * timeout) {
+ if (msleep_interruptible(MSEC_PER_SEC / 200))
return -EINTR;
}
--
2.32.0
^ permalink raw reply related
* Re: [RFC PATCH v5 37/45] KVM: x86/tdp_mmu: Alloc external_spt page for mirror page table splitting
From: Yan Zhao @ 2026-02-11 9:49 UTC (permalink / raw)
To: Sean Christopherson
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Kiryl Shutsemau, Paolo Bonzini, linux-kernel, linux-coco, kvm,
Kai Huang, Rick Edgecombe, Vishal Annapurve, Ackerley Tng,
Sagi Shahar, Binbin Wu, Xiaoyao Li, Isaku Yamahata
In-Reply-To: <aYYSIndbqLdFkaM-@google.com>
On Fri, Feb 06, 2026 at 08:09:06AM -0800, Sean Christopherson wrote:
> > So, it's incorrect to invoke is_mirror_sptep() which internally contains
> > rcu_dereference(), resulting in "WARNING: suspicious RCU usage".
>
> Ah, now I see why the previous code pass in a bool. I don't love passing a bool,
> but passing @iter is outright dangerous, so I guess this?
LGTM.
> diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c
> index a32192c35099..4d92c0d19d7c 100644
> --- a/arch/x86/kvm/mmu/tdp_mmu.c
> +++ b/arch/x86/kvm/mmu/tdp_mmu.c
> @@ -1448,7 +1448,7 @@ bool kvm_tdp_mmu_wrprot_slot(struct kvm *kvm,
> }
>
> static struct kvm_mmu_page *tdp_mmu_alloc_sp_for_split(struct kvm *kvm,
> - struct tdp_iter *iter)
> + bool is_mirror_sp)
> {
> struct kvm_mmu_page *sp;
>
> @@ -1460,7 +1460,7 @@ static struct kvm_mmu_page *tdp_mmu_alloc_sp_for_split(struct kvm *kvm,
> if (!sp->spt)
> goto err_spt;
>
> - if (is_mirror_sptep(iter->sptep)) {
> + if (is_mirror_sp) {
> sp->external_spt = (void *)kvm_x86_call(alloc_external_sp)(GFP_KERNEL_ACCOUNT);
> if (!sp->external_spt)
> goto err_external_spt;
> @@ -1525,6 +1525,7 @@ static int tdp_mmu_split_huge_pages_root(struct kvm *kvm,
> gfn_t start, gfn_t end,
> int target_level, bool shared)
> {
> + const bool is_mirror_root = is_mirror_sp(root);
> struct kvm_mmu_page *sp = NULL;
> struct tdp_iter iter;
>
> @@ -1557,7 +1558,7 @@ static int tdp_mmu_split_huge_pages_root(struct kvm *kvm,
> else
> write_unlock(&kvm->mmu_lock);
>
> - sp = tdp_mmu_alloc_sp_for_split(kvm, &iter);
> + sp = tdp_mmu_alloc_sp_for_split(kvm, is_mirror_root);
>
> if (shared)
> read_lock(&kvm->mmu_lock);
^ permalink raw reply
* Re: [PATCH v1 3/3] virt: tdx-guest: Increase Quote buffer size to 128KB
From: Kiryl Shutsemau @ 2026-02-11 11:17 UTC (permalink / raw)
To: Kuppuswamy Sathyanarayanan
Cc: Dan Williams, Dave Hansen, Rick Edgecombe, x86, linux-kernel,
linux-coco
In-Reply-To: <20260211001712.1531955-4-sathyanarayanan.kuppuswamy@linux.intel.com>
On Tue, Feb 10, 2026 at 04:17:12PM -0800, Kuppuswamy Sathyanarayanan wrote:
> Intel platforms are transitioning from traditional SGX-based
> attestation toward DICE-based attestation as part of a broader move
> toward open and standardized attestation models. DICE enables layered
> and extensible attestation, where evidence is accumulated across
> multiple boot stages.
>
> With SGX-based attestation, Quote sizes are typically under 8KB, as the
> payload consists primarily of Quote data and a small certificate bundle.
> Existing TDX guest code sizes the Quote buffer accordingly.
>
> DICE-based attestation produces significantly larger Quotes due to the
> inclusion of evidence (certificate chains) from multiple boot layers.
> The cumulative Quote size can reach approximately 100KB.
>
> Increase GET_QUOTE_BUF_SIZE to 128KB to ensure sufficient buffer
> capacity for DICE-based Quote payloads.
It worth noting that it requires guest physically-contiguous memory.
Single order-5 allocation is not that bad as long as the driver
initialized during the boot.
--
Kiryl Shutsemau / Kirill A. Shutemov
^ permalink raw reply
* Re: [PATCH v1 06/26] x86/virt/tdx: Add tdx_page_array helpers for new TDX Module objects
From: dan.j.williams @ 2026-02-11 16:24 UTC (permalink / raw)
To: Dave Hansen, Xu Yilun, linux-coco, linux-pci
Cc: chao.gao, dave.jiang, baolu.lu, yilun.xu, zhenzhong.duan, kvm,
rick.p.edgecombe, dave.hansen, dan.j.williams, kas, x86
In-Reply-To: <96d66314-a0f8-4c63-8f0d-1d392882e007@intel.com>
Dave Hansen wrote:
> On 11/16/25 18:22, Xu Yilun wrote:
> > + struct page *root __free(__free_page) = alloc_page(GFP_KERNEL |
> > + __GFP_ZERO);
> > + if (!root)
> > + return NULL;
>
> Why don't you just kcalloc() this like the rest of them?
>
> Then you won't need "mm: Add __free() support for __free_page()" either,
> right?
I saw a preview of what this comment does to the implementation and I am
not sure it is an improvement to avoid the __free() support for
alloc_page().
The seamcall prototype is:
u64 tdh_ide_stream_km(u64 spdm_id, u64 stream_id, u64 operation,
struct page *spdm_rsp, struct page *spdm_req,
u64 *spdm_req_len);
The interdiff of the effect of this review feedback is:
@@ drivers/virt/coco/tdx-host/tdx-host.c: static void tdx_spdm_session_teardown(str
+
+ do {
+ r = tdh_ide_stream_km(tlink->spdm_id, tlink->stream_id, op,
-+ tlink->in_msg, tlink->out_msg,
++ virt_to_page(tlink->in_msg),
++ virt_to_page(tlink->out_msg),
+ &out_msg_sz);
+ ret = tdx_link_event_handler(tlink, r, out_msg_sz);
+ } while (ret == -EAGAIN);
This is unfortunate because tdh_ide_stream_km() will just turn around
and call page_to_phys() on those arguments. It forfeits type safety and
inflicts the mental hurdle of "->in_msg and ->out_msg are direct-mapped
page-aligned virtual addresses, right, right!?".
So alloc_page() + __free_page() is more suitable than kzalloc(PAGE_SIZE,
...) as long as the seamcall requires 'struct page *' arguments. Another
path is the seamcall semantic is updated to handle virt_to_phys()
without alignment concerns, but it is a bit late to make that change. I
considered the concept of passing a "va page frame number" around, but
'struct page *' *is* the idiomatic expression for that concept.
^ permalink raw reply
* Re: [PATCH v1 1/3] virt: tsm: Document size limits for outblob attributes
From: Kuppuswamy Sathyanarayanan @ 2026-02-11 16:40 UTC (permalink / raw)
To: dan.j.williams, Kirill A . Shutemov
Cc: Dave Hansen, Rick Edgecombe, x86, linux-kernel, linux-coco
In-Reply-To: <698be62f7802_8c32100e2@dwillia2-mobl4.notmuch>
Hi Dan,
On 2/10/2026 6:15 PM, dan.j.williams@intel.com wrote:
> Kuppuswamy Sathyanarayanan wrote:
>> The configfs-tsm-report interface can fail with -EFBIG when the
>> attestation report generated by a TSM provider exceeds internal
>> maximums (TSM_REPORT_OUTBLOB_MAX). However, this error condition and
>> its handling are not currently documented in the ABI.
>>
>> Userspace tools need to understand how to interpret various error
>> conditions when reading attestation reports.
>>
>> Document that reads fail with -EFBIG when reports exceed size limits,
>> with guidance on how to resolve them.
>>
>> Reviewed-by: Fang Peter <peter.fang@intel.com>
>> Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
>
> Looks good, I will change the subject to:
>
> "configfs-tsm-report: Document size limits for outblob attributes"
Thanks for the review! Are you planning to apply this with the updated
subject line, or would you like me to send a v2 with the change?
--
Sathyanarayanan Kuppuswamy
Linux Kernel Developer
^ permalink raw reply
* Re: [PATCH v1 3/3] virt: tdx-guest: Increase Quote buffer size to 128KB
From: Kuppuswamy Sathyanarayanan @ 2026-02-11 18:40 UTC (permalink / raw)
To: Kiryl Shutsemau
Cc: Dan Williams, Dave Hansen, Rick Edgecombe, x86, linux-kernel,
linux-coco
In-Reply-To: <aYxjhdES2MOI7rj9@thinkstation>
Hi Kiryl,
Thanks for the review!
On 2/11/2026 3:17 AM, Kiryl Shutsemau wrote:
> On Tue, Feb 10, 2026 at 04:17:12PM -0800, Kuppuswamy Sathyanarayanan wrote:
>> Intel platforms are transitioning from traditional SGX-based
>> attestation toward DICE-based attestation as part of a broader move
>> toward open and standardized attestation models. DICE enables layered
>> and extensible attestation, where evidence is accumulated across
>> multiple boot stages.
>>
>> With SGX-based attestation, Quote sizes are typically under 8KB, as the
>> payload consists primarily of Quote data and a small certificate bundle.
>> Existing TDX guest code sizes the Quote buffer accordingly.
>>
>> DICE-based attestation produces significantly larger Quotes due to the
>> inclusion of evidence (certificate chains) from multiple boot layers.
>> The cumulative Quote size can reach approximately 100KB.
>>
>> Increase GET_QUOTE_BUF_SIZE to 128KB to ensure sufficient buffer
>> capacity for DICE-based Quote payloads.
>
> It worth noting that it requires guest physically-contiguous memory.
>
> Single order-5 allocation is not that bad as long as the driver
> initialized during the boot.
Good point! We can add following to the commit log:
The Quote buffer requires guest physically-contiguous memory and is
allocated once during driver initialization at boot time, where an
order-5 allocation (128KB) is expected to succeed reliably.
>
--
Sathyanarayanan Kuppuswamy
Linux Kernel Developer
^ permalink raw reply
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