https://github.com/VirtualBox/virtualbox/commit/280303b3f03d7087b9c955088a3cf499414f6ec1

From 280303b3f03d7087b9c955088a3cf499414f6ec1 Mon Sep 17 00:00:00 2001
From: Vadim Galitsyn <vadim.galitsyn@oracle.com>
Date: Tue, 17 Feb 2026 15:00:09 +0000
Subject: [PATCH] Linux host: Introduce initial support for kernel 6.19
 bugref:11038.

svn:sync-xref-src-repo-rev: r172809
--- a/vboxdrv/linux/SUPDrv-linux.c
+++ b/vboxdrv/linux/SUPDrv-linux.c
@@ -190,6 +190,12 @@ static bool                 g_fEnabledHwvirtUsingKvm;
 static int                  (*g_pfnKvmEnableVirtualization)(void);
 /** Function pointer to kvm_disable_virtualization(). */
 static void                 (*g_pfnKvmDisableVirtualization)(void);
+# if RTLNX_VER_MIN(6,19,0)
+/** Function pointer to cr4_update_irqsoff(). */
+static void                 (*g_pfnCr4UpdateIrqsoff)(unsigned long set, unsigned long clear);
+/** Function pointer to cr4_read_shadow(). */
+static unsigned long        (*g_pfnCr4ReadShadow)(void);
+# endif
 /** Pointer to the KVM hardware specific module. */
 struct module               *g_pKvmHwvirtModule;
 #endif
@@ -395,6 +401,28 @@ static int supdrvLinuxInitKvmSymbols(void)
         void *pfnDisable = __symbol_get("kvm_disable_virtualization");
         if (pfnDisable)
         {
+# if RTLNX_VER_MIN(6,19,0)
+            void *pfnCr4UpdateIrqsoff = __symbol_get("cr4_update_irqsoff");
+            void *pfnRr4ReadShadow = __symbol_get("cr4_read_shadow");
+
+            if (   pfnCr4UpdateIrqsoff
+                && pfnRr4ReadShadow)
+            {
+                g_pfnCr4UpdateIrqsoff   = pfnCr4UpdateIrqsoff;
+                g_pfnCr4ReadShadow      = pfnRr4ReadShadow;
+
+                printk(KERN_INFO "vboxdrv: Found extra KVM hardware-virtualization symbols\n");
+            }
+            else
+            {
+                printk(KERN_WARNING "vboxdrv: Failed to find extra KVM hardware-virtualization symbols\n");
+
+                if (pfnCr4UpdateIrqsoff)
+                    symbol_put_addr(pfnCr4UpdateIrqsoff);
+                if (pfnRr4ReadShadow)
+                    symbol_put_addr(pfnRr4ReadShadow);
+            }
+#endif
             /*
              * Try to obtain a reference to kvm_intel/kvm_amd module in addition to the
              * reference to the kvm module. If we fail, we will not try to use KVM for
@@ -479,6 +507,18 @@ static void supdrvLinuxTermKvmSymbols(void)
         symbol_put_addr(g_pfnKvmDisableVirtualization);
         g_pfnKvmDisableVirtualization = NULL;
     }
+# if RTLNX_VER_MIN(6,19,0)
+    if (g_pfnCr4UpdateIrqsoff)
+    {
+        symbol_put_addr(g_pfnCr4UpdateIrqsoff);
+        g_pfnCr4UpdateIrqsoff = NULL;
+    }
+    if (g_pfnCr4ReadShadow)
+    {
+        symbol_put_addr(g_pfnCr4ReadShadow);
+        g_pfnCr4ReadShadow = NULL;
+    }
+#endif
     if (g_pKvmHwvirtModule)
     {
         module_put(g_pKvmHwvirtModule);
@@ -1159,6 +1199,35 @@ SUPR0DECL(int) SUPDrvLinuxLdrDeregisterWrappedModule(PCSUPLDRWRAPPEDMODULE pWrap
 }
 EXPORT_SYMBOL(SUPDrvLinuxLdrDeregisterWrappedModule);
 
+/**
+ * Wrapper function for cr4_update_irqsoff() which was
+ * exported only for KVM starting from kernel 6.19.
+ */
+static void supdrvLinux_cr4_update_irqsoff(unsigned long set, unsigned long clear)
+{
+#if RTLNX_VER_MIN(6,19,0) && defined(SUPDRV_LINUX_HAS_KVM_HWVIRT_API)
+    if (g_pfnCr4UpdateIrqsoff)
+        g_pfnCr4UpdateIrqsoff(set, clear);
+#else
+    cr4_update_irqsoff(set, clear);
+#endif
+}
+
+/**
+ * Wrapper function for supdrvLinux_cr4_read_shadow() which was
+ * exported only for KVM starting from kernel 6.19.
+ */
+static unsigned long supdrvLinux_cr4_read_shadow(void)
+{
+    unsigned long cr4 = 0;
+#if RTLNX_VER_MIN(6,19,0) && defined(SUPDRV_LINUX_HAS_KVM_HWVIRT_API)
+    if (g_pfnCr4ReadShadow)
+        cr4 = g_pfnCr4ReadShadow();
+#else
+    cr4 = cr4_read_shadow();
+#endif
+    return cr4;
+}
 
 #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
 RTCCUINTREG VBOXCALL supdrvOSChangeCR4(RTCCUINTREG fOrMask, RTCCUINTREG fAndMask)
@@ -1166,10 +1235,10 @@ RTCCUINTREG VBOXCALL supdrvOSChangeCR4(RTCCUINTREG fOrMask, RTCCUINTREG fAndMask
 # if RTLNX_VER_MIN(5,8,0)
     unsigned long fSavedFlags;
     local_irq_save(fSavedFlags);
-    RTCCUINTREG const uOld = cr4_read_shadow();
-    cr4_update_irqsoff(fOrMask, ~fAndMask); /* Same as this function, only it is not returning the old value. */
-    AssertMsg(cr4_read_shadow() == ((uOld & fAndMask) | fOrMask),
-              ("fOrMask=%#RTreg fAndMask=%#RTreg uOld=%#RTreg; new cr4=%#llx\n", fOrMask, fAndMask, uOld, cr4_read_shadow()));
+    RTCCUINTREG const uOld = supdrvLinux_cr4_read_shadow();
+    supdrvLinux_cr4_update_irqsoff(fOrMask, ~fAndMask); /* Same as this function, only it is not returning the old value. */
+    AssertMsg(supdrvLinux_cr4_read_shadow() == ((uOld & fAndMask) | fOrMask),
+              ("fOrMask=%#RTreg fAndMask=%#RTreg uOld=%#RTreg; new cr4=%#llx\n", fOrMask, fAndMask, uOld, supdrvLinux_cr4_read_shadow()));
     local_irq_restore(fSavedFlags);
 # else
 #  if RTLNX_VER_MIN(3,20,0)
--- a/vboxdrv/r0drv/linux/initterm-r0drv-linux.c
+++ b/vboxdrv/r0drv/linux/initterm-r0drv-linux.c
@@ -60,6 +60,11 @@ static DECLARE_TASK_QUEUE(g_rtR0LnxWorkQueue);
  * This is a special mm structure used to manage the kernel address space. */
 struct mm_struct *g_pLnxInitMm = NULL;
 
+#if RTLNX_VER_MIN(6,19,0)
+/** Pointer to __flush_tlb_all kernel symbol. */
+void (*g_pfnLinuxFlushTlbAll)(void);
+#endif
+
 
 /**
  * Pushes an item onto the IPRT work queue.
@@ -136,6 +141,11 @@ DECLHIDDEN(int) rtR0InitNative(void)
             printk("rtR0InitNative: g_pLnxInitMm=%p\n", g_pLnxInitMm);
 
             RTR0DbgKrnlInfoRelease(hKrnlInfo);
+# if RTLNX_VER_MIN(6,19,0)
+            g_pfnLinuxFlushTlbAll = __symbol_get("__flush_tlb_all");
+            if (!RT_VALID_PTR(g_pfnLinuxFlushTlbAll))
+                printk("rtR0InitNative: can't load __flush_tlb_all\n");
+# endif
         }
         else
             printk("rtR0InitNative: RTR0DbgKrnlInfoOpen failed: %d\n", rc);
@@ -151,6 +161,12 @@ DECLHIDDEN(void) rtR0TermNative(void)
 {
     IPRT_LINUX_SAVE_EFL_AC();
 
+# if RTLNX_VER_MIN(6,19,0)
+    if (RT_VALID_PTR(g_pfnLinuxFlushTlbAll))
+        symbol_put_addr(g_pfnLinuxFlushTlbAll);
+    g_pfnLinuxFlushTlbAll = NULL;
+#endif
+
     rtR0LnxWorkqueueFlush();
 #if RTLNX_VER_MIN(2,5,41)
     destroy_workqueue(g_prtR0LnxWorkQueue);
--- a/vboxdrv/r0drv/linux/memobj-r0drv-linux.c
+++ b/vboxdrv/r0drv/linux/memobj-r0drv-linux.c
@@ -181,7 +181,7 @@ static const struct
 *   Internal Functions                                                                                                           *
 *********************************************************************************************************************************/
 static void rtR0MemObjLinuxFreePages(PRTR0MEMOBJLNX pMemLnx);
-
+static void rtR0MemObjLinuxFlushTlbAll(void);
 
 
 /**
@@ -2245,6 +2245,15 @@ DECLHIDDEN(int) rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ p
     return rc;
 }
 
+static void rtR0MemObjLinuxFlushTlbAll(void)
+{
+#if RTLNX_VER_MIN(6,19,0)
+    if (RT_LIKELY(RT_VALID_PTR(g_pfnLinuxFlushTlbAll)))
+        g_pfnLinuxFlushTlbAll();
+#else
+    __flush_tlb_all();
+#endif
+}
 
 DECLHIDDEN(int) rtR0MemObjNativeProtect(PRTR0MEMOBJINTERNAL pMem, size_t offSub, size_t cbSub, uint32_t fProt)
 {
@@ -2265,7 +2274,7 @@ DECLHIDDEN(int) rtR0MemObjNativeProtect(PRTR0MEMOBJINTERNAL pMem, size_t offSub,
             set_pte(papPtes[i], mk_pte(pMemLnx->apPages[i], fPg));
         }
         preempt_disable();
-        __flush_tlb_all();
+        rtR0MemObjLinuxFlushTlbAll();
         preempt_enable();
         return VINF_SUCCESS;
     }
@@ -2311,7 +2320,7 @@ DECLHIDDEN(int) rtR0MemObjNativeProtect(PRTR0MEMOBJINTERNAL pMem, size_t offSub,
             flush_icache_range((uintptr_t)pMemLnx->Core.pv + offSub, cbSub);
 #  if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) /* flush_tlb_kernel_range is not exported, but __flush_tlb_all is. */
         preempt_disable();
-        __flush_tlb_all();
+        rtR0MemObjLinuxFlushTlbAll();
         preempt_enable();
 #  else
         flush_tlb_kernel_range((uintptr_t)pMemLnx->Core.pv + offSub, cbSub);
--- a/vboxdrv/r0drv/linux/the-linux-kernel.h
+++ b/vboxdrv/r0drv/linux/the-linux-kernel.h
@@ -512,6 +512,9 @@ RTDECL(struct page *) rtR0MemObjLinuxVirtToPage(void *pv);
 
 
 extern struct mm_struct *g_pLnxInitMm;
+#if RTLNX_VER_MIN(6,19,0)
+extern void (*g_pfnLinuxFlushTlbAll)(void);
+#endif
 
 
 #endif /* !IPRT_INCLUDED_SRC_r0drv_linux_the_linux_kernel_h */
--- a/vboxnetflt/r0drv/linux/the-linux-kernel.h
+++ b/vboxnetflt/r0drv/linux/the-linux-kernel.h
@@ -512,6 +512,9 @@ RTDECL(struct page *) rtR0MemObjLinuxVirtToPage(void *pv);
 
 
 extern struct mm_struct *g_pLnxInitMm;
+#if RTLNX_VER_MIN(6,19,0)
+extern void (*g_pfnLinuxFlushTlbAll)(void);
+#endif
 
 
 #endif /* !IPRT_INCLUDED_SRC_r0drv_linux_the_linux_kernel_h */
--- a/vboxnetadp/r0drv/linux/the-linux-kernel.h
+++ b/vboxnetadp/r0drv/linux/the-linux-kernel.h
@@ -512,6 +512,9 @@ RTDECL(struct page *) rtR0MemObjLinuxVirtToPage(void *pv);
 
 
 extern struct mm_struct *g_pLnxInitMm;
+#if RTLNX_VER_MIN(6,19,0)
+extern void (*g_pfnLinuxFlushTlbAll)(void);
+#endif
 
 
 #endif /* !IPRT_INCLUDED_SRC_r0drv_linux_the_linux_kernel_h */
