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

‍

相关推荐
会员果汁1 小时前
函数调用和变长参数
c语言
呉師傅2 小时前
得力P2500、M2500系列打印机硒鼓加粉及清零方法【纯享版】
运维·网络·windows·电脑
ZhangJun953 小时前
从零写一个类鲁大师的硬件检测小工具,软件附上,可直接使用
windows·测试工具·电脑·笔记本电脑·硬件架构
白山编程大哥4 小时前
Lua 中使用 C 语言的用户自定义类型——userdata
c语言·junit·lua
无敌贵点大王4 小时前
RTThread学习记录13——关于要使用一个外设,RTThread与cubemx到底要怎么配合?
c语言·stm32·学习·rtthread
imperialeast5 小时前
创建WAV文件 韩文、德文、俄文等unicode音乐标签
windows·小程序
phltxy5 小时前
C 语言动态内存管理:从申请空间到安全释放
c语言·开发语言·ui
易点云徐源5 小时前
社保费管理客户端打开后进度条卡20%,等待1分钟提示获取接收配置失败
windows
上位机妹子6 小时前
C 语言 数组删除指定元素(快慢指针法)
c语言·数据结构·算法
心中有你02146 小时前
【路径规划】A*寻路算法最通俗易懂讲解(C语言完整实现+详细注释)
c语言·开发语言·算法