openEuler 安装系列详解01 | 引导与分区表简介

wiltech
发布于 2022-8-16 11:37
浏览
0收藏

作为一名优秀的码农,必须熟练掌握的技能,大家肯定都能列出一大堆出来,多线程,操作系统,分布式等等……不过,在掌握这些晦涩难懂的知识前,码农们还需要掌握的一个重要的技能,那就是要学会怎么打开计算机。


小伙伴们有没有考虑过,当你按下电脑的启动键时,是什么在冥冥之中,指引计算机找到了操作系统并完成了启动?说到这个问题,那就不得不提的是:系统引导。

 

系统引导


在计算机中,引导是启动计算机过程中的一个重要阶段。计算机从按下开机键到系统启动完成可供用户操作为止,严格的来说分为两个阶段:引导(booting)和启动(startup)。引导阶段开始于按下电源开关,结束于内核初始化完成以及 systemd 进程成功运行。引导作为上电以后的第一个步骤,承担了系统自检,加载内核的重要责任。在开机后,计算机的主内存中并没有任何软件数据,因此必须由某些程序将软件加载到内存中才能使计算机继续工作,这可以通过 CPU 中的硬件、系统固件或者系统中单独的处理器来执行这些预先预置好的程序,其中服务器上常使用的方式是 BIOS 固件。

引导的主要流程:

openEuler 安装系列详解01 | 引导与分区表简介-鸿蒙开发者社区

其中,bootloader 就是启动加载器,常见的就是 syslinux 以及 grub2。在 openEuler 中只有在使用光盘启动 legacy BIOS 的情况下使用 syslinux,其他情况下均使用 grub2,这个我们会在下篇博客中着重介绍。

 

BIOS


BIOS(Basic Input/Output System)是计算机主板上的一块很小的 ROM/闪存芯片里面的固件程序,用来在引导过程中初始化硬件并为操作系统和程序提供运行时服务。BIOS 固件是系统上电以后 CPU 运行的第一个软件,用来测试系统硬件组件并从大容量存储介质中加载 bootloader 程序。

 

legacy BIOS


传统的 BIOS 固件一般设计用于某特定计算机或主板型号,称为 legacy BIOS。不同 CPU 在系统上电时首条 PC(Program Counter)是由 CPU 设计者决定的,所以计算机启动时使用的 BIOS 程序地址会根据主板兼容的 CPU 来进行不同设置。

 

例如 i386 的 CPU 首次启动时从 0Xfffffff0h 地址开始执行指令,这个地址在 X86 体系中一般是由 CPU 芯片组转发 ROM 得到,其中 ROM 里存储着 BIOS 的运行代码。

 

legacy 在被 CPU 拉起以后,首先执行的指令一般为上电自检,检测范围包括 RAM、显卡等硬件设备,硬件检测完成后,BIOS 会将它找到的第一个有效的 MBR 分区表硬盘加载到物理内存地址 0x7C00 处(世界第一台个人 PC 中内存为 32K,为了给 OS 留下充足的连续内存使用,将 MBR 磁盘中的引导代码加载到了最后 1K 的内存中,地址即 0x7C00。因为 bootloader 在 OS 启动后不会再使用,操作系统在使用中可以覆写这块 1K 内存以达到使用最大数量的内存的目的)。legacy 中的最后一条代码指令一般都是跳转到该地址。随后 bootloader 程序将执行拉起内核的动作。

 

随着时代的发展,legacy BIOS 其自身的不足也逐渐暴露出来,例如寻址能力弱,难以集成第三方代码,自检时间长,不支持图形界面等。

 

UEFI


为了解决 BIOS 的技术局限性,英特尔开发定义了操作系统与平台固件之间的一系列软件接口规范,称之为可扩展固件接口(EFI)规范,并在 2005 年 7 月贡献给了 Unified EFI 论坛。即使没有安装操作系统,UEFI 也可以支持计算机的远程诊断和修复。

 

最新的 UEFI2.8 版本已于 2019 年 3 月发布。

 

UEFI2.8 规范文档地址:https://uefi.org/sites/default/files/resources/UEFI_Spec_2_8_final.pdf

 

UEFI 可以自动检测 bootloader,从而可以轻松的从移动设备(例如 USB 闪存驱动器)来进行引导,这种检测依赖于 bootloader 的标准化文件路径,该路径根据计算机体系结构而有所不同,文件路径的格式定义为<EFI_SYSTEM_PARTITION>\EFI\BOOT\BOOT<MECHINE_TYPE_SHORT_NAME>.EFI,EFI_SYSTEM_PARTITION 使用 fat 磁盘格式,fat 格式的磁盘文件不区分大小写,文件名保留创建时候使用的大小写名称,例如在 openEuler 操作系统上,BOOTX64.EFI/BOOTAA64.EFI 实际为 shim 生成的扫描程序,会自动扫描所有 EFI 文件夹下含有 BOOTX64.CSV/BOOTAA64.CSV 的文件夹,并根据其内容创建新的启动项,方便下次启动时直接从该目录进行引导启动。例如:BOOTAA64.CSV 文件的内容:

openEuler 安装系列详解01 | 引导与分区表简介-鸿蒙开发者社区

  • shimaa64.efi:引导启动使用的二进制程序入口
  • openEuler:创建引导启动使用的标签名

 

openEuler 上的 BIOS


在 openEuler 支持的计算机体系中,X86 支持以 legacy BIOS/UEFI 模式启动,AArch64 仅支持 UEFI 模式启动。

 

BIOS 启动后,会去磁盘上寻找 bootloader 并跳转执行 bootloader,此时 BIOS 的主要使命已经完成,后续由 bootloader 拉起内核。BIOS 是如何知道 bootloader 在磁盘上的信息的呢,请看下节。

 

分区表
有时候我们在引导操作系统时可能会碰到问题,为什么 BIOS 报没有找到可以用于启动的介质,明明安装是成功的呀,这就有可能是 bootloader 没有被成功的写入硬盘或者硬盘的分区有问题,导致分区信息无法被正确识别,BIOS 无法认出我们磁盘上的 bootloader,自然会导致磁盘失败。例如:

  1. MBR 磁盘首个 512 字节扇区数据时发现数据存在问题,bootloader 位置的数据全为 0x00。
  2. GPT 磁盘的 fat 分区创建失败,使用 ext4 分区格式并将 bootloader 错误写入。

 

想要定位这些问题,我们首先要对磁盘的分区表有个初步的了解

 

MBR(Master Boot Record)


MBR 被称为主引导记录,也称为主引导扇区,是计算机开机以后 BIOS 访问硬盘时所必须要读取的第一个扇区。其布局为:

openEuler 安装系列详解01 | 引导与分区表简介-鸿蒙开发者社区

前 446 个字节是引导代码区,存放着系统的启动引导代码。常见为 stage1(legacy)或者 boot.img(GRUB2)。

 

在引导代码之后,保存着 64 个字节的分区表记录,每条分区表记录为 16 字节,所以 MBR 分区表最大支持 4 个主磁盘分区或者 3 个主磁盘分区以及一个扩展磁盘分区(Extended boot record, EBR)。

 

在过去的 512B 扇区磁盘中,MBR 使用逻辑块地址(Logical block addressing,LBA)来进行地址寻址,逻辑块地址使用 32 位存储逻辑地址,32 位寻址模式最大可处理扇区为 2^32,每个扇区为 512 字节,即 2^9,所以可寻址的最大字节数为 2^41,即 2Tib。后来的 4K 盘能支持 MBR 寻址扩展到 4K*2^32 共 2^44,即 16TiB,但是由于向前兼容性的问题,大部分厂商仍对 MBR 分区表使用模拟 512 字节扇区的模式。

 

当从 MBR 分区表开始启动的时候,BIOS 首先需要从启动介质中加载首个 MBR 512 字节扇区,当首个扇区的数据存在问题时,BIOS 会尝试从其他启动项进行启动。如果所有的启动项都无法成功,则系统启动失败。MBR 首个 512 字节扇区的格式如下:

openEuler 安装系列详解01 | 引导与分区表简介-鸿蒙开发者社区

分区表数据说明:(80)(20 21 00)(83)(aa 28 82)(00 08 00 00)(00 00 20 00)

  • (80):0x80 代表是激活分区,可以用来引导,0x00 代表未激活分区,不能用来引导
  • (00 08 00 00):分区开始扇面,图中 CPU 为小端序,故该值为 0x800=2048,所以该分区开始于 2048 扇面
  • (00 00 20 00):分区总共扇面数,因 CPU 是小端序,故该值为 0x200000=2097152,该扇区的容量为 2097152*512KiB/1024/1024/1024=1GiB

 

GUID(Global Unique Identifiers)


GUID 是一个实体磁盘的分区表的结构布局的标准。它是 UEFI 标准中的一部分,设计之初即为了解决 MBR 分区表中使用 32 位来存储逻辑块地址、大小信息的缺点。

 

GPT(GUID Partition Table)使用 64 位作为逻辑块地址,最大支持 2^64 个扇区,对于 512B 磁盘来说,最大的大小为 2^64*512B=2^73,即 8ZiB,对于 4K 盘来说,最大支持的数据为 2^64*4K=2^76=64ZiB。

 

使用 GPT 作为启动盘符时,bootloader 必须放置于 vfat 文件格式上,UEFI 启动时,只能读取 fat 分区格式的磁盘分区,(fat 格式本身属于 UEFI 规范中),其他磁盘格式均不能用作 UEFI 启动分区格式。

 

使用 MBR/GPT 混合分区表的硬盘中,原本 MBR 位置存储了 GPT 分区表的一部分分区(通常为前四个分区),可以使不支持从 GPT 启动的操作系统从这个 MBR 启动,启动后只能操作 MBR 分区表中的分区。GUID 分区表从第二个 512 字节扇区开始,称为 GPT 表头,从 GPT 表头后,会携带数个 GPT 表分区,理论上 GPT 的表分区个数是无限的。

 

GPT 表头结构:

openEuler 安装系列详解01 | 引导与分区表简介-鸿蒙开发者社区

例如:

openEuler 安装系列详解01 | 引导与分区表简介-鸿蒙开发者社区

表头结构说明:

  1. 固定签名:”EFI PART”。
  2. 表头大小:0x5C,即 92 字节,对应结束位置为上图的 00000250 行右起第 4 个位置。
  3. 分区表的扇区位置:小端序,位置为扇区 0x01,即 01 扇区。
  4. 备份分区表的扇区位置:小端序,位置为 0x0C 7F FF FF 扇区,即第 209715199 扇区(磁盘的最后一个扇区,磁盘总大小为(209715199 + 1)*0.5KiB/1024/1024=100GiB)。
  5. 第一个可用的扇区位置:小端序,位置为 0x22 扇区,所以分区表项分区共有个 0x22-0x01=0x21 个扇区,去掉 GPT 表头扇区,所以共 32 个分区表表项扇区。
  6. 最后一个可用的扇区位置:小端序,位置为 0x0C 7F FF DE,即第 209715166 扇区,到磁盘的最后一个扇区相差 33 个扇区,其中包括 32 个 GPT 备份分区表项和 1 个 GPT 备份分区头。
  7. GPT 分区表项开始扇区:位置为 0x02。
  8. GPT 分区表项的个数:个数为 0x80,即 128 个。GUID 分区表表项中每条分区表最小为 128 字节,因 GUID 表头中记录的 GPT 分区一般为 128,故需要 128*128 字节/512Kib=32 个扇区。
    GPT 分区表表项结构:

openEuler 安装系列详解01 | 引导与分区表简介-鸿蒙开发者社区openEuler 安装系列详解01 | 引导与分区表简介-鸿蒙开发者社区

如何查看自己计算机的硬盘分区表


使用命令 parted /dev/磁盘名称后输入 p 即可看到自己磁盘使用的分区表类型:

GPT 分区表:

openEuler 安装系列详解01 | 引导与分区表简介-鸿蒙开发者社区

MBR(msdos)分区表:

openEuler 安装系列详解01 | 引导与分区表简介-鸿蒙开发者社区

 

openEuler 上使用的分区表


openEuler 一般使用 legacy BIOS + MBR、UEFI+GPT 的分区组合,所以在 x86 上如果使用的 legacy BIOS 模式,那么分区表一般是 MBR,在 x86/aarch64 的 UEFI 下,分区表一般为 GPT,大家可以自行尝试看下安装的结果哈。

 

结语


因为篇幅限制,引导启动目前只能先介绍到这里,下一期会带大家一起了解 BIOS 拉起 bootloader(grub)以及 bootloader 启动内核的相关过程,希望大家可以关注我们的文章。

 

参考资料:

  1. https://en.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface
  2. https://en.wikipedia.org/wiki/BIOS
  3. https://en.wikipedia.org/wiki/MBR
  4. https://en.wikipedia.org/wiki/GUID_Partition_Table

 

文章转载自公众号:openEuler

分类
已于2022-8-16 11:37:22修改
收藏
回复
举报
回复
    相关推荐