x86 处理器开机顺序

2019-04-14 18:38发布

           不管是千万行的linux ,还是百万行的uefi ,或者百十行的app, 它都有一个主线,应用程序是main() 函数里面所有函数执行完,程序结束。这里main() 做为程序的起点,uefi 可以认为,就是peimain.c  dxemain.c bds.c 这三个函数执行完,bios 结束,如果进一步的细分, 如果 把pei 和 sec 叫做early initialization, 这一阶段 主要就是在做microcode 更新,跳到保护模式,用cache 去模拟内存以便实现C函数的子过程调用,内存配置,内存(控制器)的配置,就是mrc 的执行,其实就是按照 JEDEC 定好的初始化顺序,主要是取得这些信息, rank的数量, 地址是8 bit 还是16 bit, 内存容量,内存的电源管理,page 关闭策略, 内存初始化好之后,就是进行memory 测试,最常见的就是ECC.  当这一切做完了,就把bios 代码 shadowing 到内存上面。  剩下来就是完成 板子上其他设备的初始化了, GPIO, 中断控制器,timer, 串口, 时钟(超频), pci bus 初始化(就是找到它们,并给它们分资源, 其实就是内存,i/o space, mmio, irq, 找到option rom ,以及执行option rom). 网卡初始化, usb, sata. 最后就是 装载os, 通过efi 的 load image 或者 int 19h 去调用 os loader.

Application Processor (AP) 初始化

        这年头,即使手机,平板电脑,也配备了多核处理器,BSP + AP 的组合方式,由BSP 负责去初始化系统, 在内存初始化之前,AP 处于未初始化状态,当内存起来之后,内存被初始化,处于等SIPI 状态, 具体是这样玩的: 1 找到microcode ,复制到内存中。 2 在SIPI 里面找到cpu code ,复制到内存中 3 向所有的处理器发送IPI 4 Disable NEM  5 对所有处理器进行micro code 更新 6 把所有处理器cache 打开 具体的细节去参考software Developer's Manual,  更详细的过程就要参考bios writer's guide了。
如果从UEFI 的角度看,那么AP 的初始化可以划在PEI 阶段。

CPUID-线程以及core

现在 对一些常见的术语进行解释: thread. -  线程, 逻辑上的处理器,与其他logical 处理器处于同一个package上面,并与其他逻辑处理器共享资源。 core.  与其他core 处于同一个packge 上面,但不需要与其他core 共享任何资源。 package 即我们看得见的芯片,可以包含任意数量的core 和 thread.

Startup Inter-Processor Interrupt (SIPI)

BSP 通过向每一个core ,thread 去发送SIPI 去叫醒(wake up) 它们。具体来说是通过BSP 的LAPIC , LAPIC 标识了SIPI 要发给哪一个AP.
发送IPI JQA是通过写寄存器ICR完成的, 先来看一下ICR, ICR是64位寄存器, 可分为两个32位寄存器,ICR 的数据结构如下图所示:


具体过程就是这样的:

AP Wakeup State

当AP 接收到SIPI 之后,就开始执行sipi 指向的代码。
Platform 初始化过程: 现行代码分成mem initial 之前的部分和mem initial 之后的部分,即PlatformInitPreMem.c 和PlatformInit.c。 premem 阶段,主要完成pch 一些基本的初始化(主要是完成对gpio的定义, LPC IO 的配置), 还有timer 的初始化,
    PCH 初始化入口为:PchInitPreMem.c  它主要也是分两个阶段 :early PEI phase(Memoyr 初始化之前) 和memory is available(memory 能用了)