文档目录架构 · 18 篇

启动协议

说明冷启动的输入、Linux 直接加载器的行为、生效命令行的组成以及冷启动序列。

译自microsoft/nvx · doc/design/5.1-boot-protocol.md。技术细节以英文原文为准。

架构文档 > 5. VM 生命周期与状态

冷启动会消费由宿主选择的内核、可选的 initramfs、初始 RAM 容量、处理器容量、设备挂载和工作负载策略。机器配置文件对这些输入进行校验,并在打开客户机执行之前构建出完整的生效配置。

5.1.1 Linux 直接加载器

加载器把内核、initramfs、命令行、拓扑、预留区域和客户机地址都视为不可信输入。它:

  1. 对 x86-64 要求小端序、未压缩的 ELF64 映像,并拒绝压缩的自解压 Linux 内核格式(bzImage)。
  2. 在各自的物理地址处加载经过校验的可加载段,并将其 BSS 尾部清零。
  3. 把可选的 initramfs 放在内核之后的第一个 2 MiB 边界处。
  4. 构建 Intel MP 1.4 处理器、ISA 总线、IOAPIC 以及传统中断项。
  5. 用规范的 e820 RAM 与预留映射构建 Linux boot_params。
  6. 安装引导用的 GDT 和 4 GiB 恒等映射页表。
  7. 在启用分页的前提下,以 x86-64 的 64 位执行模式(long mode)进入内核。

不执行任何固件;加载器既不解析也不生成 Xen 直接启动入口点的启动元数据(Xen notes 或 start-info 结构)、ACPI 表、操作系统用于定位这些表的指针(RSDP)、SMBIOS 数据或设备树。零页中的 ACPI RSDP 地址保持为零。

表 5.1 列出了初始处理器状态。

表 5.1. 初始处理器状态。

寄存器 值
指令指针(RIP) ELF 入口点
承载启动参数指针的通用寄存器(RSI) 0x2000,即 boot_params 零页
页表基址(CR3) 0x4000,即恒等映射页表
处理器控制(CR0) 置位保护模式(PE)与分页(PG)
扩展处理器控制(CR4) 置位物理地址扩展(PAE)
扩展特性使能(EFER) 启用 long mode

5.1.2 生效命令行

控制台、设备发现和宿主策略相关的标记由机器配置文件拥有,而不是调用方。基础命令行是:

earlycon=xe9 console=hvc0 reboot=t panic=-1

当存在启动 virtio-console 时,内核控制台变为 hvc1,字节通道仍作为早期控制台。用户参数跟在基础标记之后。随后一次全新启动按以下顺序追加由宿主拥有的标记:

  1. nr_cpus=<capacity>,使 Linux 按经过校验的拓扑来调整其处理器状态的规模。
  2. 可选的固定工作负载身份 nvx_workload_uid= 和 nvx_workload_gid=,以及工作负载生命周期 nvx_lifecycle=。
  3. 对于带沙箱块的捕获,nvx_snapshot_tier=<tier>。
  4. 按固定地址顺序排列的设备发现标记:网络、宿主文件系统、启动控制台、沙箱块,以及控制控制台(后跟 nvx_control_tty=hvc2)。
  5. 网络引导标记,其中只有在出站策略允许向网关进行 DNS 时才包含 DNS 服务器,并在最后、当宿主发布客户机监听器时包含入站模式,其后是宿主文件系统引导标记。

调用方不得提供 earlycon=、console=、virtio_mmio.device=、nr_cpus=、任何网络或宿主文件系统引导标记、nvx_snapshot_tier=、nvx_workload_uid=、nvx_workload_gid= 或 nvx_lifecycle=。带控制控制台的机器还要应用控制控制台规则。命令行不携带时钟参数:客户机从时间 ABI的 MSR 读取其 TSC 和 LAPIC 速率,而来自调用方或快照的 tsc_early_khz= 或 lapic_timer_hz= 会被拒绝。

启动器会添加自己的运行时标记:每个宿主共享子项一个共享标记、无块托管根的宿主映射数量,以及一个创建工作负载账号的请求。调用方还可以用一个且仅一个 nvx_overlay_upper=ramfs 标记声明基于 RAM 的叠加布局;该标记的其他任何形式都会被拒绝。

内嵌的 NUL 会被拒绝,完整的以 NUL 结尾的命令行必须能放进 64 KiB。生效字符串及其 SHA-256 摘要成为快照机器契约的一部分。恢复会原样复用该字符串,不追加任何标记。

5.1.3 冷启动序列

一次冷启动:

  1. 选择 CPU 配置文件,并拒绝命令行中的时钟标记。
  2. 在任何处理器运行之前创建分区并对后端做预检:CPU 配置文件支持、生效 CPUID、身份路由、同步集合原语,以及不存在 TSC 缩放。
  3. 读取并检查原生 TSC 与 LAPIC 速率,并将其声明为 F 和 L。
  4. 加载客户机,并把代次计数器置为零。
  5. 启动状态单元并释放处理器。

冷启动不写入 TSC:每个后端都让处理器的 TSC 一起启动。随后内核发现固定的 virtio-mmio 设备并启动客户机代理;它们在就绪之前把客户机时钟步进到宿主 UTC,组装工作负载根目录,应用隔离,并启动一次性工作负载或托管控制服务。