Magenta

来源:互联网 发布:淘宝奢侈品拍卖真假 编辑:程序博客网 时间:2024/05/16 02:26

初以学x86入行,后转战至ARM,耗时10余载,今又切回x86。忍不住吐槽一下~~


Magenta - BP启动AP(x86篇)


Magenta支持SMP,所以需要Bootstrap CPU(BP)启动Application CPU(AP)的功能。这部分和体系架构密切相关,就以x86结构为例说明。

AP的启动,在各个系统上的流程大同小异,大概都分为2大部分:

  • BP为AP初始化启动环境
  • AP自身的初始化

BP流程

不同的系统,2阶段的分工并不相同。在magenta上,BP做了如下工作:

  • 为每个CPU创建私有的idle task, 此task被pin在对应的CPU上;

  • 创建bootstrap地址空间,起始地址为0,大小为 (0x80000000-0x01000000),即在kernal base addr向下偏移0x01000000。作为AP的启动地址空间。

  • 在bootstrap空间创建地址映射表,包括2部分的identity map:

    • 基地址为0x9e000,长度是8KB。这部分将来作为AP的启动代码和参数区域;
    • kernel的GDT,以便AP可以在启动阶段就能读取kernel GDT;
  • 将启动代码复制到地址为0x9e000处,即x86_bootstrap16_entry的代码;

  • 在(0x9e00+0x1000)处创建启动参数,包括:
    • kernel的页表物理基地址
    • bootstrap的页表基地址
    • 指向GDT物理地址的gdtr
    • 64bit模式下的entry函数地址 _x86_secondary_cpu_long_mode_entry
    • 为每个CPU分配一个thread_t结构体,作为bootstrap thread,后期由各个AP自己初始化
    • 为每个CPU的bootstrap thread分配stack,大小为4KB

至此,BP已经为AP创建为运行环境。之后就是利用INIT IPI和STARTUP IPI去唤醒AP。发送STARTUP IPI时,所带的vect参数是0x9e = (0x9e000>>12),即告诉AP从地址0x9e000处开始取指执行。

然后BP会监视一个全局变量cpu_waiting_mask,等待所有的AP都启动完毕。每当一个AP启动完毕,会根据自己的CPU ID将cpu_waiting_mask中对应的bit清除。


AP流程

AP在0x9e000处看到的代码是x86_bootstrap16_entry。此时AP处于实模式下。做了如下工作:

  • 加载启动参数中的gdtr;
  • 进入保护模式;
  • 加载bootstrap的页表基地址至CR3;
  • 使能IA-32e mode和分页功能;
  • 跳转至64bit模式下的entry;

64bit下的初始化包括:

  • 设置bootstrap thread的stack为当前rsp;
  • 设置CR3为kernel的页表物理基地址;
  • 加载IDT;
  • 调用函数x86_secondary_entry,所带参数分为cpu_waiting_mask和bootstrap thread

x86_secondary_entry做了如下工作:

  • 配置本CPU的cpu控制块,此控制块的基地址被写入X86_MSR_IA32_GS_BASE,后期可以直接通过gs:[]的方式来访问控制块;
  • x86初始化
    • 包括建立TSS:
      • 在GDT中为本CPU创建TSS;
      • 为3种特殊类型的中断创建栈,分为NMI/MACHINE_CHECK/DOUBLE_FAULT;
      • 利用ltr指令加载TSS的selector;
    • 利用指令lidt加载IDT
      • IDT已由BP在之前创建完毕;
      • IDT共256个项,每个entry是中断门;
      • 每个中断门对应的函数地址定义在数组_isr_table中,最终都指向 interrupt_common;
      • 为NMI/MACHINE_CHECK/DOUBLE_FAULT这3中类型的中断设置interrupt stack table(IST),从而在此些中断发生时,CPU可以切换至TSS中对应的栈;
    • syscall的配置
      • 配置函数x86_syscall作为syscall的kernel entry;
      • 配置syscall 进入和退出时的code segment
        • 从user进入kernel时: CS = CODE_64_SELECTOR / SS = DATA_SELECTOR
        • 从kernel退回user时:CS = USER_CODE_64_SELECTOR / SS = USER_DATA_SELECTOR
      • 使能指令syscall
  • 将cpu_waiting_mask中对应本CPU的bit清除;
  • 初始化bootstrap thread,设置为最高优先级,以便可以安全调用其他初始化routine;
  • 最后,将本cpu标记为active和idle,并退出bootstrap thread。从而可以调度至CPU的idle task。

当AP可以运行至本CPU的idle task,即可认为AP的启动已经完成。


最后来张镇楼图片:

这里写图片描述