kernel 如何调用uefi的runtime service

本文详细介绍了在Linux内核中如何实现UEFI运行时服务,特别是针对ARM64架构。通过分析源代码,解释了如何设置运行时服务函数指针并调用这些服务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在drivers/firmware/efi/runtime-wrappers.c 中会建立kernel调用uefi的runtime service
static int __init arm64_enable_runtime_services(void)
{

    /* Set up runtime services function pointers */
    efi_native_runtime_setup();
    set_bit(EFI_RUNTIME_SERVICES, &efi.flags);

}
early_initcall(arm64_enable_runtime_services);
可见是通过early_initcall自动调用arm64_enable_runtime_services
void efi_native_runtime_setup(void)
{
    efi.get_time = virt_efi_get_time;
    efi.set_time = virt_efi_set_time;
    efi.get_wakeup_time = virt_efi_get_wakeup_time;
    efi.set_wakeup_time = virt_efi_set_wakeup_time;
    efi.get_variable = virt_efi_get_variable;
    efi.get_next_variable = virt_efi_get_next_variable;

}
我们以virt_efi_get_time为例
static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
{
    unsigned long flags;
    efi_status_t status;

    spin_lock_irqsave(&rtc_lock, flags);
    spin_lock(&efi_runtime_lock);
    status = efi_call_virt(get_time, tm, tc);
    spin_unlock(&efi_runtime_lock);
    spin_unlock_irqrestore(&rtc_lock, flags);
    return status;
}
efi_call_virt 定义如下:
#define efi_call_virt(f, ...)                        \
({                                    \
    efi_##f##_t *__f;                        \
    efi_status_t __s;                        \
                                    \
    kernel_neon_begin();                        \
    efi_virtmap_load();                        \
    __f = efi.systab->runtime->f;                    \
    __s = __f(__VA_ARGS__);                        \
    efi_virtmap_unload();                        \
    kernel_neon_end();                        \
    __s;                                \
})

替换掉宏定义最终还是调用efi.systab->runtime->get_time(tm,tc)

<think>好的,用户现在对fstab和UEFI启动之间的关系有疑问。之前他询问了关于grub2-install使用自定义EFI目录的问题,现在他可能遇到了启动问题,或者在深入学习Linux启动流程。需要明确fstab的作用和UEFI固件的行为区别。 用户的问题核心是:fstab的自动挂载是否影响UEFI找到ESP分区。根据之前的回答,用户可能误解了操作系统挂载分区和固件访问分区的不同。需要详细解释这两者的区别,以及为何即使fstab没有正确配置,UEFI仍然可以访问ESP分区,但操作系统在启动过程中需要挂载才能更新引导文件。 可能需要分步骤解释启动流程,区分UEFI阶段和内核加载后的阶段。指出内核挂载根文件系统后,systemd会根据fstab挂载其他分区,包括ESP。如果ESP没有挂载到/boot/efi,那么更新引导程序时会失败,但UEFI本身在启动时已经读取了引导文件,所以不影响启动,但后续维护会出问题。 用户可能没有意识到,安装引导文件到ESP是在系统运行时进行的操作,而UEFI在启动时直接读取ESP中的文件。因此,如果安装时ESP没有正确挂载,引导文件可能被安装到错误的位置,导致UEFI找不到正确的文件,从而无法启动。但用户的问题更侧重于重启后的情况,这里需要澄清即使fstab错误,只要安装时ESP正确挂载,UEFI已经记录了引导项,可能还能启动,但后续更新会失败。 还需要考虑用户可能混淆了UEFI访问分区和操作系统挂载分区的权限问题,比如文件系统类型和挂载选项的影响。需要强调fstab的作用是确保每次启动后ESP被正确挂载到指定位置,以便系统工具能够访问和更新引导文件。 总结来说,用户的疑问源于对启动流程不同阶段的理解不足,需要明确各阶段的责任和依赖关系,区分固件行为和操作系统行为。</think>### 分步解析 #### 核心矛盾点 您发现了一个关键认知误区:**UEFI固件访问ESP分区与操作系统挂载ESP分区是两个完全独立的过程**。让我们通过启动流程分解来理清这个关系: --- #### 启动阶段对比 ```mermaid sequenceDiagram participant UEFI固件 participant ESP分区 participant 内核 participant systemd participant fstab 通电启动->>UEFI固件: 1. 固件自检 UEFI固件->>ESP分区: 2. 直接读取FAT32文件系统 UEFI固件->>内核: 3. 加载vmlinuz和initramfs 内核->>systemd: 4. 启动初始化进程 systemd->>fstab: 5. 挂载所有分区 ``` --- #### 技术细节剖析 ##### 阶段1:UEFI固件操作 - **访问方式**:通过**UEFI Runtime Services**直接读取磁盘 - **特点**: - 不需要任何操作系统支持 - 仅识别FAT32文件系统 - 通过GPT分区表中的"EF00"类型码识别ESP分区 ##### 阶段2:系统挂载 - **触发条件**:内核加载完成后 - **依赖关系**: ```bash # 典型挂载流程 systemd-remount-fs.service → systemd-fstab-generator → mount units ``` --- #### 矛盾现象解释 ##### 场景模拟 | 步骤 | fstab配置 | 结果表现 | |------|-----------|----------| | 1. 首次安装 | 正确配置 | UEFI找到`/EFI/BOOT/BOOTX64.EFI` | | 2. 删除fstab条目 | 无ESP配置 | 系统仍能正常启动 | | 3. 执行`grub2-mkconfig` | 无ESP挂载 | 生成错误的grub.cfg | ##### 关键原理 - **UEFI持久化存储**:通过`efibootmgr`写入NVRAM的引导条目包含完整路径: ```bash # 示例NVRAM条目 Boot0001* Ubuntu HD(1,GPT,f32d1e5a-...)/File(\EFI\ubuntu\shimx64.efi) ``` - **路径解析规则**: - UEFI使用**物理路径**(如`FS0:\EFI\...`) - 操作系统使用**挂载点路径**(如`/boot/efi/EFI/...`) --- #### 故障发生条件 当同时满足以下两个条件时才会出现启动失败: ```python if not esp_mounted_during_install and not esp_auto_mount: # 安装时路径与实际路径不一致 create_broken_efi_entry() elif kernel_update_without_esp_mount: # 引导文件更新失败 cause_boot_failure() ``` --- #### 实际影响分析 ##### 情况1:仅fstab错误 - **系统表现**: - ✅ 能正常启动(依赖NVRAM记录) - ❌ `grub-install`等命令失败 - ❌ 内核更新无法修改引导文件 ##### 情况2:安装时路径错误 - **连锁反应**: 1. UEFI加载错误引导文件 2. 内核无法找到根文件系统 3. 触发emergency shell --- #### 深度验证方法 ##### 实验1:破坏性测试 ```bash # 删除fstab中的ESP条目 sudo sed -i '/\/boot\/efi/d' /etc/fstab # 强制更新内核 sudo dnf update kernel -y # 检查引导文件 ls -l /boot/efi/EFI # 将提示"No such file or directory" ``` ##### 实验2:NVRAM操作 ```bash # 查看当前引导条目 efibootmgr -v # 手动创建引导条目 sudo efibootmgr -c -d /dev/sda -p 1 -L "Recovery" -l "\EFI\BACKUP\grubx64.efi" ``` --- #### 标准化解决方案 ##### 正确配置示例 ```bash # 查看ESP分区UUID blkid /dev/nvme0n1p1 # 示例fstab条目 UUID=1234-ABCD /boot/efi vfat umask=0077,errors=remount-ro 0 1 # 验证配置 sudo mount -a && findmnt /boot/efi ``` ##### 紧急修复措施 ```bash # 进入救援模式后 mkdir /mnt/root mount /dev/mapper/root_vg-root_lv /mnt/root mount /dev/sda1 /mnt/root/boot/efi chroot /mnt/root nano /etc/fstab # 添加正确条目 ``` --- ### 关键结论 1. **UEFI自主访问**:固件层直接读取ESP分区,与操作系统挂载无关 2. **路径映射依赖**:操作系统工具通过挂载点访问引导文件 3. **更新机制风险**:未挂载时进行的引导相关操作会破坏引导 #### 故障矩阵 | 错误类型 | 首次启动 | 后续启动 | 内核更新 | |----------|----------|----------|----------| | fstab错误 | 正常 | 正常 | 失败 | | 安装路径错误 | 失败 | 失败 | 不可用 | | 双重错误 | 失败 | 失败 | 不可用 | 建议定期验证:`mount | grep /boot/efi && ls /boot/efi/EFI`
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值