Skip to content

Commit

Permalink
OcCpuLib: Add support for framework EFI MP services
Browse files Browse the repository at this point in the history
  • Loading branch information
al3xtjames authored and vit9696 committed Jan 17, 2020
1 parent 63102b2 commit 86839a8
Show file tree
Hide file tree
Showing 2 changed files with 186 additions and 41 deletions.
224 changes: 184 additions & 40 deletions Library/OcCpuLib/OcCpuLib.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <PiDxe.h>

#include <IndustryStandard/AppleSmBios.h>
#include <Protocol/FrameworkMpService.h>
#include <Protocol/MpService.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
Expand All @@ -31,66 +32,50 @@

STATIC
EFI_STATUS
ScanThreadCount (
OUT OC_CPU_INFO *Cpu
ScanMpServices (
IN EFI_MP_SERVICES_PROTOCOL *MpServices,
OUT OC_CPU_INFO *Cpu,
OUT UINTN *NumberOfProcessors,
OUT UINTN *NumberOfEnabledProcessors
)
{
EFI_STATUS Status;
EFI_MP_SERVICES_PROTOCOL *MpServices;
UINTN Index;
UINTN NumberOfProcessors;
UINTN NumberOfEnabledProcessors;
EFI_PROCESSOR_INFORMATION Info;

Cpu->PackageCount = 1;
Cpu->CoreCount = 1;
Cpu->ThreadCount = 1;

Status = gBS->LocateProtocol (
&gEfiMpServiceProtocolGuid,
NULL,
(VOID **) &MpServices
);

if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "OCCPU: No MP services - %r\n", Status));
return Status;
}
ASSERT (MpServices != NULL);
ASSERT (Cpu != NULL);
ASSERT (NumberOfProcessors != NULL);
ASSERT (NumberOfEnabledProcessors != NULL);

NumberOfProcessors = 0;
NumberOfEnabledProcessors = 0;
Status = MpServices->GetNumberOfProcessors (
MpServices,
&NumberOfProcessors,
&NumberOfEnabledProcessors
NumberOfProcessors,
NumberOfEnabledProcessors
);

DEBUG ((
DEBUG_INFO,
"OCCPU: MP services threads %u (enabled %u) - %r\n",
(UINT32) NumberOfProcessors,
(UINT32) NumberOfEnabledProcessors,
Status
));

if (EFI_ERROR (Status)) {
return Status;
}

if (NumberOfProcessors == 0) {
if (*NumberOfProcessors == 0) {
return EFI_NOT_FOUND;
}

//
// This code assumes that all CPUs have same amount of cores and threads.
//
for (Index = 0; Index < NumberOfProcessors; ++Index) {
for (Index = 0; Index < *NumberOfProcessors; ++Index) {
Status = MpServices->GetProcessorInfo (MpServices, Index, &Info);

if (EFI_ERROR (Status)) {
//
// It might make sense to error and exit here.
//
DEBUG ((
DEBUG_INFO,
"OCCPU: Failed to get info for processor %Lu - %r\n",
(UINT64) Index,
Status
));

continue;
}

Expand All @@ -107,6 +92,165 @@ ScanThreadCount (
}
}

return Status;
}

STATIC
EFI_STATUS
ScanFrameworkMpServices (
IN FRAMEWORK_EFI_MP_SERVICES_PROTOCOL *FrameworkMpServices,
OUT OC_CPU_INFO *Cpu,
OUT UINTN *NumberOfProcessors,
OUT UINTN *NumberOfEnabledProcessors
)
{
EFI_STATUS Status;
UINTN Index;
EFI_MP_PROC_CONTEXT Context;
UINTN ContextSize;

ASSERT (FrameworkMpServices != NULL);
ASSERT (Cpu != NULL);
ASSERT (NumberOfProcessors != NULL);
ASSERT (NumberOfEnabledProcessors != NULL);

Status = FrameworkMpServices->GetGeneralMPInfo (
FrameworkMpServices,
NumberOfProcessors,
NULL,
NumberOfEnabledProcessors,
NULL,
NULL
);

if (EFI_ERROR (Status)) {
return Status;
}

if (*NumberOfProcessors == 0) {
return EFI_NOT_FOUND;
}

//
// This code assumes that all CPUs have same amount of cores and threads.
//
for (Index = 0; Index < *NumberOfProcessors; ++Index) {
ContextSize = sizeof (Context);

Status = FrameworkMpServices->GetProcessorContext (
FrameworkMpServices,
Index,
&ContextSize,
&Context
);

if (EFI_ERROR (Status)) {
DEBUG ((
DEBUG_INFO,
"OCCPU: Failed to get context for processor %Lu - %r\n",
(UINT64) Index,
Status
));

continue;
}

if (Context.PackageNumber + 1 >= Cpu->PackageCount) {
Cpu->PackageCount = (UINT16) (Context.PackageNumber + 1);
}

//
// According to the FrameworkMpServices header, EFI_MP_PROC_CONTEXT.NumberOfCores is the
// zero-indexed physical core number for the current processor. However, Apple appears to
// set this to the total number of physical cores (observed on Xserve3,1 with 2x Xeon X5550).
//
// This number may not be accurate; on MacPro5,1 with 2x Xeon X5690, NumberOfCores is 16 when
// it should be 12 (even though NumberOfProcessors is correct). Regardless, CoreCount and
// ThreadCount will be corrected in ScanIntelProcessor.
//
// We will follow Apple's implementation, as the FrameworkMpServices fallback was added for
// legacy Macs.
//
if (Context.NumberOfCores >= Cpu->CoreCount) {
Cpu->CoreCount = (UINT16) (Context.NumberOfCores);
}

//
// Similarly, EFI_MP_PROC_CONTEXT.NumberOfThreads is supposed to be the zero-indexed logical
// thread number for the current processor. On Xserve3,1 and MacPro5,1 this was set to 2
// (presumably to indicate that there are 2 threads per physical core).
//
if (Context.NumberOfCores * Context.NumberOfThreads >= Cpu->ThreadCount) {
Cpu->ThreadCount = (UINT16) (Context.NumberOfCores * Context.NumberOfThreads);
}
}

return Status;
}

STATIC
EFI_STATUS
ScanThreadCount (
OUT OC_CPU_INFO *Cpu
)
{
EFI_STATUS Status;
EFI_MP_SERVICES_PROTOCOL *MpServices;
FRAMEWORK_EFI_MP_SERVICES_PROTOCOL *FrameworkMpServices;
UINTN NumberOfProcessors;
UINTN NumberOfEnabledProcessors;

Cpu->PackageCount = 1;
Cpu->CoreCount = 1;
Cpu->ThreadCount = 1;
NumberOfProcessors = 0;
NumberOfEnabledProcessors = 0;

Status = gBS->LocateProtocol (
&gEfiMpServiceProtocolGuid,
NULL,
(VOID **) &MpServices
);

if (EFI_ERROR (Status)) {
Status = gBS->LocateProtocol (
&gFrameworkEfiMpServiceProtocolGuid,
NULL,
(VOID **) &FrameworkMpServices
);

if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "OCCPU: No MP services - %r\n", Status));
return Status;
}

Status = ScanFrameworkMpServices (
FrameworkMpServices,
Cpu,
&NumberOfProcessors,
&NumberOfEnabledProcessors
);
} else {
Status = ScanMpServices (
MpServices,
Cpu,
&NumberOfProcessors,
&NumberOfEnabledProcessors
);
}

DEBUG ((
DEBUG_INFO,
"OCCPU: MP services threads %Lu (enabled %Lu) - %r\n",
(UINT64) NumberOfProcessors,
(UINT64) NumberOfEnabledProcessors,
Status
));

if (EFI_ERROR (Status)) {
return Status;
}

DEBUG ((
DEBUG_INFO,
"OCCPU: MP services Pkg %u Cores %u Threads %u - %r\n",
Expand Down Expand Up @@ -161,7 +305,7 @@ ScanIntelProcessor (
}

//
// When the CPU is virtualized and cpuid invtsc is enabled, then we already get
// When the CPU is virtualized and cpuid invtsc is enabled, then we already get
// the information we want outside the function, skip anyway.
// Things may be different in other hypervisors, but should work with QEMU/VMWare for now.
//
Expand Down Expand Up @@ -430,7 +574,7 @@ ScanAmdProcessor (
//
// When under virtualization this information is already available to us.
//
if (Cpu->CPUFrequencyFromVMT == 0) {
if (Cpu->CPUFrequencyFromVMT == 0) {
//
// Sometimes incorrect hypervisor configuration will lead to dividing by zero.
//
Expand Down Expand Up @@ -576,7 +720,7 @@ OcCpuScanProcessor (
));

//
// If we are under virtualization and cpuid invtsc is enabled, we can just read
// If we are under virtualization and cpuid invtsc is enabled, we can just read
// TSCFrequency and FSBFrequency from VMWare Timing node instead of reading MSR
// (which hypervisors may not implemented yet), at least in QEMU/VMWare it works.
// Source:
Expand All @@ -597,7 +741,7 @@ OcCpuScanProcessor (

Cpu->CPUFrequency = Cpu->CPUFrequencyFromVMT;
//
// We can caculate Bus Ratio here
// We can calculate Bus Ratio here
//
Cpu->MaxBusRatio = (UINT8)DivU64x32 (Cpu->CPUFrequency, (UINT32)Cpu->FSBFrequency);
//
Expand Down
3 changes: 2 additions & 1 deletion Library/OcCpuLib/OcCpuLib.inf
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
VERSION_STRING = 1.0
LIBRARY_CLASS = OcCpuLib|PEIM DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_DRIVER UEFI_APPLICATION DXE_SMM_DRIVER

# VALID_ARCHITECTURES = IA32 X64
# VALID_ARCHITECTURES = IA32 X64

[Packages]
OcSupportPkg/OcSupportPkg.dec
Expand All @@ -39,6 +39,7 @@

[Protocols]
gEfiMpServiceProtocolGuid
gFrameworkEfiMpServiceProtocolGuid

[Sources]
AppleCpuSupport.c
Expand Down

0 comments on commit 86839a8

Please sign in to comment.