QEMU启动OVMF shell超时分析

QEMU启动OVMF shell超时分析

实验环境

类型 描述
OVMF固件版本 edk2 20211219
QEMU版本 20260729
QEMU运行脚本内容 qemu-system-x86_64.exe -bios "OVMF.fd" -M "pc" -m 256 -cpu "qemu64" -boot order=dc -serial stdio -hda fat:rw:FAT

‍

运行现象

可以正常boot OVMF固件,但在QEMU使用的屏幕上打印">>Start PXE over IPv4"之后,大概会等待1min,才会进入UEFI shell界面。

‍

现象对应的代码路径

BDS 尝试启动 PXE 启动项时,走的是 EfiPxeLoadFile()​(PXE 驱动提供的 EFI_LOAD_FILE_PROTOCOL),执行顺序是:

  1. 介质检测 ​:NetLibDetectMediaWaitTimeout(..., PXEBC\_CHECK\_MEDIA\_WAITING\_TIME, ...)​,最多等 20 秒 网线/链路就绪。

  2. PxeBc->Start() ​:在 PxeBcImpl.c:129​ 打印 >>Start PXE over IPv4​,这里​只做初始化,不等待。

  3. PxeBcLoadBootFile → PxeBcDiscoverBootFile :真正耗时的是这一步里的 PxeBc->Dhcp(),即 DHCP 的 D.O.R.A. 过程。

    ‍

Root Cause分析:DHCP D.O.R.A. 超时

进入 PxeBcDhcp4Dora() 后,配置了 DHCP 重试参数:

c 复制代码
Config.DiscoverTryCount = PXEBC_DHCP_RETRIES;   // = 4
Config.DiscoverTimeout  = mPxeDhcpTimeout;      // = { 4, 8, 16, 32 } 秒
  • 超时表定义在 PxeBcDhcp4.c:28:UINT32 mPxeDhcpTimeout[4] = { 4, 8, 16, 32 };
  • 重试次数定义在 PxeBcImpl.h:69:#define PXEBC_DHCP_RETRIES 4

关键点 ​:QEMU 默认的 user-mode(SLIRP)网络​不会提供 DHCP/PXE 服务 ​,所以客户端发出 DHCP Discover 广播后永远等不到 Offer。于是按 4s → 8s → 16s → 32s 依次重发 4 次,累计等待 4+8+16+32 = 60 秒 后返回 EFI_TIMEOUT,PXE 启动失败,BDS 才转向下一个启动项。

也就是说,打印 >>Start PXE over IPv4​ 之后的"长时间停住",本质是在干等一个不存在的 DHCP 服务器,约 60 秒。如果虚拟机里配了多个网卡,每个网卡都会再重来一遍 60 秒。

‍

验证方法

  • 在 QEMU 日志里打时间戳:从打印 >>Start PXE over IPv4​ 到下一个启动项/报错,间隔应该接近 ​60 秒(若还叠加了介质检测,则是 20s + 60s)。

  • 观察是否打印 Station IP address is ...​(DHCP 成功才打印,PxeBcDhcp4.c:1741)------没有打印说明 DHCP 一直超时。

    ‍

解决办法

  1. 根本避免 PXE 尝试(推荐,最省事):

    • 用 -boot order=c(磁盘优先),让 PXE 不在启动顺序前段;
    • 或在 QEMU 命令行不给网卡指定 bootindex,配合 -boot strict=on,使网卡不进入 BootOrder;
    • 如果根本不需要网络启动,直接用 -net none / 不添加 -netdev。
  2. 确实需要网络启动:在宿主机配置 DHCP/PXE 服务器(如 dnsmasq),QEMU 的 SLIRP 不提供 PXE 服务,必须外接。

  3. 只想缩短卡顿时长 ​(改代码重编):把 mPxeDhcpTimeout​ 或 PXEBC\_DHCP\_RETRIES​ 调小(例如改成 {2, 4, 8}​ 或 retries=2),可显著减少 60s 等待,但这属于修改 UEFI 网络栈行为。

一句话:慢的原因是 UEFI 的 PXE 驱动在没有 DHCP 服务器的环境下按 4/8/16/32 秒做了 4 次 Discover 重试,累计约 60 秒 ,与 GetFrontPageTimeoutFromQemu​/PcdPlatformBootTimeOut 无关。

‍

最终选择方案

在qemu运行脚本中添加-net none,不再出现超时等待。

完整的QEMU运行脚本内容如下:

qemu-system-x86_64.exe -bios "OVMF.fd" -M "pc" -m 256 -cpu "qemu64" -boot order=dc -net none -serial stdio -hda fat:rw:FAT

‍

相关推荐
聪明的笨猪猪12 小时前
Java 工程案例:AI 生成 @Async 异步线程池踩坑
java·经验分享·面试·ai编程
Felven17 小时前
C. Brr Brrr Patapim
c语言·开发语言
Zucker n19 小时前
文献发现、课题组织与证据可追溯的论文阅读。
论文阅读·windows·ubuntu
Zwawa20 小时前
嵌入式OLED表驱动菜单:用一张表、一个栈和一个窗口重写表驱动菜单
c语言·单片机·嵌入式
仓库日记21 小时前
Excel进销存何时该换?用3项检查判断是否需要软件
经验分享·excel·进销存·开单软件
AI工具挖掘机1 天前
开源!2个Skill复刻带货视频、图文和Live,做百号矩阵
经验分享
虹科网络安全1 天前
Redis Radar:在统一视图中掌握 Redis 部署、健康与容量
经验分享·redis·艾体宝·艾体宝it·艾体宝redis
沐晓时光1 天前
C语言入门,内存函数知识讲解
c语言·开发语言
聪明的笨猪猪2 天前
实际工程问题:AI 生成 Spring Cache(@Cacheable / @CachePut / @CacheEvict)缓存注解踩坑
java·经验分享·面试·ai编程
Zwawa2 天前
C语言函数指针与宏实战:从回调、表驱动菜单到X-Macro,讲透嵌入式代码解耦
c语言·单片机·嵌入式