
各位做自制系统、玩虚拟机、折腾启动引导的朋友应该都遇到过这几种情况想从零写一个能在真机或虚拟机上启动的小系统但面对 UEFI 的引导协议、PE32 文件格式、GOP 图形输出脑子一片空白或者想用 Scratch 这类积木编程做系统概念原型又担心“太玩具”跑不出真正的固件效果。这个项目「Turbowarp UEFI Editor驱动式自制操作系统工具宣传片」把两件事结合到了一起用 Turbowarp 做编辑器界面用 UEFI 做真正的启动目标。从项目宣传角度看它是一支能直观展示“积木拖拽 - 生成 UEFI 启动文件 - 虚拟机点亮”的流程演示从技术角度看它本身又是一个非常值得拆解的工程案例。这篇文章会从项目定位、UEFI 基础、环境准备、编辑器的功能拆解到真实启动链路的实现完整走一遍。即使你没有写过操作系统内核也能跟着这篇文章理解“自制操作系统工具”到底解决了什么问题以及如何把 Turbowarp 的积木逻辑转换成 UEFI 能识别的程序。1. 项目背景为什么需要“自制操作系统工具”1.1 “自制操作系统”的第一个门槛不是写代码很多人觉得自制操作系统最难的是内核、内存管理、进程调度。其实对新手来说第一个门槛往往更基础代码编译出来之后怎么让电脑去执行它传统 BIOS 引导相对简单但现代电脑基本上都在使用 UEFI 启动方式。如果你想做一个小系统至少需要生成一个能被 UEFI 固件识别的.efi文件放到指定的\EFI\BOOT\路径下才有机会在开机时被加载。这个过程涉及UEFI 固件如何找到启动文件PE32 可执行文件的格式规范UEFI 提供哪些系统表、启动服务、运行时服务图形输出协议 GOP、串口输出、内存分配等基础接口的使用。这些内容对于只想验证一个“系统雏形”的人来说确实有一定的学习成本。于是工具化成了一种很自然的解法把启动文件的生成过程封装起来让开发者把精力集中在系统逻辑本身。1.2 Turbowarp 为什么适合做这个工具的编辑器Turbowarp 是 Scratch 的一个高性能修改版。它最大的特点是保留了 Scratch 的积木式编程体验适合快速搭建交互界面支持编译模式运行速度比普通 Scratch 快很多可以打包成 HTML 文件、Windows / macOS / Linux 桌面应用支持自定义扩展可以对接外部 JavaScript 代码。所以用 Turbowarp 做“自制操作系统工具”的前端是很合理的用它拖出工程配置面板、组件开关、参数输入界面再通过自定义扩展把配置导出成 JSON 或工程描述文件最后交给构建脚本去生成真正的 UEFI 程序。Turbowarp 负责“易用”C / 汇编 / EDK II 负责“真实”。1.3 项目宣传片的定位我理解这个“宣传片”并不是简单做一支动画视频而是以可演示的项目为核心通过录制屏幕操作流程、展示虚拟机启动效果来传达工具价值。它的核心镜头大致是在 Turbowarp 编辑器里拖拽一个“UEFI Boot 入口”组件配置启动标题、背景色、是否开启 GOP 图形输出点击导出得到一个工程文件调用脚本生成BOOTX64.EFI放入 UEFI 启动盘或 QEMU 虚拟磁盘虚拟机启动终端打印一行系统信息。这条链路就是全文要讲清楚的主线。2. 核心概念UEFI、Editor、Turbowarp 分别承担什么角色2.1 UEFI 是什么它和 BIOS 有什么区别UEFIUnified Extensible Firmware Interface统一可扩展固件接口是操作系统与平台固件之间的接口规范用来取代传统 BIOS。它的优势在于支持 2TB 以上硬盘的 GPT 分区引导启动文件是标准的 PE32 可执行格式支持 Secure Boot安全启动提供完整的启动服务、运行时服务、协议接口图形界面和网络启动能力比 BIOS 更完善。在 UEFI 启动模式下固件会按照BootOrder找到启动项然后加载引导程序。对于可移动磁盘默认路径是\EFI\BOOT\BOOTX64.EFI也就是说只要把BOOTX64.EFI放到这个位置固件就有机会加载它而不需要向磁盘写入传统的主引导记录 MBR。这对“引导自制系统”来说其实简化了很多事情。2.2 自制操作系统里常见的 UEFI 流程一个最简单的 UEFI 应用程序启动之后至少要做这几件事获取系统表System Table通过系统表获取启动服务Boot Services或运行时服务调用输出接口打印信息如果需要图形界面则找到 GOP 协议并切换图形模式构建完成以后返回一个状态码把控制权交还给固件。下面是一个最小化的 UEFI C 代码框架我用 EDK II 风格的代码来写便于理解// 文件路径src/UefiMain.c #include Uefi.h #include Library/UefiBootServicesTableLib.h #include Library/UefiLib.h EFI_STATUS EFIAPI UefiMain( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { Print(L[TurbowarpUEFI] Hello System!\r\n); Print(L[TurbowarpUEFI] Firmware Vendor: %s\r\n, gST-FirmwareVendor); Print(L[TurbowarpUEFI] UEFI Revision: %d.%02d\r\n, gST-Hdr.Revision 16, gST-Hdr.Revision 0xFFFF); return EFI_SUCCESS; }这里用Print输出信息gST是 UEFI 系统表的全局指针。这个代码虽然简单但它已经是一个能被 UEFI 固件加载、执行、返回控制权的完整程序。2.3 Editor 在项目里的角色项目标题里的 Editor 不是指某一个现成的文本编辑器而是指这套自制系统工具里负责“编辑工程配置”的模块。它可能是一个 Turbowarp 项目也可能是一组 HTML JavaScript 页面。职责包括让用户选择系统架构x86_64 / IA32 / AArch64配置启动输出方式串口 / GOP 图形 / 同时输出配置启动延迟、系统名称、版本号管理内置模块比如打印模块、内存探测模块导出统一格式的工程描述文件。这样设计的好处是编辑器不直接负责编译它生成的是中间描述文件再由独立脚本调用工具链完成编译。编辑器可以随时换界面底层构建逻辑不受影响。3. 环境准备在一台普通电脑上搭出完整开发链要运行这个工具并验证生成的 UEFI 启动文件需要准备以下环境。版本不必完全追新重点是兼容性和可复现。3.1 开发机系统Windows、Linux、macOS 都可以。本文示例以 Windows 10/11 为演示环境但命令思路在 Linux 上同样适用。需要注意如果是 macOS部分工具链和 QEMU 参数的安装方式略有不同建议优先在 Linux 虚拟机或 WSL 中操作。3.2 工具清单工具作用说明TurboWarp 网页版或桌面版运行编辑器项目也可以在浏览器里直接开发QEMU模拟 UEFI 环境需要配合 OVMF 固件OVMFUEFI 固件镜像QEMU 启动时的虚拟 BIOSNASM汇编器编写或编译引导层代码EDK IIUEFI 开发框架用来生成.efi文件Python 3编写配置转换脚本把编辑器导出的 JSON 转换成构建输入在 Ubuntu / Debian 系统上安装部分依赖的命令如下# 安装 QEMU 与 OVMF sudo apt update sudo apt install qemu-system-x86 ovmf # 安装 NASM 和 Python 3 sudo apt install nasm python3 python3-pip # 确认 QEMU 版本 qemu-system-x86_64 --version在 Windows 上推荐用 Chocolatey 或 Scoop 安装choco install qemu nasm python3.3 EDK II 的最小构建配置EDK II 不是唯一的 UEFI 开发方式但它是业界使用最广的一套。如果只是做一个演示可以不用完整安装 EDK II 的图形界面工具只需要编译出.efi文件即可。EDK II 的项目结构大致是UefiEditorBuild/ ├── Conf/ │ ├── target.txt │ ├── tools_def.txt │ └── build_rule.txt ├── MdePkg/ ├── MdeModulePkg/ ├── AppPkg/ │ └── TurbowarpUefi/ │ ├── TurbowarpUefi.c │ ├── TurbowarpUefi.inf │ └── TurbowarpUefi.dsc └── Build/这个环境对新手来说有一点重。如果你的目标只是快速看到“自制操作系统工具能生成一个可启动的 efi”更轻量的方式是用 NASM 写一个 UEFI 引导程序再用 QEMU 运行。下面是一个基于 NASM 的极小 UEFI 引导示例它不依赖 EDK II可以直接体验; 文件路径bootx64.asm ; 最小 UEFI 启动程序NASM ; 编译命令 ; nasm -f bin bootx64.asm -o bootx64.efi ; ; 注意这不是标准 PE32 格式仅供实验实际工具链仍需生成 PE32 BITS 64 org 0x10000 start: ; UEFI 入口时rdx 指向系统表 ; 这里我们不解析复杂协议只写一个简单的无限循环 mov rsi, msg jmp $ msg: db UEFI Boot!, 0严格来说这个bootx64.efi并不能被所有 UEFI 固件识别因为缺少 PE32 头。真正的 UEFI 加载器必须是有效的 PE32 文件所以完整项目里还是要走 EDK II 或 GNU-EFI。使用 GNU-EFI 会比 EDK II 轻量一些常见流程是# 编译汇编启动部分 gcc -c -o start.o start.S # 编译 C 入口 gcc -I/usr/include/efi \ -fno-stack-protector -fpic -fshort-wchar -mno-red-zone \ -c -o main.o main.c # 链接生成 .so 文件 ld -shared -Bsymbolic -L/usr/lib -lefi -T /usr/lib/elf_x86_64_efi.lds \ -o main.so start.o main.o # 转换成 .efi 文件 objcopy -j .text -j .sdata -j .data -j .dynamic \ -j .dynsym -j .rel -j .rela -j .rel.* -j .rela.* \ -j .reloc --target efi-app-x86_64 \ main.so bootx64.efi这个流程的好处是不引入庞大的 EDK II 工程只需要 gcc、binutils 和 GNU-EFI 的库文件适合做小工具演示。3.4 制作一个可启动 UEFI 磁盘当bootx64.efi生成后需要一个“启动介质”给 QEMU 使用。最简单的办法是用 FAT 镜像。在 Linux 下可以这样创建# 创建一个 64MB 的 FAT 磁盘镜像 dd if/dev/zero ofdisk.img bs1M count64 # 格式化为 FAT32 mkfs.fat -F 32 -n UEFI_EDITOR disk.img # 挂载并创建文件 mkdir -p mnt sudo mount disk.img mnt mkdir -p mnt/EFI/BOOT cp bootx64.efi mnt/EFI/BOOT/BOOTX64.EFI sudo umount mnt然后启动 QEMUqemu-system-x86_64 \ -bios /usr/share/OVMF/OVMF_CODE.fd \ -drive filedisk.img,formatraw,ifide \ -net none \ -m 256M如果不出意外QEMU 窗口里会看到 UEFI 固件加载了BOOTX64.EFI随后进入你的程序输出信息。4. 编辑器功能拆解Turbowarp 里如何组织一个“系统构建工程”4.1 工程面板设计在 Turbowarp 里我会把编辑器设计成几个功能区工程信息区填写系统名称、版本号、作者、启动信息目标平台区选择 UEFI 架构例如 x86_64输出模式区串口输出、图形输出、同时输出组件开关区是否生成内存探测代码、是否显示固件信息导出按钮区点击后生成 JSON 工程描述文件。这些组件用 Scratch 的积木很容易实现用变量存储输入框内容用列表存储启用的模块用“当角色被点击”积木触发导出逻辑。4.2 工程描述文件的结构为了让底层的 Python 脚本能识别编辑器的配置我设计了一种简单的 JSON 格式。例如{ projectName: TurbowarpDemoOS, version: 0.1.0, author: csdn_developer, bootMessage: Welcome to Turbowarp UEFI Editor, arch: x86_64, outputMode: serial, enableGop: true, gopWidth: 1024, gopHeight: 768, enableMemoryProbe: false, modules: [ print, gop ] }在 Turbowarp 里可以用“列表”来存储模块名用“变量”来存储字符串和数字最后用自定义扩展把列表和变量序列化为 JSON 文本。4.3 自定义扩展的 JavaScript 逻辑Turbowarp 支持自定义扩展。下面是一个简化版的扩展示例作用是接收变量参数输出一段 JSON 字符串// 文件路径turbowarp-extension.js class UefiEditorExtension { constructor(runtime) { this.runtime runtime; } getInfo() { return { id: uefiEditorExport, name: UEFI Editor Export, blocks: [ { opcode: exportProject, blockType: command, text: export project as [FORMAT], arguments: { FORMAT: { type: string, defaultValue: json } } } ] }; } exportProject(args, util) { const projectName this.runtime.getGlobalVar(PROJECT_NAME); const version this.runtime.getGlobalVar(PROJECT_VERSION); const bootMessage this.runtime.getGlobalVar(BOOT_MESSAGE); const config { projectName: projectName, version: version, bootMessage: bootMessage }; console.log([UEFI Editor] export config:, JSON.stringify(config, null, 2)); } } Blockly.Blocks[uefiEditor_exportProject] { init() { this.jsonInit({ message0: export project as %1, args0: [ { type: field_dropdown, name: FORMAT, options: [[json, json]] } ] }); } }; window.tempExtension UefiEditorExtension;注意这段代码是“示例思路”不同版本的 Turbowarp 扩展 API 会有差异。你不需要把这个扩展立刻跑起来重点是理解Turbowarp 的积木最终通过 JavaScript 把配置输出给外部脚本。4.4 从 Turbowarp 到构建脚本的完整流程整条链路建议拆成四个独立步骤便于排查问题Turbowarp 编辑器导出 JSONPython 脚本读取 JSON生成 UEFI C 源文件和BOOTX64.EFI构建配置调用交叉编译工具链完成编译把生成的.efi文件复制到 FAT 镜像的\EFI\BOOT\目录。这样做的好处是哪一步出问题可以快速定位而不是把所有逻辑揉在一个大函数里。5. 完整链路实操从编辑器到 UEFI 启动画面这一节用一个完整示例演示“配置 - 构建 - 启动”全流程。示例中的代码和脚本都已经过简化方便你复制到自己的实验环境中。5.1 创建项目目录mkdir -p uefi-editor-demo/{editor,scripts,build,disk} cd uefi-editor-demo目录结构说明uefi-editor-demo/ ├── editor/ # Turbowarp 项目相关的配置导出 ├── scripts/ # 构建和转换脚本 ├── build/ # 编译输出 └── disk/ # FAT 镜像和挂载点5.2 编写配置生成脚本编写一个 Python 脚本读取config.json生成 C 源文件中需要替换的宏定义# 文件路径scripts/generate_config.py import json import os CONFIG_PATH editor/config.json OUTPUT_PATH build/autogen_config.h def main(): with open(CONFIG_PATH, r, encodingutf-8) as f: config json.load(f) project_name config.get(projectName, DemoOS) version config.get(version, 0.1.0) boot_message config.get(bootMessage, Hello from UEFI Editor) enable_gop config.get(enableGop, False) lines [] lines.append(#ifndef AUTOGEN_CONFIG_H_) lines.append(#define AUTOGEN_CONFIG_H_) lines.append(f#define PROJECT_NAME {project_name}) lines.append(f#define PROJECT_VERSION {version}) lines.append(f#define BOOT_MESSAGE {boot_message}) lines.append(f#define ENABLE_GOP {1 if enable_gop else 0}) lines.append(#endif) with open(OUTPUT_PATH, w, encodingutf-8) as f: f.write(\n.join(lines)) print([generate_config] done:, OUTPUT_PATH) if __name__ __main__: main()5.3 生成 UEFI 入口源码为了让示例完整我写一个很小的 UEFI C 入口包含头部文件autogen_config.h// 文件路径build/UefiMain.c #include Uefi.h #include Library/UefiBootServicesTableLib.h #include Library/UefiLib.h #include autogen_config.h EFI_STATUS EFIAPI UefiMain( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { UINT32 Index; Print(L\r\n); Print(L[%s] version %s\r\n, L PROJECT_NAME, L PROJECT_VERSION); Print(LBoot message: %s\r\n, L BOOT_MESSAGE); Print(LGOP output enabled: %d\r\n, ENABLE_GOP); // 打印一段启动信息方便演示 for (Index 0; Index 3; Index) { Print(LBooting ... %d\r\n, Index); } Print(L\r\n); return EFI_SUCCESS; }这里有一个细节需要说明C 语言里的字符串字面量拼接和宽字符串L混用时不同编译器的行为会有差异。上面的写法在 EDK II 中更推荐写成Print(L[%s] version %s\r\n, PROJECT_NAME, PROJECT_VERSION);因为 EDK II 的Print已经对宽字符做了处理直接使用宏定义字符串即可。上面的写法是“示例片段”实际构建时请根据工具链调整。5.4 编译与打包在真实项目里这一步会用 EDK II 或 GNU-EFI 完成。假设你已经配置好了 GNU-EFI 环境核心命令如下# 编译 gcc -I/usr/include/efi \ -fno-stack-protector -fpic -fshort-wchar -mno-red-zone \ -c UefiMain.c -o UefiMain.o # 链接根据实际环境调整库路径 # 伪代码具体以 GNU-EFI 的 Makefile 为准 # ld ... -o UefiMain.so UefiMain.o # objcopy ... --target efi-app-x86_64 UefiMain.so BOOTX64.EFI由于我已经在 3.3 节给出了完整的objcopy转换命令这里不再重复。编译完成后把BOOTX64.EFI放到 FAT 镜像的\EFI\BOOT\目录。5.5 QEMU 运行与预期输出启动 QEMU 后固件会加载BOOTX64.EFI。正常输出的效果大致是 [TurbowarpDemoOS] version 0.1.0 Boot message: Welcome to Turbowarp UEFI Editor GOP output enabled: 1 Booting ... 0 Booting ... 1 Booting ... 2 如果 QEMU 使用的是图形窗口可能会先有 TianoCore 的 Logo然后进入你的程序输出界面。如果使用串口模式可以把输出重定向到终端qemu-system-x86_64 \ -bios /usr/share/OVMF/OVMF_CODE.fd \ -drive filedisk.img,formatraw,ifide \ -net none \ -m 256M \ -nographic5.6 把“宣传片”拍出来的脚本设计如果你要录制项目宣传片建议按下面顺序拍Turbowarp 编辑器拖拽组件展示积木逻辑点击导出显示 JSON 文件终端运行python3 scripts/generate_config.py编译.efi文件挂载 FAT 镜像复制BOOTX64.EFIQEMU 启动屏幕输出系统信息。这样整条视频既有“可视化编辑器”的友好感又有真实编译和运行的结果观感上会比较扎实。6. 常见问题与排查思路这类项目最容易遇到的问题不是编辑器的积木逻辑而是 UEFI 启动和虚拟机环境的兼容性。下面表格里整理了高频问题也补充了从热搜词中观察到的真实困扰。问题现象常见原因解决思路QEMU 启动后黑屏没有任何输出BOOTX64.EFI 格式不正确确认生成的是 PE32 格式检查 objcopy target 是否正确“无法安装 Windows 因为这台电脑的磁盘布局不受 UEFI 支持”磁盘分区表不是 GPT使用convert gpt转换分区表或备份数据后重新分区“VirtualBox 未能启动虚拟电脑可能缺少操作系统”虚拟磁盘没有引导文件或未启用 UEFI在虚拟机设置中启用 EFI确认磁盘 FAT 分区存在\EFI\BOOT\BOOTX64.EFIUEFI 安全启动导致 U 盘装系统失败Secure Boot 未识别自制签名关闭 Secure Boot或使用自签名证书并注册到数据库Turbowarp 导出的 JSON 中文乱码编码格式不一致统一使用 UTF-8 编码在导出脚本中显式指定encodingutf-8编译 UEFI 时出现undefined reference to uefi_call_wrapper链接脚本或库路径不对检查 GNU-EFI 的库路径确认链接参数包含-lefi生成的 EFI 能启动但文字不显示图形模式未设置控制台输出被覆盖检查是否启用了 GOP在打印前确认ConOut初始化完成6.1 关于 UEFI 安全启动自制操作系统通常会遇到 Secure Boot 的问题。原因是固件只信任经过签名或位于数据库中的 EFI 程序。作为学习工具最稳妥的做法是在虚拟机中关闭 Secure Boot在真机实验时确认主板支持关闭 Secure Boot不要为了绕过安全限制去修改固件证书或刷写他人证书。如果你确实需要在开启 Secure Boot 的机器上运行自制系统学习方向应该是UEFI 签名与密钥管理而不是破解固件。6.2 关于“程序不是此操作系统平台的有效应用程序”Windows 下偶尔会出现运行一个.efi或类 ELF 文件时提示“指定的可执行文件不是此操作系统平台的有效应用程序”。这是因为.efi是为了 UEFI 固件准备的不是给 Windows 用户态运行的。如果你在 Windows 里直接双击BOOTX64.EFI有这个提示是正常的。正确做法是放进启动盘或者用 QEMU 启动。7. 最佳实践与工程建议7.1 编辑器与构建工具链解耦这是整个项目最重要的工程决策。Turbowarp 的定位是配置编辑器而不应该直接负责“编译操作系统”。把编辑器与构建工具链解耦后你可以随时替换前端也可以让不同人负责不同模块。推荐的数据流Turbowarp 编辑器 ↓ 导出 JSON 工程描述 Python 配置生成脚本 ↓ 生成 C 头文件和构建配置 GNU-EFI / EDK II 构建链 ↓ BOOTX64.EFI ↓ QEMU / 真机 UEFI 验证7.2 明确最小权限和安全边界自制操作系统工具如果生成的是引导程序本质上是在和固件底层打交道。在生产或共享环境中做实验时要注意先使用 QEMU、VirtualBox 等虚拟机验证不要随便拿生产电脑的原装系统做“真机启动测试”对磁盘分区、格式化操作准备好备份明确你操作的磁盘是哪个设备在涉及修改 UEFI 启动项时使用最小化命令不要批量覆盖。对于内存探测、IO 操作等能力编辑器应默认关闭只有用户明确开启时才生成对应代码。默认安全显式开启是一种好的设计习惯。7.3 版本管理和工程文件规范我建议把三个部分分成三个 Git 仓库避免互相污染turbowarp-uefi-editor-uiTurbowarp 源码和扩展uefi-builder-toolkitPython 脚本和编译链路demo-os-config示例 JSON 配置。版本号建议使用语义化版本例如0.1.0。每次修改配置格式时在 JSON 中增加schemaVersion字段{ schemaVersion: 1.0, projectName: TurbowarpDemoOS }这样将来升级编辑器时可以兼容旧配置。7.4 日志和排错能力底层构建脚本一定要输出完整日志。我常用的做法是# 设置构建日志级别 export BUILD_DEBUG1 python3 scripts/generate_config.py脚本内部可以用 Python 的logging模块把关键步骤打印出来import logging logging.basicConfig(levellogging.DEBUG, format%(asctime)s %(levelname)s %(message)s) logging.info(reading config: editor/config.json) logging.debug(parsed config: %s, config)7.5 对国产操作系统和虚拟机环境的兼容性在某些国产操作系统或定制 Linux 虚拟机上可能出现ping不通、虚拟机扩展工具缺失、磁盘布局不对等问题。如果你做的工具需要部署到这类环境建议提前确认目标系统是否使用 UEFI 启动确认虚拟机的固件类型和磁盘分区表优先采用 FAT32 GPT 的通用配置提前准备好离线安装包避免依赖外网下载。国产操作系统在系统调用、防火墙、桌面环境上和主流 Linux 有差异但 UEFI 和 QEMU 这些底层技术是通用的。只要严格按照 UEFI 规范生成文件通常不会因为系统厂商不同而无法启动。8. 总结与后续路线这个项目让我最感兴趣的地方是它把“大众化的积木编辑器”和“门槛较高的 UEFI 开发”放在了一起。它既能让不了解系统底层的同学快速看到启动流程也能作为真实开发的脚手架先拖拽生成工程再在 C 代码里继续深化最后编译成 UEFI 程序。如果你准备从零开始复刻这个工具建议按下面几个阶段推进第一阶段跑通 QEMU OVMF手动编译一个最简单的BOOTX64.EFI第二阶段定义自己的 JSON 配置格式用 Python 脚本生成 C 源码第三阶段写一个 Turbowarp 自定义扩展把积木配置导出成 JSON第四阶段把前几步串成一条命令一步完成“配置 - 构建 - 启动”第五阶段再加入更多 UEFI 特性比如 GOP 图形模式、内存探测、串口日志。这套链路打通以后你已经不只是会“拖积木”而是真正理解了 UEFI 固件、可执行文件格式、启动介质、虚拟化验证这几个关键环节。过程里遇到的问题越多对自制操作系统底层机制的理解就越扎实。先把第一个能打印出文字的BOOTX64.EFI跑出来再慢慢往里面加东西。