blob: 29a345b6f4f017f6ead6721f9a59bdc939c10f6b [file] [log] [blame]
/** @file
Code for Selecting Least-Feature Processor as BSP
Copyright (c) 2013 Intel Corporation.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Intel Corporation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Module Name: SelectLfp.c
**/
#include "MpService.h"
#include "Cpu.h"
//
// Common set of processors' feature flags.
//
UINT32 CommonFeatureFlagSet[6];
//
// Flags of whether corresponding processor matches common set.
//
BOOLEAN MatchingCommonSet[FixedPcdGet32(PcdCpuMaxLogicalProcessorNumber)];
/**
Get the common set of processors' feature flags.
This function calculates the common set of processors' feature flags.
Processor's feature flags include 6 segments: CPUID(1).ECX, CPUID(1).EDX,
CPUID(0x80000001).EAX, CPUID(0x80000001).EBX, CPUID(0x80000001).ECX,
and CPUID(0x80000001).EDX. "AND" them together and result is the common set.
**/
VOID
GetCommonFeatureFlagSet (
VOID
)
{
EFI_CPUID_REGISTER *CpuidRegisters;
UINTN ProcessorNumber;
//
// Initialize common set of feature flag with all "1"s.
//
SetMem32 (CommonFeatureFlagSet, sizeof (CommonFeatureFlagSet), 0xffffffff);
//
// Traverse all processors' feature flags
//
for (ProcessorNumber = 0; ProcessorNumber < mCpuConfigConextBuffer.NumberOfProcessors; ProcessorNumber++) {
//
// AND CPUID(1).ECX and CPUID(1).EDX with common set
//
CpuidRegisters = GetProcessorCpuid (ProcessorNumber, EFI_CPUID_VERSION_INFO);
ASSERT (CpuidRegisters != NULL);
CommonFeatureFlagSet[0] &= CpuidRegisters->RegEcx;
CommonFeatureFlagSet[1] &= CpuidRegisters->RegEdx;
//
// AND CPUID(0x80000001).EAX, CPUID(0x80000001).EBX, CPUID(0x80000001).ECX,
// and CPUID(0x80000001).EDX with common set.
//
CpuidRegisters = GetProcessorCpuid (ProcessorNumber, EFI_CPUID_EXTENDED_CPU_SIG);
ASSERT (CpuidRegisters != NULL);
CommonFeatureFlagSet[2] &= CpuidRegisters->RegEax;
CommonFeatureFlagSet[3] &= CpuidRegisters->RegEbx;
CommonFeatureFlagSet[4] &= CpuidRegisters->RegEcx;
CommonFeatureFlagSet[5] &= CpuidRegisters->RegEdx;
}
}
/**
Checks which processors match the common set of feature flag
This function Checks which processors match the common set of feature flag.
@retval TRUE At least one processor matches the common set of feature flag.
@retval FALSE No processor matches the common set of feature flag.
**/
BOOLEAN
CompareProcessorsWithCommonSet (
VOID
)
{
EFI_CPUID_REGISTER *CpuidRegisters;
UINTN ProcessorNumber;
BOOLEAN ReturnValue;
ReturnValue = FALSE;
for (ProcessorNumber = 0; ProcessorNumber < mCpuConfigConextBuffer.NumberOfProcessors; ProcessorNumber++) {
MatchingCommonSet[ProcessorNumber] = FALSE;
//
// Compare CPUID(1).ECX and CPUID(1).EDX with common set
//
CpuidRegisters = GetProcessorCpuid (0, EFI_CPUID_VERSION_INFO);
ASSERT (CpuidRegisters != NULL);
if (CommonFeatureFlagSet[0] != CpuidRegisters->RegEcx || CommonFeatureFlagSet[1] != CpuidRegisters->RegEdx) {
continue;
}
//
// Compare CPUID(0x80000001).EAX, CPUID(0x80000001).EBX, CPUID(0x80000001).ECX,
// and CPUID(0x80000001).EDX with common set.
//
CpuidRegisters = GetProcessorCpuid (ProcessorNumber, EFI_CPUID_EXTENDED_CPU_SIG);
ASSERT (CpuidRegisters != NULL);
if (CommonFeatureFlagSet[2] != CpuidRegisters->RegEax || CommonFeatureFlagSet[3] != CpuidRegisters->RegEbx ||
CommonFeatureFlagSet[4] != CpuidRegisters->RegEcx || CommonFeatureFlagSet[5] != CpuidRegisters->RegEdx) {
continue;
}
//
// If the processor matches common set, flag it, and set return value as TRUE.
//
MatchingCommonSet[ProcessorNumber] = TRUE;
ReturnValue = TRUE;
}
return ReturnValue;
}
/**
Select least-feature processor as BSP
This function selects least-feature processor as BSP.
**/
VOID
SelectLfpAsBsp (
VOID
)
{
UINTN ProcessorNumber;
UINTN OldestProcessorNumber;
UINT32 OldestProcessorFms[3];
UINT32 FamilyId;
UINT32 ModelId;
UINT32 SteppingId;
BOOLEAN MatchingProcessorExist;
//
// Calculate the common set of processors' feature flags
//
GetCommonFeatureFlagSet ();
//
// Compare all logical processors with common set.
//
MatchingProcessorExist = CompareProcessorsWithCommonSet ();
OldestProcessorFms[2] = 0xffffffff;
OldestProcessorFms[1] = 0;
OldestProcessorFms[0] = 0;
OldestProcessorNumber = mCpuConfigConextBuffer.BspNumber;
for (ProcessorNumber = 0; ProcessorNumber < mCpuConfigConextBuffer.NumberOfProcessors; ProcessorNumber++) {
//
// If only 1 processor matches common set, it should be BSP
// If more than 1 processors match common set, the one with lowest CPUID should be BSP.
// If no processor matches common set, the processor with lowest CPUID should be BSP.
//
if (!MatchingProcessorExist || MatchingCommonSet[ProcessorNumber]) {
GetProcessorVersionInfo (ProcessorNumber, &FamilyId, &ModelId, &SteppingId, NULL);
if (FamilyId > OldestProcessorFms[2]) {
continue;
}
if (FamilyId == OldestProcessorFms[2]) {
if (ModelId > OldestProcessorFms[1]) {
continue;
}
if (ModelId == OldestProcessorFms[1]) {
if (SteppingId >= OldestProcessorFms[0]) {
continue;
}
}
}
OldestProcessorFms[2] = FamilyId;
OldestProcessorFms[1] = ModelId;
OldestProcessorFms[0] = SteppingId;
OldestProcessorNumber = ProcessorNumber;
}
}
//
// If current BSP is not the least-feature processor, then switch BSP.
//
if (OldestProcessorNumber != mCpuConfigConextBuffer.BspNumber) {
SwitchBSP (&mMpService, OldestProcessorNumber, TRUE);
DEBUG ((EFI_D_INFO, "BSP switched to processor: %8d\r\n", OldestProcessorNumber));
}
}