Linux-HyperV List
 help / color / mirror / Atom feed
* Re: [PATCH 7/9] KVM: SVM: Treat exit_code as an unsigned 64-bit value through all of KVM
From: Sean Christopherson @ 2025-11-14 15:27 UTC (permalink / raw)
  To: Paolo Bonzini, Vitaly Kuznetsov, K. Y. Srinivasan, Haiyang Zhang,
	Wei Liu, Dexuan Cui, kvm, linux-hyperv, linux-kernel, Jim Mattson,
	Yosry Ahmed
In-Reply-To: <20251113225621.1688428-8-seanjc@google.com>

On Thu, Nov 13, 2025, Sean Christopherson wrote:
> Fix KVM's long-standing buggy handling of SVM's exit_code as a 32-bit
> value.  Per the APM and Xen commit d1bd157fbc ("Big merge the HVM
> full-virtualisation abstractions.") (which is arguably more trustworthy
> than KVM), offset 0x70 is a single 64-bit value:
> 
>   070h 63:0 EXITCODE
> 
> Track exit_code as a single u64 to prevent reintroducing bugs where KVM
> neglects to correctly set bits 63:32.
> 
> Fixes: 6aa8b732ca01 ("[PATCH] kvm: userspace interface")
> Cc: Jim Mattson <jmattson@google.com>
> Cc: Yosry Ahmed <yosry.ahmed@linux.dev>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
> ---

...

> diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h
> index e79bc9cb7162..4c7a5cd10990 100644
> --- a/arch/x86/kvm/trace.h
> +++ b/arch/x86/kvm/trace.h
> @@ -781,7 +781,7 @@ TRACE_EVENT_KVM_EXIT(kvm_nested_vmexit);
>   * Tracepoint for #VMEXIT reinjected to the guest
>   */
>  TRACE_EVENT(kvm_nested_vmexit_inject,
> -	    TP_PROTO(__u32 exit_code,
> +	    TP_PROTO(__u64 exit_code,
>  		     __u64 exit_info1, __u64 exit_info2,
>  		     __u32 exit_int_info, __u32 exit_int_info_err, __u32 isa),
>  	    TP_ARGS(exit_code, exit_info1, exit_info2,

As pointed out by the test bot[*], the trace macro to print exit reasons needs
to use 64-bit variants to play nice with 32-bit builds.

And now I'm questioning all of my testing, because my build setup detects that
as well, _and_ the hyperv_svm_test selftest fails.  *sigh*

diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h
index 4c7a5cd10990..0fd72ce83926 100644
--- a/arch/x86/kvm/trace.h
+++ b/arch/x86/kvm/trace.h
@@ -383,10 +383,10 @@ TRACE_EVENT(kvm_apic,
 #define kvm_print_exit_reason(exit_reason, isa)                                \
        (isa == KVM_ISA_VMX) ?                                          \
        __print_symbolic(exit_reason & 0xffff, VMX_EXIT_REASONS) :      \
-       __print_symbolic(exit_reason, SVM_EXIT_REASONS),                \
+       __print_symbolic64(exit_reason, SVM_EXIT_REASONS),              \
        (isa == KVM_ISA_VMX && exit_reason & ~0xffff) ? " " : "",       \
        (isa == KVM_ISA_VMX) ?                                          \
-       __print_flags(exit_reason & ~0xffff, " ", VMX_EXIT_REASON_FLAGS) : ""
+       __print_flags64(exit_reason & ~0xffff, " ", VMX_EXIT_REASON_FLAGS) : ""
 
 #define TRACE_EVENT_KVM_EXIT(name)                                          \
 TRACE_EVENT(name,  


[*] https://lore.kernel.org/all/202511141707.t4ad044J-lkp@intel.com

^ permalink raw reply related

* Re: [PATCH 7/9] KVM: SVM: Treat exit_code as an unsigned 64-bit value through all of KVM
From: Sean Christopherson @ 2025-11-14 15:22 UTC (permalink / raw)
  To: Michael Kelley
  Cc: Paolo Bonzini, Vitaly Kuznetsov, K. Y. Srinivasan, Haiyang Zhang,
	Wei Liu, Dexuan Cui, Nuno Das Neves, kvm@vger.kernel.org,
	linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org,
	Jim Mattson, Yosry Ahmed
In-Reply-To: <SN6PR02MB4157AF057CC8539AD47F6D66D4CAA@SN6PR02MB4157.namprd02.prod.outlook.com>

On Fri, Nov 14, 2025, Michael Kelley wrote:
> From: Sean Christopherson <seanjc@google.com> Sent: Thursday, November 13, 2025 2:56 PM
> > 
> 
> Adding Microsoft's Nuno Das Neves to the "To:" line since he
> originated the work to keep the Linux headers such as hvgdk.h in
> sync with the Windows counterparts from which they originate.

...

> >  /* Exit code reserved for hypervisor/software use */
> > -#define SVM_EXIT_SW				0xf0000000
> > +#define SVM_EXIT_SW				0xf0000000ull
> > 
> > -#define SVM_EXIT_ERR           -1
> > +#define SVM_EXIT_ERR           -1ull
> > 
> 
> [snip]
> 
> > diff --git a/include/hyperv/hvgdk.h b/include/hyperv/hvgdk.h
> > index dd6d4939ea29..56b695873a72 100644
> > --- a/include/hyperv/hvgdk.h
> > +++ b/include/hyperv/hvgdk.h
> > @@ -281,7 +281,7 @@ struct hv_vmcb_enlightenments {
> >  #define HV_VMCB_NESTED_ENLIGHTENMENTS		31
> > 
> >  /* Synthetic VM-Exit */
> > -#define HV_SVM_EXITCODE_ENL			0xf0000000
> > +#define HV_SVM_EXITCODE_ENL			0xf0000000u
> 
> Is there a reason for making this Hyper-V code just "u", while
> making the SVM_VMGEXIT_* values "ull"? I don't think
> "u" vs. "ull" shouldn't make any difference when assigning to a
> u64, but the inconsistency piqued my interest ....

I hedged and went for a more "minimal" change because it isn't KVM code, and at
the time because I thought the value isn't defined by the APM.  Though looking
again at the APM, it does reserve that value for software

  F000_000h    Unused    Reserved for Host.

and I can't find anything in the TLFS.  Ah, my PDF copy is just stale, it's indeed
defined as a synthetic exit.

  https://learn.microsoft.com/en-us/virtualization/hyper-v-on-windows/tlfs/nested-virtualization#synthetic-vm-exit

Anyways, I'm in favor of making HV_SVM_EXITCODE_ENL an ull, though part of me
wonders if we should do:

  #define HV_SVM_EXITCODE_ENL	SVM_EXIT_SW

^ permalink raw reply

* Re: [REGRESSION 6.12.y] hyper-v: BUG: kernel NULL pointer dereference, address: 00000000000000a0: RIP: 0010:hv_uio_channel_cb+0xd/0x20 [uio_hv_generic]
From: Naman Jain @ 2025-11-14 14:35 UTC (permalink / raw)
  To: Peter Morrow
  Cc: Salvatore Bonaccorso, Long Li, 1120602, linux-hyperv,
	linux-kernel, regressions, stable, John Starks, Michael Kelley,
	Tianyu Lan, K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui,
	Greg Kroah-Hartman
In-Reply-To: <CAFcZKTwQgd9hrTaXnThML=+WG82TH3DK90FT1-WWsBSoRj7dRw@mail.gmail.com>



On 11/14/2025 5:19 PM, Peter Morrow wrote:
> Hi Naman,
> 
> On Fri, 14 Nov 2025 at 06:03, Naman Jain <namjain@linux.microsoft.com> wrote:
>>
>>
>>
>> On 11/13/2025 11:59 PM, Salvatore Bonaccorso wrote:
>>> Peter Morrow reported in Debian a regression, reported in
>>> https://bugs.debian.org/1120602 . The regression was seen after
>>> updating, to 6.12.57-1 in Debian, but details on the offending commit
>>> follows.
>>>
>>> His report was as follows:
>>>
>>>> Dear Maintainer,
>>>>
>>>> I'm seeing a kernel crash quite soon after boot on a debian trixie based
>>>> system running 6.12.57+deb13-amd64, unfortunately the kernel panics before
>>>> I can access the system to gather more information. Thus I'll provide details
>>>> of the system using a previously known good version. The panic is happening
>>>> 100% of the time unfortunately. I have access to the serial console however
>>>> so can enable any required verbose logging during boot if necessary.
>>>>
>>>> Crucially the crash is not seen with kernel version 6.12.41+deb13-amd64 with the
>>>> same userspace. We had pinned to that version until very recently to in order
>>>> to work around https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1109676
>>>>
>>>> I'm running a dpdk application here (VPP) on Azure, VM form factor is a
>>>> "Standard DS3 v2 (4 vcpus, 14 GiB memory)".
>>>>
>>>> The only relevant upstream commit in this area (as far as I can see) is:
>>>>
>>>> https://lore.kernel.org/linux-hyperv/1bb599ee-fe28-409d-b430-2fc086268936@linux.microsoft.com/
>>>>
>>>> The comment regarding avoiding races at start adds a bit more weight behind this
>>>> hunch, though it's only a hunch as I am most definitely nowhere near an expert
>>>> in this area.
>>>>
>>>> -- Package-specific info:
>>>>
>>>> [   19.625535] BUG: kernel NULL pointer dereference, address: 00000000000000a0
>>>> [   19.628874] #PF: supervisor read access in kernel mode
>>>> [   19.630841] #PF: error_code(0x0000) - not-present page
>>>> [   19.632788] PGD 0 P4D 0
>>>> [   19.633905] Oops: Oops: 0000 [#1] PREEMPT SMP PTI
>>>> [   19.635586] CPU: 3 UID: 0 PID: 0 Comm: swapper/3 Not tainted 6.12.57+deb13-amd64 #1  Debian 6.12.57-1
>>>> [   19.640216] Hardware name: Microsoft Corporation Virtual Machine/Virtual Machine, BIOS Hyper-V UEFI Release v4.1 09/28/2024
>>>> [   19.644514] RIP: 0010:hv_uio_channel_cb+0xd/0x20 [uio_hv_generic]
>>>> [   19.646994] Code: 02 00 00 5b 5d e9 53 98 69 e9 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 0f 1f 44 00 00 48 8b 47 10 <48> 8b b8 a0 00 00 00 f0 83 44 24 fc 00 e9 51 6f fa ff 90 90 90 90
>>>> [   19.654377] RSP: 0018:ffffb15ac01a4fa8 EFLAGS: 00010046
>>>> [   19.656385] RAX: 0000000000000000 RBX: 0000000000000015 RCX: 0000000000000015
>>>> [   19.659240] RDX: 0000000000000001 RSI: ffffffffffffffff RDI: ffff8ff69c759400
>>>> [   19.662168] RBP: ffff8ff548790200 R08: ffff8ff548790200 R09: 00fca75150b080e9
>>>> [   19.665239] R10: 0000000000000000 R11: ffffb15ac01a4ff8 R12: ffff8ff871dc1480
>>>> [   19.668193] R13: ffff8ff69c759400 R14: ffff8ff69c7596a0 R15: ffffffffc106e160
>>>> [   19.671106] FS:  0000000000000000(0000) GS:ffff8ff871d80000(0000) knlGS:0000000000000000
>>>> [   19.674281] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>>>> [   19.676533] CR2: 00000000000000a0 CR3: 0000000100ba6003 CR4: 00000000003706f0
>>>> [   19.679385] Call Trace:
>>>> [   19.680361]  <IRQ>
>>>> [   19.681181]  vmbus_isr+0x1a5/0x210 [hv_vmbus]
>>>> [   19.682916]  __sysvec_hyperv_callback+0x32/0x60
>>>> [   19.684991]  sysvec_hyperv_callback+0x6c/0x90
>>>> [   19.686665]  </IRQ>
>>>> [   19.687509]  <TASK>
>>>> [   19.688366]  asm_sysvec_hyperv_callback+0x1a/0x20
>>>> [   19.690262] RIP: 0010:pv_native_safe_halt+0xf/0x20
>>>> [   19.692067] Code: 09 e9 c5 08 01 00 0f 1f 44 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 66 90 0f 00 2d e5 3b 31 00 fb f4 <c3> cc cc cc cc 66 66 2e 0f 1f 84 00 00 00 00 00 90 90 90 90 90 90
>>>> [   19.699119] RSP: 0018:ffffb15ac0103ed8 EFLAGS: 00000246
>>>> [   19.701412] RAX: 0000000000000003 RBX: ffff8ff5403b1fc0 RCX: ffff8ff54c64ce30
>>>> [   19.704328] RDX: 0000000000000000 RSI: 0000000000000003 RDI: 000000000001f894
>>>> [   19.706910] RBP: 0000000000000003 R08: 000000000bb760d9 R09: 00fca75150b080e9
>>>> [   19.709762] R10: 0000000000000003 R11: 0000000000000001 R12: 0000000000000000
>>>> [   19.712510] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
>>>> [   19.715173]  default_idle+0x9/0x20
>>>> [   19.716846]  default_idle_call+0x29/0x100
>>>> [   19.718623]  do_idle+0x1fe/0x240
>>>> [   19.720045]  cpu_startup_entry+0x29/0x30
>>>> [   19.721595]  start_secondary+0x11e/0x140
>>>> [   19.723080]  common_startup_64+0x13e/0x141
>>>> [   19.725222]  </TASK>
>>>> [   19.726387] Modules linked in: isofs cdrom uio_hv_generic uio binfmt_misc intel_rapl_msr intel_rapl_common intel_uncore_frequency_common isst_if_mbox_msr isst_if_common rpcrdma skx_edac_common nfit sunrpc libnvdimm crct10dif_pclmul ghash_clmulni_intel sha512_ssse3 sha256_ssse3 rdma_ucm ib_iser sha1_ssse3 rdma_cm aesni_intel iw_cm gf128mul crypto_simd libiscsi cryptd ib_umad ib_ipoib scsi_transport_iscsi ib_cm rapl sg hv_utils hv_balloon evdev pcspkr joydev mpls_router ip_tunnel ramoops configfs pstore_blk efi_pstore pstore_zone nfnetlink vsock_loopback vmw_vsock_virtio_transport_common hv_sock vmw_vsock_vmci_transport vsock vmw_vmci efivarfs ip_tables x_tables autofs4 overlay squashfs dm_verity dm_bufio reed_solomon dm_mod loop ext4 crc16 mbcache jbd2 crc32c_generic mlx5_ib ib_uverbs ib_core mlx5_core mlxfw pci_hyperv pci_hyperv_intf hyperv_drm drm_shmem_helper sd_mod drm_kms_helper hv_storvsc scsi_transport_fc drm scsi_mod hid_generic hid_hyperv hid serio_raw hv_netvsc hyperv_keyboard scsi_common hv_vmbus
>>>> [   19.726466]  crc32_pclmul crc32c_intel
>>>> [   19.765771] CR2: 00000000000000a0
>>>> [   19.767524] ---[ end trace 0000000000000000 ]---
>>>> [   19.800433] RIP: 0010:hv_uio_channel_cb+0xd/0x20 [uio_hv_generic]
>>>> [   19.803170] Code: 02 00 00 5b 5d e9 53 98 69 e9 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 0f 1f 44 00 00 48 8b 47 10 <48> 8b b8 a0 00 00 00 f0 83 44 24 fc 00 e9 51 6f fa ff 90 90 90 90
>>>> [   19.811041] RSP: 0018:ffffb15ac01a4fa8 EFLAGS: 00010046
>>>> [   19.813466] RAX: 0000000000000000 RBX: 0000000000000015 RCX: 0000000000000015
>>>> [   19.816504] RDX: 0000000000000001 RSI: ffffffffffffffff RDI: ffff8ff69c759400
>>>> [   19.819484] RBP: ffff8ff548790200 R08: ffff8ff548790200 R09: 00fca75150b080e9
>>>> [   19.822625] R10: 0000000000000000 R11: ffffb15ac01a4ff8 R12: ffff8ff871dc1480
>>>> [   19.825569] R13: ffff8ff69c759400 R14: ffff8ff69c7596a0 R15: ffffffffc106e160
>>>> [   19.828804] FS:  0000000000000000(0000) GS:ffff8ff871d80000(0000) knlGS:0000000000000000
>>>> [   19.832214] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>>>> [   19.834709] CR2: 00000000000000a0 CR3: 0000000100ba6003 CR4: 00000000003706f0
>>>> [   19.837976] Kernel panic - not syncing: Fatal exception in interrupt
>>>> [   19.841825] Kernel Offset: 0x28a00000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
>>>> [   19.896620] ---[ end Kernel panic - not syncing: Fatal exception in interrupt ]---
>>>>
>>
>> <snip>
>>
>>> The offending commit appers to be the backport of b15b7d2a1b09
>>> ("uio_hv_generic: Let userspace take care of interrupt mask") for
>>> 6.12.y.
>>>
>>> Peter confirmed that reverting this commit on top of 6.12.57-1 as
>>> packaged in Debian resolves indeed the issue. Interestingly the issue
>>> is *not* seen with 6.17.7 based kernel in Debian.
>>>
>>> #regzbot introduced: 37bd91f22794dc05436130d6983302cb90ecfe7e
>>> #regzbot monitor: https://bugs.debian.org/1120602
>>>
>>> Thank you already!
>>>
>>> Regards,
>>> Salvatore
>>
>> Hi Peter, Salvatore,
>> Thanks for reporting this crash, and sorry for the trouble. Here is my
>> analysis.
>>
>> On 6.17.7, where commit d062463edf17 ("uio_hv_generic: Set event for all
>> channels on the device") is present, hv_uio_irqcontrol() supports
>> setting of interrupt mask from userspace for sub-channels as well.
>>
>> This aligns with commit e29587c07537 ("uio_hv_generic: Let userspace
>> take care of interrupt mask") which relies on userspace to manage
>> interrupt mask, so it safely removes the interrupt mask management logic
>> in the driver.
>>
>> However, in 6.12.57, the first commit is not present, but the second one
>> is, so there is no way to disable interrupt mask for sub-channels and
>> interrupt_mask stays 0, which means interrupts are not masked. So we may
>> be having an interrupt callback being handled for a sub-channel, where
>> we do not expect it to come. This may be causing this issue.
>>
>> This would have led to a crash in hv_uio_channel_cb() for sub-channels:
>> struct hv_device *hv_dev = chan->device_obj;
>>
>>
>> I have ported commit d062463edf17 ("uio_hv_generic: Set event for all
>> channels on the device") on 6.12.57, and resolved some merge conflicts.
>> Could you please help with testing this, if it works for you.
> 
> Applying the patch against the debian 6.12.57 kernel worked, I am no
> longer seeing that panic on boot:
> 
> gnos@vEdge:~$ uname -a
> Linux vEdge 6.12+unreleased-amd64 #1 SMP PREEMPT_DYNAMIC Debian
> 6.12.57-1a~test (2025-11-14) x86_64 GNU/Linux
> gnos@vEdge:~$ uptime
>   11:46:33 up 4 min,  1 user,  load average: 3.31, 2.07, 0.89
> gnos@vEdge:~$ sudo dmidecode -t system
> # dmidecode 3.6
> Getting SMBIOS data from sysfs.
> SMBIOS 3.1.0 present.
> 
> Handle 0x0001, DMI type 1, 27 bytes
> System Information
>          Manufacturer: Microsoft Corporation
>          Product Name: Virtual Machine
>          Version: Hyper-V UEFI Release v4.1
>          Serial Number: 0000-0002-8036-1108-7588-3134-50
>          UUID: 26e86d6e-140c-496a-862c-a3b3bbcd16ad
>          Wake-up Type: Power Switch
>          SKU Number: None
>          Family: Virtual Machine
> 
> Handle 0x0010, DMI type 32, 11 bytes
> System Boot Information
>          Status: No errors detected
> 
> gnos@vEdge:~$
> 
> Thanks a lot for the quick analysis!
> 
> Peter.

Hi Peter,

Thanks for confirming. I am discussing this with Long Li, to hear his 
thoughts on this, and have kept the patch ready.
Porting the same on 6.6 and older kernels would be a little different 
since we don't have commit 547fa4ffd799 ("uio_hv_generic: Enable 
interrupt for low speed VMBus devices") on these kernels and this would 
lead to merge conflicts, which needs to be handled separately.

Meanwhile, if I should be including any tags in the fix patch for debian 
bug, please let me know.

Regards,
Naman


^ permalink raw reply

* Re: [REGRESSION 6.12.y] hyper-v: BUG: kernel NULL pointer dereference, address: 00000000000000a0: RIP: 0010:hv_uio_channel_cb+0xd/0x20 [uio_hv_generic]
From: Peter Morrow @ 2025-11-14 11:49 UTC (permalink / raw)
  To: Naman Jain
  Cc: Salvatore Bonaccorso, Long Li, 1120602, linux-hyperv,
	linux-kernel, regressions, stable, John Starks, Michael Kelley,
	Tianyu Lan, K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui,
	Greg Kroah-Hartman
In-Reply-To: <7a38c04d-4e54-4f1a-96fd-43f0f11ab97b@linux.microsoft.com>

Hi Naman,

On Fri, 14 Nov 2025 at 06:03, Naman Jain <namjain@linux.microsoft.com> wrote:
>
>
>
> On 11/13/2025 11:59 PM, Salvatore Bonaccorso wrote:
> > Peter Morrow reported in Debian a regression, reported in
> > https://bugs.debian.org/1120602 . The regression was seen after
> > updating, to 6.12.57-1 in Debian, but details on the offending commit
> > follows.
> >
> > His report was as follows:
> >
> >> Dear Maintainer,
> >>
> >> I'm seeing a kernel crash quite soon after boot on a debian trixie based
> >> system running 6.12.57+deb13-amd64, unfortunately the kernel panics before
> >> I can access the system to gather more information. Thus I'll provide details
> >> of the system using a previously known good version. The panic is happening
> >> 100% of the time unfortunately. I have access to the serial console however
> >> so can enable any required verbose logging during boot if necessary.
> >>
> >> Crucially the crash is not seen with kernel version 6.12.41+deb13-amd64 with the
> >> same userspace. We had pinned to that version until very recently to in order
> >> to work around https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1109676
> >>
> >> I'm running a dpdk application here (VPP) on Azure, VM form factor is a
> >> "Standard DS3 v2 (4 vcpus, 14 GiB memory)".
> >>
> >> The only relevant upstream commit in this area (as far as I can see) is:
> >>
> >> https://lore.kernel.org/linux-hyperv/1bb599ee-fe28-409d-b430-2fc086268936@linux.microsoft.com/
> >>
> >> The comment regarding avoiding races at start adds a bit more weight behind this
> >> hunch, though it's only a hunch as I am most definitely nowhere near an expert
> >> in this area.
> >>
> >> -- Package-specific info:
> >>
> >> [   19.625535] BUG: kernel NULL pointer dereference, address: 00000000000000a0
> >> [   19.628874] #PF: supervisor read access in kernel mode
> >> [   19.630841] #PF: error_code(0x0000) - not-present page
> >> [   19.632788] PGD 0 P4D 0
> >> [   19.633905] Oops: Oops: 0000 [#1] PREEMPT SMP PTI
> >> [   19.635586] CPU: 3 UID: 0 PID: 0 Comm: swapper/3 Not tainted 6.12.57+deb13-amd64 #1  Debian 6.12.57-1
> >> [   19.640216] Hardware name: Microsoft Corporation Virtual Machine/Virtual Machine, BIOS Hyper-V UEFI Release v4.1 09/28/2024
> >> [   19.644514] RIP: 0010:hv_uio_channel_cb+0xd/0x20 [uio_hv_generic]
> >> [   19.646994] Code: 02 00 00 5b 5d e9 53 98 69 e9 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 0f 1f 44 00 00 48 8b 47 10 <48> 8b b8 a0 00 00 00 f0 83 44 24 fc 00 e9 51 6f fa ff 90 90 90 90
> >> [   19.654377] RSP: 0018:ffffb15ac01a4fa8 EFLAGS: 00010046
> >> [   19.656385] RAX: 0000000000000000 RBX: 0000000000000015 RCX: 0000000000000015
> >> [   19.659240] RDX: 0000000000000001 RSI: ffffffffffffffff RDI: ffff8ff69c759400
> >> [   19.662168] RBP: ffff8ff548790200 R08: ffff8ff548790200 R09: 00fca75150b080e9
> >> [   19.665239] R10: 0000000000000000 R11: ffffb15ac01a4ff8 R12: ffff8ff871dc1480
> >> [   19.668193] R13: ffff8ff69c759400 R14: ffff8ff69c7596a0 R15: ffffffffc106e160
> >> [   19.671106] FS:  0000000000000000(0000) GS:ffff8ff871d80000(0000) knlGS:0000000000000000
> >> [   19.674281] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> >> [   19.676533] CR2: 00000000000000a0 CR3: 0000000100ba6003 CR4: 00000000003706f0
> >> [   19.679385] Call Trace:
> >> [   19.680361]  <IRQ>
> >> [   19.681181]  vmbus_isr+0x1a5/0x210 [hv_vmbus]
> >> [   19.682916]  __sysvec_hyperv_callback+0x32/0x60
> >> [   19.684991]  sysvec_hyperv_callback+0x6c/0x90
> >> [   19.686665]  </IRQ>
> >> [   19.687509]  <TASK>
> >> [   19.688366]  asm_sysvec_hyperv_callback+0x1a/0x20
> >> [   19.690262] RIP: 0010:pv_native_safe_halt+0xf/0x20
> >> [   19.692067] Code: 09 e9 c5 08 01 00 0f 1f 44 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 66 90 0f 00 2d e5 3b 31 00 fb f4 <c3> cc cc cc cc 66 66 2e 0f 1f 84 00 00 00 00 00 90 90 90 90 90 90
> >> [   19.699119] RSP: 0018:ffffb15ac0103ed8 EFLAGS: 00000246
> >> [   19.701412] RAX: 0000000000000003 RBX: ffff8ff5403b1fc0 RCX: ffff8ff54c64ce30
> >> [   19.704328] RDX: 0000000000000000 RSI: 0000000000000003 RDI: 000000000001f894
> >> [   19.706910] RBP: 0000000000000003 R08: 000000000bb760d9 R09: 00fca75150b080e9
> >> [   19.709762] R10: 0000000000000003 R11: 0000000000000001 R12: 0000000000000000
> >> [   19.712510] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
> >> [   19.715173]  default_idle+0x9/0x20
> >> [   19.716846]  default_idle_call+0x29/0x100
> >> [   19.718623]  do_idle+0x1fe/0x240
> >> [   19.720045]  cpu_startup_entry+0x29/0x30
> >> [   19.721595]  start_secondary+0x11e/0x140
> >> [   19.723080]  common_startup_64+0x13e/0x141
> >> [   19.725222]  </TASK>
> >> [   19.726387] Modules linked in: isofs cdrom uio_hv_generic uio binfmt_misc intel_rapl_msr intel_rapl_common intel_uncore_frequency_common isst_if_mbox_msr isst_if_common rpcrdma skx_edac_common nfit sunrpc libnvdimm crct10dif_pclmul ghash_clmulni_intel sha512_ssse3 sha256_ssse3 rdma_ucm ib_iser sha1_ssse3 rdma_cm aesni_intel iw_cm gf128mul crypto_simd libiscsi cryptd ib_umad ib_ipoib scsi_transport_iscsi ib_cm rapl sg hv_utils hv_balloon evdev pcspkr joydev mpls_router ip_tunnel ramoops configfs pstore_blk efi_pstore pstore_zone nfnetlink vsock_loopback vmw_vsock_virtio_transport_common hv_sock vmw_vsock_vmci_transport vsock vmw_vmci efivarfs ip_tables x_tables autofs4 overlay squashfs dm_verity dm_bufio reed_solomon dm_mod loop ext4 crc16 mbcache jbd2 crc32c_generic mlx5_ib ib_uverbs ib_core mlx5_core mlxfw pci_hyperv pci_hyperv_intf hyperv_drm drm_shmem_helper sd_mod drm_kms_helper hv_storvsc scsi_transport_fc drm scsi_mod hid_generic hid_hyperv hid serio_raw hv_netvsc hyperv_keyboard scsi_common hv_vmbus
> >> [   19.726466]  crc32_pclmul crc32c_intel
> >> [   19.765771] CR2: 00000000000000a0
> >> [   19.767524] ---[ end trace 0000000000000000 ]---
> >> [   19.800433] RIP: 0010:hv_uio_channel_cb+0xd/0x20 [uio_hv_generic]
> >> [   19.803170] Code: 02 00 00 5b 5d e9 53 98 69 e9 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 0f 1f 44 00 00 48 8b 47 10 <48> 8b b8 a0 00 00 00 f0 83 44 24 fc 00 e9 51 6f fa ff 90 90 90 90
> >> [   19.811041] RSP: 0018:ffffb15ac01a4fa8 EFLAGS: 00010046
> >> [   19.813466] RAX: 0000000000000000 RBX: 0000000000000015 RCX: 0000000000000015
> >> [   19.816504] RDX: 0000000000000001 RSI: ffffffffffffffff RDI: ffff8ff69c759400
> >> [   19.819484] RBP: ffff8ff548790200 R08: ffff8ff548790200 R09: 00fca75150b080e9
> >> [   19.822625] R10: 0000000000000000 R11: ffffb15ac01a4ff8 R12: ffff8ff871dc1480
> >> [   19.825569] R13: ffff8ff69c759400 R14: ffff8ff69c7596a0 R15: ffffffffc106e160
> >> [   19.828804] FS:  0000000000000000(0000) GS:ffff8ff871d80000(0000) knlGS:0000000000000000
> >> [   19.832214] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> >> [   19.834709] CR2: 00000000000000a0 CR3: 0000000100ba6003 CR4: 00000000003706f0
> >> [   19.837976] Kernel panic - not syncing: Fatal exception in interrupt
> >> [   19.841825] Kernel Offset: 0x28a00000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
> >> [   19.896620] ---[ end Kernel panic - not syncing: Fatal exception in interrupt ]---
> >>
>
> <snip>
>
> > The offending commit appers to be the backport of b15b7d2a1b09
> > ("uio_hv_generic: Let userspace take care of interrupt mask") for
> > 6.12.y.
> >
> > Peter confirmed that reverting this commit on top of 6.12.57-1 as
> > packaged in Debian resolves indeed the issue. Interestingly the issue
> > is *not* seen with 6.17.7 based kernel in Debian.
> >
> > #regzbot introduced: 37bd91f22794dc05436130d6983302cb90ecfe7e
> > #regzbot monitor: https://bugs.debian.org/1120602
> >
> > Thank you already!
> >
> > Regards,
> > Salvatore
>
> Hi Peter, Salvatore,
> Thanks for reporting this crash, and sorry for the trouble. Here is my
> analysis.
>
> On 6.17.7, where commit d062463edf17 ("uio_hv_generic: Set event for all
> channels on the device") is present, hv_uio_irqcontrol() supports
> setting of interrupt mask from userspace for sub-channels as well.
>
> This aligns with commit e29587c07537 ("uio_hv_generic: Let userspace
> take care of interrupt mask") which relies on userspace to manage
> interrupt mask, so it safely removes the interrupt mask management logic
> in the driver.
>
> However, in 6.12.57, the first commit is not present, but the second one
> is, so there is no way to disable interrupt mask for sub-channels and
> interrupt_mask stays 0, which means interrupts are not masked. So we may
> be having an interrupt callback being handled for a sub-channel, where
> we do not expect it to come. This may be causing this issue.
>
> This would have led to a crash in hv_uio_channel_cb() for sub-channels:
> struct hv_device *hv_dev = chan->device_obj;
>
>
> I have ported commit d062463edf17 ("uio_hv_generic: Set event for all
> channels on the device") on 6.12.57, and resolved some merge conflicts.
> Could you please help with testing this, if it works for you.

Applying the patch against the debian 6.12.57 kernel worked, I am no
longer seeing that panic on boot:

gnos@vEdge:~$ uname -a
Linux vEdge 6.12+unreleased-amd64 #1 SMP PREEMPT_DYNAMIC Debian
6.12.57-1a~test (2025-11-14) x86_64 GNU/Linux
gnos@vEdge:~$ uptime
 11:46:33 up 4 min,  1 user,  load average: 3.31, 2.07, 0.89
gnos@vEdge:~$ sudo dmidecode -t system
# dmidecode 3.6
Getting SMBIOS data from sysfs.
SMBIOS 3.1.0 present.

Handle 0x0001, DMI type 1, 27 bytes
System Information
        Manufacturer: Microsoft Corporation
        Product Name: Virtual Machine
        Version: Hyper-V UEFI Release v4.1
        Serial Number: 0000-0002-8036-1108-7588-3134-50
        UUID: 26e86d6e-140c-496a-862c-a3b3bbcd16ad
        Wake-up Type: Power Switch
        SKU Number: None
        Family: Virtual Machine

Handle 0x0010, DMI type 32, 11 bytes
System Boot Information
        Status: No errors detected

gnos@vEdge:~$

Thanks a lot for the quick analysis!

Peter.

>
> Hi Long,
> If this works, do you see any concerns if I back-port your patch on
> older kernels (6.12 and prior)?
>
> Regards,
> Naman
>
> --------------
> Patch:
>
>  From 2f14d48d2bde3f86b153b9f756a9cd688cda3453 Mon Sep 17 00:00:00 2001
> From: Long Li <longli@microsoft.com>
> Date: Mon, 10 Mar 2025 15:12:01 -0700
> Subject: [PATCH] uio_hv_generic: Set event for all channels on the device
>
> Hyper-V may offer a non latency sensitive device with subchannels without
> monitor bit enabled. The decision is entirely on the Hyper-V host not
> configurable within guest.
>
> When a device has subchannels, also signal events for the subchannel
> if its monitor bit is disabled.
>
> This patch also removes the memory barrier when monitor bit is enabled
> as it is not necessary. The memory barrier is only needed between
> setting up interrupt mask and calling vmbus_set_event() when monitor
> bit is disabled.
>
> Signed-off-by: Long Li <longli@microsoft.com>
> Reviewed-by: Michael Kelley <mhklinux@outlook.com>
> Reviewed-by: Saurabh Sengar <ssengar@linux.microsoft.com>
> Signed-off-by: Naman Jain <namjain@linux.microsoft.com>
> ---
>   drivers/uio/uio_hv_generic.c | 32 ++++++++++++++++++++++++++------
>   1 file changed, 26 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c
> index 0b414d1168dd..9f3b124a5e09 100644
> --- a/drivers/uio/uio_hv_generic.c
> +++ b/drivers/uio/uio_hv_generic.c
> @@ -65,6 +65,16 @@ struct hv_uio_private_data {
>          char    send_name[32];
>   };
>
> +static void set_event(struct vmbus_channel *channel, s32 irq_state)
> +{
> +       channel->inbound.ring_buffer->interrupt_mask = !irq_state;
> +       if (!channel->offermsg.monitor_allocated && irq_state) {
> +               /* MB is needed for host to see the interrupt mask first */
> +               virt_mb();
> +               vmbus_set_event(channel);
> +       }
> +}
> +
>   /*
>    * This is the irqcontrol callback to be registered to uio_info.
>    * It can be used to disable/enable interrupt from user space processes.
> @@ -79,12 +89,15 @@ hv_uio_irqcontrol(struct uio_info *info, s32 irq_state)
>   {
>          struct hv_uio_private_data *pdata = info->priv;
>          struct hv_device *dev = pdata->device;
> +       struct vmbus_channel *primary, *sc;
>
> -       dev->channel->inbound.ring_buffer->interrupt_mask = !irq_state;
> -       virt_mb();
> +       primary = dev->channel;
> +       set_event(primary, irq_state);
>
> -       if (!dev->channel->offermsg.monitor_allocated && irq_state)
> -               vmbus_setevent(dev->channel);
> +       mutex_lock(&vmbus_connection.channel_mutex);
> +       list_for_each_entry(sc, &primary->sc_list, sc_list)
> +               set_event(sc, irq_state);
> +       mutex_unlock(&vmbus_connection.channel_mutex);
>
>          return 0;
>   }
> @@ -95,11 +108,18 @@ hv_uio_irqcontrol(struct uio_info *info, s32 irq_state)
>   static void hv_uio_channel_cb(void *context)
>   {
>          struct vmbus_channel *chan = context;
> -       struct hv_device *hv_dev = chan->device_obj;
> -       struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev);
> +       struct hv_device *hv_dev;
> +       struct hv_uio_private_data *pdata;
>
>          virt_mb();
>
> +       /*
> +       * The callback may come from a subchannel, in which case look
> +       * for the hv device in the primary channel
> +       */
> +       hv_dev = chan->primary_channel ?
> +       chan->primary_channel->device_obj : chan->device_obj;
> +       pdata = hv_get_drvdata(hv_dev);
>          uio_event_notify(&pdata->info);
>   }
>
> --
> 2.43.0

^ permalink raw reply

* [PATCH net-next v3 2/2] net: mana: Add standard counter rx_missed_errors
From: Erni Sri Satya Vennela @ 2025-11-14 11:43 UTC (permalink / raw)
  To: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
	kuba, pabeni, longli, kotaranov, horms, shradhagupta, ssengar,
	ernis, dipayanroy, shirazsaleem, sbhatta, linux-hyperv, netdev,
	linux-kernel, linux-rdma
In-Reply-To: <1763120599-6331-1-git-send-email-ernis@linux.microsoft.com>

Report standard counter stats->rx_missed_errors
using hc_rx_discards_no_wqe from the hardware.

Add a global workqueue to periodically run
mana_query_gf_stats every 2 seconds to get the latest
info in eth_stats and define a driver capability flag
to notify hardware of the periodic queries.

To avoid repeated failures and log flooding, the workqueue
is not rescheduled if mana_query_gf_stats fails on HWC timeout
error and the stats are reset to 0. Other errors are transient
which will not need a VF reset for recovery.

Signed-off-by: Erni Sri Satya Vennela <ernis@linux.microsoft.com>
---
Changes in v3:
* Use schedule_delayed_work (global workqueue) instead of
  queue_delayed_work (dedicated workqueue) in MANA driver.
* Update commit message.
Changes in v2:
* Update commit message.
* Stop rescheduling workqueue only when HWC timeout is observed.
* Introduce new variable in mana_context for detecting HWC timeout.
* Warn once in mana_get_stat64 when HWC timeout is observed.
---
 drivers/net/ethernet/microsoft/mana/mana_en.c | 36 +++++++++++++++++--
 .../ethernet/microsoft/mana/mana_ethtool.c    |  2 --
 include/net/mana/gdma.h                       |  6 +++-
 include/net/mana/mana.h                       |  6 +++-
 4 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index d8ce4402c696..13f47be7aca6 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -534,6 +534,11 @@ static void mana_get_stats64(struct net_device *ndev,
 
 	netdev_stats_to_stats64(st, &ndev->stats);
 
+	if (apc->ac->hwc_timeout_occurred)
+		netdev_warn_once(ndev, "HWC timeout occurred\n");
+
+	st->rx_missed_errors = apc->ac->hc_stats.hc_rx_discards_no_wqe;
+
 	for (q = 0; q < num_queues; q++) {
 		rx_stats = &apc->rxqs[q]->stats;
 
@@ -2809,7 +2814,7 @@ int mana_config_rss(struct mana_port_context *apc, enum TRI_STATE rx,
 	return 0;
 }
 
-void mana_query_gf_stats(struct mana_context *ac)
+int mana_query_gf_stats(struct mana_context *ac)
 {
 	struct gdma_context *gc = ac->gdma_dev->gdma_context;
 	struct mana_query_gf_stat_resp resp = {};
@@ -2852,14 +2857,14 @@ void mana_query_gf_stats(struct mana_context *ac)
 				sizeof(resp));
 	if (err) {
 		dev_err(dev, "Failed to query GF stats: %d\n", err);
-		return;
+		return err;
 	}
 	err = mana_verify_resp_hdr(&resp.hdr, MANA_QUERY_GF_STAT,
 				   sizeof(resp));
 	if (err || resp.hdr.status) {
 		dev_err(dev, "Failed to query GF stats: %d, 0x%x\n", err,
 			resp.hdr.status);
-		return;
+		return err;
 	}
 
 	ac->hc_stats.hc_rx_discards_no_wqe = resp.rx_discards_nowqe;
@@ -2894,6 +2899,8 @@ void mana_query_gf_stats(struct mana_context *ac)
 	ac->hc_stats.hc_tx_mcast_pkts = resp.hc_tx_mcast_pkts;
 	ac->hc_stats.hc_tx_mcast_bytes = resp.hc_tx_mcast_bytes;
 	ac->hc_stats.hc_tx_err_gdma = resp.tx_err_gdma;
+
+	return 0;
 }
 
 void mana_query_phy_stats(struct mana_port_context *apc)
@@ -3428,6 +3435,24 @@ int mana_rdma_service_event(struct gdma_context *gc, enum gdma_service_type even
 	return 0;
 }
 
+#define MANA_GF_STATS_PERIOD (2 * HZ)
+
+static void mana_gf_stats_work_handler(struct work_struct *work)
+{
+	struct mana_context *ac =
+		container_of(to_delayed_work(work), struct mana_context, gf_stats_work);
+	int err;
+
+	err = mana_query_gf_stats(ac);
+	if (err == -ETIMEDOUT) {
+		/* HWC timeout detected - reset stats and stop rescheduling */
+		ac->hwc_timeout_occurred = true;
+		memset(&ac->hc_stats, 0, sizeof(ac->hc_stats));
+		return;
+	}
+	schedule_delayed_work(&ac->gf_stats_work, MANA_GF_STATS_PERIOD);
+}
+
 int mana_probe(struct gdma_dev *gd, bool resuming)
 {
 	struct gdma_context *gc = gd->gdma_context;
@@ -3520,6 +3545,10 @@ int mana_probe(struct gdma_dev *gd, bool resuming)
 	}
 
 	err = add_adev(gd, "eth");
+
+	INIT_DELAYED_WORK(&ac->gf_stats_work, mana_gf_stats_work_handler);
+	schedule_delayed_work(&ac->gf_stats_work, MANA_GF_STATS_PERIOD);
+
 out:
 	if (err) {
 		mana_remove(gd, false);
@@ -3544,6 +3573,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending)
 	int i;
 
 	disable_work_sync(&ac->link_change_work);
+	cancel_delayed_work_sync(&ac->gf_stats_work);
 
 	/* adev currently doesn't support suspending, always remove it */
 	if (gd->adev)
diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
index 3dfd96146424..99e811208683 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -213,8 +213,6 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
 
 	if (!apc->port_is_up)
 		return;
-	/* we call mana function to update stats from GDMA */
-	mana_query_gf_stats(apc->ac);
 
 	/* We call this mana function to get the phy stats from GDMA and includes
 	 * aggregate tx/rx drop counters, Per-TC(Traffic Channel) tx/rx and pause
diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
index 637f42485dba..2e4f2f3175e5 100644
--- a/include/net/mana/gdma.h
+++ b/include/net/mana/gdma.h
@@ -592,6 +592,9 @@ enum {
 #define GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE BIT(17)
 #define GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE BIT(6)
 
+/* Driver can send HWC periodically to query stats */
+#define GDMA_DRV_CAP_FLAG_1_PERIODIC_STATS_QUERY BIT(21)
+
 #define GDMA_DRV_CAP_FLAGS1 \
 	(GDMA_DRV_CAP_FLAG_1_EQ_SHARING_MULTI_VPORT | \
 	 GDMA_DRV_CAP_FLAG_1_NAPI_WKDONE_FIX | \
@@ -601,7 +604,8 @@ enum {
 	 GDMA_DRV_CAP_FLAG_1_DYNAMIC_IRQ_ALLOC_SUPPORT | \
 	 GDMA_DRV_CAP_FLAG_1_SELF_RESET_ON_EQE | \
 	 GDMA_DRV_CAP_FLAG_1_HANDLE_RECONFIG_EQE | \
-	 GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE)
+	 GDMA_DRV_CAP_FLAG_1_HW_VPORT_LINK_AWARE | \
+	 GDMA_DRV_CAP_FLAG_1_PERIODIC_STATS_QUERY)
 
 #define GDMA_DRV_CAP_FLAGS2 0
 
diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
index 3484f42803e3..d37f4cea0ac3 100644
--- a/include/net/mana/mana.h
+++ b/include/net/mana/mana.h
@@ -480,6 +480,10 @@ struct mana_context {
 	struct mana_eq *eqs;
 	struct dentry *mana_eqs_debugfs;
 
+	/* Workqueue for querying hardware stats */
+	struct delayed_work gf_stats_work;
+	bool hwc_timeout_occurred;
+
 	struct net_device *ports[MAX_PORTS_IN_MANA_DEV];
 
 	/* Link state change work */
@@ -581,7 +585,7 @@ u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq,
 struct bpf_prog *mana_xdp_get(struct mana_port_context *apc);
 void mana_chn_setxdp(struct mana_port_context *apc, struct bpf_prog *prog);
 int mana_bpf(struct net_device *ndev, struct netdev_bpf *bpf);
-void mana_query_gf_stats(struct mana_context *ac);
+int mana_query_gf_stats(struct mana_context *ac);
 int mana_query_link_cfg(struct mana_port_context *apc);
 int mana_set_bw_clamp(struct mana_port_context *apc, u32 speed,
 		      int enable_clamping);
-- 
2.34.1


^ permalink raw reply related

* [PATCH net-next v3 1/2] net: mana: Move hardware counter stats from per-port to per-VF context
From: Erni Sri Satya Vennela @ 2025-11-14 11:43 UTC (permalink / raw)
  To: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
	kuba, pabeni, longli, kotaranov, horms, shradhagupta, ssengar,
	ernis, dipayanroy, shirazsaleem, sbhatta, linux-hyperv, netdev,
	linux-kernel, linux-rdma
In-Reply-To: <1763120599-6331-1-git-send-email-ernis@linux.microsoft.com>

Move hardware counter (HC) statistics from mana_port_context to
mana_context to enable sharing stats across multiple network ports
on the same MANA VF. Previously, each network port queried
hardware counters independently using MANA_QUERY_GF_STAT command
(GF = Generic Function stats from GDMA hardware), resulting in
redundant queries when multiple ports existed on the same device.

Isolate hardware counter stats by introducing mana_ethtool_hc_stats
in mana_context and update the code to ensure all stats are properly
reported via ethtool -S <interface>, maintaining consistency with
previous behavior.

Signed-off-by: Erni Sri Satya Vennela <ernis@linux.microsoft.com>
---
Changes in v3:
* Update commit message for more readability.
* Use reverse x-mas tree format in mana_query_gf_stats.
Changes in v2:
* No change
---
 drivers/net/ethernet/microsoft/mana/mana_en.c | 67 ++++++++-------
 .../ethernet/microsoft/mana/mana_ethtool.c    | 85 ++++++++++---------
 include/net/mana/mana.h                       | 14 +--
 3 files changed, 90 insertions(+), 76 deletions(-)

diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index cccd5b63cee6..d8ce4402c696 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -2809,11 +2809,12 @@ int mana_config_rss(struct mana_port_context *apc, enum TRI_STATE rx,
 	return 0;
 }
 
-void mana_query_gf_stats(struct mana_port_context *apc)
+void mana_query_gf_stats(struct mana_context *ac)
 {
+	struct gdma_context *gc = ac->gdma_dev->gdma_context;
 	struct mana_query_gf_stat_resp resp = {};
 	struct mana_query_gf_stat_req req = {};
-	struct net_device *ndev = apc->ndev;
+	struct device *dev = gc->dev;
 	int err;
 
 	mana_gd_init_req_hdr(&req.hdr, MANA_QUERY_GF_STAT,
@@ -2847,52 +2848,52 @@ void mana_query_gf_stats(struct mana_port_context *apc)
 			STATISTICS_FLAGS_HC_TX_BCAST_BYTES |
 			STATISTICS_FLAGS_TX_ERRORS_GDMA_ERROR;
 
-	err = mana_send_request(apc->ac, &req, sizeof(req), &resp,
+	err = mana_send_request(ac, &req, sizeof(req), &resp,
 				sizeof(resp));
 	if (err) {
-		netdev_err(ndev, "Failed to query GF stats: %d\n", err);
+		dev_err(dev, "Failed to query GF stats: %d\n", err);
 		return;
 	}
 	err = mana_verify_resp_hdr(&resp.hdr, MANA_QUERY_GF_STAT,
 				   sizeof(resp));
 	if (err || resp.hdr.status) {
-		netdev_err(ndev, "Failed to query GF stats: %d, 0x%x\n", err,
-			   resp.hdr.status);
+		dev_err(dev, "Failed to query GF stats: %d, 0x%x\n", err,
+			resp.hdr.status);
 		return;
 	}
 
-	apc->eth_stats.hc_rx_discards_no_wqe = resp.rx_discards_nowqe;
-	apc->eth_stats.hc_rx_err_vport_disabled = resp.rx_err_vport_disabled;
-	apc->eth_stats.hc_rx_bytes = resp.hc_rx_bytes;
-	apc->eth_stats.hc_rx_ucast_pkts = resp.hc_rx_ucast_pkts;
-	apc->eth_stats.hc_rx_ucast_bytes = resp.hc_rx_ucast_bytes;
-	apc->eth_stats.hc_rx_bcast_pkts = resp.hc_rx_bcast_pkts;
-	apc->eth_stats.hc_rx_bcast_bytes = resp.hc_rx_bcast_bytes;
-	apc->eth_stats.hc_rx_mcast_pkts = resp.hc_rx_mcast_pkts;
-	apc->eth_stats.hc_rx_mcast_bytes = resp.hc_rx_mcast_bytes;
-	apc->eth_stats.hc_tx_err_gf_disabled = resp.tx_err_gf_disabled;
-	apc->eth_stats.hc_tx_err_vport_disabled = resp.tx_err_vport_disabled;
-	apc->eth_stats.hc_tx_err_inval_vportoffset_pkt =
+	ac->hc_stats.hc_rx_discards_no_wqe = resp.rx_discards_nowqe;
+	ac->hc_stats.hc_rx_err_vport_disabled = resp.rx_err_vport_disabled;
+	ac->hc_stats.hc_rx_bytes = resp.hc_rx_bytes;
+	ac->hc_stats.hc_rx_ucast_pkts = resp.hc_rx_ucast_pkts;
+	ac->hc_stats.hc_rx_ucast_bytes = resp.hc_rx_ucast_bytes;
+	ac->hc_stats.hc_rx_bcast_pkts = resp.hc_rx_bcast_pkts;
+	ac->hc_stats.hc_rx_bcast_bytes = resp.hc_rx_bcast_bytes;
+	ac->hc_stats.hc_rx_mcast_pkts = resp.hc_rx_mcast_pkts;
+	ac->hc_stats.hc_rx_mcast_bytes = resp.hc_rx_mcast_bytes;
+	ac->hc_stats.hc_tx_err_gf_disabled = resp.tx_err_gf_disabled;
+	ac->hc_stats.hc_tx_err_vport_disabled = resp.tx_err_vport_disabled;
+	ac->hc_stats.hc_tx_err_inval_vportoffset_pkt =
 					     resp.tx_err_inval_vport_offset_pkt;
-	apc->eth_stats.hc_tx_err_vlan_enforcement =
+	ac->hc_stats.hc_tx_err_vlan_enforcement =
 					     resp.tx_err_vlan_enforcement;
-	apc->eth_stats.hc_tx_err_eth_type_enforcement =
+	ac->hc_stats.hc_tx_err_eth_type_enforcement =
 					     resp.tx_err_ethtype_enforcement;
-	apc->eth_stats.hc_tx_err_sa_enforcement = resp.tx_err_SA_enforcement;
-	apc->eth_stats.hc_tx_err_sqpdid_enforcement =
+	ac->hc_stats.hc_tx_err_sa_enforcement = resp.tx_err_SA_enforcement;
+	ac->hc_stats.hc_tx_err_sqpdid_enforcement =
 					     resp.tx_err_SQPDID_enforcement;
-	apc->eth_stats.hc_tx_err_cqpdid_enforcement =
+	ac->hc_stats.hc_tx_err_cqpdid_enforcement =
 					     resp.tx_err_CQPDID_enforcement;
-	apc->eth_stats.hc_tx_err_mtu_violation = resp.tx_err_mtu_violation;
-	apc->eth_stats.hc_tx_err_inval_oob = resp.tx_err_inval_oob;
-	apc->eth_stats.hc_tx_bytes = resp.hc_tx_bytes;
-	apc->eth_stats.hc_tx_ucast_pkts = resp.hc_tx_ucast_pkts;
-	apc->eth_stats.hc_tx_ucast_bytes = resp.hc_tx_ucast_bytes;
-	apc->eth_stats.hc_tx_bcast_pkts = resp.hc_tx_bcast_pkts;
-	apc->eth_stats.hc_tx_bcast_bytes = resp.hc_tx_bcast_bytes;
-	apc->eth_stats.hc_tx_mcast_pkts = resp.hc_tx_mcast_pkts;
-	apc->eth_stats.hc_tx_mcast_bytes = resp.hc_tx_mcast_bytes;
-	apc->eth_stats.hc_tx_err_gdma = resp.tx_err_gdma;
+	ac->hc_stats.hc_tx_err_mtu_violation = resp.tx_err_mtu_violation;
+	ac->hc_stats.hc_tx_err_inval_oob = resp.tx_err_inval_oob;
+	ac->hc_stats.hc_tx_bytes = resp.hc_tx_bytes;
+	ac->hc_stats.hc_tx_ucast_pkts = resp.hc_tx_ucast_pkts;
+	ac->hc_stats.hc_tx_ucast_bytes = resp.hc_tx_ucast_bytes;
+	ac->hc_stats.hc_tx_bcast_pkts = resp.hc_tx_bcast_pkts;
+	ac->hc_stats.hc_tx_bcast_bytes = resp.hc_tx_bcast_bytes;
+	ac->hc_stats.hc_tx_mcast_pkts = resp.hc_tx_mcast_pkts;
+	ac->hc_stats.hc_tx_mcast_bytes = resp.hc_tx_mcast_bytes;
+	ac->hc_stats.hc_tx_err_gdma = resp.tx_err_gdma;
 }
 
 void mana_query_phy_stats(struct mana_port_context *apc)
diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
index a1afa75a9463..3dfd96146424 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -15,66 +15,69 @@ struct mana_stats_desc {
 static const struct mana_stats_desc mana_eth_stats[] = {
 	{"stop_queue", offsetof(struct mana_ethtool_stats, stop_queue)},
 	{"wake_queue", offsetof(struct mana_ethtool_stats, wake_queue)},
-	{"hc_rx_discards_no_wqe", offsetof(struct mana_ethtool_stats,
+	{"tx_cq_err", offsetof(struct mana_ethtool_stats, tx_cqe_err)},
+	{"tx_cqe_unknown_type", offsetof(struct mana_ethtool_stats,
+					tx_cqe_unknown_type)},
+	{"rx_coalesced_err", offsetof(struct mana_ethtool_stats,
+					rx_coalesced_err)},
+	{"rx_cqe_unknown_type", offsetof(struct mana_ethtool_stats,
+					rx_cqe_unknown_type)},
+};
+
+static const struct mana_stats_desc mana_hc_stats[] = {
+	{"hc_rx_discards_no_wqe", offsetof(struct mana_ethtool_hc_stats,
 					   hc_rx_discards_no_wqe)},
-	{"hc_rx_err_vport_disabled", offsetof(struct mana_ethtool_stats,
+	{"hc_rx_err_vport_disabled", offsetof(struct mana_ethtool_hc_stats,
 					      hc_rx_err_vport_disabled)},
-	{"hc_rx_bytes", offsetof(struct mana_ethtool_stats, hc_rx_bytes)},
-	{"hc_rx_ucast_pkts", offsetof(struct mana_ethtool_stats,
+	{"hc_rx_bytes", offsetof(struct mana_ethtool_hc_stats, hc_rx_bytes)},
+	{"hc_rx_ucast_pkts", offsetof(struct mana_ethtool_hc_stats,
 				      hc_rx_ucast_pkts)},
-	{"hc_rx_ucast_bytes", offsetof(struct mana_ethtool_stats,
+	{"hc_rx_ucast_bytes", offsetof(struct mana_ethtool_hc_stats,
 				       hc_rx_ucast_bytes)},
-	{"hc_rx_bcast_pkts", offsetof(struct mana_ethtool_stats,
+	{"hc_rx_bcast_pkts", offsetof(struct mana_ethtool_hc_stats,
 				      hc_rx_bcast_pkts)},
-	{"hc_rx_bcast_bytes", offsetof(struct mana_ethtool_stats,
+	{"hc_rx_bcast_bytes", offsetof(struct mana_ethtool_hc_stats,
 				       hc_rx_bcast_bytes)},
-	{"hc_rx_mcast_pkts", offsetof(struct mana_ethtool_stats,
-			hc_rx_mcast_pkts)},
-	{"hc_rx_mcast_bytes", offsetof(struct mana_ethtool_stats,
+	{"hc_rx_mcast_pkts", offsetof(struct mana_ethtool_hc_stats,
+				      hc_rx_mcast_pkts)},
+	{"hc_rx_mcast_bytes", offsetof(struct mana_ethtool_hc_stats,
 				       hc_rx_mcast_bytes)},
-	{"hc_tx_err_gf_disabled", offsetof(struct mana_ethtool_stats,
+	{"hc_tx_err_gf_disabled", offsetof(struct mana_ethtool_hc_stats,
 					   hc_tx_err_gf_disabled)},
-	{"hc_tx_err_vport_disabled", offsetof(struct mana_ethtool_stats,
+	{"hc_tx_err_vport_disabled", offsetof(struct mana_ethtool_hc_stats,
 					      hc_tx_err_vport_disabled)},
 	{"hc_tx_err_inval_vportoffset_pkt",
-	 offsetof(struct mana_ethtool_stats,
+	 offsetof(struct mana_ethtool_hc_stats,
 		  hc_tx_err_inval_vportoffset_pkt)},
-	{"hc_tx_err_vlan_enforcement", offsetof(struct mana_ethtool_stats,
+	{"hc_tx_err_vlan_enforcement", offsetof(struct mana_ethtool_hc_stats,
 						hc_tx_err_vlan_enforcement)},
 	{"hc_tx_err_eth_type_enforcement",
-	 offsetof(struct mana_ethtool_stats, hc_tx_err_eth_type_enforcement)},
-	{"hc_tx_err_sa_enforcement", offsetof(struct mana_ethtool_stats,
+	 offsetof(struct mana_ethtool_hc_stats, hc_tx_err_eth_type_enforcement)},
+	{"hc_tx_err_sa_enforcement", offsetof(struct mana_ethtool_hc_stats,
 					      hc_tx_err_sa_enforcement)},
 	{"hc_tx_err_sqpdid_enforcement",
-	 offsetof(struct mana_ethtool_stats, hc_tx_err_sqpdid_enforcement)},
+	 offsetof(struct mana_ethtool_hc_stats, hc_tx_err_sqpdid_enforcement)},
 	{"hc_tx_err_cqpdid_enforcement",
-	 offsetof(struct mana_ethtool_stats, hc_tx_err_cqpdid_enforcement)},
-	{"hc_tx_err_mtu_violation", offsetof(struct mana_ethtool_stats,
+	 offsetof(struct mana_ethtool_hc_stats, hc_tx_err_cqpdid_enforcement)},
+	{"hc_tx_err_mtu_violation", offsetof(struct mana_ethtool_hc_stats,
 					     hc_tx_err_mtu_violation)},
-	{"hc_tx_err_inval_oob", offsetof(struct mana_ethtool_stats,
+	{"hc_tx_err_inval_oob", offsetof(struct mana_ethtool_hc_stats,
 					 hc_tx_err_inval_oob)},
-	{"hc_tx_err_gdma", offsetof(struct mana_ethtool_stats,
+	{"hc_tx_err_gdma", offsetof(struct mana_ethtool_hc_stats,
 				    hc_tx_err_gdma)},
-	{"hc_tx_bytes", offsetof(struct mana_ethtool_stats, hc_tx_bytes)},
-	{"hc_tx_ucast_pkts", offsetof(struct mana_ethtool_stats,
+	{"hc_tx_bytes", offsetof(struct mana_ethtool_hc_stats, hc_tx_bytes)},
+	{"hc_tx_ucast_pkts", offsetof(struct mana_ethtool_hc_stats,
 					hc_tx_ucast_pkts)},
-	{"hc_tx_ucast_bytes", offsetof(struct mana_ethtool_stats,
+	{"hc_tx_ucast_bytes", offsetof(struct mana_ethtool_hc_stats,
 					hc_tx_ucast_bytes)},
-	{"hc_tx_bcast_pkts", offsetof(struct mana_ethtool_stats,
+	{"hc_tx_bcast_pkts", offsetof(struct mana_ethtool_hc_stats,
 					hc_tx_bcast_pkts)},
-	{"hc_tx_bcast_bytes", offsetof(struct mana_ethtool_stats,
+	{"hc_tx_bcast_bytes", offsetof(struct mana_ethtool_hc_stats,
 					hc_tx_bcast_bytes)},
-	{"hc_tx_mcast_pkts", offsetof(struct mana_ethtool_stats,
+	{"hc_tx_mcast_pkts", offsetof(struct mana_ethtool_hc_stats,
 					hc_tx_mcast_pkts)},
-	{"hc_tx_mcast_bytes", offsetof(struct mana_ethtool_stats,
+	{"hc_tx_mcast_bytes", offsetof(struct mana_ethtool_hc_stats,
 					hc_tx_mcast_bytes)},
-	{"tx_cq_err", offsetof(struct mana_ethtool_stats, tx_cqe_err)},
-	{"tx_cqe_unknown_type", offsetof(struct mana_ethtool_stats,
-					tx_cqe_unknown_type)},
-	{"rx_coalesced_err", offsetof(struct mana_ethtool_stats,
-					rx_coalesced_err)},
-	{"rx_cqe_unknown_type", offsetof(struct mana_ethtool_stats,
-					rx_cqe_unknown_type)},
 };
 
 static const struct mana_stats_desc mana_phy_stats[] = {
@@ -138,7 +141,7 @@ static int mana_get_sset_count(struct net_device *ndev, int stringset)
 	if (stringset != ETH_SS_STATS)
 		return -EINVAL;
 
-	return ARRAY_SIZE(mana_eth_stats) + ARRAY_SIZE(mana_phy_stats) +
+	return ARRAY_SIZE(mana_eth_stats) + ARRAY_SIZE(mana_phy_stats) + ARRAY_SIZE(mana_hc_stats) +
 			num_queues * (MANA_STATS_RX_COUNT + MANA_STATS_TX_COUNT);
 }
 
@@ -150,10 +153,12 @@ static void mana_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
 
 	if (stringset != ETH_SS_STATS)
 		return;
-
 	for (i = 0; i < ARRAY_SIZE(mana_eth_stats); i++)
 		ethtool_puts(&data, mana_eth_stats[i].name);
 
+	for (i = 0; i < ARRAY_SIZE(mana_hc_stats); i++)
+		ethtool_puts(&data, mana_hc_stats[i].name);
+
 	for (i = 0; i < ARRAY_SIZE(mana_phy_stats); i++)
 		ethtool_puts(&data, mana_phy_stats[i].name);
 
@@ -186,6 +191,7 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
 	struct mana_port_context *apc = netdev_priv(ndev);
 	unsigned int num_queues = apc->num_queues;
 	void *eth_stats = &apc->eth_stats;
+	void *hc_stats = &apc->ac->hc_stats;
 	void *phy_stats = &apc->phy_stats;
 	struct mana_stats_rx *rx_stats;
 	struct mana_stats_tx *tx_stats;
@@ -208,7 +214,7 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
 	if (!apc->port_is_up)
 		return;
 	/* we call mana function to update stats from GDMA */
-	mana_query_gf_stats(apc);
+	mana_query_gf_stats(apc->ac);
 
 	/* We call this mana function to get the phy stats from GDMA and includes
 	 * aggregate tx/rx drop counters, Per-TC(Traffic Channel) tx/rx and pause
@@ -219,6 +225,9 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
 	for (q = 0; q < ARRAY_SIZE(mana_eth_stats); q++)
 		data[i++] = *(u64 *)(eth_stats + mana_eth_stats[q].offset);
 
+	for (q = 0; q < ARRAY_SIZE(mana_hc_stats); q++)
+		data[i++] = *(u64 *)(hc_stats + mana_hc_stats[q].offset);
+
 	for (q = 0; q < ARRAY_SIZE(mana_phy_stats); q++)
 		data[i++] = *(u64 *)(phy_stats + mana_phy_stats[q].offset);
 
diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
index 8906901535f5..3484f42803e3 100644
--- a/include/net/mana/mana.h
+++ b/include/net/mana/mana.h
@@ -375,6 +375,13 @@ struct mana_tx_qp {
 struct mana_ethtool_stats {
 	u64 stop_queue;
 	u64 wake_queue;
+	u64 tx_cqe_err;
+	u64 tx_cqe_unknown_type;
+	u64 rx_coalesced_err;
+	u64 rx_cqe_unknown_type;
+};
+
+struct mana_ethtool_hc_stats {
 	u64 hc_rx_discards_no_wqe;
 	u64 hc_rx_err_vport_disabled;
 	u64 hc_rx_bytes;
@@ -402,10 +409,6 @@ struct mana_ethtool_stats {
 	u64 hc_tx_mcast_pkts;
 	u64 hc_tx_mcast_bytes;
 	u64 hc_tx_err_gdma;
-	u64 tx_cqe_err;
-	u64 tx_cqe_unknown_type;
-	u64 rx_coalesced_err;
-	u64 rx_cqe_unknown_type;
 };
 
 struct mana_ethtool_phy_stats {
@@ -473,6 +476,7 @@ struct mana_context {
 	u16 num_ports;
 	u8 bm_hostmode;
 
+	struct mana_ethtool_hc_stats hc_stats;
 	struct mana_eq *eqs;
 	struct dentry *mana_eqs_debugfs;
 
@@ -577,7 +581,7 @@ u32 mana_run_xdp(struct net_device *ndev, struct mana_rxq *rxq,
 struct bpf_prog *mana_xdp_get(struct mana_port_context *apc);
 void mana_chn_setxdp(struct mana_port_context *apc, struct bpf_prog *prog);
 int mana_bpf(struct net_device *ndev, struct netdev_bpf *bpf);
-void mana_query_gf_stats(struct mana_port_context *apc);
+void mana_query_gf_stats(struct mana_context *ac);
 int mana_query_link_cfg(struct mana_port_context *apc);
 int mana_set_bw_clamp(struct mana_port_context *apc, u32 speed,
 		      int enable_clamping);
-- 
2.34.1


^ permalink raw reply related

* [PATCH net-next v3 0/2] net: mana: Refactor GF stats handling and add rx_missed_errors counter
From: Erni Sri Satya Vennela @ 2025-11-14 11:43 UTC (permalink / raw)
  To: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
	kuba, pabeni, longli, kotaranov, horms, shradhagupta, ssengar,
	ernis, dipayanroy, shirazsaleem, sbhatta, linux-hyperv, netdev,
	linux-kernel, linux-rdma

Restructure mana_query_gf_stats() to operate on the per-VF mana_context,
instead of per-port statistics. Introduce mana_ethtool_hc_stats to
isolate hardware counter statistics and update the
"ethtool -S <interface>" output to expose all relevant counters while
preserving backward compatibility.

Add support for the standard rx_missed_errors counter by mapping it to
the hardware's hc_rx_discards_no_wqe metric. Introduce a
global workqueue that refreshes statistics every 2 seconds, ensuring
timely and consistent updates of hardware counters.

---
Changes in v3:
* Use schedule_delayed_work (global workqueue) instead of
  queue_delayed_work (dedicated workqueue for MANA driver).
* Update commit message for more readability.
* Use reverse x-mas tree format in mana_query_gf_stats.
Changes in v2:
* Update commit message.
* Stop rescheduling workqueue only when HWC timeout is observed.
* Introduce new variable in mana_context for detecting HWC timeout.
* Warn once in mana_get_stat64 when HWC timeout is observed.
---
Erni Sri Satya Vennela (2):
  net: mana: Move hardware counter stats from per-port to per-device
    context
  net: mana: Add standard counter rx_missed_errors

 drivers/net/ethernet/microsoft/mana/mana_en.c | 101 ++++++++++++------
 .../ethernet/microsoft/mana/mana_ethtool.c    |  85 ++++++++-------
 include/net/mana/gdma.h                       |   6 +-
 include/net/mana/mana.h                       |  18 +++-
 4 files changed, 130 insertions(+), 80 deletions(-)

-- 
2.34.1
For internal review only. 

^ permalink raw reply

* [PATCH] Drivers: hv: ioctl for self targeted passthrough hvcalls
From: Anirudh Rayabharam @ 2025-11-14  9:58 UTC (permalink / raw)
  To: K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li
  Cc: anirudh, linux-hyperv, linux-kernel

From: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>

Allow MSHV_ROOT_HVCALL IOCTL on the /dev/mshv fd. This IOCTL would
execute a passthrough hypercall targeting the root/parent partition
i.e. HV_PARTITION_ID_SELF.

This will be useful for the VMM to query things like supported
synthetic processor features, supported VMM capabiliites etc.

While at it, add HVCALL_GET_PARTITION_PROPERTY_EX to the allowed list of
passthrough hypercalls.

Signed-off-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
---
 drivers/hv/mshv_root_main.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/hv/mshv_root_main.c b/drivers/hv/mshv_root_main.c
index 20eda00a1b5a..98f56322cd19 100644
--- a/drivers/hv/mshv_root_main.c
+++ b/drivers/hv/mshv_root_main.c
@@ -122,6 +122,7 @@ static struct miscdevice mshv_dev = {
  */
 static u16 mshv_passthru_hvcalls[] = {
 	HVCALL_GET_PARTITION_PROPERTY,
+	HVCALL_GET_PARTITION_PROPERTY_EX,
 	HVCALL_SET_PARTITION_PROPERTY,
 	HVCALL_INSTALL_INTERCEPT,
 	HVCALL_GET_VP_REGISTERS,
@@ -159,6 +160,7 @@ static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition,
 	unsigned int pages_order;
 	void *input_pg = NULL;
 	void *output_pg = NULL;
+	u64 pt_id = partition ? partition->pt_id : HV_PARTITION_ID_SELF;
 
 	if (copy_from_user(&args, user_args, sizeof(args)))
 		return -EFAULT;
@@ -180,7 +182,7 @@ static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition,
 	is_async = mshv_hvcall_is_async(args.code);
 	if (is_async) {
 		/* async hypercalls can only be called from partition fd */
-		if (!partition_locked)
+		if (!partition || !partition_locked)
 			return -EINVAL;
 		ret = mshv_init_async_handler(partition);
 		if (ret)
@@ -208,7 +210,7 @@ static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition,
 	 * NOTE: This only works because all the allowed hypercalls' input
 	 * structs begin with a u64 partition_id field.
 	 */
-	*(u64 *)input_pg = partition->pt_id;
+	*(u64 *)input_pg = pt_id;
 
 	if (args.reps)
 		status = hv_do_rep_hypercall(args.code, args.reps, 0,
@@ -226,7 +228,7 @@ static int mshv_ioctl_passthru_hvcall(struct mshv_partition *partition,
 	}
 
 	if (hv_result(status) == HV_STATUS_INSUFFICIENT_MEMORY) {
-		ret = hv_call_deposit_pages(NUMA_NO_NODE, partition->pt_id, 1);
+		ret = hv_call_deposit_pages(NUMA_NO_NODE, pt_id, 1);
 		if (!ret)
 			ret = -EAGAIN;
 	} else if (!hv_result_success(status)) {
@@ -2048,6 +2050,9 @@ static long mshv_dev_ioctl(struct file *filp, unsigned int ioctl,
 	case MSHV_CREATE_PARTITION:
 		return mshv_ioctl_create_partition((void __user *)arg,
 						misc->this_device);
+	case MSHV_ROOT_HVCALL:
+		return mshv_ioctl_passthru_hvcall(NULL, false,
+					(void __user *)arg);
 	}
 
 	return -ENOTTY;
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH net-next v9 06/14] vsock/loopback: add netns support
From: Stefano Garzarella @ 2025-11-14  9:33 UTC (permalink / raw)
  To: Bobby Eshleman
  Cc: Shuah Khan, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Stefan Hajnoczi, Michael S. Tsirkin,
	Jason Wang, Xuan Zhuo, Eugenio Pérez, K. Y. Srinivasan,
	Haiyang Zhang, Wei Liu, Dexuan Cui, Bryan Tan, Vishnu Dasa,
	Broadcom internal kernel review list, virtualization, netdev,
	linux-kselftest, linux-kernel, kvm, linux-hyperv, Sargun Dhillon,
	berrange, Bobby Eshleman
In-Reply-To: <aRYivEKsa44u5Mh+@devvm11784.nha0.facebook.com>

On Thu, Nov 13, 2025 at 10:26:04AM -0800, Bobby Eshleman wrote:
>On Thu, Nov 13, 2025 at 04:24:44PM +0100, Stefano Garzarella wrote:
>> On Wed, Nov 12, 2025 at 10:27:18AM -0800, Bobby Eshleman wrote:
>> > On Wed, Nov 12, 2025 at 03:19:47PM +0100, Stefano Garzarella wrote:
>> > > On Tue, Nov 11, 2025 at 10:54:48PM -0800, Bobby Eshleman wrote:
>> > > > From: Bobby Eshleman <bobbyeshleman@meta.com>
>> > > >
>> > > > Add NS support to vsock loopback. Sockets in a global mode netns
>> > > > communicate with each other, regardless of namespace. Sockets in a local
>> > > > mode netns may only communicate with other sockets within the same
>> > > > namespace.
>> > > >
>> > > > Signed-off-by: Bobby Eshleman <bobbyeshleman@meta.com>
>
>[...]
>
>> > > > @@ -131,7 +136,41 @@ static void vsock_loopback_work(struct work_struct *work)
>> > > > 		 */
>> > > > 		virtio_transport_consume_skb_sent(skb, false);
>> > > > 		virtio_transport_deliver_tap_pkt(skb);
>> > > > -		virtio_transport_recv_pkt(&loopback_transport, skb, NULL, 0);
>> > > > +
>> > > > +		/* In the case of virtio_transport_reset_no_sock(), the skb
>> > > > +		 * does not hold a reference on the socket, and so does not
>> > > > +		 * transitively hold a reference on the net.
>> > > > +		 *
>> > > > +		 * There is an ABA race condition in this sequence:
>> > > > +		 * 1. the sender sends a packet
>> > > > +		 * 2. worker calls virtio_transport_recv_pkt(), using the
>> > > > +		 *    sender's net
>> > > > +		 * 3. virtio_transport_recv_pkt() uses t->send_pkt() passing the
>> > > > +		 *    sender's net
>> > > > +		 * 4. virtio_transport_recv_pkt() free's the skb, dropping the
>> > > > +		 *    reference to the socket
>> > > > +		 * 5. the socket closes, frees its reference to the net
>> > > > +		 * 6. Finally, the worker for the second t->send_pkt() call
>> > > > +		 *    processes the skb, and uses the now stale net pointer for
>> > > > +		 *    socket lookups.
>> > > > +		 *
>> > > > +		 * To prevent this, we acquire a net reference in vsock_loopback_send_pkt()
>> > > > +		 * and hold it until virtio_transport_recv_pkt() completes.
>> > > > +		 *
>> > > > +		 * Additionally, we must grab a reference on the skb before
>> > > > +		 * calling virtio_transport_recv_pkt() to prevent it from
>> > > > +		 * freeing the skb before we have a chance to release the net.
>> > > > +		 */
>> > > > +		net_mode = virtio_vsock_skb_net_mode(skb);
>> > > > +		net = virtio_vsock_skb_net(skb);
>> > >
>> > > Wait, we are adding those just for loopback (in theory used only for
>> > > testing/debugging)? And only to support virtio_transport_reset_no_sock() use
>> > > case?
>> >
>> > Yes, exactly, only loopback + reset_no_sock(). The issue doesn't exist
>> > for vhost-vsock because vhost_vsock holds a net reference, and it
>> > doesn't exist for non-reset_no_sock calls because after looking up the
>> > socket we transfer skb ownership to it, which holds down the skb -> sk ->
>> > net reference chain.
>> >
>> > >
>> > > Honestly I don't like this, do we have any alternative?
>> > >
>> > > I'll also try to think something else.
>> > >
>> > > Stefano
>> >
>> >
>> > I've been thinking about this all morning... maybe
>> > we can do something like this:
>> >
>> > ```
>> >
>> > virtio_transport_recv_pkt(...,  struct sock *reply_sk) {... }
>> >
>> > virtio_transport_reset_no_sock(..., reply_sk)
>> > {
>> > 	if (reply_sk)
>> > 		skb_set_owner_sk_safe(reply, reply_sk)
>>
>> Interesting, but what about if we call skb_set_owner_sk_safe() in
>> vsock_loopback.c just before calling virtio_transport_recv_pkt() for every
>> skb?
>
>I think the issue with this is that at the time vsock_loopback calls
>virtio_transport_recv_pkt() the reply skb hasn't yet been allocated by
>virtio_transport_reset_no_sock() and we can't wait for it to return
>because the original skb may be freed by then.

Right!

>
>We might be able to keep it all in vsock_loopback if we removed the need
>to use the original skb or sk by just using the net. But to do that we
>would need to add a netns_tracker per net somewhere. I guess that would
>end up in a list or hashmap in struct vsock_loopback.
>
>Another option that does simplify a little, but unfortunately still doesn't keep
>everything in loopback:
>
>@@ -1205,7 +1205,7 @@ static int virtio_transport_reset_no_sock(const struct virtio_transport *t,
> 	if (!reply)
> 		return -ENOMEM;
>
>-	return t->send_pkt(reply, net, net_mode);
>+	return t->send_pkt(reply, net, net_mode, skb->sk);
> }
>
>@@ -27,11 +27,16 @@ static u32 vsock_loopback_get_local_cid(void)
> }
>
> static int vsock_loopback_send_pkt(struct sk_buff *skb, struct net *net,
>-				   enum vsock_net_mode net_mode)
>+				   enum vsock_net_mode net_mode,
>+				   struct sock *rst_owner)
> {
> 	struct vsock_loopback *vsock = &the_vsock_loopback;
> 	int len = skb->len;
>
>+	if (!skb->sk && rst_owner)
>+		WARN_ONCE(!skb_set_owner_sk_safe(skb, rst_owner),
>+			  "loopback socket has sk_refcnt == 0\n");
>+

This doesn't seem too bad IMO, but at this point, why we can't do that
in virtio_transport_reset_no_sock() for any kind of transport?

I mean, in any case the RST packet should be handled by the same net of 
the "sender", no?

At this point, can we just put the `vsk` of the sender in the `info` and 
virtio_transport_alloc_skb() will already do that.

WDYT?
Am I missing something?

> 	virtio_vsock_skb_queue_tail(&vsock->pkt_queue, skb);
> 	queue_work(vsock->workqueue, &vsock->pkt_work);
>
>>
>> Maybe we should refactor a bit virtio_transport_recv_pkt() e.g. moving
>> `skb_set_owner_sk_safe()` to be sure it's called only when we are sure it's
>> the right socket (e.g. after checking SOCK_DONE).
>>
>> WDYT?
>
>I agree, it is called a little prematurely.

Yep, but I'll leave this out for now :-)

Thanks,
Stefano


^ permalink raw reply

* Instalacja pv
From: Bartosz Witkowski @ 2025-11-14  8:56 UTC (permalink / raw)
  To: linux-hyperv

Dzień dobry,

wiem, że fotowoltaika to dla Państwa dobrze znany temat, ale pozwolę sobie jedynie zwrócić uwagę na najnowsze dane dotyczące opłacalności tej inwestycji.

System o mocy 5 kW pozwala obecnie zaoszczędzić nawet 5000 zł rocznie, a dobrze dobrana instalacja pokrywa do 80% rocznego zapotrzebowania na energię, zmniejszając rachunki. 

Nowoczesne panele są coraz wydajniejsze i trwalsze, a rosnące ceny prądu tylko wzmacniają rentowność projektu.

Czy chcieliby Państwo sprawdzić, jak zoptymalizować istniejącą lub planowaną instalację?


Pozdrawiam
Bartosz Witkowski

^ permalink raw reply

* Re: [REGRESSION 6.12.y] hyper-v: BUG: kernel NULL pointer dereference, address: 00000000000000a0: RIP: 0010:hv_uio_channel_cb+0xd/0x20 [uio_hv_generic]
From: Naman Jain @ 2025-11-14  6:03 UTC (permalink / raw)
  To: Salvatore Bonaccorso, Peter Morrow, Long Li
  Cc: 1120602, linux-hyperv, linux-kernel, regressions, stable,
	John Starks, Michael Kelley, Long Li, Tianyu Lan,
	K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui,
	Greg Kroah-Hartman
In-Reply-To: <aRYjk4JBqHvVl-wN@eldamar.lan>



On 11/13/2025 11:59 PM, Salvatore Bonaccorso wrote:
> Peter Morrow reported in Debian a regression, reported in
> https://bugs.debian.org/1120602 . The regression was seen after
> updating, to 6.12.57-1 in Debian, but details on the offending commit
> follows.
> 
> His report was as follows:
> 
>> Dear Maintainer,
>>
>> I'm seeing a kernel crash quite soon after boot on a debian trixie based
>> system running 6.12.57+deb13-amd64, unfortunately the kernel panics before
>> I can access the system to gather more information. Thus I'll provide details
>> of the system using a previously known good version. The panic is happening
>> 100% of the time unfortunately. I have access to the serial console however
>> so can enable any required verbose logging during boot if necessary.
>>
>> Crucially the crash is not seen with kernel version 6.12.41+deb13-amd64 with the
>> same userspace. We had pinned to that version until very recently to in order
>> to work around https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1109676
>>
>> I'm running a dpdk application here (VPP) on Azure, VM form factor is a
>> "Standard DS3 v2 (4 vcpus, 14 GiB memory)".
>>
>> The only relevant upstream commit in this area (as far as I can see) is:
>>
>> https://lore.kernel.org/linux-hyperv/1bb599ee-fe28-409d-b430-2fc086268936@linux.microsoft.com/
>>
>> The comment regarding avoiding races at start adds a bit more weight behind this
>> hunch, though it's only a hunch as I am most definitely nowhere near an expert
>> in this area.
>>
>> -- Package-specific info:
>>
>> [   19.625535] BUG: kernel NULL pointer dereference, address: 00000000000000a0
>> [   19.628874] #PF: supervisor read access in kernel mode
>> [   19.630841] #PF: error_code(0x0000) - not-present page
>> [   19.632788] PGD 0 P4D 0
>> [   19.633905] Oops: Oops: 0000 [#1] PREEMPT SMP PTI
>> [   19.635586] CPU: 3 UID: 0 PID: 0 Comm: swapper/3 Not tainted 6.12.57+deb13-amd64 #1  Debian 6.12.57-1
>> [   19.640216] Hardware name: Microsoft Corporation Virtual Machine/Virtual Machine, BIOS Hyper-V UEFI Release v4.1 09/28/2024
>> [   19.644514] RIP: 0010:hv_uio_channel_cb+0xd/0x20 [uio_hv_generic]
>> [   19.646994] Code: 02 00 00 5b 5d e9 53 98 69 e9 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 0f 1f 44 00 00 48 8b 47 10 <48> 8b b8 a0 00 00 00 f0 83 44 24 fc 00 e9 51 6f fa ff 90 90 90 90
>> [   19.654377] RSP: 0018:ffffb15ac01a4fa8 EFLAGS: 00010046
>> [   19.656385] RAX: 0000000000000000 RBX: 0000000000000015 RCX: 0000000000000015
>> [   19.659240] RDX: 0000000000000001 RSI: ffffffffffffffff RDI: ffff8ff69c759400
>> [   19.662168] RBP: ffff8ff548790200 R08: ffff8ff548790200 R09: 00fca75150b080e9
>> [   19.665239] R10: 0000000000000000 R11: ffffb15ac01a4ff8 R12: ffff8ff871dc1480
>> [   19.668193] R13: ffff8ff69c759400 R14: ffff8ff69c7596a0 R15: ffffffffc106e160
>> [   19.671106] FS:  0000000000000000(0000) GS:ffff8ff871d80000(0000) knlGS:0000000000000000
>> [   19.674281] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>> [   19.676533] CR2: 00000000000000a0 CR3: 0000000100ba6003 CR4: 00000000003706f0
>> [   19.679385] Call Trace:
>> [   19.680361]  <IRQ>
>> [   19.681181]  vmbus_isr+0x1a5/0x210 [hv_vmbus]
>> [   19.682916]  __sysvec_hyperv_callback+0x32/0x60
>> [   19.684991]  sysvec_hyperv_callback+0x6c/0x90
>> [   19.686665]  </IRQ>
>> [   19.687509]  <TASK>
>> [   19.688366]  asm_sysvec_hyperv_callback+0x1a/0x20
>> [   19.690262] RIP: 0010:pv_native_safe_halt+0xf/0x20
>> [   19.692067] Code: 09 e9 c5 08 01 00 0f 1f 44 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 66 90 0f 00 2d e5 3b 31 00 fb f4 <c3> cc cc cc cc 66 66 2e 0f 1f 84 00 00 00 00 00 90 90 90 90 90 90
>> [   19.699119] RSP: 0018:ffffb15ac0103ed8 EFLAGS: 00000246
>> [   19.701412] RAX: 0000000000000003 RBX: ffff8ff5403b1fc0 RCX: ffff8ff54c64ce30
>> [   19.704328] RDX: 0000000000000000 RSI: 0000000000000003 RDI: 000000000001f894
>> [   19.706910] RBP: 0000000000000003 R08: 000000000bb760d9 R09: 00fca75150b080e9
>> [   19.709762] R10: 0000000000000003 R11: 0000000000000001 R12: 0000000000000000
>> [   19.712510] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000
>> [   19.715173]  default_idle+0x9/0x20
>> [   19.716846]  default_idle_call+0x29/0x100
>> [   19.718623]  do_idle+0x1fe/0x240
>> [   19.720045]  cpu_startup_entry+0x29/0x30
>> [   19.721595]  start_secondary+0x11e/0x140
>> [   19.723080]  common_startup_64+0x13e/0x141
>> [   19.725222]  </TASK>
>> [   19.726387] Modules linked in: isofs cdrom uio_hv_generic uio binfmt_misc intel_rapl_msr intel_rapl_common intel_uncore_frequency_common isst_if_mbox_msr isst_if_common rpcrdma skx_edac_common nfit sunrpc libnvdimm crct10dif_pclmul ghash_clmulni_intel sha512_ssse3 sha256_ssse3 rdma_ucm ib_iser sha1_ssse3 rdma_cm aesni_intel iw_cm gf128mul crypto_simd libiscsi cryptd ib_umad ib_ipoib scsi_transport_iscsi ib_cm rapl sg hv_utils hv_balloon evdev pcspkr joydev mpls_router ip_tunnel ramoops configfs pstore_blk efi_pstore pstore_zone nfnetlink vsock_loopback vmw_vsock_virtio_transport_common hv_sock vmw_vsock_vmci_transport vsock vmw_vmci efivarfs ip_tables x_tables autofs4 overlay squashfs dm_verity dm_bufio reed_solomon dm_mod loop ext4 crc16 mbcache jbd2 crc32c_generic mlx5_ib ib_uverbs ib_core mlx5_core mlxfw pci_hyperv pci_hyperv_intf hyperv_drm drm_shmem_helper sd_mod drm_kms_helper hv_storvsc scsi_transport_fc drm scsi_mod hid_generic hid_hyperv hid serio_raw hv_netvsc hyperv_keyboard scsi_common hv_vmbus
>> [   19.726466]  crc32_pclmul crc32c_intel
>> [   19.765771] CR2: 00000000000000a0
>> [   19.767524] ---[ end trace 0000000000000000 ]---
>> [   19.800433] RIP: 0010:hv_uio_channel_cb+0xd/0x20 [uio_hv_generic]
>> [   19.803170] Code: 02 00 00 5b 5d e9 53 98 69 e9 0f 1f 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 0f 1f 44 00 00 48 8b 47 10 <48> 8b b8 a0 00 00 00 f0 83 44 24 fc 00 e9 51 6f fa ff 90 90 90 90
>> [   19.811041] RSP: 0018:ffffb15ac01a4fa8 EFLAGS: 00010046
>> [   19.813466] RAX: 0000000000000000 RBX: 0000000000000015 RCX: 0000000000000015
>> [   19.816504] RDX: 0000000000000001 RSI: ffffffffffffffff RDI: ffff8ff69c759400
>> [   19.819484] RBP: ffff8ff548790200 R08: ffff8ff548790200 R09: 00fca75150b080e9
>> [   19.822625] R10: 0000000000000000 R11: ffffb15ac01a4ff8 R12: ffff8ff871dc1480
>> [   19.825569] R13: ffff8ff69c759400 R14: ffff8ff69c7596a0 R15: ffffffffc106e160
>> [   19.828804] FS:  0000000000000000(0000) GS:ffff8ff871d80000(0000) knlGS:0000000000000000
>> [   19.832214] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>> [   19.834709] CR2: 00000000000000a0 CR3: 0000000100ba6003 CR4: 00000000003706f0
>> [   19.837976] Kernel panic - not syncing: Fatal exception in interrupt
>> [   19.841825] Kernel Offset: 0x28a00000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
>> [   19.896620] ---[ end Kernel panic - not syncing: Fatal exception in interrupt ]---
>>

<snip>

> The offending commit appers to be the backport of b15b7d2a1b09
> ("uio_hv_generic: Let userspace take care of interrupt mask") for
> 6.12.y.
> 
> Peter confirmed that reverting this commit on top of 6.12.57-1 as
> packaged in Debian resolves indeed the issue. Interestingly the issue
> is *not* seen with 6.17.7 based kernel in Debian.
> 
> #regzbot introduced: 37bd91f22794dc05436130d6983302cb90ecfe7e
> #regzbot monitor: https://bugs.debian.org/1120602
> 
> Thank you already!
> 
> Regards,
> Salvatore

Hi Peter, Salvatore,
Thanks for reporting this crash, and sorry for the trouble. Here is my 
analysis.

On 6.17.7, where commit d062463edf17 ("uio_hv_generic: Set event for all 
channels on the device") is present, hv_uio_irqcontrol() supports 
setting of interrupt mask from userspace for sub-channels as well.

This aligns with commit e29587c07537 ("uio_hv_generic: Let userspace 
take care of interrupt mask") which relies on userspace to manage 
interrupt mask, so it safely removes the interrupt mask management logic 
in the driver.

However, in 6.12.57, the first commit is not present, but the second one 
is, so there is no way to disable interrupt mask for sub-channels and 
interrupt_mask stays 0, which means interrupts are not masked. So we may 
be having an interrupt callback being handled for a sub-channel, where 
we do not expect it to come. This may be causing this issue.

This would have led to a crash in hv_uio_channel_cb() for sub-channels:
struct hv_device *hv_dev = chan->device_obj;


I have ported commit d062463edf17 ("uio_hv_generic: Set event for all 
channels on the device") on 6.12.57, and resolved some merge conflicts. 
Could you please help with testing this, if it works for you.

Hi Long,
If this works, do you see any concerns if I back-port your patch on 
older kernels (6.12 and prior)?

Regards,
Naman

--------------
Patch:

 From 2f14d48d2bde3f86b153b9f756a9cd688cda3453 Mon Sep 17 00:00:00 2001
From: Long Li <longli@microsoft.com>
Date: Mon, 10 Mar 2025 15:12:01 -0700
Subject: [PATCH] uio_hv_generic: Set event for all channels on the device

Hyper-V may offer a non latency sensitive device with subchannels without
monitor bit enabled. The decision is entirely on the Hyper-V host not
configurable within guest.

When a device has subchannels, also signal events for the subchannel
if its monitor bit is disabled.

This patch also removes the memory barrier when monitor bit is enabled
as it is not necessary. The memory barrier is only needed between
setting up interrupt mask and calling vmbus_set_event() when monitor
bit is disabled.

Signed-off-by: Long Li <longli@microsoft.com>
Reviewed-by: Michael Kelley <mhklinux@outlook.com>
Reviewed-by: Saurabh Sengar <ssengar@linux.microsoft.com>
Signed-off-by: Naman Jain <namjain@linux.microsoft.com>
---
  drivers/uio/uio_hv_generic.c | 32 ++++++++++++++++++++++++++------
  1 file changed, 26 insertions(+), 6 deletions(-)

diff --git a/drivers/uio/uio_hv_generic.c b/drivers/uio/uio_hv_generic.c
index 0b414d1168dd..9f3b124a5e09 100644
--- a/drivers/uio/uio_hv_generic.c
+++ b/drivers/uio/uio_hv_generic.c
@@ -65,6 +65,16 @@ struct hv_uio_private_data {
         char    send_name[32];
  };

+static void set_event(struct vmbus_channel *channel, s32 irq_state)
+{
+       channel->inbound.ring_buffer->interrupt_mask = !irq_state;
+       if (!channel->offermsg.monitor_allocated && irq_state) {
+               /* MB is needed for host to see the interrupt mask first */
+               virt_mb();
+               vmbus_set_event(channel);
+       }
+}
+
  /*
   * This is the irqcontrol callback to be registered to uio_info.
   * It can be used to disable/enable interrupt from user space processes.
@@ -79,12 +89,15 @@ hv_uio_irqcontrol(struct uio_info *info, s32 irq_state)
  {
         struct hv_uio_private_data *pdata = info->priv;
         struct hv_device *dev = pdata->device;
+       struct vmbus_channel *primary, *sc;

-       dev->channel->inbound.ring_buffer->interrupt_mask = !irq_state;
-       virt_mb();
+       primary = dev->channel;
+       set_event(primary, irq_state);

-       if (!dev->channel->offermsg.monitor_allocated && irq_state)
-               vmbus_setevent(dev->channel);
+       mutex_lock(&vmbus_connection.channel_mutex);
+       list_for_each_entry(sc, &primary->sc_list, sc_list)
+               set_event(sc, irq_state);
+       mutex_unlock(&vmbus_connection.channel_mutex);

         return 0;
  }
@@ -95,11 +108,18 @@ hv_uio_irqcontrol(struct uio_info *info, s32 irq_state)
  static void hv_uio_channel_cb(void *context)
  {
         struct vmbus_channel *chan = context;
-       struct hv_device *hv_dev = chan->device_obj;
-       struct hv_uio_private_data *pdata = hv_get_drvdata(hv_dev);
+       struct hv_device *hv_dev;
+       struct hv_uio_private_data *pdata;

         virt_mb();

+       /*
+       * The callback may come from a subchannel, in which case look
+       * for the hv device in the primary channel
+       */
+       hv_dev = chan->primary_channel ?
+       chan->primary_channel->device_obj : chan->device_obj;
+       pdata = hv_get_drvdata(hv_dev);
         uio_event_notify(&pdata->info);
  }

--
2.43.0

^ permalink raw reply related

* RE: [PATCH 7/9] KVM: SVM: Treat exit_code as an unsigned 64-bit value through all of KVM
From: Michael Kelley @ 2025-11-14  5:26 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini, Vitaly Kuznetsov,
	K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui,
	Nuno Das Neves
  Cc: kvm@vger.kernel.org, linux-hyperv@vger.kernel.org,
	linux-kernel@vger.kernel.org, Jim Mattson, Yosry Ahmed
In-Reply-To: <20251113225621.1688428-8-seanjc@google.com>

From: Sean Christopherson <seanjc@google.com> Sent: Thursday, November 13, 2025 2:56 PM
> 

Adding Microsoft's Nuno Das Neves to the "To:" line since he
originated the work to keep the Linux headers such as hvgdk.h in
sync with the Windows counterparts from which they originate.

> Fix KVM's long-standing buggy handling of SVM's exit_code as a 32-bit
> value.  Per the APM and Xen commit d1bd157fbc ("Big merge the HVM
> full-virtualisation abstractions.") (which is arguably more trustworthy
> than KVM), offset 0x70 is a single 64-bit value:
> 
>   070h 63:0 EXITCODE
> 
> Track exit_code as a single u64 to prevent reintroducing bugs where KVM
> neglects to correctly set bits 63:32.
> 
> Fixes: 6aa8b732ca01 ("[PATCH] kvm: userspace interface")
> Cc: Jim Mattson <jmattson@google.com>
> Cc: Yosry Ahmed <yosry.ahmed@linux.dev>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
> ---
>  arch/x86/include/asm/svm.h      |  3 +--
>  arch/x86/include/uapi/asm/svm.h | 32 ++++++++++++++---------------
>  arch/x86/kvm/svm/hyperv.c       |  1 -
>  arch/x86/kvm/svm/nested.c       | 13 +++---------
>  arch/x86/kvm/svm/sev.c          | 36 +++++++++++----------------------
>  arch/x86/kvm/svm/svm.c          |  7 ++-----
>  arch/x86/kvm/svm/svm.h          |  4 +---
>  arch/x86/kvm/trace.h            |  2 +-
>  include/hyperv/hvgdk.h          |  2 +-
>  9 files changed, 37 insertions(+), 63 deletions(-)
> 
> diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
> index e69b6d0dedcf..66b22cffedfc 100644
> --- a/arch/x86/include/asm/svm.h
> +++ b/arch/x86/include/asm/svm.h
> @@ -136,8 +136,7 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
>  	u32 int_vector;
>  	u32 int_state;
>  	u8 reserved_3[4];
> -	u32 exit_code;
> -	u32 exit_code_hi;
> +	u64 exit_code;
>  	u64 exit_info_1;
>  	u64 exit_info_2;
>  	u32 exit_int_info;
> diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h
> index 650e3256ea7d..010a45c9f614 100644
> --- a/arch/x86/include/uapi/asm/svm.h
> +++ b/arch/x86/include/uapi/asm/svm.h
> @@ -103,38 +103,38 @@
>  #define SVM_EXIT_VMGEXIT       0x403
> 
>  /* SEV-ES software-defined VMGEXIT events */
> -#define SVM_VMGEXIT_MMIO_READ			0x80000001
> -#define SVM_VMGEXIT_MMIO_WRITE			0x80000002
> -#define SVM_VMGEXIT_NMI_COMPLETE		0x80000003
> -#define SVM_VMGEXIT_AP_HLT_LOOP			0x80000004
> -#define SVM_VMGEXIT_AP_JUMP_TABLE		0x80000005
> +#define SVM_VMGEXIT_MMIO_READ			0x80000001ull
> +#define SVM_VMGEXIT_MMIO_WRITE			0x80000002ull
> +#define SVM_VMGEXIT_NMI_COMPLETE		0x80000003ull
> +#define SVM_VMGEXIT_AP_HLT_LOOP			0x80000004ull
> +#define SVM_VMGEXIT_AP_JUMP_TABLE		0x80000005ull
>  #define SVM_VMGEXIT_SET_AP_JUMP_TABLE		0
>  #define SVM_VMGEXIT_GET_AP_JUMP_TABLE		1
> -#define SVM_VMGEXIT_PSC				0x80000010
> -#define SVM_VMGEXIT_GUEST_REQUEST		0x80000011
> -#define SVM_VMGEXIT_EXT_GUEST_REQUEST		0x80000012
> -#define SVM_VMGEXIT_AP_CREATION			0x80000013
> +#define SVM_VMGEXIT_PSC				0x80000010ull
> +#define SVM_VMGEXIT_GUEST_REQUEST		0x80000011ull
> +#define SVM_VMGEXIT_EXT_GUEST_REQUEST		0x80000012ull
> +#define SVM_VMGEXIT_AP_CREATION			0x80000013ull
>  #define SVM_VMGEXIT_AP_CREATE_ON_INIT		0
>  #define SVM_VMGEXIT_AP_CREATE			1
>  #define SVM_VMGEXIT_AP_DESTROY			2
> -#define SVM_VMGEXIT_SNP_RUN_VMPL		0x80000018
> -#define SVM_VMGEXIT_SAVIC			0x8000001a
> +#define SVM_VMGEXIT_SNP_RUN_VMPL		0x80000018ull
> +#define SVM_VMGEXIT_SAVIC			0x8000001aull
>  #define SVM_VMGEXIT_SAVIC_REGISTER_GPA		0
>  #define SVM_VMGEXIT_SAVIC_UNREGISTER_GPA	1
>  #define SVM_VMGEXIT_SAVIC_SELF_GPA		~0ULL
> -#define SVM_VMGEXIT_HV_FEATURES			0x8000fffd
> -#define SVM_VMGEXIT_TERM_REQUEST		0x8000fffe
> +#define SVM_VMGEXIT_HV_FEATURES			0x8000fffdull
> +#define SVM_VMGEXIT_TERM_REQUEST		0x8000fffeull
>  #define SVM_VMGEXIT_TERM_REASON(reason_set, reason_code)	\
>  	/* SW_EXITINFO1[3:0] */					\
>  	(((((u64)reason_set) & 0xf)) |				\
>  	/* SW_EXITINFO1[11:4] */				\
>  	((((u64)reason_code) & 0xff) << 4))
> -#define SVM_VMGEXIT_UNSUPPORTED_EVENT		0x8000ffff
> +#define SVM_VMGEXIT_UNSUPPORTED_EVENT		0x8000ffffull
> 
>  /* Exit code reserved for hypervisor/software use */
> -#define SVM_EXIT_SW				0xf0000000
> +#define SVM_EXIT_SW				0xf0000000ull
> 
> -#define SVM_EXIT_ERR           -1
> +#define SVM_EXIT_ERR           -1ull
> 

[snip]

> diff --git a/include/hyperv/hvgdk.h b/include/hyperv/hvgdk.h
> index dd6d4939ea29..56b695873a72 100644
> --- a/include/hyperv/hvgdk.h
> +++ b/include/hyperv/hvgdk.h
> @@ -281,7 +281,7 @@ struct hv_vmcb_enlightenments {
>  #define HV_VMCB_NESTED_ENLIGHTENMENTS		31
> 
>  /* Synthetic VM-Exit */
> -#define HV_SVM_EXITCODE_ENL			0xf0000000
> +#define HV_SVM_EXITCODE_ENL			0xf0000000u

Is there a reason for making this Hyper-V code just "u", while
making the SVM_VMGEXIT_* values "ull"? I don't think
"u" vs. "ull" shouldn't make any difference when assigning to a
u64, but the inconsistency piqued my interest ....

Michael

^ permalink raw reply

* Re: [PATCH 8/9] KVM: SVM: Limit incorrect check on SVM_EXIT_ERR to running as a VM
From: Yosry Ahmed @ 2025-11-14  0:11 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Paolo Bonzini, Vitaly Kuznetsov, K. Y. Srinivasan, Haiyang Zhang,
	Wei Liu, Dexuan Cui, kvm, linux-hyperv, linux-kernel, Jim Mattson
In-Reply-To: <20251113225621.1688428-9-seanjc@google.com>

On Thu, Nov 13, 2025 at 02:56:20PM -0800, Sean Christopherson wrote:
> Limit KVM's incorrect check for VMXEXIT_INVALID, a.k.a. SVM_EXIT_ERR, to
> running as a VM, as detected by X86_FEATURE_HYPERVISOR.  The exit_code and
> all failure codes, e.g. VMXEXIT_INVALID, are 64-bit values, and so checking
> only bits 31:0 could result in false positives when running on non-broken
> hardware, e.g. in the extremely unlikely scenario exit code 0xffffffffull
> is ever generated by hardware.
> 
> Keep the 32-bit check to play nice with running on broken KVM (for years,
> KVM has not set bits 63:32 when synthesizing nested SVM VM-Exits).
> 
> Signed-off-by: Sean Christopherson <seanjc@google.com>

Reviewed-by: Yosry Ahmed <yosry.ahmed@linux.dev>

> ---
>  arch/x86/kvm/svm/svm.h | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
> index 31ee4f65dcc2..801dcfc64d0b 100644
> --- a/arch/x86/kvm/svm/svm.h
> +++ b/arch/x86/kvm/svm/svm.h
> @@ -427,7 +427,10 @@ static __always_inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
>  
>  static inline bool svm_is_vmrun_failure(u64 exit_code)
>  {
> -	return (u32)exit_code == (u32)SVM_EXIT_ERR;
> +	if (cpu_feature_enabled(X86_FEATURE_HYPERVISOR))
> +		return (u32)exit_code == (u32)SVM_EXIT_ERR;
> +
> +	return exit_code == SVM_EXIT_ERR;
>  }
>  
>  /*
> -- 
> 2.52.0.rc1.455.g30608eb744-goog
> 

^ permalink raw reply

* Re: [PATCH 7/9] KVM: SVM: Treat exit_code as an unsigned 64-bit value through all of KVM
From: Yosry Ahmed @ 2025-11-14  0:08 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Paolo Bonzini, Vitaly Kuznetsov, K. Y. Srinivasan, Haiyang Zhang,
	Wei Liu, Dexuan Cui, kvm, linux-hyperv, linux-kernel, Jim Mattson
In-Reply-To: <20251113225621.1688428-8-seanjc@google.com>

On Thu, Nov 13, 2025 at 02:56:19PM -0800, Sean Christopherson wrote:
> Fix KVM's long-standing buggy handling of SVM's exit_code as a 32-bit
> value.  Per the APM and Xen commit d1bd157fbc ("Big merge the HVM
> full-virtualisation abstractions.") (which is arguably more trustworthy
> than KVM), offset 0x70 is a single 64-bit value:
> 
>   070h 63:0 EXITCODE
> 
> Track exit_code as a single u64 to prevent reintroducing bugs where KVM
> neglects to correctly set bits 63:32.
> 
> Fixes: 6aa8b732ca01 ("[PATCH] kvm: userspace interface")
> Cc: Jim Mattson <jmattson@google.com>
> Cc: Yosry Ahmed <yosry.ahmed@linux.dev>
> Signed-off-by: Sean Christopherson <seanjc@google.com>

Reviewed-by: Yosry Ahmed <yosry.ahmed@linux.dev>

> ---
>  arch/x86/include/asm/svm.h      |  3 +--
>  arch/x86/include/uapi/asm/svm.h | 32 ++++++++++++++---------------
>  arch/x86/kvm/svm/hyperv.c       |  1 -
>  arch/x86/kvm/svm/nested.c       | 13 +++---------
>  arch/x86/kvm/svm/sev.c          | 36 +++++++++++----------------------
>  arch/x86/kvm/svm/svm.c          |  7 ++-----
>  arch/x86/kvm/svm/svm.h          |  4 +---
>  arch/x86/kvm/trace.h            |  2 +-
>  include/hyperv/hvgdk.h          |  2 +-
>  9 files changed, 37 insertions(+), 63 deletions(-)
> 
> diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
> index e69b6d0dedcf..66b22cffedfc 100644
> --- a/arch/x86/include/asm/svm.h
> +++ b/arch/x86/include/asm/svm.h
> @@ -136,8 +136,7 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
>  	u32 int_vector;
>  	u32 int_state;
>  	u8 reserved_3[4];
> -	u32 exit_code;
> -	u32 exit_code_hi;
> +	u64 exit_code;
>  	u64 exit_info_1;
>  	u64 exit_info_2;
>  	u32 exit_int_info;
> diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h
> index 650e3256ea7d..010a45c9f614 100644
> --- a/arch/x86/include/uapi/asm/svm.h
> +++ b/arch/x86/include/uapi/asm/svm.h
> @@ -103,38 +103,38 @@
>  #define SVM_EXIT_VMGEXIT       0x403
>  
>  /* SEV-ES software-defined VMGEXIT events */
> -#define SVM_VMGEXIT_MMIO_READ			0x80000001
> -#define SVM_VMGEXIT_MMIO_WRITE			0x80000002
> -#define SVM_VMGEXIT_NMI_COMPLETE		0x80000003
> -#define SVM_VMGEXIT_AP_HLT_LOOP			0x80000004
> -#define SVM_VMGEXIT_AP_JUMP_TABLE		0x80000005
> +#define SVM_VMGEXIT_MMIO_READ			0x80000001ull
> +#define SVM_VMGEXIT_MMIO_WRITE			0x80000002ull
> +#define SVM_VMGEXIT_NMI_COMPLETE		0x80000003ull
> +#define SVM_VMGEXIT_AP_HLT_LOOP			0x80000004ull
> +#define SVM_VMGEXIT_AP_JUMP_TABLE		0x80000005ull
>  #define SVM_VMGEXIT_SET_AP_JUMP_TABLE		0
>  #define SVM_VMGEXIT_GET_AP_JUMP_TABLE		1
> -#define SVM_VMGEXIT_PSC				0x80000010
> -#define SVM_VMGEXIT_GUEST_REQUEST		0x80000011
> -#define SVM_VMGEXIT_EXT_GUEST_REQUEST		0x80000012
> -#define SVM_VMGEXIT_AP_CREATION			0x80000013
> +#define SVM_VMGEXIT_PSC				0x80000010ull
> +#define SVM_VMGEXIT_GUEST_REQUEST		0x80000011ull
> +#define SVM_VMGEXIT_EXT_GUEST_REQUEST		0x80000012ull
> +#define SVM_VMGEXIT_AP_CREATION			0x80000013ull
>  #define SVM_VMGEXIT_AP_CREATE_ON_INIT		0
>  #define SVM_VMGEXIT_AP_CREATE			1
>  #define SVM_VMGEXIT_AP_DESTROY			2
> -#define SVM_VMGEXIT_SNP_RUN_VMPL		0x80000018
> -#define SVM_VMGEXIT_SAVIC			0x8000001a
> +#define SVM_VMGEXIT_SNP_RUN_VMPL		0x80000018ull
> +#define SVM_VMGEXIT_SAVIC			0x8000001aull
>  #define SVM_VMGEXIT_SAVIC_REGISTER_GPA		0
>  #define SVM_VMGEXIT_SAVIC_UNREGISTER_GPA	1
>  #define SVM_VMGEXIT_SAVIC_SELF_GPA		~0ULL
> -#define SVM_VMGEXIT_HV_FEATURES			0x8000fffd
> -#define SVM_VMGEXIT_TERM_REQUEST		0x8000fffe
> +#define SVM_VMGEXIT_HV_FEATURES			0x8000fffdull
> +#define SVM_VMGEXIT_TERM_REQUEST		0x8000fffeull
>  #define SVM_VMGEXIT_TERM_REASON(reason_set, reason_code)	\
>  	/* SW_EXITINFO1[3:0] */					\
>  	(((((u64)reason_set) & 0xf)) |				\
>  	/* SW_EXITINFO1[11:4] */				\
>  	((((u64)reason_code) & 0xff) << 4))
> -#define SVM_VMGEXIT_UNSUPPORTED_EVENT		0x8000ffff
> +#define SVM_VMGEXIT_UNSUPPORTED_EVENT		0x8000ffffull
>  
>  /* Exit code reserved for hypervisor/software use */
> -#define SVM_EXIT_SW				0xf0000000
> +#define SVM_EXIT_SW				0xf0000000ull
>  
> -#define SVM_EXIT_ERR           -1
> +#define SVM_EXIT_ERR           -1ull
>  
>  #define SVM_EXIT_REASONS \
>  	{ SVM_EXIT_READ_CR0,    "read_cr0" }, \
> diff --git a/arch/x86/kvm/svm/hyperv.c b/arch/x86/kvm/svm/hyperv.c
> index 088f6429b24c..3ec580d687f5 100644
> --- a/arch/x86/kvm/svm/hyperv.c
> +++ b/arch/x86/kvm/svm/hyperv.c
> @@ -11,7 +11,6 @@ void svm_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu)
>  	struct vcpu_svm *svm = to_svm(vcpu);
>  
>  	svm->vmcb->control.exit_code = HV_SVM_EXITCODE_ENL;
> -	svm->vmcb->control.exit_code_hi = 0;
>  	svm->vmcb->control.exit_info_1 = HV_SVM_ENL_EXITCODE_TRAP_AFTER_FLUSH;
>  	svm->vmcb->control.exit_info_2 = 0;
>  	nested_svm_vmexit(svm);
> diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
> index 8070e20ed5a7..89120245cd22 100644
> --- a/arch/x86/kvm/svm/nested.c
> +++ b/arch/x86/kvm/svm/nested.c
> @@ -45,7 +45,6 @@ static void nested_svm_inject_npf_exit(struct kvm_vcpu *vcpu,
>  		 * correctly fill in the high bits of exit_info_1.
>  		 */
>  		vmcb->control.exit_code = SVM_EXIT_NPF;
> -		vmcb->control.exit_code_hi = 0;
>  		vmcb->control.exit_info_1 = (1ULL << 32);
>  		vmcb->control.exit_info_2 = fault->address;
>  	}
> @@ -421,7 +420,6 @@ void __nested_copy_vmcb_control_to_cache(struct kvm_vcpu *vcpu,
>  	to->int_vector          = from->int_vector;
>  	to->int_state           = from->int_state;
>  	to->exit_code           = from->exit_code;
> -	to->exit_code_hi        = from->exit_code_hi;
>  	to->exit_info_1         = from->exit_info_1;
>  	to->exit_info_2         = from->exit_info_2;
>  	to->exit_int_info       = from->exit_int_info;
> @@ -727,8 +725,8 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm,
>  	enter_guest_mode(vcpu);
>  
>  	/*
> -	 * Filled at exit: exit_code, exit_code_hi, exit_info_1, exit_info_2,
> -	 * exit_int_info, exit_int_info_err, next_rip, insn_len, insn_bytes.
> +	 * Filled at exit: exit_code, exit_info_1, exit_info_2, exit_int_info,
> +	 * exit_int_info_err, next_rip, insn_len, insn_bytes.
>  	 */
>  
>  	if (guest_cpu_cap_has(vcpu, X86_FEATURE_VGIF) &&
> @@ -985,7 +983,6 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu)
>  	if (!nested_vmcb_check_save(vcpu) ||
>  	    !nested_vmcb_check_controls(vcpu)) {
>  		vmcb12->control.exit_code    = SVM_EXIT_ERR;
> -		vmcb12->control.exit_code_hi = -1u;
>  		vmcb12->control.exit_info_1  = 0;
>  		vmcb12->control.exit_info_2  = 0;
>  		goto out;
> @@ -1018,7 +1015,6 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu)
>  	svm->soft_int_injected = false;
>  
>  	svm->vmcb->control.exit_code    = SVM_EXIT_ERR;
> -	svm->vmcb->control.exit_code_hi = -1u;
>  	svm->vmcb->control.exit_info_1  = 0;
>  	svm->vmcb->control.exit_info_2  = 0;
>  
> @@ -1130,7 +1126,6 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
>  
>  	vmcb12->control.int_state         = vmcb02->control.int_state;
>  	vmcb12->control.exit_code         = vmcb02->control.exit_code;
> -	vmcb12->control.exit_code_hi      = vmcb02->control.exit_code_hi;
>  	vmcb12->control.exit_info_1       = vmcb02->control.exit_info_1;
>  	vmcb12->control.exit_info_2       = vmcb02->control.exit_info_2;
>  
> @@ -1422,7 +1417,7 @@ static int nested_svm_intercept_ioio(struct vcpu_svm *svm)
>  
>  static int nested_svm_intercept(struct vcpu_svm *svm)
>  {
> -	u32 exit_code = svm->vmcb->control.exit_code;
> +	u64 exit_code = svm->vmcb->control.exit_code;
>  	int vmexit = NESTED_EXIT_HOST;
>  
>  	if (svm_is_vmrun_failure(exit_code))
> @@ -1494,7 +1489,6 @@ static void nested_svm_inject_exception_vmexit(struct kvm_vcpu *vcpu)
>  	struct vmcb *vmcb = svm->vmcb;
>  
>  	vmcb->control.exit_code = SVM_EXIT_EXCP_BASE + ex->vector;
> -	vmcb->control.exit_code_hi = 0;
>  
>  	if (ex->has_error_code)
>  		vmcb->control.exit_info_1 = ex->error_code;
> @@ -1669,7 +1663,6 @@ static void nested_copy_vmcb_cache_to_control(struct vmcb_control_area *dst,
>  	dst->int_vector           = from->int_vector;
>  	dst->int_state            = from->int_state;
>  	dst->exit_code            = from->exit_code;
> -	dst->exit_code_hi         = from->exit_code_hi;
>  	dst->exit_info_1          = from->exit_info_1;
>  	dst->exit_info_2          = from->exit_info_2;
>  	dst->exit_int_info        = from->exit_int_info;
> diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
> index 0835c664fbfd..5aedd07194aa 100644
> --- a/arch/x86/kvm/svm/sev.c
> +++ b/arch/x86/kvm/svm/sev.c
> @@ -3264,11 +3264,6 @@ void sev_free_vcpu(struct kvm_vcpu *vcpu)
>  		kvfree(svm->sev_es.ghcb_sa);
>  }
>  
> -static u64 kvm_get_cached_sw_exit_code(struct vmcb_control_area *control)
> -{
> -	return (((u64)control->exit_code_hi) << 32) | control->exit_code;
> -}
> -
>  static void dump_ghcb(struct vcpu_svm *svm)
>  {
>  	struct vmcb_control_area *control = &svm->vmcb->control;
> @@ -3290,7 +3285,7 @@ static void dump_ghcb(struct vcpu_svm *svm)
>  	 */
>  	pr_err("GHCB (GPA=%016llx) snapshot:\n", svm->vmcb->control.ghcb_gpa);
>  	pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_code",
> -	       kvm_get_cached_sw_exit_code(control), kvm_ghcb_sw_exit_code_is_valid(svm));
> +	       control->exit_code, kvm_ghcb_sw_exit_code_is_valid(svm));
>  	pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_info_1",
>  	       control->exit_info_1, kvm_ghcb_sw_exit_info_1_is_valid(svm));
>  	pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_info_2",
> @@ -3324,7 +3319,6 @@ static void sev_es_sync_from_ghcb(struct vcpu_svm *svm)
>  	struct vmcb_control_area *control = &svm->vmcb->control;
>  	struct kvm_vcpu *vcpu = &svm->vcpu;
>  	struct ghcb *ghcb = svm->sev_es.ghcb;
> -	u64 exit_code;
>  
>  	/*
>  	 * The GHCB protocol so far allows for the following data
> @@ -3358,9 +3352,7 @@ static void sev_es_sync_from_ghcb(struct vcpu_svm *svm)
>  		__kvm_emulate_msr_write(vcpu, MSR_IA32_XSS, kvm_ghcb_get_xss(svm));
>  
>  	/* Copy the GHCB exit information into the VMCB fields */
> -	exit_code = kvm_ghcb_get_sw_exit_code(svm);
> -	control->exit_code = lower_32_bits(exit_code);
> -	control->exit_code_hi = upper_32_bits(exit_code);
> +	control->exit_code = kvm_ghcb_get_sw_exit_code(svm);
>  	control->exit_info_1 = kvm_ghcb_get_sw_exit_info_1(svm);
>  	control->exit_info_2 = kvm_ghcb_get_sw_exit_info_2(svm);
>  	svm->sev_es.sw_scratch = kvm_ghcb_get_sw_scratch_if_valid(svm);
> @@ -3373,15 +3365,8 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
>  {
>  	struct vmcb_control_area *control = &svm->vmcb->control;
>  	struct kvm_vcpu *vcpu = &svm->vcpu;
> -	u64 exit_code;
>  	u64 reason;
>  
> -	/*
> -	 * Retrieve the exit code now even though it may not be marked valid
> -	 * as it could help with debugging.
> -	 */
> -	exit_code = kvm_get_cached_sw_exit_code(control);
> -
>  	/* Only GHCB Usage code 0 is supported */
>  	if (svm->sev_es.ghcb->ghcb_usage) {
>  		reason = GHCB_ERR_INVALID_USAGE;
> @@ -3395,7 +3380,7 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
>  	    !kvm_ghcb_sw_exit_info_2_is_valid(svm))
>  		goto vmgexit_err;
>  
> -	switch (exit_code) {
> +	switch (control->exit_code) {
>  	case SVM_EXIT_READ_DR7:
>  		break;
>  	case SVM_EXIT_WRITE_DR7:
> @@ -3496,15 +3481,19 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
>  	return 0;
>  
>  vmgexit_err:
> +	/*
> +	 * Print the exit code even though it may not be marked valid as it
> +	 * could help with debugging.
> +	 */
>  	if (reason == GHCB_ERR_INVALID_USAGE) {
>  		vcpu_unimpl(vcpu, "vmgexit: ghcb usage %#x is not valid\n",
>  			    svm->sev_es.ghcb->ghcb_usage);
>  	} else if (reason == GHCB_ERR_INVALID_EVENT) {
>  		vcpu_unimpl(vcpu, "vmgexit: exit code %#llx is not valid\n",
> -			    exit_code);
> +			    control->exit_code);
>  	} else {
>  		vcpu_unimpl(vcpu, "vmgexit: exit code %#llx input is not valid\n",
> -			    exit_code);
> +			    control->exit_code);
>  		dump_ghcb(svm);
>  	}
>  
> @@ -4343,7 +4332,7 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
>  {
>  	struct vcpu_svm *svm = to_svm(vcpu);
>  	struct vmcb_control_area *control = &svm->vmcb->control;
> -	u64 ghcb_gpa, exit_code;
> +	u64 ghcb_gpa;
>  	int ret;
>  
>  	/* Validate the GHCB */
> @@ -4385,8 +4374,7 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
>  
>  	svm_vmgexit_success(svm, 0);
>  
> -	exit_code = kvm_get_cached_sw_exit_code(control);
> -	switch (exit_code) {
> +	switch (control->exit_code) {
>  	case SVM_VMGEXIT_MMIO_READ:
>  		ret = setup_vmgexit_scratch(svm, true, control->exit_info_2);
>  		if (ret)
> @@ -4478,7 +4466,7 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
>  		ret = -EINVAL;
>  		break;
>  	default:
> -		ret = svm_invoke_exit_handler(vcpu, exit_code);
> +		ret = svm_invoke_exit_handler(vcpu, control->exit_code);
>  	}
>  
>  	return ret;
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index 3b05476296d0..85bc99f93275 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -2433,7 +2433,6 @@ static bool check_selective_cr0_intercepted(struct kvm_vcpu *vcpu,
>  
>  	if (cr0 ^ val) {
>  		svm->vmcb->control.exit_code = SVM_EXIT_CR0_SEL_WRITE;
> -		svm->vmcb->control.exit_code_hi = 0;
>  		ret = (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE);
>  	}
>  
> @@ -3265,7 +3264,7 @@ static void dump_vmcb(struct kvm_vcpu *vcpu)
>  	pr_err("%-20s%08x\n", "int_ctl:", control->int_ctl);
>  	pr_err("%-20s%08x\n", "int_vector:", control->int_vector);
>  	pr_err("%-20s%08x\n", "int_state:", control->int_state);
> -	pr_err("%-20s%08x\n", "exit_code:", control->exit_code);
> +	pr_err("%-20s%016llx\n", "exit_code:", control->exit_code);
>  	pr_err("%-20s%016llx\n", "exit_info1:", control->exit_info_1);
>  	pr_err("%-20s%016llx\n", "exit_info2:", control->exit_info_2);
>  	pr_err("%-20s%08x\n", "exit_int_info:", control->exit_int_info);
> @@ -3515,7 +3514,6 @@ static int svm_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
>  {
>  	struct vcpu_svm *svm = to_svm(vcpu);
>  	struct kvm_run *kvm_run = vcpu->run;
> -	u32 exit_code = svm->vmcb->control.exit_code;
>  
>  	/* SEV-ES guests must use the CR write traps to track CR registers. */
>  	if (!sev_es_guest(vcpu->kvm)) {
> @@ -3551,7 +3549,7 @@ static int svm_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
>  	if (exit_fastpath != EXIT_FASTPATH_NONE)
>  		return 1;
>  
> -	return svm_invoke_exit_handler(vcpu, exit_code);
> +	return svm_invoke_exit_handler(vcpu, svm->vmcb->control.exit_code);
>  }
>  
>  static int pre_svm_run(struct kvm_vcpu *vcpu)
> @@ -4618,7 +4616,6 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
>  	if (static_cpu_has(X86_FEATURE_NRIPS))
>  		vmcb->control.next_rip  = info->next_rip;
>  	vmcb->control.exit_code = icpt_info.exit_code;
> -	vmcb->control.exit_code_hi = 0;
>  	vmexit = nested_svm_exit_handled(svm);
>  
>  	ret = (vmexit == NESTED_EXIT_DONE) ? X86EMUL_INTERCEPTED
> diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
> index 6b35925e3a33..31ee4f65dcc2 100644
> --- a/arch/x86/kvm/svm/svm.h
> +++ b/arch/x86/kvm/svm/svm.h
> @@ -162,8 +162,7 @@ struct vmcb_ctrl_area_cached {
>  	u32 int_ctl;
>  	u32 int_vector;
>  	u32 int_state;
> -	u32 exit_code;
> -	u32 exit_code_hi;
> +	u64 exit_code;
>  	u64 exit_info_1;
>  	u64 exit_info_2;
>  	u32 exit_int_info;
> @@ -769,7 +768,6 @@ int nested_svm_vmexit(struct vcpu_svm *svm);
>  static inline int nested_svm_simple_vmexit(struct vcpu_svm *svm, u32 exit_code)
>  {
>  	svm->vmcb->control.exit_code	= exit_code;
> -	svm->vmcb->control.exit_code_hi	= 0;
>  	svm->vmcb->control.exit_info_1	= 0;
>  	svm->vmcb->control.exit_info_2	= 0;
>  	return nested_svm_vmexit(svm);
> diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h
> index e79bc9cb7162..4c7a5cd10990 100644
> --- a/arch/x86/kvm/trace.h
> +++ b/arch/x86/kvm/trace.h
> @@ -781,7 +781,7 @@ TRACE_EVENT_KVM_EXIT(kvm_nested_vmexit);
>   * Tracepoint for #VMEXIT reinjected to the guest
>   */
>  TRACE_EVENT(kvm_nested_vmexit_inject,
> -	    TP_PROTO(__u32 exit_code,
> +	    TP_PROTO(__u64 exit_code,
>  		     __u64 exit_info1, __u64 exit_info2,
>  		     __u32 exit_int_info, __u32 exit_int_info_err, __u32 isa),
>  	    TP_ARGS(exit_code, exit_info1, exit_info2,
> diff --git a/include/hyperv/hvgdk.h b/include/hyperv/hvgdk.h
> index dd6d4939ea29..56b695873a72 100644
> --- a/include/hyperv/hvgdk.h
> +++ b/include/hyperv/hvgdk.h
> @@ -281,7 +281,7 @@ struct hv_vmcb_enlightenments {
>  #define HV_VMCB_NESTED_ENLIGHTENMENTS		31
>  
>  /* Synthetic VM-Exit */
> -#define HV_SVM_EXITCODE_ENL			0xf0000000
> +#define HV_SVM_EXITCODE_ENL			0xf0000000u
>  #define HV_SVM_ENL_EXITCODE_TRAP_AFTER_FLUSH	(1)
>  
>  /* VM_PARTITION_ASSIST_PAGE */
> -- 
> 2.52.0.rc1.455.g30608eb744-goog
> 

^ permalink raw reply

* Re: [PATCH 6/9] KVM: SVM: Filter out 64-bit exit codes when invoking exit handlers on bare metal
From: Yosry Ahmed @ 2025-11-14  0:06 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Paolo Bonzini, Vitaly Kuznetsov, K. Y. Srinivasan, Haiyang Zhang,
	Wei Liu, Dexuan Cui, kvm, linux-hyperv, linux-kernel, Jim Mattson
In-Reply-To: <20251113225621.1688428-7-seanjc@google.com>

On Thu, Nov 13, 2025 at 02:56:18PM -0800, Sean Christopherson wrote:
> Explicitly filter out 64-bit exit codes when invoking exit handlers, as
> svm_exit_handlers[] will never be sized with entries that use bits 63:32.
> 
> Processing the non-failing exit code as a 32-bit value will allow tracking
> exit_code as a single 64-bit value (which it is, architecturally).  This
> will also allow hardening KVM against Spectre-like attacks without needing
> to do silly things to avoid build failures on 32-bit kernels
> (array_index_nospec() rightly asserts that the index fits in an "unsigned
> long").
> 
> Omit the check when running as a VM, as KVM has historically failed to set
> bits 63:32 appropriately when synthesizing VM-Exits, i.e. KVM could get
> false positives when running as a VM on an older, broken KVM/kernel.  From
> a functional perspective, omitting the check is "fine", as any unwanted
> collision between e.g. VMEXIT_INVALID and a 32-bit exit code will be
> fatal to KVM-on-KVM regardless of what KVM-as-L1 does.
> 
> Signed-off-by: Sean Christopherson <seanjc@google.com>

Reviewed-by: Yosry Ahmed <yosry.ahmed@linux.dev>

> ---
>  arch/x86/kvm/svm/svm.c | 18 ++++++++++++++++--
>  1 file changed, 16 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index 202a4d8088a2..3b05476296d0 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -3433,8 +3433,22 @@ static void dump_vmcb(struct kvm_vcpu *vcpu)
>  		sev_free_decrypted_vmsa(vcpu, save);
>  }
>  
> -int svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 exit_code)
> +int svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 __exit_code)
>  {
> +	u32 exit_code = __exit_code;
> +
> +	/*
> +	 * SVM uses negative values, i.e. 64-bit values, to indicate that VMRUN
> +	 * failed.  Report all such errors to userspace (note, VMEXIT_INVALID,
> +	 * a.k.a. SVM_EXIT_ERR, is special cased by svm_handle_exit()).  Skip
> +	 * the check when running as a VM, as KVM has historically left garbage
> +	 * in bits 63:32, i.e. running KVM-on-KVM would hit false positives if
> +	 * the underlying kernel is buggy.
> +	 */
> +	if (!cpu_feature_enabled(X86_FEATURE_HYPERVISOR) &&
> +	    (u64)exit_code != __exit_code)
> +		goto unexpected_vmexit;
> +
>  #ifdef CONFIG_MITIGATION_RETPOLINE
>  	if (exit_code == SVM_EXIT_MSR)
>  		return msr_interception(vcpu);
> @@ -3461,7 +3475,7 @@ int svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 exit_code)
>  
>  unexpected_vmexit:
>  	dump_vmcb(vcpu);
> -	kvm_prepare_unexpected_reason_exit(vcpu, exit_code);
> +	kvm_prepare_unexpected_reason_exit(vcpu, __exit_code);
>  	return 0;
>  }
>  
> -- 
> 2.52.0.rc1.455.g30608eb744-goog
> 

^ permalink raw reply

* Re: [PATCH 5/9] KVM: SVM: Check for an unexpected VM-Exit after RETPOLINE "fast" handling
From: Yosry Ahmed @ 2025-11-14  0:04 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Paolo Bonzini, Vitaly Kuznetsov, K. Y. Srinivasan, Haiyang Zhang,
	Wei Liu, Dexuan Cui, kvm, linux-hyperv, linux-kernel, Jim Mattson
In-Reply-To: <20251113225621.1688428-6-seanjc@google.com>

On Thu, Nov 13, 2025 at 02:56:17PM -0800, Sean Christopherson wrote:
> Check for an unexpected/unhandled VM-Exit after the manual RETPOLINE=y
> handling.  The entire point of the RETPOLINE checks is to optimize for
> common VM-Exits, i.e. checking for the rare case of an unsupported
> VM-Exit is counter-productive.  This also aligns SVM and VMX exit handling.
> 
> No functional change intended.
> 
> Signed-off-by: Sean Christopherson <seanjc@google.com>

Reviewed-by: Yosry Ahmed <yosry.ahmed@linux.dev>

> ---
>  arch/x86/kvm/svm/svm.c | 12 ++++++------
>  1 file changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index 638a67ef0c37..202a4d8088a2 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -3435,12 +3435,6 @@ static void dump_vmcb(struct kvm_vcpu *vcpu)
>  
>  int svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 exit_code)
>  {
> -	if (exit_code >= ARRAY_SIZE(svm_exit_handlers))
> -		goto unexpected_vmexit;
> -
> -	if (!svm_exit_handlers[exit_code])
> -		goto unexpected_vmexit;
> -
>  #ifdef CONFIG_MITIGATION_RETPOLINE
>  	if (exit_code == SVM_EXIT_MSR)
>  		return msr_interception(vcpu);
> @@ -3457,6 +3451,12 @@ int svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 exit_code)
>  		return sev_handle_vmgexit(vcpu);
>  #endif
>  #endif
> +	if (exit_code >= ARRAY_SIZE(svm_exit_handlers))
> +		goto unexpected_vmexit;
> +
> +	if (!svm_exit_handlers[exit_code])
> +		goto unexpected_vmexit;
> +
>  	return svm_exit_handlers[exit_code](vcpu);
>  
>  unexpected_vmexit:
> -- 
> 2.52.0.rc1.455.g30608eb744-goog
> 

^ permalink raw reply

* Re: [PATCH 3/9] KVM: SVM: Add a helper to detect VMRUN failures
From: Sean Christopherson @ 2025-11-13 23:35 UTC (permalink / raw)
  To: Yosry Ahmed
  Cc: Paolo Bonzini, Vitaly Kuznetsov, K. Y. Srinivasan, Haiyang Zhang,
	Wei Liu, Dexuan Cui, kvm, linux-hyperv, linux-kernel, Jim Mattson
In-Reply-To: <ellmjkhqmgpsbhc4if3emhn3fzbqd3ji4u2dnyvmub6bjgfnti@vtvjhn5cjwrs>

On Thu, Nov 13, 2025, Yosry Ahmed wrote:
> On Thu, Nov 13, 2025 at 02:56:15PM -0800, Sean Christopherson wrote:
> > Add a helper to detect VMRUN failures so that KVM can guard against its
> > own long-standing bug, where KVM neglects to set exitcode[63:32] when
> > synthesizing a nested VMFAIL_INVALID VM-Exit.  This will allow fixing
> > KVM's mess of treating exitcode as two separate 32-bit values without
> > breaking KVM-on-KVM when running on an older, unfixed KVM.
> > 
> > Cc: Jim Mattson <jmattson@google.com>
> > Cc: Yosry Ahmed <yosry.ahmed@linux.dev>
> > Signed-off-by: Sean Christopherson <seanjc@google.com>
> > ---
> >  arch/x86/kvm/svm/nested.c | 16 +++++++---------
> >  arch/x86/kvm/svm/svm.c    |  4 ++--
> >  arch/x86/kvm/svm/svm.h    |  5 +++++
> >  3 files changed, 14 insertions(+), 11 deletions(-)
> > 
> > diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
> > index ba0f11c68372..8070e20ed5a7 100644
> > --- a/arch/x86/kvm/svm/nested.c
> > +++ b/arch/x86/kvm/svm/nested.c
> > @@ -1134,7 +1134,7 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
> >  	vmcb12->control.exit_info_1       = vmcb02->control.exit_info_1;
> >  	vmcb12->control.exit_info_2       = vmcb02->control.exit_info_2;
> >  
> > -	if (vmcb12->control.exit_code != SVM_EXIT_ERR)
> > +	if (svm_is_vmrun_failure(vmcb12->control.exit_code))
> 
> This was flipped, wasn't it?

Ugh, yes.  Hrm, I'm surprised this wasn't caught by svm_nested_soft_inject_test.c.

Oof.  We should probably also extend svm_is_vmrun_failure() (in the future) to
detect any failure, e.g. VMEXIT_INVALID_PMC might be relevant soon?

> >  		nested_save_pending_event_to_vmcb12(svm, vmcb12);

^ permalink raw reply

* Re: [PATCH 4/9] KVM: SVM: Open code handling of unexpected exits in svm_invoke_exit_handler()
From: Yosry Ahmed @ 2025-11-13 23:33 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Paolo Bonzini, Vitaly Kuznetsov, K. Y. Srinivasan, Haiyang Zhang,
	Wei Liu, Dexuan Cui, kvm, linux-hyperv, linux-kernel, Jim Mattson
In-Reply-To: <20251113225621.1688428-5-seanjc@google.com>

On Thu, Nov 13, 2025 at 02:56:16PM -0800, Sean Christopherson wrote:
> Fold svm_check_exit_valid() and svm_handle_invalid_exit() into their sole
> caller, svm_invoke_exit_handler(), as having tiny single-use helpers makes
> the code unncessarily difficult to follow.  This will also allow for
> additional cleanups in svm_invoke_exit_handler().
> 
> No functional change intended.
> 
> Suggested-by: Yosry Ahmed <yosry.ahmed@linux.dev>
> Signed-off-by: Sean Christopherson <seanjc@google.com>

Reviewed-by: Yosry Ahmed <yosry.ahmed@linux.dev>

> ---
>  arch/x86/kvm/svm/svm.c | 25 ++++++++++---------------
>  1 file changed, 10 insertions(+), 15 deletions(-)
> 
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index 52b759408853..638a67ef0c37 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -3433,23 +3433,13 @@ static void dump_vmcb(struct kvm_vcpu *vcpu)
>  		sev_free_decrypted_vmsa(vcpu, save);
>  }
>  
> -static bool svm_check_exit_valid(u64 exit_code)
> -{
> -	return (exit_code < ARRAY_SIZE(svm_exit_handlers) &&
> -		svm_exit_handlers[exit_code]);
> -}
> -
> -static int svm_handle_invalid_exit(struct kvm_vcpu *vcpu, u64 exit_code)
> -{
> -	dump_vmcb(vcpu);
> -	kvm_prepare_unexpected_reason_exit(vcpu, exit_code);
> -	return 0;
> -}
> -
>  int svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 exit_code)
>  {
> -	if (!svm_check_exit_valid(exit_code))
> -		return svm_handle_invalid_exit(vcpu, exit_code);
> +	if (exit_code >= ARRAY_SIZE(svm_exit_handlers))
> +		goto unexpected_vmexit;
> +
> +	if (!svm_exit_handlers[exit_code])
> +		goto unexpected_vmexit;
>  
>  #ifdef CONFIG_MITIGATION_RETPOLINE
>  	if (exit_code == SVM_EXIT_MSR)
> @@ -3468,6 +3458,11 @@ int svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 exit_code)
>  #endif
>  #endif
>  	return svm_exit_handlers[exit_code](vcpu);
> +
> +unexpected_vmexit:
> +	dump_vmcb(vcpu);
> +	kvm_prepare_unexpected_reason_exit(vcpu, exit_code);
> +	return 0;
>  }
>  
>  static void svm_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason,
> -- 
> 2.52.0.rc1.455.g30608eb744-goog
> 

^ permalink raw reply

* Re: [PATCH 3/9] KVM: SVM: Add a helper to detect VMRUN failures
From: Yosry Ahmed @ 2025-11-13 23:30 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Paolo Bonzini, Vitaly Kuznetsov, K. Y. Srinivasan, Haiyang Zhang,
	Wei Liu, Dexuan Cui, kvm, linux-hyperv, linux-kernel, Jim Mattson
In-Reply-To: <20251113225621.1688428-4-seanjc@google.com>

On Thu, Nov 13, 2025 at 02:56:15PM -0800, Sean Christopherson wrote:
> Add a helper to detect VMRUN failures so that KVM can guard against its
> own long-standing bug, where KVM neglects to set exitcode[63:32] when
> synthesizing a nested VMFAIL_INVALID VM-Exit.  This will allow fixing
> KVM's mess of treating exitcode as two separate 32-bit values without
> breaking KVM-on-KVM when running on an older, unfixed KVM.
> 
> Cc: Jim Mattson <jmattson@google.com>
> Cc: Yosry Ahmed <yosry.ahmed@linux.dev>
> Signed-off-by: Sean Christopherson <seanjc@google.com>
> ---
>  arch/x86/kvm/svm/nested.c | 16 +++++++---------
>  arch/x86/kvm/svm/svm.c    |  4 ++--
>  arch/x86/kvm/svm/svm.h    |  5 +++++
>  3 files changed, 14 insertions(+), 11 deletions(-)
> 
> diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
> index ba0f11c68372..8070e20ed5a7 100644
> --- a/arch/x86/kvm/svm/nested.c
> +++ b/arch/x86/kvm/svm/nested.c
> @@ -1134,7 +1134,7 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
>  	vmcb12->control.exit_info_1       = vmcb02->control.exit_info_1;
>  	vmcb12->control.exit_info_2       = vmcb02->control.exit_info_2;
>  
> -	if (vmcb12->control.exit_code != SVM_EXIT_ERR)
> +	if (svm_is_vmrun_failure(vmcb12->control.exit_code))

This was flipped, wasn't it?

>  		nested_save_pending_event_to_vmcb12(svm, vmcb12);
>  
>  	if (guest_cpu_cap_has(vcpu, X86_FEATURE_NRIPS))
> @@ -1425,6 +1425,9 @@ static int nested_svm_intercept(struct vcpu_svm *svm)
>  	u32 exit_code = svm->vmcb->control.exit_code;
>  	int vmexit = NESTED_EXIT_HOST;
>  
> +	if (svm_is_vmrun_failure(exit_code))
> +		return NESTED_EXIT_DONE;
> +
>  	switch (exit_code) {
>  	case SVM_EXIT_MSR:
>  		vmexit = nested_svm_exit_handled_msr(svm);
> @@ -1432,7 +1435,7 @@ static int nested_svm_intercept(struct vcpu_svm *svm)
>  	case SVM_EXIT_IOIO:
>  		vmexit = nested_svm_intercept_ioio(svm);
>  		break;
> -	case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 0x1f: {
> +	case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 0x1f:
>  		/*
>  		 * Host-intercepted exceptions have been checked already in
>  		 * nested_svm_exit_special.  There is nothing to do here,
> @@ -1440,15 +1443,10 @@ static int nested_svm_intercept(struct vcpu_svm *svm)
>  		 */
>  		vmexit = NESTED_EXIT_DONE;
>  		break;
> -	}
> -	case SVM_EXIT_ERR: {
> -		vmexit = NESTED_EXIT_DONE;
> -		break;
> -	}
> -	default: {
> +	default:
>  		if (vmcb12_is_intercept(&svm->nested.ctl, exit_code))
>  			vmexit = NESTED_EXIT_DONE;
> -	}
> +		break;
>  	}
>  
>  	return vmexit;
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index 7ea034ee6b6c..52b759408853 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -3530,7 +3530,7 @@ static int svm_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
>  			return 1;
>  	}
>  
> -	if (svm->vmcb->control.exit_code == SVM_EXIT_ERR) {
> +	if (svm_is_vmrun_failure(svm->vmcb->control.exit_code)) {
>  		kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
>  		kvm_run->fail_entry.hardware_entry_failure_reason
>  			= svm->vmcb->control.exit_code;
> @@ -4302,7 +4302,7 @@ static __no_kcsan fastpath_t svm_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags)
>  
>  		/* Track VMRUNs that have made past consistency checking */
>  		if (svm->nested.nested_run_pending &&
> -		    svm->vmcb->control.exit_code != SVM_EXIT_ERR)
> +		    !svm_is_vmrun_failure(svm->vmcb->control.exit_code))
>                          ++vcpu->stat.nested_run;
>  
>  		svm->nested.nested_run_pending = 0;
> diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
> index 253a8dca412c..6b35925e3a33 100644
> --- a/arch/x86/kvm/svm/svm.h
> +++ b/arch/x86/kvm/svm/svm.h
> @@ -426,6 +426,11 @@ static __always_inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
>  	return container_of(vcpu, struct vcpu_svm, vcpu);
>  }
>  
> +static inline bool svm_is_vmrun_failure(u64 exit_code)
> +{
> +	return (u32)exit_code == (u32)SVM_EXIT_ERR;
> +}
> +
>  /*
>   * Only the PDPTRs are loaded on demand into the shadow MMU.  All other
>   * fields are synchronized on VM-Exit, because accessing the VMCB is cheap.
> -- 
> 2.52.0.rc1.455.g30608eb744-goog
> 

^ permalink raw reply

* Re: [PATCH 2/9] KVM: nSVM: Set exit_code_hi to -1 when synthesizing SVM_EXIT_ERR (failed VMRUN)
From: Yosry Ahmed @ 2025-11-13 23:28 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Paolo Bonzini, Vitaly Kuznetsov, K. Y. Srinivasan, Haiyang Zhang,
	Wei Liu, Dexuan Cui, kvm, linux-hyperv, linux-kernel, Jim Mattson
In-Reply-To: <20251113225621.1688428-3-seanjc@google.com>

On Thu, Nov 13, 2025 at 02:56:14PM -0800, Sean Christopherson wrote:
> Set exit_code_hi to -1u as a temporary band-aid to fix a long-standing
> (effectively since KVM's inception) bug where KVM treats the exit code as
> a 32-bit value, when in reality it's a 64-bit value.  Per the APM, offset
> 0x70 is a single 64-bit value:
> 
>   070h 63:0 EXITCODE
> 
> And a sane reading of the error values defined in "Table C-1. SVM Intercept
> Codes" is that negative values use the full 64 bits:
> 
>   –1 VMEXIT_INVALID Invalid guest state in VMCB.
>   –2 VMEXIT_BUSYBUSY bit was set in the VMSA
>   –3 VMEXIT_IDLE_REQUIREDThe sibling thread is not in an idle state
>   -4 VMEXIT_INVALID_PMC Invalid PMC state
> 
> And that interpretation is confirmed by testing on Milan and Turin (by
> setting bits in CR0[63:32] to generate VMEXIT_INVALID on VMRUN).
> 
> Furthermore, Xen has treated exitcode as a 64-bit value since HVM support
> was adding in 2006 (see Xen commit d1bd157fbc ("Big merge the HVM
> full-virtualisation abstractions.")).
> 
> Cc: Jim Mattson <jmattson@google.com>
> Cc: Yosry Ahmed <yosry.ahmed@linux.dev>
> Cc: stable@vger.kernel.org
> Signed-off-by: Sean Christopherson <seanjc@google.com>

Reviewed-by: Yosry Ahmed <yosry.ahmed@linux.dev>

> ---
>  arch/x86/kvm/svm/nested.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
> index c81005b24522..ba0f11c68372 100644
> --- a/arch/x86/kvm/svm/nested.c
> +++ b/arch/x86/kvm/svm/nested.c
> @@ -985,7 +985,7 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu)
>  	if (!nested_vmcb_check_save(vcpu) ||
>  	    !nested_vmcb_check_controls(vcpu)) {
>  		vmcb12->control.exit_code    = SVM_EXIT_ERR;
> -		vmcb12->control.exit_code_hi = 0;
> +		vmcb12->control.exit_code_hi = -1u;
>  		vmcb12->control.exit_info_1  = 0;
>  		vmcb12->control.exit_info_2  = 0;
>  		goto out;
> @@ -1018,7 +1018,7 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu)
>  	svm->soft_int_injected = false;
>  
>  	svm->vmcb->control.exit_code    = SVM_EXIT_ERR;
> -	svm->vmcb->control.exit_code_hi = 0;
> +	svm->vmcb->control.exit_code_hi = -1u;
>  	svm->vmcb->control.exit_info_1  = 0;
>  	svm->vmcb->control.exit_info_2  = 0;
>  
> -- 
> 2.52.0.rc1.455.g30608eb744-goog
> 

^ permalink raw reply

* Re: [PATCH 2/9] KVM: nSVM: Set exit_code_hi to -1 when synthesizing SVM_EXIT_ERR (failed VMRUN)
From: Yosry Ahmed @ 2025-11-13 23:17 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Paolo Bonzini, Vitaly Kuznetsov, K. Y. Srinivasan, Haiyang Zhang,
	Wei Liu, Dexuan Cui, kvm, linux-hyperv, linux-kernel, Jim Mattson
In-Reply-To: <20251113225621.1688428-3-seanjc@google.com>

On Thu, Nov 13, 2025 at 02:56:14PM -0800, Sean Christopherson wrote:
> Set exit_code_hi to -1u as a temporary band-aid to fix a long-standing
> (effectively since KVM's inception) bug where KVM treats the exit code as
> a 32-bit value, when in reality it's a 64-bit value.  Per the APM, offset
> 0x70 is a single 64-bit value:
> 
>   070h 63:0 EXITCODE
> 
> And a sane reading of the error values defined in "Table C-1. SVM Intercept
> Codes" is that negative values use the full 64 bits:
> 
>   –1 VMEXIT_INVALID Invalid guest state in VMCB.
>   –2 VMEXIT_BUSYBUSY bit was set in the VMSA
>   –3 VMEXIT_IDLE_REQUIREDThe sibling thread is not in an idle state
>   -4 VMEXIT_INVALID_PMC Invalid PMC state
> 
> And that interpretation is confirmed by testing on Milan and Turin (by
> setting bits in CR0[63:32] to generate VMEXIT_INVALID on VMRUN).
> 
> Furthermore, Xen has treated exitcode as a 64-bit value since HVM support
> was adding in 2006 (see Xen commit d1bd157fbc ("Big merge the HVM
> full-virtualisation abstractions.")).
> 
> Cc: Jim Mattson <jmattson@google.com>
> Cc: Yosry Ahmed <yosry.ahmed@linux.dev>
> Cc: stable@vger.kernel.org
> Signed-off-by: Sean Christopherson <seanjc@google.com>

Reviewed-by: Yosry Ahmed <yosry.ahmed@linux.dev>

> ---
>  arch/x86/kvm/svm/nested.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
> index c81005b24522..ba0f11c68372 100644
> --- a/arch/x86/kvm/svm/nested.c
> +++ b/arch/x86/kvm/svm/nested.c
> @@ -985,7 +985,7 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu)
>  	if (!nested_vmcb_check_save(vcpu) ||
>  	    !nested_vmcb_check_controls(vcpu)) {
>  		vmcb12->control.exit_code    = SVM_EXIT_ERR;
> -		vmcb12->control.exit_code_hi = 0;
> +		vmcb12->control.exit_code_hi = -1u;
>  		vmcb12->control.exit_info_1  = 0;
>  		vmcb12->control.exit_info_2  = 0;
>  		goto out;
> @@ -1018,7 +1018,7 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu)
>  	svm->soft_int_injected = false;
>  
>  	svm->vmcb->control.exit_code    = SVM_EXIT_ERR;
> -	svm->vmcb->control.exit_code_hi = 0;
> +	svm->vmcb->control.exit_code_hi = -1u;
>  	svm->vmcb->control.exit_info_1  = 0;
>  	svm->vmcb->control.exit_info_2  = 0;
>  
> -- 
> 2.52.0.rc1.455.g30608eb744-goog
> 

^ permalink raw reply

* Re: [PATCH 1/9] KVM: nSVM: Clear exit_code_hi in VMCB when synthesizing nested VM-Exits
From: Yosry Ahmed @ 2025-11-13 23:03 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Paolo Bonzini, Vitaly Kuznetsov, K. Y. Srinivasan, Haiyang Zhang,
	Wei Liu, Dexuan Cui, kvm, linux-hyperv, linux-kernel, Jim Mattson
In-Reply-To: <20251113225621.1688428-2-seanjc@google.com>

On Thu, Nov 13, 2025 at 02:56:13PM -0800, Sean Christopherson wrote:
> Explicitly clear exit_code_hi in the VMCB when synthesizing "normal"
> nested VM-Exits, as the full exit code is a 64-bit value (spoiler alert),
> and all exit codes for non-failing VMRUN use only bits 31:0.
> 
> Cc: Jim Mattson <jmattson@google.com>
> Cc: Yosry Ahmed <yosry.ahmed@linux.dev>
> Cc: stable@vger.kernel.org
> Signed-off-by: Sean Christopherson <seanjc@google.com>

Reviewed-by: Yosry Ahmed <yosry.ahmed@linux.dev>

> ---
>  arch/x86/kvm/svm/svm.c | 2 ++
>  arch/x86/kvm/svm/svm.h | 7 ++++---
>  2 files changed, 6 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index fc42bcdbb520..7ea034ee6b6c 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -2433,6 +2433,7 @@ static bool check_selective_cr0_intercepted(struct kvm_vcpu *vcpu,
>  
>  	if (cr0 ^ val) {
>  		svm->vmcb->control.exit_code = SVM_EXIT_CR0_SEL_WRITE;
> +		svm->vmcb->control.exit_code_hi = 0;
>  		ret = (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE);
>  	}
>  
> @@ -4608,6 +4609,7 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
>  	if (static_cpu_has(X86_FEATURE_NRIPS))
>  		vmcb->control.next_rip  = info->next_rip;
>  	vmcb->control.exit_code = icpt_info.exit_code;
> +	vmcb->control.exit_code_hi = 0;
>  	vmexit = nested_svm_exit_handled(svm);
>  
>  	ret = (vmexit == NESTED_EXIT_DONE) ? X86EMUL_INTERCEPTED
> diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
> index c2acaa49ee1c..253a8dca412c 100644
> --- a/arch/x86/kvm/svm/svm.h
> +++ b/arch/x86/kvm/svm/svm.h
> @@ -763,9 +763,10 @@ int nested_svm_vmexit(struct vcpu_svm *svm);
>  
>  static inline int nested_svm_simple_vmexit(struct vcpu_svm *svm, u32 exit_code)
>  {
> -	svm->vmcb->control.exit_code   = exit_code;
> -	svm->vmcb->control.exit_info_1 = 0;
> -	svm->vmcb->control.exit_info_2 = 0;
> +	svm->vmcb->control.exit_code	= exit_code;
> +	svm->vmcb->control.exit_code_hi	= 0;
> +	svm->vmcb->control.exit_info_1	= 0;
> +	svm->vmcb->control.exit_info_2	= 0;
>  	return nested_svm_vmexit(svm);
>  }
>  
> -- 
> 2.52.0.rc1.455.g30608eb744-goog
> 

^ permalink raw reply

* [PATCH 9/9] KVM: SVM: Harden exit_code against being used in Spectre-like attacks
From: Sean Christopherson @ 2025-11-13 22:56 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini, Vitaly Kuznetsov,
	K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui
  Cc: kvm, linux-hyperv, linux-kernel, Jim Mattson, Yosry Ahmed
In-Reply-To: <20251113225621.1688428-1-seanjc@google.com>

Explicitly clamp the exit code used to index KVM's exit handlers to guard
against Spectre-like attacks, mainly to provide consistency between VMX
and SVM (VMX was given the same treatment by commit c926f2f7230b ("KVM:
x86: Protect exit_reason from being used in Spectre-v1/L1TF attacks").

For normal VMs, it's _extremely_ unlikely the exit code could be used to
exploit a speculation vulnerability, as the exit code is set by hardware
and unexpected/unknown exit codes should be quite well bounded (as is/was
the case with VMX).  But with SEV-ES+, the exit code is guest-controlled
as it comes from the GHCB, not from hardware, i.e. an attack from the
guest is at least somewhat plausible.

Irrespective of SEV-ES+, hardening KVM is easy and inexpensive, and such
an attack is theoretically possible.

Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 arch/x86/kvm/svm/svm.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 85bc99f93275..308c70b6924e 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -3467,6 +3467,7 @@ int svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 __exit_code)
 	if (exit_code >= ARRAY_SIZE(svm_exit_handlers))
 		goto unexpected_vmexit;
 
+	exit_code = array_index_nospec(exit_code, ARRAY_SIZE(svm_exit_handlers));
 	if (!svm_exit_handlers[exit_code])
 		goto unexpected_vmexit;
 
-- 
2.52.0.rc1.455.g30608eb744-goog


^ permalink raw reply related

* [PATCH 8/9] KVM: SVM: Limit incorrect check on SVM_EXIT_ERR to running as a VM
From: Sean Christopherson @ 2025-11-13 22:56 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini, Vitaly Kuznetsov,
	K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui
  Cc: kvm, linux-hyperv, linux-kernel, Jim Mattson, Yosry Ahmed
In-Reply-To: <20251113225621.1688428-1-seanjc@google.com>

Limit KVM's incorrect check for VMXEXIT_INVALID, a.k.a. SVM_EXIT_ERR, to
running as a VM, as detected by X86_FEATURE_HYPERVISOR.  The exit_code and
all failure codes, e.g. VMXEXIT_INVALID, are 64-bit values, and so checking
only bits 31:0 could result in false positives when running on non-broken
hardware, e.g. in the extremely unlikely scenario exit code 0xffffffffull
is ever generated by hardware.

Keep the 32-bit check to play nice with running on broken KVM (for years,
KVM has not set bits 63:32 when synthesizing nested SVM VM-Exits).

Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 arch/x86/kvm/svm/svm.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 31ee4f65dcc2..801dcfc64d0b 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -427,7 +427,10 @@ static __always_inline struct vcpu_svm *to_svm(struct kvm_vcpu *vcpu)
 
 static inline bool svm_is_vmrun_failure(u64 exit_code)
 {
-	return (u32)exit_code == (u32)SVM_EXIT_ERR;
+	if (cpu_feature_enabled(X86_FEATURE_HYPERVISOR))
+		return (u32)exit_code == (u32)SVM_EXIT_ERR;
+
+	return exit_code == SVM_EXIT_ERR;
 }
 
 /*
-- 
2.52.0.rc1.455.g30608eb744-goog


^ permalink raw reply related

* [PATCH 7/9] KVM: SVM: Treat exit_code as an unsigned 64-bit value through all of KVM
From: Sean Christopherson @ 2025-11-13 22:56 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini, Vitaly Kuznetsov,
	K. Y. Srinivasan, Haiyang Zhang, Wei Liu, Dexuan Cui
  Cc: kvm, linux-hyperv, linux-kernel, Jim Mattson, Yosry Ahmed
In-Reply-To: <20251113225621.1688428-1-seanjc@google.com>

Fix KVM's long-standing buggy handling of SVM's exit_code as a 32-bit
value.  Per the APM and Xen commit d1bd157fbc ("Big merge the HVM
full-virtualisation abstractions.") (which is arguably more trustworthy
than KVM), offset 0x70 is a single 64-bit value:

  070h 63:0 EXITCODE

Track exit_code as a single u64 to prevent reintroducing bugs where KVM
neglects to correctly set bits 63:32.

Fixes: 6aa8b732ca01 ("[PATCH] kvm: userspace interface")
Cc: Jim Mattson <jmattson@google.com>
Cc: Yosry Ahmed <yosry.ahmed@linux.dev>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 arch/x86/include/asm/svm.h      |  3 +--
 arch/x86/include/uapi/asm/svm.h | 32 ++++++++++++++---------------
 arch/x86/kvm/svm/hyperv.c       |  1 -
 arch/x86/kvm/svm/nested.c       | 13 +++---------
 arch/x86/kvm/svm/sev.c          | 36 +++++++++++----------------------
 arch/x86/kvm/svm/svm.c          |  7 ++-----
 arch/x86/kvm/svm/svm.h          |  4 +---
 arch/x86/kvm/trace.h            |  2 +-
 include/hyperv/hvgdk.h          |  2 +-
 9 files changed, 37 insertions(+), 63 deletions(-)

diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index e69b6d0dedcf..66b22cffedfc 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -136,8 +136,7 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
 	u32 int_vector;
 	u32 int_state;
 	u8 reserved_3[4];
-	u32 exit_code;
-	u32 exit_code_hi;
+	u64 exit_code;
 	u64 exit_info_1;
 	u64 exit_info_2;
 	u32 exit_int_info;
diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h
index 650e3256ea7d..010a45c9f614 100644
--- a/arch/x86/include/uapi/asm/svm.h
+++ b/arch/x86/include/uapi/asm/svm.h
@@ -103,38 +103,38 @@
 #define SVM_EXIT_VMGEXIT       0x403
 
 /* SEV-ES software-defined VMGEXIT events */
-#define SVM_VMGEXIT_MMIO_READ			0x80000001
-#define SVM_VMGEXIT_MMIO_WRITE			0x80000002
-#define SVM_VMGEXIT_NMI_COMPLETE		0x80000003
-#define SVM_VMGEXIT_AP_HLT_LOOP			0x80000004
-#define SVM_VMGEXIT_AP_JUMP_TABLE		0x80000005
+#define SVM_VMGEXIT_MMIO_READ			0x80000001ull
+#define SVM_VMGEXIT_MMIO_WRITE			0x80000002ull
+#define SVM_VMGEXIT_NMI_COMPLETE		0x80000003ull
+#define SVM_VMGEXIT_AP_HLT_LOOP			0x80000004ull
+#define SVM_VMGEXIT_AP_JUMP_TABLE		0x80000005ull
 #define SVM_VMGEXIT_SET_AP_JUMP_TABLE		0
 #define SVM_VMGEXIT_GET_AP_JUMP_TABLE		1
-#define SVM_VMGEXIT_PSC				0x80000010
-#define SVM_VMGEXIT_GUEST_REQUEST		0x80000011
-#define SVM_VMGEXIT_EXT_GUEST_REQUEST		0x80000012
-#define SVM_VMGEXIT_AP_CREATION			0x80000013
+#define SVM_VMGEXIT_PSC				0x80000010ull
+#define SVM_VMGEXIT_GUEST_REQUEST		0x80000011ull
+#define SVM_VMGEXIT_EXT_GUEST_REQUEST		0x80000012ull
+#define SVM_VMGEXIT_AP_CREATION			0x80000013ull
 #define SVM_VMGEXIT_AP_CREATE_ON_INIT		0
 #define SVM_VMGEXIT_AP_CREATE			1
 #define SVM_VMGEXIT_AP_DESTROY			2
-#define SVM_VMGEXIT_SNP_RUN_VMPL		0x80000018
-#define SVM_VMGEXIT_SAVIC			0x8000001a
+#define SVM_VMGEXIT_SNP_RUN_VMPL		0x80000018ull
+#define SVM_VMGEXIT_SAVIC			0x8000001aull
 #define SVM_VMGEXIT_SAVIC_REGISTER_GPA		0
 #define SVM_VMGEXIT_SAVIC_UNREGISTER_GPA	1
 #define SVM_VMGEXIT_SAVIC_SELF_GPA		~0ULL
-#define SVM_VMGEXIT_HV_FEATURES			0x8000fffd
-#define SVM_VMGEXIT_TERM_REQUEST		0x8000fffe
+#define SVM_VMGEXIT_HV_FEATURES			0x8000fffdull
+#define SVM_VMGEXIT_TERM_REQUEST		0x8000fffeull
 #define SVM_VMGEXIT_TERM_REASON(reason_set, reason_code)	\
 	/* SW_EXITINFO1[3:0] */					\
 	(((((u64)reason_set) & 0xf)) |				\
 	/* SW_EXITINFO1[11:4] */				\
 	((((u64)reason_code) & 0xff) << 4))
-#define SVM_VMGEXIT_UNSUPPORTED_EVENT		0x8000ffff
+#define SVM_VMGEXIT_UNSUPPORTED_EVENT		0x8000ffffull
 
 /* Exit code reserved for hypervisor/software use */
-#define SVM_EXIT_SW				0xf0000000
+#define SVM_EXIT_SW				0xf0000000ull
 
-#define SVM_EXIT_ERR           -1
+#define SVM_EXIT_ERR           -1ull
 
 #define SVM_EXIT_REASONS \
 	{ SVM_EXIT_READ_CR0,    "read_cr0" }, \
diff --git a/arch/x86/kvm/svm/hyperv.c b/arch/x86/kvm/svm/hyperv.c
index 088f6429b24c..3ec580d687f5 100644
--- a/arch/x86/kvm/svm/hyperv.c
+++ b/arch/x86/kvm/svm/hyperv.c
@@ -11,7 +11,6 @@ void svm_hv_inject_synthetic_vmexit_post_tlb_flush(struct kvm_vcpu *vcpu)
 	struct vcpu_svm *svm = to_svm(vcpu);
 
 	svm->vmcb->control.exit_code = HV_SVM_EXITCODE_ENL;
-	svm->vmcb->control.exit_code_hi = 0;
 	svm->vmcb->control.exit_info_1 = HV_SVM_ENL_EXITCODE_TRAP_AFTER_FLUSH;
 	svm->vmcb->control.exit_info_2 = 0;
 	nested_svm_vmexit(svm);
diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c
index 8070e20ed5a7..89120245cd22 100644
--- a/arch/x86/kvm/svm/nested.c
+++ b/arch/x86/kvm/svm/nested.c
@@ -45,7 +45,6 @@ static void nested_svm_inject_npf_exit(struct kvm_vcpu *vcpu,
 		 * correctly fill in the high bits of exit_info_1.
 		 */
 		vmcb->control.exit_code = SVM_EXIT_NPF;
-		vmcb->control.exit_code_hi = 0;
 		vmcb->control.exit_info_1 = (1ULL << 32);
 		vmcb->control.exit_info_2 = fault->address;
 	}
@@ -421,7 +420,6 @@ void __nested_copy_vmcb_control_to_cache(struct kvm_vcpu *vcpu,
 	to->int_vector          = from->int_vector;
 	to->int_state           = from->int_state;
 	to->exit_code           = from->exit_code;
-	to->exit_code_hi        = from->exit_code_hi;
 	to->exit_info_1         = from->exit_info_1;
 	to->exit_info_2         = from->exit_info_2;
 	to->exit_int_info       = from->exit_int_info;
@@ -727,8 +725,8 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm,
 	enter_guest_mode(vcpu);
 
 	/*
-	 * Filled at exit: exit_code, exit_code_hi, exit_info_1, exit_info_2,
-	 * exit_int_info, exit_int_info_err, next_rip, insn_len, insn_bytes.
+	 * Filled at exit: exit_code, exit_info_1, exit_info_2, exit_int_info,
+	 * exit_int_info_err, next_rip, insn_len, insn_bytes.
 	 */
 
 	if (guest_cpu_cap_has(vcpu, X86_FEATURE_VGIF) &&
@@ -985,7 +983,6 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu)
 	if (!nested_vmcb_check_save(vcpu) ||
 	    !nested_vmcb_check_controls(vcpu)) {
 		vmcb12->control.exit_code    = SVM_EXIT_ERR;
-		vmcb12->control.exit_code_hi = -1u;
 		vmcb12->control.exit_info_1  = 0;
 		vmcb12->control.exit_info_2  = 0;
 		goto out;
@@ -1018,7 +1015,6 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu)
 	svm->soft_int_injected = false;
 
 	svm->vmcb->control.exit_code    = SVM_EXIT_ERR;
-	svm->vmcb->control.exit_code_hi = -1u;
 	svm->vmcb->control.exit_info_1  = 0;
 	svm->vmcb->control.exit_info_2  = 0;
 
@@ -1130,7 +1126,6 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
 
 	vmcb12->control.int_state         = vmcb02->control.int_state;
 	vmcb12->control.exit_code         = vmcb02->control.exit_code;
-	vmcb12->control.exit_code_hi      = vmcb02->control.exit_code_hi;
 	vmcb12->control.exit_info_1       = vmcb02->control.exit_info_1;
 	vmcb12->control.exit_info_2       = vmcb02->control.exit_info_2;
 
@@ -1422,7 +1417,7 @@ static int nested_svm_intercept_ioio(struct vcpu_svm *svm)
 
 static int nested_svm_intercept(struct vcpu_svm *svm)
 {
-	u32 exit_code = svm->vmcb->control.exit_code;
+	u64 exit_code = svm->vmcb->control.exit_code;
 	int vmexit = NESTED_EXIT_HOST;
 
 	if (svm_is_vmrun_failure(exit_code))
@@ -1494,7 +1489,6 @@ static void nested_svm_inject_exception_vmexit(struct kvm_vcpu *vcpu)
 	struct vmcb *vmcb = svm->vmcb;
 
 	vmcb->control.exit_code = SVM_EXIT_EXCP_BASE + ex->vector;
-	vmcb->control.exit_code_hi = 0;
 
 	if (ex->has_error_code)
 		vmcb->control.exit_info_1 = ex->error_code;
@@ -1669,7 +1663,6 @@ static void nested_copy_vmcb_cache_to_control(struct vmcb_control_area *dst,
 	dst->int_vector           = from->int_vector;
 	dst->int_state            = from->int_state;
 	dst->exit_code            = from->exit_code;
-	dst->exit_code_hi         = from->exit_code_hi;
 	dst->exit_info_1          = from->exit_info_1;
 	dst->exit_info_2          = from->exit_info_2;
 	dst->exit_int_info        = from->exit_int_info;
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 0835c664fbfd..5aedd07194aa 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -3264,11 +3264,6 @@ void sev_free_vcpu(struct kvm_vcpu *vcpu)
 		kvfree(svm->sev_es.ghcb_sa);
 }
 
-static u64 kvm_get_cached_sw_exit_code(struct vmcb_control_area *control)
-{
-	return (((u64)control->exit_code_hi) << 32) | control->exit_code;
-}
-
 static void dump_ghcb(struct vcpu_svm *svm)
 {
 	struct vmcb_control_area *control = &svm->vmcb->control;
@@ -3290,7 +3285,7 @@ static void dump_ghcb(struct vcpu_svm *svm)
 	 */
 	pr_err("GHCB (GPA=%016llx) snapshot:\n", svm->vmcb->control.ghcb_gpa);
 	pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_code",
-	       kvm_get_cached_sw_exit_code(control), kvm_ghcb_sw_exit_code_is_valid(svm));
+	       control->exit_code, kvm_ghcb_sw_exit_code_is_valid(svm));
 	pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_info_1",
 	       control->exit_info_1, kvm_ghcb_sw_exit_info_1_is_valid(svm));
 	pr_err("%-20s%016llx is_valid: %u\n", "sw_exit_info_2",
@@ -3324,7 +3319,6 @@ static void sev_es_sync_from_ghcb(struct vcpu_svm *svm)
 	struct vmcb_control_area *control = &svm->vmcb->control;
 	struct kvm_vcpu *vcpu = &svm->vcpu;
 	struct ghcb *ghcb = svm->sev_es.ghcb;
-	u64 exit_code;
 
 	/*
 	 * The GHCB protocol so far allows for the following data
@@ -3358,9 +3352,7 @@ static void sev_es_sync_from_ghcb(struct vcpu_svm *svm)
 		__kvm_emulate_msr_write(vcpu, MSR_IA32_XSS, kvm_ghcb_get_xss(svm));
 
 	/* Copy the GHCB exit information into the VMCB fields */
-	exit_code = kvm_ghcb_get_sw_exit_code(svm);
-	control->exit_code = lower_32_bits(exit_code);
-	control->exit_code_hi = upper_32_bits(exit_code);
+	control->exit_code = kvm_ghcb_get_sw_exit_code(svm);
 	control->exit_info_1 = kvm_ghcb_get_sw_exit_info_1(svm);
 	control->exit_info_2 = kvm_ghcb_get_sw_exit_info_2(svm);
 	svm->sev_es.sw_scratch = kvm_ghcb_get_sw_scratch_if_valid(svm);
@@ -3373,15 +3365,8 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
 {
 	struct vmcb_control_area *control = &svm->vmcb->control;
 	struct kvm_vcpu *vcpu = &svm->vcpu;
-	u64 exit_code;
 	u64 reason;
 
-	/*
-	 * Retrieve the exit code now even though it may not be marked valid
-	 * as it could help with debugging.
-	 */
-	exit_code = kvm_get_cached_sw_exit_code(control);
-
 	/* Only GHCB Usage code 0 is supported */
 	if (svm->sev_es.ghcb->ghcb_usage) {
 		reason = GHCB_ERR_INVALID_USAGE;
@@ -3395,7 +3380,7 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
 	    !kvm_ghcb_sw_exit_info_2_is_valid(svm))
 		goto vmgexit_err;
 
-	switch (exit_code) {
+	switch (control->exit_code) {
 	case SVM_EXIT_READ_DR7:
 		break;
 	case SVM_EXIT_WRITE_DR7:
@@ -3496,15 +3481,19 @@ static int sev_es_validate_vmgexit(struct vcpu_svm *svm)
 	return 0;
 
 vmgexit_err:
+	/*
+	 * Print the exit code even though it may not be marked valid as it
+	 * could help with debugging.
+	 */
 	if (reason == GHCB_ERR_INVALID_USAGE) {
 		vcpu_unimpl(vcpu, "vmgexit: ghcb usage %#x is not valid\n",
 			    svm->sev_es.ghcb->ghcb_usage);
 	} else if (reason == GHCB_ERR_INVALID_EVENT) {
 		vcpu_unimpl(vcpu, "vmgexit: exit code %#llx is not valid\n",
-			    exit_code);
+			    control->exit_code);
 	} else {
 		vcpu_unimpl(vcpu, "vmgexit: exit code %#llx input is not valid\n",
-			    exit_code);
+			    control->exit_code);
 		dump_ghcb(svm);
 	}
 
@@ -4343,7 +4332,7 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
 	struct vmcb_control_area *control = &svm->vmcb->control;
-	u64 ghcb_gpa, exit_code;
+	u64 ghcb_gpa;
 	int ret;
 
 	/* Validate the GHCB */
@@ -4385,8 +4374,7 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
 
 	svm_vmgexit_success(svm, 0);
 
-	exit_code = kvm_get_cached_sw_exit_code(control);
-	switch (exit_code) {
+	switch (control->exit_code) {
 	case SVM_VMGEXIT_MMIO_READ:
 		ret = setup_vmgexit_scratch(svm, true, control->exit_info_2);
 		if (ret)
@@ -4478,7 +4466,7 @@ int sev_handle_vmgexit(struct kvm_vcpu *vcpu)
 		ret = -EINVAL;
 		break;
 	default:
-		ret = svm_invoke_exit_handler(vcpu, exit_code);
+		ret = svm_invoke_exit_handler(vcpu, control->exit_code);
 	}
 
 	return ret;
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 3b05476296d0..85bc99f93275 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -2433,7 +2433,6 @@ static bool check_selective_cr0_intercepted(struct kvm_vcpu *vcpu,
 
 	if (cr0 ^ val) {
 		svm->vmcb->control.exit_code = SVM_EXIT_CR0_SEL_WRITE;
-		svm->vmcb->control.exit_code_hi = 0;
 		ret = (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE);
 	}
 
@@ -3265,7 +3264,7 @@ static void dump_vmcb(struct kvm_vcpu *vcpu)
 	pr_err("%-20s%08x\n", "int_ctl:", control->int_ctl);
 	pr_err("%-20s%08x\n", "int_vector:", control->int_vector);
 	pr_err("%-20s%08x\n", "int_state:", control->int_state);
-	pr_err("%-20s%08x\n", "exit_code:", control->exit_code);
+	pr_err("%-20s%016llx\n", "exit_code:", control->exit_code);
 	pr_err("%-20s%016llx\n", "exit_info1:", control->exit_info_1);
 	pr_err("%-20s%016llx\n", "exit_info2:", control->exit_info_2);
 	pr_err("%-20s%08x\n", "exit_int_info:", control->exit_int_info);
@@ -3515,7 +3514,6 @@ static int svm_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
 	struct kvm_run *kvm_run = vcpu->run;
-	u32 exit_code = svm->vmcb->control.exit_code;
 
 	/* SEV-ES guests must use the CR write traps to track CR registers. */
 	if (!sev_es_guest(vcpu->kvm)) {
@@ -3551,7 +3549,7 @@ static int svm_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
 	if (exit_fastpath != EXIT_FASTPATH_NONE)
 		return 1;
 
-	return svm_invoke_exit_handler(vcpu, exit_code);
+	return svm_invoke_exit_handler(vcpu, svm->vmcb->control.exit_code);
 }
 
 static int pre_svm_run(struct kvm_vcpu *vcpu)
@@ -4618,7 +4616,6 @@ static int svm_check_intercept(struct kvm_vcpu *vcpu,
 	if (static_cpu_has(X86_FEATURE_NRIPS))
 		vmcb->control.next_rip  = info->next_rip;
 	vmcb->control.exit_code = icpt_info.exit_code;
-	vmcb->control.exit_code_hi = 0;
 	vmexit = nested_svm_exit_handled(svm);
 
 	ret = (vmexit == NESTED_EXIT_DONE) ? X86EMUL_INTERCEPTED
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 6b35925e3a33..31ee4f65dcc2 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -162,8 +162,7 @@ struct vmcb_ctrl_area_cached {
 	u32 int_ctl;
 	u32 int_vector;
 	u32 int_state;
-	u32 exit_code;
-	u32 exit_code_hi;
+	u64 exit_code;
 	u64 exit_info_1;
 	u64 exit_info_2;
 	u32 exit_int_info;
@@ -769,7 +768,6 @@ int nested_svm_vmexit(struct vcpu_svm *svm);
 static inline int nested_svm_simple_vmexit(struct vcpu_svm *svm, u32 exit_code)
 {
 	svm->vmcb->control.exit_code	= exit_code;
-	svm->vmcb->control.exit_code_hi	= 0;
 	svm->vmcb->control.exit_info_1	= 0;
 	svm->vmcb->control.exit_info_2	= 0;
 	return nested_svm_vmexit(svm);
diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h
index e79bc9cb7162..4c7a5cd10990 100644
--- a/arch/x86/kvm/trace.h
+++ b/arch/x86/kvm/trace.h
@@ -781,7 +781,7 @@ TRACE_EVENT_KVM_EXIT(kvm_nested_vmexit);
  * Tracepoint for #VMEXIT reinjected to the guest
  */
 TRACE_EVENT(kvm_nested_vmexit_inject,
-	    TP_PROTO(__u32 exit_code,
+	    TP_PROTO(__u64 exit_code,
 		     __u64 exit_info1, __u64 exit_info2,
 		     __u32 exit_int_info, __u32 exit_int_info_err, __u32 isa),
 	    TP_ARGS(exit_code, exit_info1, exit_info2,
diff --git a/include/hyperv/hvgdk.h b/include/hyperv/hvgdk.h
index dd6d4939ea29..56b695873a72 100644
--- a/include/hyperv/hvgdk.h
+++ b/include/hyperv/hvgdk.h
@@ -281,7 +281,7 @@ struct hv_vmcb_enlightenments {
 #define HV_VMCB_NESTED_ENLIGHTENMENTS		31
 
 /* Synthetic VM-Exit */
-#define HV_SVM_EXITCODE_ENL			0xf0000000
+#define HV_SVM_EXITCODE_ENL			0xf0000000u
 #define HV_SVM_ENL_EXITCODE_TRAP_AFTER_FLUSH	(1)
 
 /* VM_PARTITION_ASSIST_PAGE */
-- 
2.52.0.rc1.455.g30608eb744-goog


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox