龙芯平台多核Mp逻辑分析

多核Mp逻辑分析

有关龙芯处理器的新接口规范ACPI_3.0是如下定义固件下多核启动跳转到内核下的多核运行:

需要知道的基本问题

  • MailBox,芯片内的广播,用于各个处理器核间共享数据,可以互相访问的Mail,芯片内以一个寄存器来表述.
  • Mp,Multi-Core.
  • SlaveCore,被动运行的Core,通过其他核通知其跳转.

上电处理器核如何运行?

  • 首先,针对龙芯处理器来说,当处理器上电,所有的核都会同一时刻通过spi去flash去取指令和数据,在此刻内存没有被初始化.
  • 然后,每个Core此刻看到和运行的指令是一致的,由于没有写回共享内存或flash数据,所以互补影响,只是简单的配置自身的一些芯片级Config.
  • 之后,SlaveCore去轮寻等待被主核调度,即轮寻MailBox,在龙芯平台下,针对3.0接口规范下有两次被主核调度:

调度流程图

Created with Raphaël 2.2.0 Start SlaveCore轮寻 主核MailBox,查看是否 存在有效信息.例:跳转地址 Yes or No? SlaveCore轮寻 从核自身的MailBox 获得有效信息. Yes or No? End yes no yes no
  • 以上为从核的上电流程,而对应MailBox里的信息,例:函数入口地址,参数,内存块的传递是主核来添写,借此来调度从核,每一次跳转是为了需要从核完成一个特定的功能:
    例:第一次跳转是为了获取从核的有关信息与从核的个数,第二次跳转是为了将主核Boot到内核

Mp是如何详细被调度的?

  • 调度过程到底是为了完成哪些操作?

代码片段:

 496 /**
 497   MP Initialize Library initialization.
 498 
 499   This service will allocate AP reset vector and wakeup all APs to do APs
 500   initialization.
 501   
 502   This service must be invoked before all other MP Initialize Library
 503   service are invoked.     
 504 
 505   @retval  EFI_SUCCESS           MP initialization succeeds.                                                                   
 506   @retval  Others                MP initialization fails.
 507 
 508 **/
 509 EFI_STATUS        
 510 EFIAPI
 511 MpInitLibInitialize (
 512   VOID
 513   ) 
 514 { 
 515   CPU_MP_DATA              *OldCpuMpData;
 516   CPU_INFO_IN_HOB          *CpuInfoInHob;
 517   UINT32                   MaxLogicalProcessorNumber;
 518   UINTN                    BufferSize;
 519   VOID                     *MpBuffer;
 520   CPU_MP_DATA              *CpuMpData;
 521   UINTN                    Index;
 522   
 523   OldCpuMpData = GetCpuMpDataFromGuidedHob (); 
 524   if (OldCpuMpData == NULL) {
 525     MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
 526   } else {
 527     MaxLogicalProcessorNumber = OldCpuMpData->CpuCount;
 528   }
 529   ASSERT (MaxLogicalProcessorNumber != 0);
 530 
 533   BufferSize  = 0;
 514 { 
 515   CPU_MP_DATA              *OldCpuMpData;
 516   CPU_INFO_IN_HOB          *CpuInfoInHob;
 517   UINT32                   MaxLogicalProcessorNumber;
 518   UINTN                    BufferSize;
 519   VOID                     *MpBuffer;
 520   CPU_MP_DATA              *CpuMpData;
 521   UINTN                    Index;
 522   
 523   OldCpuMpData = GetCpuMpDataFromGuidedHob (); 
 524   if (OldCpuMpData == NULL) {
 525     MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
 526   } else {
 527     MaxLogicalProcessorNumber = OldCpuMpData->CpuCount;
 528   }
 529   ASSERT (MaxLogicalProcessorNumber != 0);
 530 
 533   BufferSize  = 0;
 534   BufferSize += sizeof (CPU_MP_DATA);
 535   BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;
 536   MpBuffer    = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));
 537   ASSERT (MpBuffer != NULL);
 538   ZeroMem (MpBuffer, BufferSize); 
 539 
 541   CpuMpData = (CPU_MP_DATA *) MpBuffer;
 542   CpuMpData->CpuCount         = 1;
 543   CpuMpData->BspNumber        = 0;
 544   CpuMpData->CpuData          = (CPU_AP_DATA *) (CpuMpData + 1);
 545   CpuMpData->CpuInfoInHob     = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
 546   InitializeSpinLock(&CpuMpData->MpLock);
 547   //
 548   // Set BSP basic information
 549   //
 550   InitializeApData (CpuMpData, 0, 0);
 552     
 553   if (OldCpuMpData == NULL) {
 554     if (MaxLogicalProcessorNumber > 1) {
 555       //
 556       // Wakeup all APs and calculate the processor count in system
 557       //
 558       CollectProcessorCount (CpuMpData);
 559     } 
 560   } else {
 561     // 
 562     // APs have been wakeup before, just get the CPU Information
 563     // from HOB
 564     //
 565     CpuMpData->CpuCount  = OldCpuMpData->CpuCount;
 566     CpuMpData->BspNumber = OldCpuMpData->BspNumber;
 567     CpuMpData->CpuInfoInHob = OldCpuMpData->CpuInfoInHob;
 568     CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
 569     for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
 570       InitializeSpinLock(&CpuMpData->CpuData[Index].ApLock);
 571       CpuMpData->CpuData[Index].CpuHealthy = (CpuInfoInHob[Index].Health == 0)? TRUE:FALSE;
 572     }
 573     if (MaxLogicalProcessorNumber > 1) {
 574       for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
 575         SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);
 576       }
 577     }
 578   }
 579 
 581   //
 582   // Initialize global data for MP support
 583   //
 584   InitMpGlobalData (CpuMpData);
 585   
 586   return EFI_SUCCESS;
 587 }

先来看下CPU_MP_DATA的定义:

 108 //
 109 // CPU MP Data save in memory
 110 //
 111 struct _CPU_MP_DATA {
 112   UINT64                         CpuInfoInHob;
 113   UINT32                         CpuCount;
 114   UINT32                         BspNumber;
 115   //
 116   // The above fields data will be passed from PEI to DXE
 117   // Please make sure the fields offset same in the different
 118   // architecture.
 119   //
 120   SPIN_LOCK                      MpLock;
 121 
 122   volatile UINT32                FinishedCount;
 123   BOOLEAN                        *Finished;
 124   UINT64                         ExpectedTime;
 125   UINT64                         CurrentTime;
 126   UINT64                         TotalTime;
 127 
 128   CPU_AP_DATA                    *CpuData;
 129 }

这个结构贯穿整个Mp结构,从核填写的数据也是写在这个结构里,然后由主核整理集合,下面仔细分析逻辑:

  1. GetCpuMpDataFromGuidedHob:查询是否已经存在一块Hob内存提供了Mp的资源,如果存在将使用改内存中的处理器核数等进行初始化.
  2. 我们这个默认不存在,所以初始化了逻辑上最大支持的处理器数量 PcdCpuMaxLogicalProcessorNumber=64
  3. 分配内存: MpData, ApData, + (MaxProcessNum * CPU_INFO_IN_HOB)…
  4. 初始化MpData, 因为主核是一直狂奔,所以首先给自身core加入了Mp中,CpuCount=1.
    结构布局: CpuMpData->CpuData = (CPU_AP_DATA *)(CpuMpData + 1); CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
  5. InitializeApData : 初始化ApData, 这里只的是单核的数据,主核狂奔所以这个首先将自身的Cpu信息填写: ApicId及自身的状态etc…
  6. CollectProcessorCount: 主核已经将自身信息填写好,剩余就是第一次通过MailBox调度从核进行各自初始化各自的数据,
  7. 例: 主核为Core0,从核为Core1,从核被调度后,首先进行了几个操作,关中断,占用CpuMpData的内存,将该数据里的CpuCount自增加1(将自身核填写到Mp),依旧按照主核的逻辑,从核自己去填写自己的ApData
  8. 然后,拿到Mp的从核完成自身操作后,将结束标志填写到CpuMpData->FinishedCount,然后等待被内核进行第二次调度进入内核Kernel.
  9. 主核Pause等待所有从核都进行完7,8操作.
  10. 主核等待机制: 完成条件:
    1. 主核设置了超时时间,如果从核还未填写好Ap以及Mp信息,主核将不再等待. 这里超时机制设计到了时钟问题,暂时不说,后期详聊,
    1. 主核设置了最大支持核数, MaxProcessNum , 如果获取到FinshedCount将超过最大支持核数也不再等待.
    1. 例: 最近在调32个核的龙芯服务器, 就已此为例. 默认最大支持64核,当最后一个Core31填写完MpData->CpuCount = 32, InitAp(ApicId=31,…ApState.Idle)etc…,MpData->FinshedCount = 32, 标志着所有核第一次调度初始化完成,从核将轮寻等待主核去内核进行调度,主核将继续狂奔.
    1. 最终不忘将Mp的数据保存起来,供其他服务使用,比如ACPI需要知道启动了多少个核,才能允许内核BootCore的个数.

到这里,Mp的逻辑进行了简单的梳理,希望共同学习,有所收获,本人是小白一枚,在这里祝愿龙芯越来越好

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

来杯清咖_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值