Skip to content

drivers: hv: SNP perf fixes - #156

Merged
Brian Perkins (Brian-Perkins) merged 2 commits into
microsoft:product/hcl-main/6.18from
Brian-Perkins:more_snp_perf
Aug 12, 2026
Merged

drivers: hv: SNP perf fixes#156
Brian Perkins (Brian-Perkins) merged 2 commits into
microsoft:product/hcl-main/6.18from
Brian-Perkins:more_snp_perf

Conversation

@Brian-Perkins

Copy link
Copy Markdown
Contributor

Decode register values with vmsa key.

Don't send ipi to cpu that is already pending an interrupt scan.

Check for interrupts handled entirely in the kernel.

Add kernel fast-path for some stimer0 operations.

Copilot AI left a comment

Copy link
Copy Markdown

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 improves Hyper-V VTL (VTL2) performance for SEV-SNP guests by reducing avoidable user/kernel transitions and unnecessary IPIs, and by adding a kernel fast-path for select synthetic timer operations.

Changes:

  • Add an SNP per-vCPU context block to the shared mshv_vtl_run page, including a VMSA tweak bitmap and synthetic timer (stimer0) state.
  • Coalesce proxy-IRR scan wakeups so CPUs aren’t sent reschedule IPIs when a scan is already pending.
  • Add SNP kernel handling for interrupt-entry and for HV_X64_MSR_STIMER0_COUNT writes (including an hrtimer-backed wakeup path).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
drivers/hv/mshv_vtl.h Introduces snp_vp_context in the run-page union and defines stimer0 flag bits used by the SNP fast-path.
drivers/hv/mshv_vtl_main.c Implements IPI coalescing for proxy IRR scans, adds VMSA register decode helpers, and adds an hrtimer-backed kernel fast-path for stimer0 count writes and interrupt-entry handling.

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

@Brian-Perkins
Brian Perkins (Brian-Perkins) force-pushed the more_snp_perf branch 2 times, most recently from b03f589 to c9d4f91 Compare August 11, 2026 00:11
Copilot AI review requested due to automatic review settings August 11, 2026 00:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (2)

drivers/hv/mshv_vtl_main.c:566

  • wake_cpus is a full struct cpumask on the stack. This adds another potentially large cpumask stack allocation on top of callers that already have a stack cpumask (e.g. mshv_snp_handle_simple_icr_write() / mshv_tdx_handle_simple_icr_write()), which can push stack usage over kernel frame size limits on configs with large NR_CPUS.

Consider avoiding a second on-stack cpumask here (e.g., reuse/mutate local_mask to hold only CPUs that actually need waking, or send per-CPU IPIs when xchg(&run->scan_proxy_irr, 1) transitions 0->1).

	struct cpumask wake_cpus;
	unsigned int cpu;

drivers/hv/mshv_vtl_main.c:2334

  • stimer0_flags is modified via atomic operations elsewhere (e.g. atomic_or() / atomic_set()), but this check uses READ_ONCE(). Use atomic_read() for consistency with the atomic updates and to avoid mixed atomic/non-atomic access patterns.
	if (!(READ_ONCE(run->snp_context.stimer0_flags) &
	      MSHV_VTL_SNP_STIMER0_KERNEL_UPDATE))
		return;

tiala
tiala previously approved these changes Aug 11, 2026
Comment thread drivers/hv/mshv_vtl_main.c Outdated
Comment thread drivers/hv/mshv_vtl_main.c

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (4)

drivers/hv/mshv_vtl_main.c:2117

  • Same issue as the read helper: byte_index is a u8 and can wrap or go out of bounds when derived from offset, leading to incorrect tweak decisions or out-of-bounds bitmap access. Use a wider index type and validate bounds before indexing.
	u8 byte_index = offset / 64;
	u8 bit_index = (offset % 64) / 8;

	if (READ_ONCE(run->snp_context.vmsa_tweak_bitmap[byte_index]) & BIT(bit_index))
		value ^= READ_ONCE(*(u64 *)vmsa->reserved_0x300);

drivers/hv/mshv_vtl_main.c:569

  • wake_cpus adds another full-size struct cpumask on the stack in a hot path that already has stack-allocated cpumasks in the call chain (e.g. mshv_snp_handle_simple_icr_write()), which can become a significant stack footprint on large-NR_CPUS builds. Consider avoiding an additional stack cpumask (e.g. reuse/mutate local_mask as the wake mask, or send IPIs directly for the CPUs that need waking).
	struct cpumask wake_cpus;
	unsigned int cpu;

	cpumask_clear(&wake_cpus);
	for_each_cpu(cpu, local_mask) {

drivers/hv/mshv_vtl_main.c:2104

  • byte_index is a u8, so large offsets will silently wrap (and can also index past vmsa_tweak_bitmap[]), potentially causing incorrect tweak handling or out-of-bounds reads. Use a wider type for the index and add a bounds check before indexing the bitmap.

This issue also appears on line 2113 of the same file.

	u8 byte_index = offset / 64;
	u8 bit_index = (offset % 64) / 8;
	u64 value = READ_ONCE(*(u64 *)((u8 *)vmsa + offset));

	if (READ_ONCE(run->snp_context.vmsa_tweak_bitmap[byte_index]) & BIT(bit_index)) {

drivers/hv/mshv_vtl_main.c:2334

  • stimer0_flags is treated as an atomic_t elsewhere (atomic_or/atomic_set), but this check uses READ_ONCE(). Use atomic_read() here for consistency and to avoid mixing atomic/non-atomic accesses to the same variable.
	if (!(READ_ONCE(run->snp_context.stimer0_flags) &
	      MSHV_VTL_SNP_STIMER0_KERNEL_UPDATE))
		return;

Share the VMSA key with userspace to allow decoding register values.
Return to VTL0 if the only operation was a kernel handled interrupt.
Don't resend IPI to a processor for interrupt processing.

Signed-off-by: Brian Perkins <brian.perkins@microsoft.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (2)

drivers/hv/mshv_vtl_main.c:1065

  • The stimer0 hrtimer callback only sets run->cancel = 1, but that doesn’t necessarily wake the VTL thread if it is sleeping in the idle2vtl0 (schedule) path. That can prevent userspace from being woken for timer delivery as the comment intends.
static enum hrtimer_restart mshv_snp_stimer0_timer_fn(struct hrtimer *timer)
{
	struct mshv_vtl_per_cpu *per_cpu =
		container_of(timer, struct mshv_vtl_per_cpu, snp_stimer0_timer);
	struct mshv_vtl_run *run = READ_ONCE(per_cpu->run);

	if (run) {
		/* Wake userspace to handle timer delivery. */
		atomic_or(MSHV_VTL_SNP_STIMER0_EXPIRED,
			  (atomic_t *)&run->snp_context.stimer0_flags);
		WRITE_ONCE(run->cancel, 1);
	}

drivers/hv/mshv_vtl.h:128

  • struct snp_vp_context relies on implicit tail padding (4 bytes) to reach 1024 bytes. For a fixed-size context shared with user mode, make the padding explicit so the layout doesn’t depend on trailing alignment rules.
struct snp_vp_context {
	__u8 vmsa_tweak_bitmap[64];
	__u64 stimer0_config;
	__u64 stimer0_count;
	__u64 stimer0_programmed_ref_time;
	__u32 stimer0_flags;
	__u8 pad[928];
};

Signed-off-by: Brian Perkins <brian.perkins@microsoft.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (2)

drivers/hv/mshv_vtl_main.c:2121

  • Same alignment concern in mshv_snp_write_vmsa_reg(): dereferencing a u64 * derived from a u8 * can trigger -Wcast-align. Cast through void * to avoid alignment warnings and keep the access intent clear.
	if (READ_ONCE(run->snp_context.vmsa_tweak_bitmap[byte_index]) & BIT(bit_index))
		value ^= READ_ONCE(*(u64 *)vmsa->reserved_0x300);

	WRITE_ONCE(*(u64 *)((u8 *)vmsa + offset), value);

drivers/hv/mshv_vtl_main.c:2105

  • mshv_snp_read_vmsa_reg() casts a u8 * to u64 * and dereferences it. This can trigger -Wcast-align (and makes the alignment assumption implicit). Cast through void * (or use an unaligned helper) to make the intent explicit and avoid alignment warnings.

This issue also appears on line 2118 of the same file.

	u64 value = READ_ONCE(*(u64 *)((u8 *)vmsa + offset));

	if (READ_ONCE(run->snp_context.vmsa_tweak_bitmap[byte_index]) & BIT(bit_index)) {
		static_assert(offsetof(struct sev_es_save_area, reserved_0x300) == 0x300);
		value ^= READ_ONCE(*(u64 *)vmsa->reserved_0x300);

@tiala
tiala self-requested a review August 12, 2026 02:24

@tiala tiala left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Look good.

@Brian-Perkins
Brian Perkins (Brian-Perkins) merged commit dc23d48 into microsoft:product/hcl-main/6.18 Aug 12, 2026
11 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.

3 participants