给一台老机器装完系统之后,开机引导界面只有 640x480 的文本模式,屏幕上字大得离谱,一行只能塞下不到 40 个字符。你上网搜了一圈,所有人都在说同一个词:vga=791。可真去改的时候,发现 GRUB 配置文件里填上它,重启不是黑屏就是没反应,折腾半天也不知道问题出在哪。
这一期就把 SVGA Text Mode 这条链路彻底讲透。它不是什么复杂功能,就是 Linux 启动早期设置控制台显示分辨率的一整套机制。你会在本文里看到 vga= 参数的真实作用、模式编号怎么换算、如何用 vga=ask 和 hwinfo 这类命令查看硬件实际支持的模式,以及现代 UEFI 环境下怎么绕过老掉牙的 BIOS 调用。内容偏实操,适合正在调引导界面、控制台分辨率或遇到过花屏黑屏的读者。
1. 为什么文本模式也要讲“SVGA分辨率”
1.1 从 BIOS 时代遗留下来的机制
PC 在还没有任何操作系统接管之前,屏幕上的字符是靠固件(BIOS/UEFI)维护的。老式 VGA 文本模式默认是 80 列 25 行,字符由显卡内置的点阵字体渲染,显示区域通常是 720x400 或者 640x400 的像素范围。这就是你看到的“字特别大”的根源——分辨率本身很低,字符点阵再大一点,整个屏幕就显得很原始。
SVGA 的出现让问题变得不一样。SVGA(Super VGA)扩展了标准 VGA 的分辨率范围,可以通过 VESA BIOS Extensions(VBE)协定,在操作系统启动前切换到更高分辨率。Linux 内核提供了一个非常老但一直保留的参数 vga=,它的作用就是让早期控制台在初始化时通过显卡 BIOS 中断(Int 10h)切换到某个 SVGA 模式,从而获得更大的显示尺寸和更多的行列。
这里要注意:现在大家说的“文本模式”,很多时候其实已经不是你想象中的纯文本字符模式了。Linux 控制台在较高分辨率下是先把整块屏幕当作一个图形帧缓冲,然后把字符以位图方式画上去。这种方式的好处是分辨率越高,能显示的行列数越多,字符边缘也更干净。所以这一整套东西被称为 SVGA Text Mode 或者 VGA Text Mode,实际执行时和帧缓冲(framebuffer)密不可分。
1.2 一张模式编号表解决 80% 的困惑
网上常见的 vga=791,本质上是十六进制模式编号 0x317 的十进制写法。你在各个论坛贴吧里看到的老教程,十有八九都是从二三十年前的 VESA 模式表里抄出来的。对于传统 vga= 参数来说,内核和显卡固件共同遵守的是一套固定的模式编号,下面这张表是使用频率最高的部分:
| VGA模式(十六进制) | 十进制写法 | 分辨率 | 色深 |
|---|---|---|---|
| 0x301 | 769 | 640x400 | 8位(256色) |
| 0x302 | 770 | 640x400 | 16位 |
| 0x303 | 771 | 640x400 | 24位 |
| 0x304 | 772 | 640x480 | 8位 |
| 0x305 | 773 | 640x480 | 16位 |
| 0x306 | 774 | 640x480 | 24位 |
| 0x307 | 775 | 800x600 | 8位 |
| 0x308 | 776 | 800x600 | 16位 |
| 0x309 | 777 | 800x600 | 24位 |
| 0x30A | 778 | 1024x768 | 8位 |
| 0x30B | 779 | 1024x768 | 16位 |
| 0x30C | 780 | 1024x768 | 24位 |
| 0x30D | 781 | 1280x1024 | 8位 |
| 0x30E | 782 | 1280x1024 | 16位 |
| 0x30F | 783 | 1280x1024 | 24位 |
| 0x314 | 788 | 640x480 | 32位 |
| 0x315 | 789 | 800x600 | 32位 |
| 0x316 | 790 | 1024x768 | 32位 |
| 0x317 | 791 | 1280x1024 | 32位 |
| 0x318 | 792 | 1600x1200 | 32位 |
看到这里你应该明白,网上流行的 vga=791 就是让早期控制台尝试切到 1280x1024、32 位色深。这个参数本身没有毛病,问题在于你的显卡、虚拟机和固件到底支不支持这个模式。老显卡基本都支持,但新机器在 UEFI 环境下可能直接忽略这个调用,后面我会专门讲。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. vga=参数的模式编号换算:看懂那张表,你就不会被 791/0x317 绕晕
2.1 十进制、十六进制和 vga= 参数怎么换算
网上教程经常同时出现 vga=0x317 和 vga=791 两种写法,很多新手以为它们是不同的参数。其实完全等价,一个是十六进制表示,一个是十进制表示。0x317 转成十进制就是:
bash复制printf "%d\n" 0x317
输出就是 791。反过来:
bash复制printf "%x\n" 791
输出就是 317。如果你自己在 hwinfo 之类的工具里看到一个新的模式编号,想把它填进 vga= 参数,只要用这个命令换算一下,然后分别用 vga=0x编号 和 vga=十进制 都试一次,哪种能用就用哪种。
实际操作中我建议优先写十六进制,因为 vga= 参数在老内核文档里就是用 0x 开头的十六进制编号来定义的,十六进制形式在启动日志里也更容易和 VESA 模式编号对上号。不过有些引导器自定义脚本会把参数里的数字拿去解析,这时候省略 0x 前缀反而更稳,所以两种写法都值得掌握。
2.2 vbeinfo 显示的模式编号为什么不能直接抄进 vga=
这是一个容易踩的坑。GRUB 自带一个 vbeinfo 命令,在 GRUB 命令行界面输入它,会列出当前显卡通过 VESA 能提供的分辨率、色深和刷新率。比如一块老显卡可能会输出:
text复制0x11b: 1280x1024 x 32
0x11c: 1280x1024 x 24
很多人看到 0x11b 觉得这就是 1280x1024x32 的模式编号,然后填到内核参数里写成 vga=0x11b,结果不是黑屏就是没变化。
原因很简单:GRUB 的 vbeinfo 显示的是显卡 VBE 的原生模式编号,而 Linux 的 vga= 参数使用的是内核自己整理过的 VESA 帧缓冲模式编号体系。两者的编号范围不同,含义也不完全一样。0x11b 在 VBE 里可能是 1280x1024x32,但在 Linux 的体系里对应的其实是 0x317(791)。所以 vbeinfo 适合用来选择 GRUB 自己显示界面的分辨率,不适合直接作为 Linux 内核的 vga= 参数。
那怎么查 Linux 体系下的编号呢?最直接的方法是下面第三节的 vga=ask,还有进入系统后用 hwinfo --framebuffer,它输出的列表会明确标注 Mode 0x317: 1280x1024 这种格式,和 vga= 参数使用的是同一套编号体系。
3. 实操第一步:用 vga=ask 让内核自己列模式,顺便测试临时生效
3.1 以 vga=ask 启动的完整过程
既然记模式编号容易错,就让内核自己把支持的列表打出来。方法是在启动参数上临时加一个 vga=ask,它会进入交互式模式,由你从内核检测到的模式列表里挑一个。
具体操作流程是这样的:
- 重启电脑,看到启动菜单时按
e进入编辑模式。 - 找到以
linux开头的那一行,这行通常会携带内核路径和一堆参数。 - 在整行的末尾加上一个空格,然后输入
vga=ask。 - 按
Ctrl+X或F10启动系统。
启动过程中,内核会发现 vga=ask,然后停留在提示界面,大致会显示:
text复制Video mode <number> ?
这里不要直接输入数字,先按回车键或者等待,内核会列出所有它能用的模式,一行一个:
text复制0x301 640x400 8bits
0x304 640x480 8bits
0x307 800x600 8bits
0x30A 1024x768 8bits
0x30D 1280x1024 8bits
0x315 800x600 16bits
0x316 1024x768 16bits
0x317 1280x1024 32bits
...
看到这个列表之后,输入你想要的那一项的编号,然后按回车,系统就会带着这个模式继续启动。如果屏幕正常显示、字迹清晰,说明这个模式可用;如果花屏、黑屏或者字符错位,就重启再试另一个编号。
需要提醒的是,vga=ask 是一次性临时修改,不会写入任何配置文件。这个设计其实很合理,因为 SVGA 模式每台机器支持情况不同,先用交互模式找到能用的编号,比反复盲改配置文件高效得多。
3.2 用临时参数验证,能少重启好几次
我自己的习惯是从来不会直接改配置文件就重启。不管是从论坛抄到的 vga=791,还是自己换算出来的 vga=0x30A,我都建议先通过启动菜单临时添加,验证完确实能正常进系统、控制台分辨率也符合预期,再回系统里改配置文件。
临时验证时还可以顺便看一下,一旦进入图形界面之后,这个文本模式是否被覆盖。如果开机阶段字变清晰了,但进入桌面后屏幕又被图形驱动切成另一个分辨率,这不是参数没生效,而是显卡驱动在接管显示。这种情况放到第六节单独讲。
另外补一个细节:如果你用的是不太新的发行版,vga=ask 运行时列出的列表可能很长,而且底部没有明显的“输入编号”提示。碰到这种情况,选完模式后如果卡住不动,可以尝试按一下回车再等。交互流程在不同内核版本下细节有点差异,但核心思路不变——让它列模式,挑一个,启动看看效果。
4. 持久化配置:改 /etc/default/grub 的正确姿势和常见翻车现场
4.1 改 /etc/default/grub 的正确姿势
临时验证有效之后,下一步就是把这个模式写入持久配置。绝大多数使用 GRUB 2 的发行版,真正生成启动菜单时不会手写 /boot/grub/grub.cfg,而是先读 /etc/default/grub 这个文件,再执行 grub-mkconfig 重新生成。所以我们要改的不是 grub.cfg,而是 /etc/default/grub。
先打开它:
bash复制sudo nano /etc/default/grub
看到类似这样的内容:
text复制GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX=""
要把 vga= 参数加进去。我建议加在 GRUB_CMDLINE_LINUX 里,因为这一项同时作用于普通启动和恢复启动,GRUB_CMDLINE_LINUX_DEFAULT 则只作用于默认入口。如果你只需要默认启动生效,加在 DEFAULT 里也行,但为了减少意外,我还是写进不带 DEFAULT 的那一行:
text复制GRUB_CMDLINE_LINUX="vga=0x317"
如果这一行原本有其他参数,就在引号内追加,用空格隔开。比如:
text复制GRUB_CMDLINE_LINUX="vga=0x317 consoleblank=0"
保存文件之后,执行重新生成启动菜单的命令。不同发行版命令不一样,常见两种:
bash复制sudo grub-mkconfig -o /boot/grub/grub.cfg
或者:
bash复制sudo update-grub
执行成功后会看到类似 Found linux image ... 的输出,然后重新生成 grub.cfg。这里一定要记住:跑完生成命令,配置才算真正生效。很多新手只改了 /etc/default/grub 没重新生成,重启自然没变化。
4.2 翻车之后的恢复方法
改完 vga= 参数重启,发现黑屏、花屏或者画面撕裂,这是最常见的翻车现场。不用慌,恢复方法很简单。
重启电脑,进入启动菜单,按 e 编辑刚才那个启动项,找到内核参数那一行,把 vga=0x317 删掉,或者直接改成:
text复制vga=normal
然后按 Ctrl+X 启动,就能以最保守的标准 80x25 文本模式进入系统。进入系统之后,再把 /etc/default/grub 里的 vga=0x317 删掉或改掉,重新执行一遍 grub-mkconfig 即可。
这里说一个经验:vga=normal 不是只能用来救急,它本身也是一个合法参数。它的作用是把控制台切回最基础的 VGA 文本模式,不加载任何 SVGA 分辨率。当你需要排查复杂显示问题,比如判断到底是显卡驱动问题还是帧缓冲参数问题时,vga=normal 是很好的隔离手段。如果 vga=normal 都花屏,那基本可以确定不是模式编号的问题,而是硬件或驱动层面出了问题。
另一个经验是:改 GRUB 参数之前,最好先用手机拍一张当前启动参数的截图。特别是那些手边没有第二台电脑可以查资料的用户,一旦黑屏,拍下来的参数就是你的救命稻草。我自己就吃过这个亏,改完参数黑屏,一时想不起来原先那行到底写了什么,只好盲敲命令行慢慢恢复。
5. 现代设备的另一条路:GRUB_GFXMODE 与 GRUF_GFXPAYLOAD_LINUX 组合
5.1 GRUB 图形模式与内核帧缓冲的关系
如果你用的是一台 UEFI 新机器,或者显卡不支持老式 VESA BIOS 调用,vga= 参数可能完全没有效果。现代 Linux 引导链已经很少依赖 BIOS 中断了,GRUB 在 UEFI 下通过 GOP(Graphics Output Protocol)获取显示能力,内核则通过 efifb、vesafb 等驱动建立早期控制台。
这时候更好的做法是利用 GRUB 自己的图形模式参数。最核心的两个变量是:
text复制GRUB_GFXMODE=1280x1024x32,1024x768x24,800x600x16
GRUB_GFXPAYLOAD_LINUX=keep
GRUB_GFXMODE 决定 GRUB 菜单界面本身的分辨率,后面的列表可以写多个,GRUB 会按顺序尝试第一个能被显卡支持的模式。GRUB_GFXPAYLOAD_LINUX=keep 的意思是:当 Linux 内核启动时,不要重新设定显示模式,继续保持 GRUB 当前已经设置好的分辨率。
这两个参数组合起来,就不需要再写 vga= 了。内核帧缓冲会沿用 GRUB 的分辨率,控制台字体自然也会在更高的像素尺寸上显示。这样既绕开了 BIOS VBE 的兼容性问题,又能让开机菜单和内核控制台保持同一种分辨率,视觉上更统一。
5.2 一份可以直接抄的配置示例
下面是一份我在实际使用中验证过的配置模板,放在 /etc/default/grub 里:
text复制GRUB_GFXMODE=1280x1024x32,1024x768x24,800x600x16
GRUB_GFXPAYLOAD_LINUX=keep
GRUB_CMDLINE_LINUX="quiet"
保存后执行:
bash复制sudo grub-mkconfig -o /boot/grub/grub.cfg
重启后,GRUB 菜单首先尝试用 1280x1024x32 显示;如果显卡不支持,自动降级到 1024x768x24;再不行就降到 800x600x16。内核在启动时继续沿用这个模式,整个过程基本不涉及 vga= 参数。
需要提醒一点:GRUB_GFXMODE 中第一项是优先模式,后面是兜底。不要只写一个分辨率然后就指望所有机器都能起来。新电脑的显卡通常支持 1920x1080 甚至更高,可以适当往列表里加一个更高分辨率作为首选,但千万别把兜底项删掉。
在 GRUB 命令行界面,也可以用 videoinfo 或 vbeinfo 查看当前显卡支持哪些模式。在启动菜单里按 c 进入 grub 提示符,输入:
text复制videoinfo
输出会列出可用分辨率,你把支持的模式整理一下再填进 GRUB_GFXMODE,成功率会高不少。注意 videoinfo 输出的模式编号仍然只是 GRUB 用的,不要把它抄进 vga= 参数。
6. 踩坑清单:驱动、KMS、UEFI 环境下 vga= 失效的排查思路
6.1 KMS 驱动接管:为什么你的 vga= 突然失效
这是所有设置 vga= 的人最后都会撞上的墙:显卡驱动一加载,vga= 就失效了。
现代 Linux 显卡驱动普遍使用 KMS(Kernel Mode Setting),也就是由内核态的显卡驱动直接管理显示模式。Intel 的 i915、AMD 的 amdgpu、厂家的特殊驱动都属于这类。它们一旦初始化成功,就会接管原来由 vga= 指定的早期控制台,重新设置成驱动认为合理的分辨率。所以你启动时可能看到:vga= 让控制台先正常显示了,但在某个启动阶段屏幕闪一下,分辨率又被换掉,最后进入系统时看到的不是你要的分辨率。
判断是不是 KMS 接管,最简单的方法是看启动过程:如果系统 Logo、开机动画或者登录界面出现前后,分辨率发生过明显变化,基本就是驱动接管了。此时你再去改 vga= 参数,纯属白费力气。
如果非要让 vga= 生效,一种思路是在启动参数里加上 nomodeset,让内核不要初始化 KMS 驱动,退回使用简单的帧缓冲驱动。这时候 vga= 又能起作用了,控制台分辨率也会按你的设置显示。但代价是显卡加速通常会被禁用,桌面环境可能变得迟钝,有些显示服务器甚至起不来,所以这只能是应急手段。
我的建议是:如果目的是把 GRUB 菜单和控制台文字调清楚,用第五节的方法就够了;如果你想要的是桌面图形界面的分辨率,那就应该去桌面环境的显示设置里调整,而不是继续折腾 vga=。
6.2 UEFI 机器和 old BIOS 机器要区分对待
BIOS 时代的机器调用 Int 10h 设置 SVGA 模式,整个过程很顺畅。UEFI 就不同了,它在启动早期走的是 GOP/UGA 协议,老式的 VBE 调用可能不再提供,或者只能在兼容模式下用。所以网上流传的那些 vga=791 教程,在 UEFI 新机器上经常会直接没反应。
判断方法是先看固件模式:
bash复制ls /sys/firmware/efi
如果这个目录存在,说明当前是 UEFI 模式。UEFI 模式下遇到 vga= 失效,优先考虑 GRUB_GFXMODE 方案。如果是在 BIOS/Legacy 模式下,vga= 和历史 VESA 模式表仍然可以一战,但要注意现在很多“老教程”对应的显卡支持范围和今天并不完全相同。
还有一类特殊情况是虚拟机。虚拟机里的显卡大多是虚拟设备,比如某虚拟机环境提供的 SVGA 驱动,这类设备的 VBE 支持通常比较完整,vga= 参数往往能用;但在开启 3D 加速之后,行为又不一定符合预期。我建议在虚拟机里调整显示分辨率时,优先用 GRUB_GFXMODE 方案,因为它依赖的是 GRUB 和内核的通用显示协议,不像 vga= 那样对固件支持敏感。
7. 控制台字体和边界设置:文本模式体验优化的最后一步
7.1 setfont 给控制台换一套更清晰的字体
分辨率设置对了,屏幕上的行列数会变多,但如果字体本身模糊、比例不好看,体验还是会打折扣。Linux 控制台的字形不是由分辨率自动完美决定的,它需要加载点阵字体文件,这时就要用 setfont。
先看系统里有哪些字体可用:
bash复制ls /usr/share/kbd/consolefonts/ | head
不同发行版字体目录路径略有差异,但基本都在 /usr/share/kbd/consolefonts/ 下。常见的字体文件有 Lat2-Terminus16.psf.gz、ter-116n.psf.gz、sun16.psf.gz 这些。找到合适的后,直接加载:
bash复制setfont /usr/share/kbd/consolefonts/Lat2-Terminus16.psf.gz
加载之后,当前虚拟终端的分辨率如果没有变,字符会立刻换成新的点阵风格。很多人说 Linux 文本模式字太小或字太丑,其实换一套终端字体就能改善一半。
如果希望字体大小随分辨率调整,可以多看几个不同尺寸的字体文件。比如终端分辨率切到 1280x1024 之后,16 号字体通常比较舒适;如果切到 1920x1080,可能试试 20 号左右的字体。不同发行版打包的字体名不一样,直接用 ls 查看,按文件名里的像素尺寸选就行。
7.2 永久生效的字体配置位置
setfont 只对当前会话生效,重启之后会恢复默认字体。想要永久生效,需要把字体配置写进系统配置文件。
systemd 系的发行版通常读 /etc/vconsole.conf,文件内容一般是这样的:
text复制FONT=Lat2-Terminus16.psf.gz
KEYMAP=us
修改后保存重启,或者执行:
bash复制sudo systemctl restart systemd-vconsole-setup
执行这条命令之后,新的字体配置会立刻应用到所有虚拟终端,不需要重启。
旧一点的 SysVinit 风格发行版可能用 /etc/sysconfig/console 之类的路径,格式类似。如果你不确定当前系统读哪个文件,先搜索一下:
bash复制grep -r "FONT" /etc/vconsole.conf /etc/sysconfig/console
看到哪个文件真实存在,就改哪个。
这里补充一个实操体验:字体配置和分辨率要配合着看,不要单独追求高分辨率。我曾经把控制台切到 1600x1200,但字体还是默认的 8x16,结果屏幕上的字符个个长得像蚂蚁,反而更难读。正确姿势是先设好分辨率,再根据实际观感挑一个合适的点阵字体,两步都到位之后,文本终端才真正好用。
最后再分享一点个人的经验
SVGA Text Mode 这套机制虽然老,但理解它仍然有实际价值。我在实际使用中体会最深的一点是:不要一上来就抄 vga=791,也不要直接改 /etc/default/grub。先把 vga=ask 跑一遍,让硬件告诉你它能做什么,然后再决定配置。这样至少能省下三到五次没必要的重启。
如果你的机器是 UEFI,优先用 GRUB_GFXMODE 和 GRUB_GFXPAYLOAD_LINUX=keep;如果还是老 BIOS 机器,vga= 参数加模式编号表依然可靠。再往下一步,用 setfont 调字体,控制台才能真正达到让你愿意长时间面对它的状态。
改任何启动参数之前,记得拍照留底,再准备一条恢复路径。这些经验看起来琐碎,但真遇到黑屏花屏的时候,它们比任何教程都管用。
