virtualbox-5.2.24 dkms build failed against x86_32 kernel 5.0.0-rc2+

最近想在本子上装个 virtualbox 跑个 winxp,旧本子,一直用的 32 位 Debian,内核经常更新,现在版本是 5.0.0-rc2+

apt install virtualbox virtualbox-dkms 安装完后,建立虚拟机的时候报错,说不能加载 vboxdrv 模块

dkms build

想着可能是因为内核新,所以 dkms 工作没做好,干脆跑一下 dkms build。结果一跑,报错了:

    # dkms build -m virtualbox -v 5.2.24

    Kernel preparation unnecessary for this kernel.  Skipping...

    Building module:
    cleaning build area...
    make -j2 KERNELRELEASE=5.0.0-rc2+ -C /lib/modules/5.0.0-rc2+/build M=/var/lib/dkms/virtualbox/5.2.24/build........(bad exit status: 2)
    Error! Bad return status for module build on kernel: 5.0.0-rc2+ (i686)
    Consult /var/lib/dkms/virtualbox/5.2.24/build/make.log for more information.

查看一下 log /var/lib/dkms/virtualbox/5.2.24/build/make.log

    ...
      CC [M]  /var/lib/dkms/virtualbox/5.2.24/build/vboxdrv/r0drv/linux/memuserkernel-r0drv-linux.o
    /var/lib/dkms/virtualbox/5.2.24/build/vboxdrv/r0drv/linux/memuserkernel-r0drv-linux.c: In function ‘VBoxHost_RTR0MemUserIsValidAddr’:
    /var/lib/dkms/virtualbox/5.2.24/build/vboxdrv/r0drv/linux/memuserkernel-r0drv-linux.c:69:55: error: macro "access_ok" passed 3 arguments, but takes just 2
         bool fRc = access_ok(VERIFY_READ, (void *)R3Ptr, 1);
                                                       ^
    /var/lib/dkms/virtualbox/5.2.24/build/vboxdrv/r0drv/linux/memuserkernel-r0drv-linux.c:69:16: error: ‘access_ok’ undeclared (first use in this function)
         bool fRc = access_ok(VERIFY_READ, (void *)R3Ptr, 1);
                    ^~~~~~~~~
    /var/lib/dkms/virtualbox/5.2.24/build/vboxdrv/r0drv/linux/memuserkernel-r0drv-linux.c:69:16: note: each undeclared identifier is reported only once for each function it appears in
    ...

第一次遇到这个问题,说 access_ok 宏定义有问题。看了下 /var/lib/dkms/virtualbox/5.2.24/build/vboxdrv/r0drv/linux/the-linux-kernel.h,已经 include 了 uaccess.h 文件,回头看内核源码,access_ok 确实只定义了两个参数。

纳闷,按理说 virtualbox 这么大个项目不应该出这种问题,内核 API 使用都不对。尝试各种杂乱的修改,最后想起看一下 git log,毕竟内核比较新;结果一查,找到了,commit 96d4f267e40f9509e8a66e2b39e8b95655617693 原来以后会逐渐放弃对 x86_32 的支持,修改主要是:

    -#define access_ok(type, addr, size)       \
    +#define access_ok(addr, size) 

upstream 对此做了修改,自己对 access_ok 不是很了解,不过既然 git log 里面提到了 type 参数不常用,干脆也把 virtualbox 代码中对 access_ok 的使用去掉这个参数。注意,修改的是 /usr/src/virtualbox-5.2.24/r0drv/linux/memuserkernel-r0drv-linux.c;/var/lib/dkms/virtualbox/ 下的是符号链接,如果在这里修改后运行 dkms build 会把修改覆盖掉

     66 RTR0DECL(bool) RTR0MemUserIsValidAddr(RTR3PTR R3Ptr)
     67 {
     68     IPRT_LINUX_SAVE_EFL_AC();
     69     /*bool fRc = access_ok(VERIFY_READ, (void *)R3Ptr, 1);*/
     70     bool fRc = access_ok((void *)R3Ptr, 1);     去掉 type 参数
     71     IPRT_LINUX_RESTORE_EFL_AC();
     72     return fRc;
     73 }
     74 RT_EXPORT_SYMBOL(RTR0MemUserIsValidAddr);

修改完成后再 build 成功:

    # dkms build -m virtualbox -v 5.2.24

    Kernel preparation unnecessary for this kernel.  Skipping...

    Building module:
    cleaning build area...
    make -j2 KERNELRELEASE=5.0.0-rc2+ -C /lib/modules/5.0.0-rc2+/build M=/var/lib/dkms/virtualbox/5.2.24/build................
    cleaning build area...

    DKMS: build completed.

注意,/var/lib/dkms/virtualbox/5.2.24/ 下多了子目录 /var/lib/dkms/virtualbox/5.2.24/5.0.0-rc2+ 存放成功编译的 virtualbox模块

既然 build 完成了,就加载 vboxdrv 模块试试:

    # modprobe vboxdrv
    modprobe: FATAL: Module vboxdrv not found in directory /lib/modules/5.0.0-rc2+

手动试试:

    # cd /var/lib/dkms/virtualbox/5.2.24/5.0.0-rc2+/i686/module

    # ls
    vboxdrv.ko  vboxnetadp.ko  vboxnetflt.ko  vboxpci.ko

    # insmod vboxdrv.ko 
    # lsmod | grep vboxdrv
    vboxdrv               303104  0

dkms autoinstall

dkms 有个 autoinstall 子命令,执行 autoinstall 后就可以用 modprobe 加载模块了:

    # dkms autoinstall

    vboxdrv.ko:
    Running module version sanity check.
     - Original module
       - No original module exists within this kernel
     - Installation
       - Installing to /lib/modules/5.0.0-rc2+/updates/dkms/

    vboxnetadp.ko:
    Running module version sanity check.
     - Original module
       - No original module exists within this kernel
     - Installation
       - Installing to /lib/modules/5.0.0-rc2+/updates/dkms/

    vboxnetflt.ko:
    Running module version sanity check.
     - Original module
       - No original module exists within this kernel
     - Installation
       - Installing to /lib/modules/5.0.0-rc2+/updates/dkms/

    vboxpci.ko:
    Running module version sanity check.
     - Original module
       - No original module exists within this kernel
     - Installation
       - Installing to /lib/modules/5.0.0-rc2+/updates/dkms/

    depmod...........

    DKMS: install completed.    

再确认一下:

    # modprobe vboxdrv

    # modinfo vboxdrv
    filename:       /lib/modules/5.0.0-rc2+/updates/dkms/vboxdrv.ko
    version:        5.2.24_Debian r128122 (0x00290001)
    license:        GPL
    description:    Oracle VM VirtualBox Support Driver
    author:         Oracle Corporation
    srcversion:     254458DAEA255FA9AD97991
    depends:        
    retpoline:      Y
    name:           vboxdrv
    vermagic:       5.0.0-rc2+ SMP mod_unload modversions 686 
    parm:           force_async_tsc:force the asynchronous TSC mode (int)

这下 virtualbox 就可以用了