三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

BSP 和 AP 的启动路径分离

BSP 和 AP 的启动路径分离

/*
* Now that this CPU is running on its own stack, drop the realmode
* protection. For the boot CPU the pointer is NULL!
*/
movq trampoline_lock(%rip), %rax
testq %rax, %rax
jz .Lsetup_gdt
movl $0, (%rax)

这段汇编代码是 Linux 内核启动流程中,应用处理器(AP)解除对实模式代码保护的关键步骤,确保其顺利进入保护模式。

可以将代码拆解为三个核心逻辑部分,并结合背景来理解。

背景:释放实模式锁

在 x86 多核启动中,所有 AP(应用处理器)在唤醒时,最初都在实模式下运行。为了防止多个 CPU 同时争抢或破坏共享的实模式代码和数据(trampoline),内核使用了一个自旋锁(spinlock)来确保同一时刻只有一个 CPU 在执行这段代码。

当 AP 成功切换到 64 位模式并拥有了自己的栈后,它就需要释放这个锁,以便唤醒下一个 AP 核心。这就是这段代码的最终目的。

代码逻辑详解

  1. 获取锁的地址

    movq trampoline_lock(%rip), %rax

    这行代码获取了名为trampoline_lock的锁变量的当前地址(RIP-relative 寻址)并存入%rax

  2. 检查锁是否有效

    testq %rax, %rax jz .Lsetup_gdt
    • testq指令检查%rax是否为 0(即NULL)。

    • 如果%rax == 0,说明当前执行的是主 CPU(BSP),因为 BSP 是从 BIOS 直接启动的,并不通过 trampoline 代码唤醒,所以它没有持有这个锁,直接跳转到.Lsetup_gdt继续执行。

    • 如果%rax != 0,则说明当前是 AP CPU,需要执行释放锁的操作。

  3. 释放锁

    movl $0, (%rax)

    这是释放锁的实际操作,它将trampoline_lock指向的内存地址的值设置为0。这个动作会解除锁的保护,并唤醒下一个在等待的 AP 核心。

设计意图:明确的职责分离

这段代码体现了内核启动中一个重要的设计思路:BSP 和 AP 的启动路径分离

  • BSP (Boot Strap Processor):在head_64.S中,BSP 的入口会跳过锁释放的步骤,直接进入 GDT 设置,因为它从未占用过这个锁。

  • AP (Application Processor):所有 AP 在secondary_startup_64中都会经过这段逻辑,释放trampoline_lock,确保唤醒机制的正确性和数据的一致性。trampoline_lock本身是一个在arch/x86/kernel/smpboot.c中定义的全局指针。

这个设计确保了在复杂的多核启动过程中,共享资源的访问是安全且有序的。

← 返回列表