From: Sérgio Basto References: bsc#1258115 Support building against kernel 6.19 -- cr4_update_irqsoff and cr4_read_shadow were unexported in 6276c67. This contains https://github.com/VirtualBox/virtualbox/compare/d52f0680a4e4...33992f0e56b8 Backport from: https://github.com/rpmfusion/VirtualBox-kmod/commit/ec4795b37621 Adapted to these sources by Jiri Slaby. --- src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c | 79 ++++++++++++++++++-- src/VBox/Runtime/r0drv/linux/initterm-r0drv-linux.c | 16 ++++ src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c | 15 +++ src/VBox/Runtime/r0drv/linux/the-linux-kernel.h | 3 4 files changed, 107 insertions(+), 6 deletions(-) --- a/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c +++ b/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c @@ -190,6 +190,12 @@ static bool g_fEnabledHw 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(voi 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 @@ -466,6 +494,18 @@ static void supdrvLinuxTermKvmSymbols(vo 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); @@ -1146,6 +1186,37 @@ SUPR0DECL(int) SUPDrvLinuxLdrDeregisterW } EXPORT_SYMBOL(SUPDrvLinuxLdrDeregisterWrappedModule); +#if RTLNX_VER_MIN(5,8,0) +/** + * 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; +} +#endif /* 5.8.0 */ #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) RTCCUINTREG VBOXCALL supdrvOSChangeCR4(RTCCUINTREG fOrMask, RTCCUINTREG fAndMask) @@ -1153,10 +1224,10 @@ RTCCUINTREG VBOXCALL supdrvOSChangeCR4(R # 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/src/VBox/Runtime/r0drv/linux/initterm-r0drv-linux.c +++ b/src/VBox/Runtime/r0drv/linux/initterm-r0drv-linux.c @@ -60,6 +60,11 @@ static DECLARE_TASK_QUEUE(g_rtR0LnxWorkQ * 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/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c +++ b/src/VBox/Runtime/r0drv/linux/memobj-r0drv-linux.c @@ -2108,6 +2108,17 @@ DECLHIDDEN(int) rtR0MemObjNativeMapUser( return rc; } +#if defined(IPRT_USE_ALLOC_VM_AREA_FOR_EXEC) || defined(IPRT_USE_APPLY_TO_PAGE_RANGE_FOR_EXEC) +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 +} +#endif DECLHIDDEN(int) rtR0MemObjNativeProtect(PRTR0MEMOBJINTERNAL pMem, size_t offSub, size_t cbSub, uint32_t fProt) { @@ -2128,7 +2139,7 @@ DECLHIDDEN(int) rtR0MemObjNativeProtect( set_pte(papPtes[i], mk_pte(pMemLnx->apPages[i], fPg)); } preempt_disable(); - __flush_tlb_all(); + rtR0MemObjLinuxFlushTlbAll(); preempt_enable(); return VINF_SUCCESS; } @@ -2174,7 +2185,7 @@ DECLHIDDEN(int) rtR0MemObjNativeProtect( 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/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h +++ b/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h @@ -512,6 +512,9 @@ RTDECL(struct page *) rtR0MemObjLinuxVir 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 */