secondary_startup_64

secondary_startup_64 是 Linux 内核中,为系统中除主引导处理器(BSP,即第1个CPU核心)外的所有其他CPU核心(Application Processors, APs) 准备的64位启动入口点

它承担着“唤醒其他CPU核心并让它们进入工作状态”的使命。这些AP核心在系统启动或休眠唤醒时,会被BSP通过特殊的处理器间中断(IPI)唤醒,然后从实模式或保护模式经过一系列跳转,最终进入这个 secondary_startup_64 入口。

secondary_startup_64 主要任务

当AP核心执行到这里时,它已经处于64位模式,但还需要完成最后的初始化才能成为系统的一员。它的核心任务是:

  1. 为进入C语言世界做准备

    • 设置自己的内核栈:它不能再用BSP的栈,需要根据CPU编号或per-CPU数据,将栈指针%rsp切换到专属的内核栈空间

    • 设置%gs基地址:通过wrmsr指令写入MSR_GS_BASE寄存器,为当前CPU建立per-CPU数据区的基址,以便能安全地访问当前CPU相关的变量。

    • 传递启动参数:将boot_params结构体指针(保存在%rsi中)作为第一个参数,通过movq %rsi, %rdi传递给即将调用的C函数。

  2. 完成最后的环境切换

    • 在完成上述准备后,它会通过一个长返回(lretq间接跳转,跳转到initial_code变量所指向的C语言函数地址。在标准的SMP启动流程中,这个函数就是 start_secondary()

    • start_secondary()函数会完成CPU热插拔、调度器初始化等剩余工作,最终让该CPU核心进入空闲状态,等待调度器分配任务。

特殊场景与优化

  • 代码复用与维护:为了精简代码并统一BSP和AP的启动路径,secondary_startup_64后半部分(设置栈、跳转到C代码)会与start_cpu0(用于CPU热插拔重启)共享相同的逻辑。这部分代码曾通过一个名为 start_cpu 的公共函数实现,后来被优化为直接整合进secondary_startup_64内部的一个标签(如.Ljump_to_C_code)中。

  • 安全启动与虚拟化

    • 在支持Intel TXT(可信执行技术)的安全启动场景下,AP的唤醒流程可能不走常规的INIT/SIPI信号,而是通过特殊的MONITOR/MWAIT指令。在这种方式下,AP最终也会汇聚到 secondary_startup_64 这个标准入口。

    • 对于AMD SEV(安全加密虚拟化)环境,为了避免在启动早期进行不必要的CPU特性验证,内核可能会提供一个跳过verify_cpu()检查的版本,例如 secondary_startup_64_no_verify

/*
 * secondary_startup_64
 */
0x1000000 <startup_64>                  lea    0x1203f51(%rip),%rsp        # 0x2203f58
0x1000007 <startup_64+7>                callq  0x10000e0 <verify_cpu>
0x100000c <startup_64+12>               lea    -0x13(%rip),%rdi        # 0x1000000 <startup_64>
0x1000013 <startup_64+19>               push   %rsi
0x1000014 <startup_64+20>               callq  0x10001ec <__startup_64>
0x1000019 <startup_64+25>               pop    %rsi
0x100001a <startup_64+26>               add    $0x23fc000,%rax                      // rax=0x23fc000
0x1000020 <startup_64+32>               jmp    0x1000042 <secondary_startup_64+18>
0x1000022 <startup_64+34>               data16 nopw %cs:0x0(%rax,%rax,1)
0x100002d <startup_64+45>               nopl   (%rax)
0x1000030 <secondary_startup_64>        callq  0x10000e0 <verify_cpu>
0x1000035 <secondary_startup_64+5>      push   %rsi
0x1000036 <secondary_startup_64+6>      callq  0x10004eb <__startup_secondary_64>
0x100003b <secondary_startup_64+11>     pop    %rsi     
0x100003c <secondary_startup_64+12>     add    $0x220a000,%rax
0x1000042 <secondary_startup_64+18>     mov    $0xa0,%ecx               // ecx=0xa0 
0x1000047 <secondary_startup_64+23>     mov    %rcx,%cr4                // rcx=0xa0
0x100004a <secondary_startup_64+26>     add    0x1210fbf(%rip),%rax        # 0x2211010      rax=0x23fc000
0x1000051 <secondary_startup_64+33>     mov    %rax,%cr3                // cr3=0x23fc000
0x1000054 <secondary_startup_64+36>     mov    $0xffffffff8100005d,%rax // rax=ffffffff8100005d
0x100005b <secondary_startup_64+43>     jmpq   *%rax                    // jump 0x100005d   执行完指令后变成虚拟地址
0x100005d <secondary_startup_64+45>     mov    $0x80000001,%eax         // eax=0x80000001
0x1000062 <secondary_startup_64+50>     cpuid 
0x1000064 <secondary_startup_64+52>     mov    %edx,%edi                // edi=0x20100800
0x1000066 <secondary_startup_64+54>     mov    $0xc0000080,%ecx         // ecx=0xc0000080
0x100006b <secondary_startup_64+59>     rdmsr
0x100006d <secondary_startup_64+61>     bts    $0x0,%eax                // eax=0x500 --> 0x501 
0x1000071 <secondary_startup_64+65>     bt     $0x14,%edi               // edi=0x20100800 --> 0x20100800
0x1000075 <secondary_startup_64+69>     jae    0x1000084 <secondary_startup_64+84>  // not jump
0x1000077 <secondary_startup_64+71>     bts    $0xb,%eax                // eax=0x501 -> 0xd01
0x100007b <secondary_startup_64+75>     btsq   $0x3f,0x1210f94(%rip)        # 0x2211018     // 0xffffffff82211018 <early_pmd_flags>
0x1000084 <secondary_startup_64+84>     wrmsr                           // ecx=0xc0000080
0x1000086 <secondary_startup_64+86>     mov    $0x80050033,%eax
0x100008b <secondary_startup_64+91>     mov    %rax,%cr0                // rax=0x80050033
0x100008e <secondary_startup_64+94>     mov    0x1308ee3(%rip),%rsp        # 0x2308f78  rsp=0xffffffff82203f58, 0x2308f78:0xffffffff82203f58
0x1000095 <secondary_startup_64+101>    pushq  $0x0                     // eflags         0x6                 [ IOPL=0 PF ]
0x1000097 <secondary_startup_64+103>    popfq
0x1000098 <secondary_startup_64+104>    lgdt   0x1210f61(%rip)        # 0x2211000   // 0xffffffff82211000:0xffff82356000007f
0x100009f <secondary_startup_64+111>    xor    %eax,%eax                // eax=0
0x10000a1 <secondary_startup_64+113>    mov    %eax,%ds                 // ds=0
0x10000a3 <secondary_startup_64+115>    mov    %eax,%ss                 // ss=0
0x10000a5 <secondary_startup_64+117>    mov    %eax,%es                 // es=0
0x10000a7 <secondary_startup_64+119>    mov    %eax,%fs                 // fs=0
0x10000a9 <secondary_startup_64+121>    mov    %eax,%gs                 // gs=0
0x10000ab <secondary_startup_64+123>    mov    $0xc0000101,%ecx         // ecx=0xc0000101
0x10000b0 <secondary_startup_64+128>    mov    0x1308eba(%rip),%eax        # 0x2308f70  eax=0x8234d000, 0xffffffff82308f70:0xffffffff8234d000
0x10000b6 <secondary_startup_64+134>    mov    0x1308eb8(%rip),%edx        # 0x2308f74  edx=0xffffffff, 0xffffffff82308f74:0x82203f58ffffffff
0x10000bc <secondary_startup_64+140>    wrmsr
0x10000be <secondary_startup_64+142>    mov    %rsi,%rdi                // rdi=0x14310
0x10000c1 <secondary_startup_64+145>    pushq  $0xffffffff810000d4      // 此处继续运行
0x10000c6 <secondary_startup_64+150>    xor    %ebp,%ebp
0x10000c8 <secondary_startup_64+152>    mov    0x1308e99(%rip),%rax        # 0x2308f68
0x10000cf <secondary_startup_64+159>    pushq  $0x10
0x10000d1 <secondary_startup_64+161>    push   %rax
0x10000d2 <secondary_startup_64+162>    lretq
0x10000d4                                   data16 nopw %cs:0x0(%rax,%rax,1)
0x10000df                                   nop

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值