x86平台OpenHarmony引导实战:UEFI与grub2配置详解

发布时间:2026/10/14 20:19:16
x86平台OpenHarmony引导实战:UEFI与grub2配置详解
简介《OpenHarmony-X86-引导程序》是一份面向X86架构硬件运行OpenHarmony系统的启动引导资源适用于嵌入式开发者、系统集成工程师以及希望将鸿蒙开源系统移植到PC或服务器场景的实践者主要解决X86设备冷启动时的引导加载、内核装载与硬件抽象层衔接等问题。压缩包仅4.43MB共含311个文件以265个mod引导模块为主体辅以efi可执行文件、cfg配置、lst模块清单和png示意图既展示了从UEFI到GRUB再到内核的完整引导链路也便于按需裁剪模块。目前已有1697人学习/下载在X86适配场景中具备一定参考热度。资源内保留了EFI启动文件、GRUB配置、模块依赖列表与加载顺序定义可以直接作为定制启动流程的基线对于需要分析X86引导过程、排查启动异常或编译精简模块的开发者这是具备实操价值的样例。理解这份引导程序还需要了解引导加载程序原理与内核加载机制因此它也适合作为系统底层学习的小型案例。1. OpenHarmony 上 x86难的不是编译而是引导大多数人默认 OpenHarmony 是 ARM 的专属系统拿到 x86 的板子第一反应是“官方不支持吧”。实际上只要引导链路走得通x86 平台跑 OpenHarmony 内核反而比某些 ARM 开发板省事——你有标准 UEFI 固件、有现成的 grub2 工具链、有随处可见的串口调试线。这个资源包里装的不是系统镜像而是一整套引导程序框架从 UEFI 启动到 grub2 菜单、再到内核 cmdline 传参和 ramdisk 加载每一步都有对应的脚本和配置文件。适合两类人一是要在 x86 工控机或 NUC 上评估 OpenHarmony 的开发者二是想彻底搞懂 Linux 系内核引导机制、把启动流程每一帧都看清楚的学习者。这里不讨论怎么编译系统只讲怎么让它正常站起来。2. 引导链路拆解x86 平台为什么绕不开这三段2.1 从 UEFI 到 grub2firmware 怎么把控制权交出来x86 平台的 OpenHarmony 引导和 ARM 上最大的区别在第一跳。ARM 开发板通常用 U-Bootx86 板子则几乎全是 UEFI 固件。UEFI 启动时会扫描 ESP 分区EFI System Partition里的 .efi 文件找到 \EFI\BOOT\BOOTX64.EFI 就加载执行。这个 BOOTX64.EFI 就是我们放进去的 grub2 引导器。很多人第一次接触会问OpenHarmony 内核不能直接被 UEFI 加载吗理论上如果内核编成了 EFI stub 格式UEFI 可以直接引导 vmlinuz。但实际项目中没人这么干原因很直接你需要在启动阶段动态决定内核参数、切换不同的 ramdisk、甚至同一块硬盘上保留多个系统版本回退。grub2 给了你一个交互式命令行和脚本环境这是 EFI stub 给不了的。这套资源的引导配置文件不是随手写的模板它包含了对分区 UUID 的自动探测逻辑。传统 grub.cfg 里直接写 root/dev/sda3 这种硬编码换一块硬盘或者换一个 USB 口就可能崩。资源里的做法是search --no-floppy --fs-uuid --setroot 你的根分区UUID这段命令的含义是让 grub 遍历所有可见设备找到 UUID 匹配的分区把它设为 root 变量。后面所有加载内核和 ramdisk 的路径都基于这个变量展开相对路径写起来也干净。--setroot 指定结果变量名--fs-uuid 表示按文件系统 UUID 匹配--no-floppy 跳过软驱设备加快扫描速度。2.2 内核传参cmdline 才是 OpenHarmony 上 x86 的关键玄学OpenHarmony 内核跑在 x86 上系统能否起来多半取决于 cmdline 是否给了足够的线索。ARM 平台很多设备驱动靠设备树描述x86 平台没有设备树的概念一切靠 ACPI 和内核参数。资源包里给出的 cmdline 模板有几个参数值得单独拿出来说root/dev/mmcblk0p3 rw rootwait consolettyS0,115200n8 consoletty0 quietroot 指定根文件系统位置。这个资源的默认配置用的是 /dev/mmcblk0p3对应很多 x86 开发板引导时把系统装在 eMMC 或 SD 卡上的场景rw 表示根分区挂载为读写系统起来后要写 /var、/tmp 这类目录只读会直接导致启动失败rootwait 让内核无限期等待根设备出现对 USB 硬盘或慢速 SD 卡是必要的否则内核可能在设备枚举完成前就尝试挂载consolettyS0,115200n8 把内核日志输出到串口调试必备consoletty0 同时保留显示输出两者共存时内核会把消息发给所有 console 设备quiet 减少启动时的内核打印如果调试阶段建议去掉否则看不到设备枚举过程实际调试中遇到无声无息的黑屏九成和 console 参数有关。常见做法是先去 quiet 和 consoleblank0让内核全部日志铺满屏幕。曾经在一台工控机上怎么都起不来去掉 quiet 才发现是 ACPI 表解析阶段卡死了。2.3 引导器选型为什么是 grub2 而不是 systemd-boot资源包选 grub2一个很实际的理由是生态完整。x86 平台上的 OpenHarmony 移植还不是主流操作文档少、可参考的案例少那么引导器就应该选最不挑环境、报错最直接的那个。grub2 的命令行交互界面对排查启动问题几乎是不可替代的启动时按 c 进入 grub shell可以手动执行 ls、search、cat 这些命令确认设备和文件系统状态。systemd-boot 配置简单但一旦起不来基本只能干瞪眼。处理多系统共存的时候 grub2 的 os-prober 和 chainloader 也比 systemd-boot 灵活。比如一块硬盘上同时有 OpenHarmony 根分区和另一个 Linux 发行版grub2 可以做启动菜单选择。资源包里的 40_custom 脚本就展示了怎么用 chainloader 跳转。menuentry Other Linux { search --no-floppy --fs-uuid --setroot 目标分区UUID chainloader 1 }这里 chainloader 1 表示加载当前 root 分区起始扇区的引导代码适合 MBR 分区表或者待跳转分区自带引导器的情况。如果是 EFI 系统应该改成 chainloader /EFI/BOOT/BOOTX64.EFI 直接加载另一个系统的 EFI 引导文件。3. 手把手配置引导菜单直接可以抄作业的 grub.cfg3.1 基础菜单结构定义默认项和超时资源包里提供的 grub.cfg 不是精简到没法看的玩具而是带完整菜单框架、可以直接放到真实设备上跑的结构。最外层是超时和默认项定义。set default0 set timeout5 menuentry OpenHarmony x86 { insmod part_gpt insmod ext2 search --no-floppy --fs-uuid --setroot 4f7a-9c3b-2e11-8a6d linux /boot/kernel-ohos root/dev/mmcblk0p3 rw rootwait consolettyS0,115200n8 consoletty0 initrd /boot/ramdisk-ohos.img }set default0 表示默认启动第一个菜单项set timeout5 表示停留 5 秒后自动进入默认项。insmod part_gpt 加载 GPT 分区表支持模块insmod ext2 加载 ext 文件系统驱动这两个模块不加载的话后面 search 和 linux 命令都无法工作因为 grub 既读不出分区也读不出文件。linux 和 initrd 两行是核心。linux 指令加载内核镜像到内存后面跟的是传给内核的 cmdline。initrd 指令把 ramdisk 镜像加载到内存内核起来后会把它作为临时根文件系统。注意这里 root/dev/mmcblk0p3 和前面 search 的 UUID 指向的分区应该是同一个只不过 search 是 grub 阶段用来定位启动文件root 是内核阶段用来挂根文件系统。两者职责不同经常有人把这两处搞混。3.2 多版本回退菜单给你的系统留一颗后悔药做过系统移植的人都有这种经历新内核起不来旧内核又被覆盖了只能重新刷机。资源包里的配置专门做了多版本菜单每个版本对应一个菜单项避免这种尴尬。menuentry OpenHarmony x86 5.10.1 { linux /boot/kernel-5.10.1 root/dev/mmcblk0p3 rw rootwait initrd /boot/ramdisk-5.10.1.img } menuentry OpenHarmony x86 5.10.0 (backup) { linux /boot/kernel-5.10.0 root/dev/mmcblk0p3 rw rootwait initrd /boot/ramdisk-5.10.0.img }这里把内核版本号直接写进文件名好处是菜单一眼可以看出当前引导的是哪个版本。开发阶段建议至少保留两个版本一个是已知能启动的兜底版本一个是正在调试的新版本。grub.cfg 里 set default 可以临时改成备份项的编号按住 shift 键也可以在启动时强制显示菜单手动选择鼠标键盘操作比重新烧录快太多了。3.3 ramdisk 与根文件系统的配合方式OpenHarmony 的 x86 引导中ramdisk 的作用在某些场景下会被放大。如果根文件系统是只读的 squashfs 镜像那么 ramdisk 不仅要完成内核模块的加载还要承担把 overlayfs 挂起来的任务——也就是把可写层覆盖到只读层上面。mount -t squashfs /dev/mmcblk0p3 /mnt/root-ro mount -t overlay overlay -o lowerdir/mnt/root-ro,upperdir/mnt/root-rw,workdir/mnt/root-work /mnt/root这段脚本通常放在 ramdisk 里的 init 脚本中。第一步把只读的 squashfs 挂到临时目录第二步用 overlayfs 把可写目录叠加上去最终根目录变成可写的。lowerdir 是只读底层upperdir 是改动写入层workdir 是 overlayfs 的工作目录三者缺一不可。如果 ramdisk 里没有这套逻辑只读根文件系统的系统会出现启动后无法创建临时文件、服务起不来的现象。资源包里附带的 ramdisk 构建脚本用的就是这种方案把 init 脚本做成模块化的加载设备驱动、挂载根 fs、切换到真实根目录三步分离每一步都有 set -x 开启详细日志方便调试时在串口上逐行看执行到哪一步挂掉的。4. 制作可启动镜像把引导程序固化到介质上4.1 分区表布局ESP 分区不能省拿到这套引导程序资源第一步不是改代码而是把镜像写到一块空白 U 盘或者硬盘上。x86 设备从 UEFI 启动介质上必须有一个 FAT 格式的 ESP 分区否则固件根本找不到启动文件。sudo parted /dev/sdX --script mklabel gpt sudo parted /dev/sdX --script mkpart ESP fat32 1MiB 513MiB sudo parted /dev/sdX --script set 1 esp on sudo parted /dev/sdX --script mkpart root ext4 513MiB 100%三行 parted 命令完成分区布局。mklabel gpt 把磁盘标签设为 GPT这是 UEFI 启动的前提Legacy MBR 虽然也能引导但不是这套资源的目标场景。mkpart ESP fat32 1MiB 513MiB 创建 512MiB 的 ESP 分区set 1 esp on 给它打上 ESP 标记。第二个分区给根文件系统ext4 格式。1MiB 起始偏移是给 grub2 的 BIOS 引导区留空间虽然纯 UEFI 模式用不到但保留这个偏移不会错。分区做完后分别格式化sudo mkfs.vfat -F 32 /dev/sdX1 sudo mkfs.ext4 /dev/sdX24.2 拷贝引导文件到 ESP 分区引导程序资源包的核心文件是 grubx64.efi、grub.cfg、kernel 和 ramdisk 镜像。ESP 分区的目录结构有讲究UEFI 固件默认找 \EFI\BOOT\BOOTX64.EFI所以 grubx64.efi 必须放成这个名字。sudo mount /dev/sdX1 /mnt sudo mkdir -p /mnt/EFI/BOOT sudo cp grubx64.efi /mnt/EFI/BOOT/BOOTX64.EFI sudo cp grub.cfg /mnt/EFI/BOOT/grub.cfggrub.cfg 放在 BOOTX64.EFI 同目录下是 grub2 的默认搜索路径之一它会先找 /EFI/BOOT/grub.cfg找不到再尝试 /boot/grub/grub.cfg。对于做引导移植的场景把两者都放一份是稳妥做法。grub.cfg 里 linux 和 initrd 指向的 /boot/kernel-ohos 和 /boot/ramdisk-ohos.img 文件在哪个分区答案在 4.1 里的 grub.cfg 配置——search 命令会定位到根文件系统所在分区然后从该分区的 /boot 目录读取这些文件。所以要么把整个根分区内容拷贝进去要么至少把 /boot 目录结构搭好。这里有个资源包已经处理好的细节root/dev/mmcblk0p3 是块设备路径但实际运行时内核设备名可能因为存储控制器驱动加载顺序不同而变化。更稳的办法是 rootUUID一串十六进制值内核会按 UUID 去扫设备。资源包里的模板两种写法都给了注释里明确建议生产环境用 UUID。提取 UUID 用 blkid 命令sudo blkid /dev/sdX24.3 验证引导介质完整性写完了别急着拔 U 盘先用 grub 自带的校验工具确认配置语法没问题。资源包里带了 grub-script-check 脚本和 grub2 工具链一起装机时有。grub-script-check grub.cfg这个工具只检查语法是否正确不检查文件路径是否存在所以还需要手动确认内核和 ramdisk 文件路径。sudo mount /dev/sdX2 /mnt/root ls -lh /mnt/root/boot/kernel-ohos ls -lh /mnt/root/boot/ramdisk-ohos.img特别注意文件的权限位内核和 ramdisk 文件不需要可执行权限但必须对 grub 可读。曾经遇到过文件权限 600、只有 root 可读的情况grub 在加载时表现为主机直接重启不报任何错误——这个问题非常隐蔽检查权限是第一步。再确认分区的 UUID 和 grub.cfg 里写的一致不一致的话 search 命令会静默失败。blkid /dev/sdX1比较输出里的 UUID 和 grub.cfg 里 search 行的值就可以了。5. 引导排查避坑起不来别急着重刷先看这几个位置5.1 现象grub 菜单能显示选启动项后黑屏这是最常见的故障态。菜单出来了、倒计时走了、回车之后屏幕一黑就没有下文。原因列表里第一个要看的就是 cmdline 的 console 参数。前面提到过这个追查套路——黑屏后先敲一下键盘看屏幕有没有反应如果 NumLock 灯都无响应大概率在内核早期初始化就挂了。此时唯一的信息来源是串口。解决方法是把 consoletty0 去掉只保留 consolettyS0,115200n8然后接上 USB 转串口线看完整日志。串口输出比屏幕输出更全内核早期日志不会丢。看到最后一行打印停在某个驱动初始化、或者 ACPI 报错再对症处理。资源包的调试文档里专门有一章列出常见卡点对应的日志特征。5.2 现象串口输出显示 VFS: Unable to mount root fs内核起来了设备驱动加载了但挂载不了根文件系统。原因很直接root 参数指向的设备不存在。在 x86 平台上块设备命名可能随驱动加载顺序变化——同样的 /dev/mmcblk0p3换一次 BIOS 设置或者换一个启动介质插口就可能变成 /dev/mmcblk1p3。解决方式是改用 UUID。rootUUIDxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx这种写法由内核自己扫描所有块设备的 UUID不依赖设备节点命名顺序。另外一个注意点是 initrd 里要有对应块设备的驱动比如 NVMe 硬盘需要 nvme 驱动如果 ramdisk 里没打进去内核永远找不到 root 设备。确认方法是在串口日志里搜 nvme 或 mmcblk 字样看设备是否被枚举出来。5.3 现象initrd 解压失败报 bad gzip magicramdisk 镜像损坏或者格式不对。资源包里构建 ramdisk 时常见的压缩格式是 gzipgrub 的 initrd 指令能自动识别压缩格式但它不管压缩流是否完整。最常出现这种错误是在 Windows 环境下解压再重新打包 ramdisk文件格式被改变。解决办法是在 Linux 环境重新用构建脚本生成 ramdiskgzip -t ramdisk-ohos.img这条命令测试 gzip 压缩流的完整性返回正常才说明文件没坏。如果构建脚本输出的本来就是未压缩的 cpio 格式grub 一样能加载但文件会大很多。5.4 现象grub 菜单都出不来直接进固件设置ESP 分区没有正确制作或者 BOOTX64.EFI 文件不在标准路径。UEFI 固件找不到启动项时通常不会报错直接回退到固件设置界面。检查方法有两个一是看 ESP 分区是否标记了 esp 标志二是确认 BOOTX64.EFI 文件名完全正确。x86 UEFI 固件对启动文件名的大小写不敏感但路径分隔符必须用反斜杠拷贝时别把整个 EFI 目录放在盘符根路径下。有时候是固件里启动了 Secure Boot 导致 grubx64.efi 签名校验失败。资源包里的 grubx64.efi 没有签名遇到这种情况要么在固件里关掉 Secure Boot要么给 grub 配一个 Machine Owner Key 做签名。对调试阶段而言关掉 Secure Boot 是最直接的路径。5.5 现象内核启动后重启循环这种症状最迷惑人。如果串口日志最后几行是 kernel panic那就是根文件系统 init 进程执行失败如果日志直接断开没有任何 panic 信息多半是 ACPI 触发了系统复位。x86 平台上跑非主流系统ACPI 表里某些 _DSM 方法不兼容可能导致固件直接断电重启。解决方案是给 cmdline 加 acpioff 试一次——如果加了之后能正常启动说明确实是 ACPI 兼容性问题再逐步缩小范围定位具体是哪个表的问题。但注意 acpioff 会禁用大部分电源管理和设备枚举功能只适合做故障定位不适合长期运行。6. 验证引导成果三段日志确认系统真正跑起来了引导程序配好不能只看屏幕亮了就宣布成功。OpenHarmony 内核起来后你要在三个时间点各瞄一眼日志确认整个链路是健康的。第一段在 grub 阶段。启动时按 c 进入 grub shell执行 ls 命令看到所有分区再执行 ls (hd0,1)/ 能看到 EFI 目录里的文件。这说明 grub 的文件系统驱动、分区识别、设备扫描都正常。这一步能拦下 80% 的“文件没拷全”类问题。第二段在内核早期。串口或屏幕输出里出现 Freeing unused kernel memory 和 Run /init as init process 字样说明内核解压完成、ramdisk 挂载成功、init 进程开始执行。第三段是系统真正起来。串口上有 getty 登录提示符或者网络接口能拿到 DHCP 地址。从那以后我每次做完引导配置都会强制走一遍这三段日志检查不跳过任何一步。之前偷懒只看屏幕亮了就收工结果有一次 root 分区虽然挂上了但 overlay 层没起来系统看似正常一写文件就报只读错误排查花了一下午。从那以后连 mount 状态都用 cat /proc/mounts | grep overlay 确认过才放心。这套流程走完OpenHarmony 在 x86 上的引导链路就是完全可控的状态了——从 UEFI 到 grub 到内核再到 rootfs每一跳都有日志可查、有命令可验证。就算以后再遇到起不来的新内核也只需要按着 5.5 里的排查顺序走下去大概率十分钟内能定位到问题。希望帮到你。本文还有配套的精品资源点击获取