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:28UINT32 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

相关推荐
_Narcissus_3 小时前
枚举和模拟算法笔记
c语言·数据结构·c++·笔记·算法·模拟·枚举
宏集科技工业物联网4 小时前
微型线性伺服执行器如何驱动人形机器人关节?从驱动原理到实际选型
经验分享·机器人·具身智能·人形机器人·线性伺服执行器
QVeris Friends4 小时前
QVeris MCP上架SCNet 实操教程:把超算客户端变成“万能数据工具箱”
经验分享
老当益壮梁奶奶4 小时前
Linux软件编程学习笔记(二)Linux文件IO编程入门:从fopen到fgetc
linux·c语言·c++·笔记·学习
sunoo-2294 小时前
C 语言文件 IO 全攻略:从基础函数到实战踩坑(BMP 读取 + 词典查询)
linux·c语言·前端·笔记·vscode·学习
LuminousCPP5 小时前
栈和队列专题(四):LeetCode 232. 用栈实现队列|双栈分工 + 按需迁移 + 摊还 O(1)
c语言·数据结构·笔记·算法·leetcode
随便做点啥6 小时前
32卡×4090 24GB,Qwen3.8-27B-FP8 集群部署报告
服务器·经验分享·docker·vllm
流浪0016 小时前
C/C++ 后端筑基系列(一):C语言 —— 从基础到进阶系统指南
c语言
comedate14 小时前
Windows / Linux GPU 虚拟内存布局差异与 CUDA 越界访问行为
linux·windows·mmu·cuda 越界访问