背景:最近在安装显卡驱动,查找了一些网上的教程,但总感觉思路不够清晰,没办法弄清背后涉及的Linux原理,于是参考网上教程,并查阅了相关资料,希望能对显卡驱动安装作一个梳理,以做记录。
首先,查看版本信息
# cat /etc/system-release
CentOS Linux release 7.6.1810 (Core)# uname -r
3.10.0-957.21.3.el7.x86_64
一、Linux module(模块)机制
Linux内核作用有以下作用:
1、管理内存
2、调度任务
3、驱动硬件
4、网络功能
5、安全
6、管理文件系统
Linux内核框架庞大,随着新硬件、文件系统和新功能的不断发展,如果把所有需要的功能都编译到Linux内核中,会造成内核体积庞大,每次加入新的功能都需要重新编译内核,非常麻烦。
为解决这个问题,Linux引入了模块机制,简单来讲,就是kernel(内核)只负责最主要的功能,当需要添加新的硬件和功能时,可以把新功能和新硬件的驱动单独编译为一个模块,开机载入kernel时,系统会同时载入模块,从而提高灵活性。当然,也可以把模块看作kernel的一部分。
在我的机器上,驱动模块放在以下目录中
/lib/modules/3.10.0-957.21.3.el7.x86_64/kernel/drivers
来看看该目录下有什么东西:
# ls /lib/modules/3.10.0-957.21.3.el7.x86_64/kernel/drivers
acpi block crypto firewire hv infiniband md misc nvdimm pinctrl ptp staging usb virtio
ata bluetooth dax firmware hwmon input media mmc nvme platform pwm target uwb watchdog
auxdisplay cdrom dca gpio i2c iommu memstick mtd parport power rtc thermal vfio xen
base char dma gpu idle isdn message net pci powercap scsi tty vhost
bcma cpufreq edac hid iio leds mfd ntb pcmcia pps ssb uio video
可以看到有acpi电源管理驱动,cdrom驱动,gpu驱动,还有nvme,pci,scsi,usb等驱动。由于本文主要讨论显卡驱动,我们进入gpu目录来看看有什么。
# cd gpu
# ls
drm
# cd drm
# ls
amd bochs drm_kms_helper.ko.xz drm_panel_orientation_quirks.ko.xz i2c mgag200 qxl scheduler udl vmwgfx
ast cirrus drm.ko.xz gma500 i915 nouveau radeon ttm virtio
可以看到有以.ko.xz结尾的文件,这就是Linux下模块的文件类型。还有一个特别要注意的目录nouveau,该目录下有nouveau.ko.xz文件,在我们没有安装Nvidia官方驱动时,系统开机默认使用的就是这个驱动。(nouveau是一个开源驱动,性能很差)
由于安装显卡驱动模块,要重新编译模块,所以需要内核模块编译的相关文件kernel-header和kernel-devel,通过yum安装
# yum -y install kernel-header
# yum -y install kernel-devel
二、initramfs文件(参考自鸟哥的Linux私房菜)
开机时我们需要识别硬盘并挂载/目录,从而载入kernel,然而此时并没有硬盘SATA接口的SCSI驱动,那么该如何挂载并载入kernel呢?
Linux提供了initramfs文件,他的目的在于提供开机过程中所需要的最重要核心模块,以让系统开机过程可以顺利完成。initramfs 可以将/lib/modules/.... 内的“开机过程当中一定需要的模块”包成一个文件 (文件名就是initramfs),然后在开机时通过主机的INT 13硬件功能将该文件读出来解压缩,并且initramfs在内存内会仿真成为根目录,由于此虚拟文件系统 (Initial RAM Disk) 主要包含磁盘与文件系统的模块,因此我们的核心最后就能够认识实际的磁盘,那就能够进行实际根目录的挂载。
initramfs文件位于以下目录:
# cd /boot
# ls
config-3.10.0-957.21.3.el7.x86_64
efi
grub
grub2
initramfs-0-rescue-740f2d9ceee54b1cb523569c7bf00ac8.img
initramfs-3.10.0-957.21.3.el7.x86_64.img
initramfs-3.10.0-957.21.3.el7.x86_64kdump.img
symvers-3.10.0-957.21.3.el7.x86_64.gz
System.map-3.10.0-957.21.3.el7.x86_64
vmlinuz-0-rescue-740f2d9ceee54b1cb523569c7bf00ac8
vmlinuz-3.10.0-957.21.3.el7.x86_64
就是后缀为.img的文件,系统会载入内核对应的.img文件。
所以说,initramfs 内所包含的模块大多是与开机过程有关,而主要以文件系统及硬盘模块 (如usb,SCSI 等) 为主。
一般来说,需要initramfs的时刻为:
根目录所在磁盘为 SATA、USB 或 SCSI等接口;
根目录所在文件系统为 LVM,RAID 等特殊格式;
根目录所在文件系统为非传统 Linux 认识的文件系统时;
其他必须要在核心载入时提供的模块。
以上参考自鸟哥的Linux私房菜,然而,通过我的实践,发现 initramfs不仅仅载入了以上模块,同时还载入了显卡驱动,通过lsinitrd命令可以看到initramfs文件的内容。
通过lsinitrd | grep gpu 查看 gpu相关内容
# lsinitrd | grep gpu
drwxr-xr-x 3 root root 0 Jul 13 20:24 usr/lib/modules/3.10.0-957.21.3.el7.x86_64/kernel/drivers/gpu
drwxr-xr-x 4 root root 0 Jul 13 20:24 usr/lib/modules/3.10.0-957.21.3.el7.x86_64/kernel/drivers/gpu/drm
-rw-r--r-- 1 root root 69320 Jun 19 00:57 usr/lib/modules/3.10.0-957.21.3.el7.x86_64/kernel/drivers/gpu/drm/drm_kms_helper.ko.xz
-rw-r--r-- 1 root root 145824 Jun 19 00:57 usr/lib/modules/3.10.0-957.21.3.el7.x86_64/kernel/drivers/gpu/drm/drm.ko.xz
-rw-r--r-- 1 root root 2080 Jun 19 00:57 usr/lib/modules/3.10.0-957.21.3.el7.x86_64/kernel/drivers/gpu/drm/drm_panel_orientation_quirks.ko.xz
drwxr-xr-x 2 root root 0 Jul 13 20:24 usr/lib/modules/3.10.0-957.21.3.el7.x86_64/kernel/drivers/gpu/drm/nouveau
-rw-r--r-- 1 root root 554788 Jun 19 00:57 usr/lib/modules/3.10.0-957.21.3.el7.x86_64/kernel/drivers/gpu/drm/nouveau/nouveau.ko.xz
drwxr-xr-x 2 root root 0 Jul 13 20:24 usr/lib/modules/3.10.0-957.21.3.el7.x86_64/kernel/drivers/gpu/drm/ttm
-rw-r--r-- 1 root root 43728 Jun 19 00:57 usr/lib/modules/3.10.0-957.21.3.el7.x86_64/kernel/drivers/gpu/drm/ttm/ttm.ko.xz
可以看到initramfs有nouveau.ko.xz显卡驱动载入的相关设置。
三、initramfs文件相关设置
既然我们要安装新的显卡驱动,首先需要屏蔽掉nouveau这个开源驱动,而这个驱动是由 initramfs载入的,所以我们需要修改initramfs文件,然而initramfs非常重要,随意修改可能会导致系统无法正常开机。
要修改initramfs,Linux需要修改其配置文件,通过 options 选项来带入相关参数,然后使用dracut命令重新生成 initramfs,配置文件路径如下
/lib/modprobe.d/dist-blacklist.conf
(CentOS 6.x系统配置文件在/etc/modprobe.d/blacklist.conf下
)
使用vim编辑此配置文件
# vim /lib/modprobe.d/dist-blacklist.conf#
# Listing a module here prevents the hotplug scripts from loading it.
# Usually that'd be so that some other driver will bind it instead,
# no matter which driver happens to get probed first. Sometimes user
# mode tools can also control driver binding.
#
# Syntax: see modprobe.conf(5).
## watchdog drivers
blacklist i8xx_tco# framebuffer drivers
blacklist aty128fb
blacklist atyfb
blacklist radeonfb
blacklist i810fb
blacklist cirrusfb
blacklist intelfb
blacklist kyrofb
blacklist i2c-matroxfb
blacklist hgafb
#blacklist nvidiafb /*
blacklist nouveau * 修改的内容
options nouveau modeset=0 */
blacklist rivafb
blacklist savagefb
blacklist sstfb
blacklist neofb
blacklist tridentfb
blacklist tdfxfb
blacklist virgefb
blacklist vga16fb
blacklist viafb# ISDN - see bugs 154799, 159068
blacklist hisax
blacklist hisax_fcpcipnp# sound drivers
blacklist snd-pcsp# I/O dynamic configuration support for s390x (bz #563228)
blacklist chsc_sch# crypto algorithms
blacklist sha1-mb# see bz #1562114
blacklist sha256-mb
找到# framebuffer drivers这一栏,我们需要解释一下 framebuffer
帧缓冲(framebuffer)是Linux为显示设备提供的一个接口,把显存抽象后的一种设备,他允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。framebuffer是LCD对应的一中HAL(硬件抽象层),提供抽象的,统一的接口操作,用户不必关心硬件层是怎么实施的。这些都是由 Framebuffer设备驱动来完成的。
Linux FrameBuffer 本质上只是提供了对图形设备的硬件抽象,在开发者看来,FrameBuffer 是一块显示缓存,往显示缓存中写入特定格式的数据就意味着向屏幕输出内容。
简单来讲, framebuffer就是kernel与显卡驱动的一个中间层(framebuffer也是驱动),然而,由于各显卡厂商(AMD/Nvidia)的硬件架构,寄存器有差异,所以需要使用相对应的framebuffer驱动。
我们可以在# framebuffer drivers 看到 radeonfb 对应AMD显卡,nvidiafb对应 Nvidia显卡,不过默认都是被屏蔽掉的(因为系统默认使用nouveau驱动)。
我们要安装Nvidia显卡驱动,所以在blacklist nvidiafb前面加#号,取消nvidiafb的屏蔽。
那么又该如何屏蔽nouveau驱动呢?在 # framebuffer drivers下写入以下配置:
blacklist nouveau //屏蔽 nouveau
options nouveau modeset=0 //关于这一行,网上的教程没有给出这么写的原因,通过搜索网络,我找到这么如下解释:
linux内核的modeset=0 或者 nomodeset参数的作用是什么啊?zhidao.baidu.com字符界面也可以打开 framebuffer 来提供 2D 加速,图形显示的功能。不过有的时候如果有问题,内核还会继续设置显示模式而导致显示不正常。这个时候这个命令就让内核不再去设置显示模式而保证系统还可以进入字符界面。不过当然就是标准的显示状态了,至少能用的显示状态。
`nomodeset` 做什么_ubuntu_帮酷www.helplib.com最新的内核已经将视频模式设置移到内核中。 所以在X 服务器启动时,所有的硬件特定时钟速率和寄存器上的寄存器都会发生。 这使得得到高分辨率的( 引导) 显示屏和闪烁的自由转换从启动屏幕到登录屏幕是可以能的。 不幸的是,有些卡不能正常工作,你最终会得到一个 black 屏幕。 添加nomodeset参数指示内核不加载视频驱动程序,而是使用BIOS模式,直到加载了X。
也就是说,如果不加这一行,字符界面下,可能导致显示器黑屏,无法安装驱动。
通过以上设置,我们完成了/lib/modprobe.d/dist-blacklist.conf的配置,接下来需要使用dracut命令根据我们的设置重新生成initramfs文件,从而完成显卡驱动安装前的准备工作。
四、安装显卡驱动
1.安装内核模块编译的相关文件kernel-header和kernel-devel
# yum -y install kernel-header
# yum -y install kernel-devel
2.下载显卡相对应的显卡驱动(AMD/Nvidia官网),我的驱动放在了根目录下, 文件以.run结尾
# cd /
# ls
bin dev home lib64 mnt opt root sbin sys usr
boot etc lib media NVIDIA-Linux-x86_64-430.34.run proc run srv tmp var
3. 屏蔽默认的开源驱动nouveau
vim 编辑配置文件
# vim /lib/modprobe.d/dist-blacklist.conf
找到 # framebuffer drivers一栏
将nvidiafb注释掉
# blacklist nvidiafb
然后添加以下语句:
blacklist nouveau
options nouveau modeset=0
4. 重新生成 initramfs image 文件
mv /boot/initramfs-3.10.0-957.21.3.el7.x86_64.img /boot/initramfs-3.10.0-957.21.3.el7.x86_64.img.bak
上面这一行的作用是把旧的initramfs文件名进行修改,在文件名末尾加入.bak代表这是弃用的initramfs文件,这样做是为了保险,当然,你也可以把这个文件删除掉,因为我们要生成新的initramfs文件。
使用 dracut 命令重新生成 initramfs image 文件
dracut /boot/initramfs-3.10.0-957.21.3.el7.x86_64.img 3.10.0-957.21.3.el7.x86_64
5. 重启计算机
# reboot
由于我们禁用了nouvenv驱动,所以重启后显示效果很差
6.进入字符界面
# init 3
7.赋予Nvidia驱动执行权限
# chmod 777 NVIDIA-Linux-x86_64-430.34.run
8. 执行Nvidia驱动
# ./NVIDIA-Linux-x86_64-430.34.run
安装过程全部选择Yes
9.返回图形界面
# init 5
10.重启计算机
# reboot
到此安装完成
重启后我们可以使用 nvidia-smi 命令查看显卡状态
# nvidia-smi
Sat Jul 20 23:06:28 2019
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 430.34 Driver Version: 430.34 CUDA Version: 10.1 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 GeForce GTX 770 Off | 00000000:01:00.0 N/A | N/A |
| 31% 56C P0 N/A / N/A | 283MiB / 1996MiB | N/A Default |
+-------------------------------+----------------------+----------------------++-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 Not Supported |
+-----------------------------------------------------------------------------+