在U盘中安装Ubuntu并支持在BIOS/UEFI 2种引导方式下启动

概述

目标

  • 向目标U盘中安装Ubuntu系统
  • 该安装能够在BIOS或UEFI引导下进入系统
  • 无需制作另外的LiveCD安装介质

方法

  • 使用虚拟机(VMWare为例)作为安装环境, 安全无污染, 不必担心宿主机环境被损毁
  • 使用GPT分区表, 预留bios_grub分区, 先进行UEFI引导下的安装, 之后添加BIOS引导
  • 使用虚拟机(VMWare为例)作为测试环境, 无需开关宿主机就可以验证安装是否成功

需求

  • Ubuntu镜像, iso格式, 本教程使用20.04.1, 对于其他linux发行版有待验证
  • VMWare Workstation Pro或其替代品, 能够支持:
    • 创建并管理虚拟机, 需要提供虚拟光驱, USB
    • (安装用)UEFI模式引导虚拟机系统
    • (安装用)挂载USB设备, 或将宿主机UAS设备挂载为虚拟机SCSI磁盘
    • (测试用)BIOS模式引导虚拟机系统
    • (测试用)将宿主机UAS设备挂载为虚拟机SCSI磁盘
  • U盘
    • 16GB或更高, USB3.1或更高
    • (推荐)使用固态硬盘+转换盒组成的固态U盘

警告

  • 升级内核时或者大版本时, 请务必谨慎
  • 如果出现升级后无法引导的情况, 请查阅下文当中的维护U盘中的Ubuntu

向U盘安装Ubuntu

准备U盘

  • 备份U盘中的任何数据, 如果有必要
  • 必须确认U盘中的数据可以全部被删除
  • 删除所有已经存在的分区, 并将U盘分区表转换为GPT类型

创建虚拟机

  • 虚拟机名称: 随意
  • 虚拟机版本: 默认
  • 客户机操作系统: Ubuntu 64位
  • 硬件: 全部默认

更改虚拟机属性

  • 移除-虚拟网络控制器
  • 移除-虚拟硬盘
  • 修改-USB控制器版本, 匹配宿主机目标U盘的实际协议
  • 修改-虚拟光驱, 挂载Ubuntu镜像iso, 勾选启动时连接
  • 修改-虚拟机设置>选项>高级>固件类型, 设置为UEFI

启动虚拟机, 准备安装

  • 开机-虚拟机应当引导进入Ubuntu LiveCD, 直到出现Try UbuntuInstall Ubuntu字样
  • 选择-Try Ubuntu, 直到进入LiveCD桌面
  • 挂载-右下角托盘, 将目标U盘作为USB设备挂载到虚拟机
  • 选择-检测到USB设备后, Install Ubuntu xxxx, 启动安装程序

开始安装

  • 选择-按需选择语言, 安装规模等, 直到Installation Type页面
  • 选择-Something Else, 即手动进行分区并安装

对U盘进行分区

  • 新建分区表-右键U盘设备, 应当为/dev/sda, 选择New partition table
  • 添加分区-添加如下的分区, 分区大小仅供参考
    • (必须)大小1MB, 类型为Reserved BIOS boot area
      • 添加该分区后, 您可能会注意到, 磁盘头部出现33MB的未分配空间, 而该分区大小变为33MB, 这是完全正常的
    • (必须)大小500MB, 类型为EFI System Partition
    • (可选)大小500MB, 类型为Ext4 journaling file system, 挂载点/boot
      • 该操作不推荐, 99%的情况下不必要
      • 某些老旧的BIOS无法识别存在于8GB或64GB之后的可引导分区, 因此该操作曾经有意义
      • 使用raid等方式安装系统时, 该操作是必须的, 很明显我们没有这样做
    • (必须)大小10GB+, 类型为Ext4 journaling file system, 挂载点/
      • 若有单独为/home分区, 该大小推荐设置为20GB左右
      • 若无单独/home, 占满磁盘剩余空间即可, 若有需要可以保留一些未分配空间
    • (可选)大小10GB+, 类型为Ext4 journaling file system, 挂载点/home
      • 看个人情况, 占满剩余磁盘空间或保留一些未分配空间
  • 确认分区-必须包括如下分区
    • (必须)大小50MB, 类型为Reserved BIOS boot area
    • (必须)大小500MB, 类型为EFI System Partition
    • (必须)大小10GB+, 类型为Ext4 journaling file system, 挂载点/

完成安装

  • 地区, 账户按需要填写, 等待安装完成, 不要退出安装程序
  • 选择-Continue trying

为BIOS添加引导

  • 切换到root用户

    1
    sudo su
  • 确定挂载各个位置, 以您创建分区的顺序为依据

    1
    2
    3
    fdisk -l
    # 教程假定挂载点为'/boot'的分区(若存在)为/dev/sda3, 请根据需要修改
    # 教程假定挂载点为'/'的分区为/dev/sda3, 请根据需要修改
  • 挂载/的分区到当前系统 或 挂载/boot的分区到当前系统

    1
    2
    mkdir /mnt/sda3
    mount /dev/sda3 /mnt/sda3
  • 安装grub, 根据挂载的是否为/boot挂载点的分区选择您待执行的命令

    1
    2
    3
    4
    # 如果您挂载的是'/'分区, 其为/dev/sda3, 则
    grub-install --target=i386-pc --boot-directory=/mnt/sda3/boot /dev/sda
    # 如果您挂载的是'/boot'分区, 其为/dev/sda3, 则
    grub-install --target=i386-pc --boot-directory=/mnt/sda3 /dev/sda
  • 检查分区情况

    • 启动gparted
    • 如果您发现添加时设置为1MB的分区, 此时拥有文件系统grub core.img, 说明grub-pc安装完毕

关闭虚拟机

测试U盘中的Ubuntu

更改虚拟机属性

  • 添加-虚拟硬盘, 磁盘类型设置为使用物理驱动器, 选择目标U盘, 一般为最后一个
  • 修改-虚拟光驱, 取消勾选启动时连接

启动虚拟机(UEFI)

  • 虚拟机应当成功引导进入Ubuntu桌面, 执行下面的命令, 以验证当前的引导类型
    1
    2
    ls /sys/firmware/efi
    # 若成功执行, 说明为UEFI引导; 若提示找不到文件, 则为BIOS引导

更改虚拟机属性

  • 修改-虚拟机设置>选项>高级>固件类型, 设置为BIOS

启动虚拟机(BIOS)

  • 虚拟机应当成功引导进入Ubuntu桌面, 执行上文的命令, 以验证当前的引导类型

关闭虚拟机

维护U盘中的Ubuntu

  • 如果发生无法引导的状况, 可以参考该节进行维护, 仍使用虚拟机方法

创建虚拟机

  • 与前文用于安装的虚拟机配置相同

启动至LiveCD

  • 选择-Try Ubuntu
  • 进入-终端

开始修复

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# root
sudo su

# 定位分区
fdisk -l
# 假设 /dev/sda2 为 efi 分区
# 假设 /dev/sda3 为 / 分区
# 假设 /dev/sda3 为 /boot 分区, 如果有

# 挂载分区
mkdir /mnt/sda2
mkdir /mnt/sda3
mount /dev/sda2 /mnt/sda2
mount /dev/sda3 /mnt/sda3

# 安装efi需要的依赖
apt install grub-efi-amd64

# 以下命令针对没有单独/boot分区的用户
## 修复UEFI引导
grub-install --target=x86_64-efi --boot-directory=/mnt/sda3/boot --efi-directory=/mnt/sda2 --removable /dev/sda
## 修复BIOS引导
grub-install --target=i386-pc --boot-directory=/mnt/sda3/boot /dev/sda

# 以下命令针对单独/boot分区的用户
## 修复UEFI引导
grub-install --target=x86_64-efi --boot-directory=/mnt/sda3 --efi-directory=/mnt/sda2 --removable /dev/sda
## 修复BIOS引导
grub-install --target=i386-pc --boot-directory=/mnt/sda3 /dev/sda

测试修复结果

  • 与前文安装后进行的测试相同

发生甚么事了

  • 这一部分将解释为什么上文的操作能行, 核心的概念:
    • UEFI与BIOS引导
    • MBR与GPT分区表
  • 我不是BIOS或者UEFI或者MBR或者GPT专家, 这里的介绍仅供参考
    • 只介绍了用的上的部分

MBR分区表

  • MBR: 主引导记录, 在磁盘扇区0, 包括一段引导代码和分区表之类的
  • 神秘的空间: 扇区1~扇区62

GPT分区表

  • GPT: 在磁盘扇区1
  • protective MBR: 在磁盘扇区0
    • 主要为了防止不认识GPT的程序, 将磁盘误认为未分区, 因此添加该部分, 假装自己是MBR
    • 尽管具有正常MBR的结构, 但是这里把整个磁盘分为一个区, 意思就是”别瞎搞”
    • 正因此结构, BIOS+GPT的组合才能成功
  • bios_grub分区
    • 代替”神秘的空间”, 专门为grub-pc在GPT上运行

BIOS引导

  • 流程概述
    • 加载主板rom当中的BIOS固件
    • 磁盘扇区0为MBR, 加载其中的代码段
    • 代码段执行, 直接加载操作系统, 或者加载更多代码直到加载操作系统
  • grub-pc
    • MBR扇区代码段, 被grub-install替代为boot.img的内容, 该代码将加载一个硬编码地址的core.img
      • 由于GPT存在protective MBR, 在GPT分区下依然可以安放这段代码, 而BIOS固件根本不在乎分区表类型, 因此可以启动
    • core.img存放在:
      • MBR下: 扇区1~扇区62的这个部分里, “神秘的空间”, 和bootkit类病毒肩并肩
      • GPT下: 带有bios_grub的分区内
    • core.img执行时, 将根据配置文件加载操作系统

UEFI引导

  • 流程概述
    • 加载主板nvram当中的UEFI固件
    • 磁盘带esp flag的分区, 加载其中的.efi文件
    • 加载操作系统
  • grub-efi
    • 没什么特别的, 本体就是一个.efi文件

UEFI+GPT

  • 美滋滋, 最新最好的引导和分区方式, 一种标准范式
  • windows使用UEFI引导强制要求GPT, 这是windows的错误

UEFI+MBR

  • 可以配合BIOS+MBR实现双启动
  • 我也尝试过了, 但是不优雅, 等我心情好在写在这里
  • MBR面临主分区最大4个或3个, 外带拓展分区和逻辑分区的问题, 不影响使用, 但不够优雅

BIOS+GPT

  • 本文方法, 配合UEFI+GPT实现双启动
  • BIOS只查看第一个扇区, 加载里面的代码, 然后跳转走人, 因此只要第一个扇区是一个有效的MBR即可, 而GPT恰好可以
  • UEFI只看一个esp分区, 也是同样

BIOS+MBR

  • 另一个标准范式

总结

  • 本文操作能成功的关键
    • GPT的protective MBR, 允许一个GPT分区兼容MBR的代码段
    • grub-pc针对GPT提供的bios_grub解决方法