Skip to content

Conversation

@hargar19
Copy link
Collaborator

Mirror the CVM TDX changes from product/hcl-main/6.12 branch.
Buddy build for this update: https://msazure.visualstudio.com/LSG-linux/_build/results?buildId=146743117&view=results

Signed-off-by: Hardik Garg [email protected]

yamahata and others added 16 commits December 4, 2025 09:46
TD partitioning provides a timer service for L1 (VTL2) guest to set
a preemption timer for L2 (VTL0) vCPUs.

Add members for a new timer service to the tdx_vp_context struct for
the L1 (VTL2) userspace to pass a timeout value down to the L1 (VTL2)
kernel.

Signed-off-by: Isaku Yamahata <[email protected]>
Refactor __tdcall() for a dedicated wrapper for TDG.VP.WR() operation.
This prepares for additional calls of TDG.VP.WR() cleanly while avoiding
repeated open-coding.

No functional change intended.

Signed-off-by: Isaku Yamahata <[email protected]>
Program the TD partitioning TSC deadline timer service for L2 (VTL0) vCPUs
when the L1 (VTL2) userspace requests.  Then, the TDX module sets
preemption timer for L2 vCPU.  If the timer expires, the L2 (VTL0) vCPU
exits with a VMX preemption timer exit reason.  The mshv_vtl driver then
exits to the userspace, and the userspace is notified of the exit.

The TDX module does not clear TDVPS deadline on a preemption timer exit.
Disarm the TSC deadline explicitly on the preemption timer exit.  Otherwise
the following TDG.VP.ENTER() immediately exits without executing the L2
guest.

Reported-by: Dexuan Cui <[email protected]>
Signed-off-by: Isaku Yamahata <[email protected]>
As the tdcall is slow, cache the previously written TSC deadline value and
skip unnecessary tdg.vp.wr(TSC deadline) if the value doesn't change.  This
is also a preparation for hlt emulation case that requires the previously
written TSC deadline value.

Signed-off-by: Isaku Yamahata <[email protected]>
The TDX timer service sets a preemption timer for the L2 (VTL0) vCPU.
tdg.vp.enter() exits with preemption timer exit reason on timer expiry.
The HLT emulation path needs extra change where the L1 (VTL2) kernel issues
TDG.VP.VMCALL(HLT) because the host (L0) VMM doesn't know the L2 deadline
timer value.

When the L1 kernel issues TDG.VP.VMCALL(HLT), start per-CPU hrtimer to wake
up from the L0 HLT emulation by L1 getting timer interrupt.  Cancel the
hrtimer after it returns from the L0 VMM.

Signed-off-by: Isaku Yamahata <[email protected]>
On timer expiry path, it unconditionally issues
tdg.vp.wr(TSC deadline = disarm).  The following tdg.vp.enter() execution
path may overwrite tdg.vp.wr(new TSC deadline).  Delete the duplicated
tdg.vp.wr() call as optimization.

Signed-off-by: Isaku Yamahata <[email protected]>
Add an extension for the TDX timer service, so that the userspace can query
the feature before use.

Signed-off-by: Isaku Yamahata <[email protected]>
…akeup AP callback")

The commit df21bf3 ("arch/x86: Provide the CPU number in the wakeup AP
callback") changed the signature of struct apic::wakeup_secondary_cpu(),
but it did not update numachip_wakeup_secondary().  Update it to fix the
compile error.

arch/x86/kernel/apic/apic_numachip.c:228:43: error: initialization of 'int (*)(u32,  long unsigned int,  unsigned int)' {aka 'int (*)(unsigned int,  long unsigned int,  unsigned int)'} from incompatible pointer type 'int (*)(u32,  long unsigned int)' {aka 'int (*)(unsigned int,  long unsigned int)'} [-Wincompatible-pointer-types]
  228 |         .wakeup_secondary_cpu           = numachip_wakeup_secondary,
      |                                           ^~~~~~~~~~~~~~~~~~~~~~~~~

Fixes: df21bf3 ("arch/x86: Provide the CPU number in the wakeup AP callback")
Signed-off-by: Isaku Yamahata <[email protected]>
TDX module supports timer service for L1. When L1 writes tdcs value with TDG.VP.WR(TSC DEADLINE), tdg.vp.enter() exits with timer preemption when deadline expires. (Not injecting timer interrupt to L2 guest).

Update tdx vp context shared between L1 kernel and L1 userspace so that openvmm can use TDX timer service.
Unless the userspace uses it, the L1 OHCL kernel behavior keeps the same behavior as before.
Add ifdef and define to fix arm64 build.

drivers/hv/mshv_vtl_main.c: In function ‘mshv_tdx_setup_halt_timer’:
drivers/hv/mshv_vtl_main.c:1163:15: error: implicit declaration of function ‘rdtsc’ [-Werror=implicit-function-declaration]
 1163 |         now = rdtsc();
      |               ^~~~~
drivers/hv/mshv_vtl_main.c:1170:73: error: ‘tsc_khz’ undeclared (first use in this function)
 1170 |                 time = mul_u64_u64_div_u64(deadline - now, 1000 * 1000, tsc_khz);
      |                                                                         ^~~~~~~
drivers/hv/mshv_vtl_main.c:1170:73: note: each undeclared identifier is reported only once for each function it appears in
drivers/hv/mshv_vtl_main.c: In function ‘mshv_vtl_switch_to_vtl0_irqoff’:
drivers/hv/mshv_vtl_main.c:1242:49: error: ‘MSHV_VTL_RUN_FLAG_HALTED’ undeclared (first use in this function)
 1242 |         armed = mshv_tdx_halt_timer_pre(flags & MSHV_VTL_RUN_FLAG_HALTED);
      |                                                 ^~~~~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors

Fixes: fc1601f ("mshv_vtl/tdx: Arm per-cpu timer to wake up from L0 HLT emulation")
Signed-off-by: Isaku Yamahata <[email protected]>
In case of !CONFIG_INTEL_TDX_GUEST, gcc complains as
"parameter name omitted".  Add missing parameter names.

Fixes: 151bf98 ("mshv_vtl/tdx: Handle some APIC functionality in kernel")
Signed-off-by: Isaku Yamahata <[email protected]>
Move up one of define(CONFIG_X86_64) && defined(CONFIG_INTEL_TDX_GUEST)
for consistency.

Fixes: 1bf0706 ("mshv_vtl/tdx: Set TSC deadline if userspace requests")
Signed-off-by: Isaku Yamahata <[email protected]>
Fix arm64 build failure caused by this PR #107

build failure:
drivers/hv/mshv_vtl_main.c: In function ‘mshv_tdx_setup_halt_timer’: drivers/hv/mshv_vtl_main.c:1163:15: error: implicit declaration of function ‘rdtsc’ [-Werror=implicit-function-declaration]
1163 | now = rdtsc();
| ^~~~~
drivers/hv/mshv_vtl_main.c:1170:73: error: ‘tsc_khz’ undeclared (first use in this function)
1170 | time = mul_u64_u64_div_u64(deadline - now, 1000 * 1000, tsc_khz);
| ^~~~~~~
drivers/hv/mshv_vtl_main.c:1170:73: note: each undeclared identifier is reported only once for each function it appears in
drivers/hv/mshv_vtl_main.c: In function ‘mshv_vtl_switch_to_vtl0_irqoff’:
drivers/hv/mshv_vtl_main.c:1242:49: error: ‘MSHV_VTL_RUN_FLAG_HALTED’ undeclared (first use in this function)
1242 | armed = mshv_tdx_halt_timer_pre(flags & MSHV_VTL_RUN_FLAG_HALTED);
| ^~~~~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
…rted

Returning -EOPNOTSUPP is a fatal error. It means that The driver doesn't
know the feature.  Not that the feature is not supported due to the runtime
platform reason.  Return 0 for MSHV_CAP_LOWER_VTL_TIMER_VIRT on non-TDX
platform, which is safer.

Fixes: 3528fd7 ("drivers: hv: mshv_vtl: Advertise TDX timer service extension")
Signed-off-by: Isaku Yamahata <[email protected]>
…feature unsupported

Returning -EOPNOTSUPP is a fatal error. It means that the driver doesn't know the feature. Not that the feature is not supported due to the runtime platform reason. Return 0 for MSHV_CAP_LOWER_VTL_TIMER_VIRT on non-TDX platform, which is safer.

Fixes: 3528fd7: 3528fd7 ("drivers: hv: mshv_vtl: Advertise TDX timer service extension")
Copilot AI review requested due to automatic review settings December 15, 2025 21:42
@hargar19 hargar19 requested a review from benhillis December 15, 2025 21:47
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR merges TDX (Trust Domain Extensions) timer virtualization support from the product/hcl-main/6.12 branch, specifically adding L2 VM TSC deadline timer management for CVM (Confidential VM) workloads running under TDX isolation.

Key changes include:

  • Addition of TSC deadline timer support for L2 VMs in TDX partitioning architecture
  • Implementation of halt timer emulation to handle timer interrupts during HLT operations
  • Extension of capability checks to support lower VTL timer virtualization

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
include/uapi/linux/mshv.h Adds new capability flag MSHV_CAP_LOWER_VTL_TIMER_VIRT for timer virtualization support
drivers/hv/mshv_vtl_main.c Implements TSC deadline timer handling, halt timer setup/cancellation, helper functions for timer conversion, and capability checks for TDX timer virtualization
drivers/hv/mshv_vtl.h Adds tdx_l2_tsc_deadline structure to track timer deadline values and update flags, with corresponding padding adjustments to maintain alignment
arch/x86/kernel/apic/apic_numachip.c Updates numachip_wakeup_secondary function signature to include cpu parameter for API compatibility
MSFT-Merge/config.json Updates branch reference from product/underhill-dev/6.12 to product/underhill-main/6.12

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

/*
* Userspace sets this bit for the kernel to issue TDG.VP.WR(TSC_DEADLINE)
* when it changed deadline.
* The kernel clears this bits on TDG.VP.WR(TSC_DEADLINE).
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grammatical error: 'bits' should be singular 'bit' since only one bit (BIT(0)) is being cleared.

Suggested change
* The kernel clears this bits on TDG.VP.WR(TSC_DEADLINE).
* The kernel clears this bit on TDG.VP.WR(TSC_DEADLINE).

Copilot uses AI. Check for mistakes.
Comment on lines +1157 to +1158
if (time < 0)
time = KTIME_MAX;
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comparison if (time < 0) is checking a signed value (ktime_t is s64), but time is always non-negative at this point. When deadline > now, time is assigned a result from mul_u64_u64_div_u64 which returns u64, a non-negative value. When deadline <= now, time is initialized to 0. This condition will never be true and represents unreachable code.

Suggested change
if (time < 0)
time = KTIME_MAX;

Copilot uses AI. Check for mistakes.
}

static int numachip_wakeup_secondary(u32 phys_apicid, unsigned long start_rip)
static int numachip_wakeup_secondary(u32 phys_apicid, unsigned long start_rip, unsigned int cpu)
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameter cpu is added to the function signature but is not used in the function body. If this parameter is required for API compatibility, consider adding a comment explaining why it's unused, or use the __maybe_unused attribute to document the intentional non-use.

Suggested change
static int numachip_wakeup_secondary(u32 phys_apicid, unsigned long start_rip, unsigned int cpu)
static int numachip_wakeup_secondary(u32 phys_apicid, unsigned long start_rip, unsigned int __maybe_unused cpu)

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@hargar19 hargar19 merged commit 0d143c8 into project/hcl-dev/6.12 Dec 16, 2025
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants