Step to UEFI (72) ----- MP_Service_Protocol 获得CPU信息

UEFI本身不支持多线程,据说主要原因是:UEFI设计本身是为了启动硬件,做一些比较简单的事情,如果支持多线程会使得设计复杂度直线上升,出现问题也不容易调试。

不过UEFI本身是有对应的Protocol 的,称作 EFI_MP_SERVICES_PROTOCOL 。 具体的这个 Protocol 可以在 PI spec 中找到(UEFI Spec中没有)。下面来自【参考1】

image001

同样可以作为参考的还有EFI_Toolkit_2.0.0.1 中的process.c 程序。

程序很简单,首先 LocateProtocol 到EFI_MP_SERVICES_PROTOCOL。然后,用 Protocol 提供的EFI_MP_SERVICES_GET_NUMBER_OF_PROCESSORS 和EFI_MP_SERVICES_GET_PROCESSOR_INFO 来获得关于处理器的一些信息。需要注意的是EFI_MP_SERVICES_GET_PROCESSOR_INFO,输入的参数ProcessorNumber 意思是:当前要获得的 Processor 号,输入0 表示你要去的编号为 0 的Processor 的信息,输入3 表示你要去的编号为 3 的Processor 的信息,取值范围从0到NumberOfProcessors -1。

image002

最终的代码:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>
#include  <Pi/PiDxeCis.h>
#include  <Protocol/MpService.h>

EFI_GUID  gEfiMpServiceProtocolGuid = { 0x3fdda605, 0xa76e, 0x4f46, 
						{ 0xad, 0x29, 0x12, 0xf4, 0x53, 0x1b, 0x3d, 0x08 }};
  
extern EFI_BOOT_SERVICES         *gBS;

int
EFIAPI
main (
  IN int Argc,
  IN CHAR16 **Argv
  )
{
	EFI_STATUS	Status;
	EFI_MP_SERVICES_PROTOCOL	*MP=NULL;
	UINTN   i;	
	UINTN	NumProcessors;
	UINTN	NumberOfEnabledProcessors;

	EFI_PROCESSOR_INFORMATION	ProcessorInfo;
	
	//Get MP_Service Protocol
	Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID**)&MP);
	if (EFI_ERROR (Status)) {
		Print(L"Unable to initialize MP protocol interface!");
		return EFI_UNSUPPORTED;
	}
	
	// Determine number of processors
	Status = MP->GetNumberOfProcessors( MP, &NumProcessors , &NumberOfEnabledProcessors );
	
	if (EFI_ERROR (Status))
	{
		Print( L"MP->GetNumEnabledProcessors:Unable to determine number of processors\n") ;
		return EFI_UNSUPPORTED;
	}	
	Print(L"Number of Processors %d\n",NumProcessors);
	Print(L"Number of Enabled Processors %d\n",NumberOfEnabledProcessors);
	
	//Get more information by GetProcessorInfo
	for (i=0;i<NumProcessors;i++)
	{
		Status = MP->GetProcessorInfo(MP, i , &ProcessorInfo);
		
		Print( L"Prcoessor #%d ACPI Processor ID = %lX, Flags = %x, Package = %x, Core = %x, Thread = %x \n", 
					i,
					ProcessorInfo.ProcessorId, 
					ProcessorInfo.StatusFlag,
					ProcessorInfo.Location.Package,
					ProcessorInfo.Location.Core,
					ProcessorInfo.Location.Thread);
	}
	
	return EFI_SUCCESS;
}

运行结果:

image003

完整的代码下载:

MPTest1

关于这部分程序,在《UEFI 原理与编程》第13章 深入了解多任务 有更详细的论述,如果你有这方面的需求,推荐直接阅读。

另外,如果你想获得更多CPU方面的信息,比如 Cache大小, 还可以通过 CPUID,但是非常不建议通过 SMBIOS 来获得,因为他并不可靠......

最后特别提醒:

开始编写程序时,我遇到了下面的错误,错误代码对于解决问题毫无帮助,最后经过分析发现是因为没有添加PiDxe.h头文件(感谢Marco指出)导致的。

c:\edk\MdePkg\Include\Protocol/MpService.h(361) : error C2146: syntax error : missing ')' before identifier 'Procedure'
c:\edk\MdePkg\Include\Protocol/MpService.h(361) : error C2081: 'EFI_AP_PROCEDURE' : name in formal parameter list illegal
c:\edk\MdePkg\Include\Protocol/MpService.h(361) : error C2061: syntax error : identifier 'Procedure'
c:\edk\MdePkg\Include\Protocol/MpService.h(361) : error C2059: syntax error : ';'
c:\edk\MdePkg\Include\Protocol/MpService.h(361) : error C2059: syntax error : ','
c:\edk\MdePkg\Include\Protocol/MpService.h(367) : error C2059: syntax error : ')'
c:\edk\MdePkg\Include\Protocol/MpService.h(459) : error C2146: syntax error : missing ')' before identifier 'Procedure'
c:\edk\MdePkg\Include\Protocol/MpService.h(459) : error C2081: 'EFI_AP_PROCEDURE' : name in formal parameter list illegal
c:\edk\MdePkg\Include\Protocol/MpService.h(459) : error C2061: syntax error : identifier 'Procedure'
c:\edk\MdePkg\Include\Protocol/MpService.h(459) : error C2059: syntax error : ';'
c:\edk\MdePkg\Include\Protocol/MpService.h(459) : error C2059: syntax error : ','
c:\edk\MdePkg\Include\Protocol/MpService.h(465) : error C2059: syntax error : ')'
c:\edk\MdePkg\Include\Protocol/MpService.h(623) : error C2061: syntax error : identifier 'EFI_MP_SERVICES_STARTUP_ALL_APS'
c:\edk\MdePkg\Include\Protocol/MpService.h(624) : error C2061: syntax error : identifier 'StartupThisAP'
c:\edk\MdePkg\Include\Protocol/MpService.h(624) : error C2059: syntax error : ';'
c:\edk\MdePkg\Include\Protocol/MpService.h(628) : error C2059: syntax error : '}'
NMAKE : fatal error U1077: '"C:\Program Files\Microsoft Visual Studio 9.0\Vc\bin\cl.exe"' : return code '0x2'
Stop.

参考:

1. Vol2_DXE CIS_1_3.pdf P174

《Step to UEFI (72) ----- MP_Service_Protocol 获得CPU信息》有10个想法

  1. Hello
    First let me thank you for your work and examples.
    Second,I don't know any programming language so I ask for help.
    Try to build x64 version but no luck yet.
    Used Ubuntu few version (14 16 and 18) and few version of EDK2 but allway get these errors.
    For two of them I find a workaround but one still remain.
    Can you provide a fix?
    Thankyou.

    Library error
    error 4000: Instance of library class [LibC] is not found
    in [/home/G62/src/edk2/MPTest1/MPTest1.inf] [X64]
    -solved by adding "!include StdLib\StdLib.inc"

    main error
    /home/G62/src/edk2/MPTest1/MPTest1.c:14:1: error: second argument of ‘main’ should be ‘char **’ [-Werror=main]
    main ( ...

    return EFI_UNSUPPORTED error
    /home/G62/src/edk2/MdePkg/Include/Base.h:927:38: error: overflow in implicit constant conversion [-Werror=overflow]
    #define ENCODE_ERROR(StatusCode) ((RETURN_STATUS)(MAX_BIT | (StatusCode)))
    -quick fix replaced return EFI_UNSUPPORTED with return EFI_SUCCESS

  2. Hello again
    Thanks for answer.
    Indeed under windows works.
    But my HP laptop Insyde 3.5 BIOS use an deprecated protocol
    FRAMEWORK_EFI_MP_SERVICES_PROTOCOL_GUID:[0xf33261e7, 0x23cb, 0x11d5, 0xbd, 0x5c, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81]
    Using your code as template I made this,don't know if is correct but result is
    Number of Processors 4
    Max number of Processors 8
    Number of Enabled Processors 4
    RendezvousIntNumber 0
    RendezvousProcLength 4096
    Processor #0 ACPI Apic ID = 0, Enabled = 1, Designation = 1, Health = 0, PackageNumber = 0, NumberOfCores = 8, NumberOfThreads = 2, ProcessorPALCompatibilityFlags = 2, ProcessorTestMask = 0
    Processor #1 ACPI Apic ID = 1, Enabled = 1, Designation = 0, Health = 0, PackageNumber = 0, NumberOfCores = 8, NumberOfThreads = 2, ProcessorPALCompatibilityFlags = 2, ProcessorTestMask = 0
    Processor #2 ACPI Apic ID = 4, Enabled = 1, Designation = 0, Health = 0, PackageNumber = 0, NumberOfCores = 8, NumberOfThreads = 2, ProcessorPALCompatibilityFlags = 2, ProcessorTestMask = 0
    Processor #3 ACPI Apic ID = 5, Enabled = 1, Designation = 0, Health = 0, PackageNumber = 0, NumberOfCores = 8, NumberOfThreads = 2, ProcessorPALCompatibilityFlags = 2, ProcessorTestMask = 0

    I did something wrong since it say 8 cores.
    On some generation of HP laptops there is a problem with some OS, doesn't detect right all cores and complain about LAPIC,So I try to investigate what's the problem not all cores enabled by BIOS or LAPIC doesn't configured properly.
    Here is what I did

    #include
    #include
    #include
    #include
    #include

    EFI_GUID gFrameworkEfiMpServiceProtocolGuid = { 0xf33261e7, 0x23cb, 0x11d5,
    { 0xbd, 0x5c, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 }};

    extern EFI_BOOT_SERVICES *gBS;

    int
    EFIAPI
    main (
    IN int Argc,
    IN CHAR16 **Argv
    )
    {
    EFI_STATUS Status;
    FRAMEWORK_EFI_MP_SERVICES_PROTOCOL *MP=NULL;
    UINTN i;
    UINTN NumberOfCPUs;
    UINTN NumberOfEnabledCPUs;
    UINTN BufferLenght;
    UINTN MaximumNumberOfCPUs;
    UINTN RendezvousIntNumber;
    UINTN RendezvousProcLength;
    EFI_MP_PROC_CONTEXT ProcessorContextBuffer;

    //Get MP_Service Protocol
    Status = gBS->LocateProtocol (&gFrameworkEfiMpServiceProtocolGuid, NULL, (VOID**)&MP);
    if (EFI_ERROR (Status)) {
    Print(L"Unable to initialize MP protocol interface!");
    return EFI_UNSUPPORTED;
    }

    // Determine number of processors
    Status = MP->GetGeneralMPInfo( MP, &NumberOfCPUs , &MaximumNumberOfCPUs , &NumberOfEnabledCPUs , &RendezvousIntNumber , &RendezvousProcLength );

    if (EFI_ERROR (Status))
    {
    Print( L"MP->GetNumEnabledProcessors:Unable to determine number of processors\n") ;
    return EFI_UNSUPPORTED;
    }
    Print(L"Number of Processors %d\n",NumberOfCPUs);
    Print(L"Max number of Processors %d\n",MaximumNumberOfCPUs);
    Print(L"Number of Enabled Processors %d\n",NumberOfEnabledCPUs);
    Print(L"RendezvousIntNumber %d\n",RendezvousIntNumber);
    Print(L"RendezvousProcLength %d\n",RendezvousProcLength);

    //Get more information by GetProcessorContext
    for (i=0;iGetProcessorContext(MP, i , &BufferLenght , &ProcessorContextBuffer);

    Print( L"Processor #%d ACPI Apic ID = %lX, Enabled = %x, Designation = %x, Health = %x, PackageNumber = %x, NumberOfCores = %x, NumberOfThreads = %x, ProcessorPALCompatibilityFlags = %x, ProcessorTestMask = %x \n",
    i,
    ProcessorContextBuffer.ApicID,
    ProcessorContextBuffer.Enabled,
    ProcessorContextBuffer.Designation,
    ProcessorContextBuffer.Health,
    ProcessorContextBuffer.PackageNumber,
    ProcessorContextBuffer.NumberOfCores,
    ProcessorContextBuffer.NumberOfThreads,
    ProcessorContextBuffer.ProcessorPALCompatibilityFlags,
    ProcessorContextBuffer.ProcessorTestMask);
    }

    return EFI_SUCCESS;
    }

    1. You can compare the test result with CPU-z under OS. BIOS may be return an error result as this Protocol is not an important one.

      And if you just want to get the number of CPU cores, you may study the usage of CPUID.

  3. #include
    #include
    #include
    #include
    #include
    Seem like some parts of text doesn't appear in previous message.
    Anyway if this get same result I write again. what is at include
    Uefi.h
    Library/UefiLib.h
    Library/ShellCEntryLib.h
    Pi/PiDxeCis.h
    Include/Protocol/FrameworkMpService.h

  4. 今天刚遇到了和博主同样的问题,当时无奈只得将APP改为DXE才能编过。终于在这就得到答案了。感谢博主,又学习了。

  5. 感謝博主分享,
    在.c 中
    EFI_GUID gEfiMpServiceProtocolGuid = {0x3fdda605, 0xa76e, 0x4f46, {0xad, 0x29, 0x12, 0xf4, 0x53, 0x1b, 0x3d, 0x08}}; 這個GUID 可以在.inf 中宣告即可:
    [Protocols]
    gEfiMpServiceProtocolGuid
    這個 GUID 已經在 MdePkg.dec 中定義,而 MdePkg 已包在 .inf 的 packages 中

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注