Discussion:
[edk2] [Patch 01/28] UefiCpuPkg: Add CpuMpPei module
Jeff Fan
2015-07-03 15:09:54 UTC
Permalink
This module is to provide MP PPI services defined in PI 1.4.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/CpuMpPei.c | 41 +++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/CpuMpPei.h | 26 +++++++++++++++++
UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 51 ++++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/CpuMpPei.uni | Bin 0 -> 1706 bytes
UefiCpuPkg/CpuMpPei/CpuMpPeiExtra.uni | Bin 0 -> 1344 bytes
UefiCpuPkg/UefiCpuPkg.dsc | 1 +
6 files changed, 119 insertions(+)
create mode 100644 UefiCpuPkg/CpuMpPei/CpuMpPei.c
create mode 100644 UefiCpuPkg/CpuMpPei/CpuMpPei.h
create mode 100644 UefiCpuPkg/CpuMpPei/CpuMpPei.inf
create mode 100644 UefiCpuPkg/CpuMpPei/CpuMpPei.uni
create mode 100644 UefiCpuPkg/CpuMpPei/CpuMpPeiExtra.uni

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
new file mode 100644
index 0000000..c1684c2
--- /dev/null
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
@@ -0,0 +1,41 @@
+/** @file
+ CPU PEI Module installs CPU Multiple Processor PPI.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "CpuMpPei.h"
+
+
+/**
+ The Entry point of the MP CPU PEIM.
+
+ This function will wakeup APs and collect CPU AP count and install the
+ Mp Service Ppi.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS MpServicePpi is installed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuMpPeimInit (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+
+
+
+ return EFI_SUCCESS;
+}
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
new file mode 100644
index 0000000..00e95cf
--- /dev/null
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
@@ -0,0 +1,26 @@
+/** @file
+ Definitions to install Multiple Processor PPI.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _CPU_MP_PEI_H_
+#define _CPU_MP_PEI_H_
+
+#include <PiPei.h>
+
+
+#include <Library/BaseLib.h>
+#include <Library/PeimEntryPoint.h>
+
+
+
+#endif
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
new file mode 100644
index 0000000..05db141
--- /dev/null
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
@@ -0,0 +1,51 @@
+## @file
+# CPU driver installs CPU PI Multi-processor PPI.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CpuMpPei
+ MODULE_UNI_FILE = CpuMpPei.uni
+ FILE_GUID = EDADEB9D-DDBA-48BD-9D22-C1C169C8C5C6
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = CpuMpPeimInit
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ CpuMpPei.h
+ CpuMpPei.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PeimEntryPoint
+
+
+
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ CpuMpPeiExtra.uni
+
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.uni b/UefiCpuPkg/CpuMpPei/CpuMpPei.uni
new file mode 100644
index 0000000000000000000000000000000000000000..00c41e2faa60bc9dd497538c9c19f1a14f41ab5c
GIT binary patch
literal 1706
zcmc(gU60aW5QXR3#Q)H+H)?i4H}S?8BP>-Lb!iredS%MTvQ1!1pzO+@cYV$j+O5Ip
zg~pJ+Uo-E_nKP&5?t9Bx7Vtdb7uajNwAAJ{wTJeAQ`***@iQ^t=***@ZEMRd
z!F$fC@{28E_t7?-=lGr2k{g+gxw+<-`Tdxvku}Ra|1)0(!mU>~vnwzM_6W3(nNRJh
zJ+tR_%sQgtoEqk=&%BDIkBL{AVQpe*J0HQlXyRt&wTn6NH^K9zb?m}k9jJc*hSV7?
zc$;x6u?0~Qa!i<WJf^-MgEPanblcXuGQ+Z9FRbdAI<zkHD2mVooTlCr^--9r__{sW
zWw>E2MI<(2)V+<PC{(aVQsi1V>OD#!6W+AsM@(cWtg4`6ee1ISP{UGb;nukrGYVb3
z+7vX3C=3N($|X&z>Jd1lzI|T;6R*O5>B>|Wh58%g&#3Cm6l`ws8tv|9I}U^?zsIb!
zlhcbA{^m$kQy7rqH(-+fo2*wh!(Pv^=46EDgtw(`X%gj%***@51XYZVdiIvF
z&08m(_8GfA4>*lb+7R#1nI76XbI5rWq3S|}vO_%j9=XR#iq_a*R$N7IFn4^f-EoO6
zuus^9tLGWDZ<9&L&N+{Wsu(@be!))Ib*7vHyyT;-h1VN=***@L1Jdn`h(H!<90DXIwV
za~Y?K9>***@H?X~UdyqIQ$0tedamhF01EN<l}J5e42c%9Yg2n+X~Wh4zhC{1
y{Jl}E4N950dZdUGVhL#jbbsS3+9<2|vkKJzKG>y=xa9m$6~C|G-~KyPmHhy=@&yb4

literal 0
HcmV?d00001

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPeiExtra.uni b/UefiCpuPkg/CpuMpPei/CpuMpPeiExtra.uni
new file mode 100644
index 0000000000000000000000000000000000000000..55ca4f0292bf02765477f80a582ccae533be83d1
GIT binary patch
literal 1344
zcmZ9MS#Q%&5QXO%iT_}Q7eGw{NW36~NE!ncZDM5+@Kj}MYAKB)Cus>k9{A39Ya+|{
z-r3HaJ2Upbzin$<!26mfu+MgDiLGsE&+Qpn*)DBs2fJpC(I;rGEVa2!@k{Ivx&^wC
z?JYyz*vfXuQ%=%f;=94N^tD7S_uRg<qsOl74$r_|g8qvAoxQQQ_TDZyM+M5dz|7#2
z5;Y|***@f<BI9XQEDOmZ}F$;iIr&FsP1w(O&IZD^***@HWa7g?HTl`Z{l;a+h@<w|+
zmM+iXnPS_z?O5DCKqFSlmvCBxR^w06Dq6LhbJ{pFRjR~S^rFb{z*+s6+Kg3k2O?z6
zIG0TFT=&kpL=***@iIo1<ab3FBL%urUQgeOuTFhC+?)0_^9E2zidA*cthpb!A
z;Q6#KfvK+Ie~TsWky!u6>zvhTW%***@tPI!X;A}l+***@k??KKR_Gobu|*Kl56*
zxPL}R+h^6^p_##bVa+p33zR$***@xO`+TzyRxxulu&=Bgz7fsoh_&bY7;VI)P4EuA
z(i7{mhv;jBx(g9sONhtFkq4YK(OMhq!WDXhz3Z~1i;7!dKd_6}z%xqjkV(w?=p#^t
zG4Sj|BypEcImdX(M_F^PFZe3*7yEZCVy-VSEVAUc2<>NuQ=>=JB4)0XvuCY}V_iS}
zZ`!Vx?nN~@`hVzeqT1aQ)r~<JRyVi-djRSL{1Bf$EU!7`IQmwEabREh#Aphdc#qtp
oL5*XifEZ1prnE_i^{wlB-0^5i)LGqBJ?$YU{_n`BzVejse?!L4(EtDd

literal 0
HcmV?d00001

diff --git a/UefiCpuPkg/UefiCpuPkg.dsc b/UefiCpuPkg/UefiCpuPkg.dsc
index f533a14..5fcff15 100644
--- a/UefiCpuPkg/UefiCpuPkg.dsc
+++ b/UefiCpuPkg/UefiCpuPkg.dsc
@@ -83,6 +83,7 @@
UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.inf

[Components.IA32, Components.X64]
+ UefiCpuPkg/CpuMpPei/CpuMpPei.inf
UefiCpuPkg/CpuDxe/CpuDxe.inf
UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf
UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:09:56 UTC
Permalink
Search memory resource HOB list to find one available system memory under 1MB
for AP reset code and exchange information between BSP and APs.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/CpuMpPei.c | 71 ++++++++++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/CpuMpPei.h | 1 +
UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 1 +
3 files changed, 73 insertions(+)

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
index 78299b3..0e34f26 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
@@ -38,6 +38,77 @@ GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR mGdt = {
(UINTN) mGdtEntries
};

+/**
+ Get available system memory below 1MB by specified size.
+
+ @param WakeupBufferSize Wakeup buffer size required
+
+ @retval other Return wakeup buffer address below 1MB.
+ @retval -1 Cannot find free memory below 1MB.
+**/
+UINTN
+GetWakeupBuffer (
+ IN UINTN WakeupBufferSize
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ UINTN WakeupBufferStart;
+ UINTN WakeupBufferEnd;
+
+ //
+ // Get the HOB list for processing
+ //
+ Hob.Raw = GetHobList ();
+
+ //
+ // Collect memory ranges
+ //
+ while (!END_OF_HOB_LIST (Hob)) {
+ if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&
+ (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
+ ((Hob.ResourceDescriptor->ResourceAttribute &
+ (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
+ EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
+ )) == 0)
+ ) {
+ //
+ // Need memory under 1MB to be collected here
+ //
+ WakeupBufferEnd = (UINTN) (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength);
+ if (WakeupBufferEnd > BASE_1MB) {
+ //
+ // Wakeup buffer should be under 1MB
+ //
+ WakeupBufferEnd = BASE_1MB;
+ }
+ //
+ // Wakeup buffer should be aligned on 4KB
+ //
+ WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);
+ if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {
+ continue;
+ }
+ //
+ // Create a memory allocation HOB.
+ //
+ BuildMemoryAllocationHob (
+ WakeupBufferStart,
+ WakeupBufferSize,
+ EfiBootServicesData
+ );
+ return WakeupBufferStart;
+ }
+ }
+ //
+ // Find the next HOB
+ //
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+
+ return (UINTN) -1;
+}

/**
The Entry point of the MP CPU PEIM.
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
index 611a296..da01fda 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
@@ -19,6 +19,7 @@


#include <Library/BaseLib.h>
+#include <Library/HobLib.h>
#include <Library/PeimEntryPoint.h>

#pragma pack(1)
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
index 1dfee4e..7cf33d3 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
@@ -49,6 +49,7 @@

[LibraryClasses]
BaseLib
+ HobLib
PeimEntryPoint
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:09:57 UTC
Permalink
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/CpuMpPei.h | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
index da01fda..3f4fa92 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
@@ -23,6 +23,7 @@
#include <Library/PeimEntryPoint.h>

#pragma pack(1)
+
typedef union {
struct {
UINT32 LimitLow : 16;
@@ -41,6 +42,24 @@ typedef union {
} Bits;
UINT64 Uint64;
} IA32_GDT;
+
+//
+// MP CPU exchange information for AP reset code
+//
+typedef struct {
+ UINTN Lock;
+ UINTN StackStart;
+ UINTN StackSize;
+ UINTN CFunction;
+ IA32_DESCRIPTOR GdtrProfile;
+ IA32_DESCRIPTOR IdtrProfile;
+ UINTN BufferStart;
+ UINTN PmodeOffset;
+ UINTN NumApsExecuting;
+ UINTN LmodeOffset;
+ UINTN Cr3;
+} MP_CPU_EXCHANGE_INFO;
+
#pragma pack()
/**
Assembly code to load GDT table and update segment accordingly.
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:09:58 UTC
Permalink
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc | 12 ++++
UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm | 117 ++++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm | 107 +++++++++++++++++++++++++++++++
3 files changed, 236 insertions(+)

diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc b/UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc
index 2d30db4..1f02dad 100644
--- a/UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc
+++ b/UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc
@@ -21,4 +21,16 @@
PROTECT_MODE_CS equ 10h
PROTECT_MODE_DS equ 18h

+VacantFlag equ 00h
+NotVacantFlag equ 0ffh
+
+LockLocation equ (RendezvousFunnelProcEnd - RendezvousFunnelProcStart)
+StackStartAddressLocation equ LockLocation + 04h
+StackSizeLocation equ LockLocation + 08h
+ApProcedureLocation equ LockLocation + 0Ch
+GdtrLocation equ LockLocation + 10h
+IdtrLocation equ LockLocation + 16h
+BufferStartLocation equ LockLocation + 1Ch
+PmodeOffsetLocation equ LockLocation + 20h
+NumApsExecutingLoction equ LockLocation + 24h

diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
index ca9c15a..c8bdc52 100644
--- a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
+++ b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
@@ -22,8 +22,125 @@
.model flat

include MpEqu.inc
+
.code

+;-------------------------------------------------------------------------------------
+;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
+;procedure serializes all the AP processors through an Init sequence. It must be
+;noted that APs arrive here very raw...ie: real mode, no stack.
+;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
+;IS IN MACHINE CODE.
+;-------------------------------------------------------------------------------------
+RendezvousFunnelProc PROC PUBLIC
+RendezvousFunnelProcStart::
+; At this point CS = 0x(vv00) and ip= 0x0.
+; Save BIST information to ebp firstly
+ db 66h, 08bh, 0e8h ; mov ebp, eax ; save BIST information
+
+ db 8ch,0c8h ; mov ax,cs
+ db 8eh,0d8h ; mov ds,ax
+ db 8eh,0c0h ; mov es,ax
+ db 8eh,0d0h ; mov ss,ax
+ db 33h,0c0h ; xor ax,ax
+ db 8eh,0e0h ; mov fs,ax
+ db 8eh,0e8h ; mov gs,ax
+
+ db 0BEh ; opcode of mov si, mem16
+ dw BufferStartLocation ; mov si, BufferStartLocation
+ db 66h, 8Bh, 1Ch ; mov ebx,dword ptr [si]
+
+ db 0BFh ; opcode of mov di, mem16
+ dw PmodeOffsetLocation ; mov di, PmodeOffsetLocation
+ db 66h, 8Bh, 05h ; mov eax,dword ptr [di]
+ db 8Bh, 0F8h ; mov di, ax
+ db 83h, 0EFh,06h ; sub di, 06h
+ db 66h, 03h, 0C3h ; add eax, ebx
+ db 66h, 89h, 05h ; mov dword ptr [di],eax
+
+ db 0BEh ; opcode of mov si, mem16
+ dw GdtrLocation ; mov si, GdtrLocation
+ db 66h ; db 66h
+ db 2Eh, 0Fh, 01h, 14h ; lgdt fword ptr cs:[si]
+
+ db 0BEh
+ dw IdtrLocation ; mov si, IdtrLocation
+ db 66h ; db 66h
+ db 2Eh,0Fh, 01h, 1Ch ; lidt fword ptr cs:[si]
+
+ db 33h, 0C0h ; xor ax, ax
+ db 8Eh, 0D8h ; mov ds, ax
+
+ db 0Fh, 20h, 0C0h ; mov eax, cr0 ;Get control register 0
+ db 66h, 83h, 0C8h, 03h ; or eax, 000000003h ;Set PE bit (bit #0) & MP
+ db 0Fh, 22h, 0C0h ; mov cr0, eax
+
+ db 66h, 67h, 0EAh ; far jump
+ dd 0h ; 32-bit offset
+ dw PROTECT_MODE_CS ; 16-bit selector
+
+Flat32Start:: ; protected mode entry point
+ mov ax, PROTECT_MODE_DS
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ mov esi, ebx
+ mov edi, esi
+ add edi, LockLocation
+ mov eax, NotVacantFlag
+
+TestLock:
+ xchg dword ptr [edi], eax
+ cmp eax, NotVacantFlag
+ jz TestLock
+
+ mov edi, esi
+ add edi, NumApsExecutingLoction
+ inc dword ptr [edi]
+ mov ebx, dword ptr [edi]
+
+ProgramStack:
+ mov edi, esi
+ add edi, StackSizeLocation
+ mov eax, dword ptr [edi]
+ mov edi, esi
+ add edi, StackStartAddressLocation
+ add eax, dword ptr [edi]
+ mov esp, eax
+ mov dword ptr [edi], eax
+
+Releaselock:
+ mov eax, VacantFlag
+ mov edi, esi
+ add edi, LockLocation
+ xchg dword ptr [edi], eax
+
+CProcedureInvoke:
+ push ebp ; push BIST data at top of AP stack
+ xor ebp, ebp ; clear ebp for call stack trace
+ push ebp
+ mov ebp, esp
+
+
+ push ebx ; Push NumApsExecuting
+ mov eax, esi
+ add eax, LockLocation
+ push eax ; push address of exchange info data buffer
+
+ mov edi, esi
+ add edi, ApProcedureLocation
+ mov eax, dword ptr [edi]
+
+ call eax ; invoke C function
+
+ jmp $ ; never reach here
+
+RendezvousFunnelProc ENDP
+RendezvousFunnelProcEnd::
+

AsmInitializeGdt PROC near C PUBLIC
push ebp
diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
index 180b637..379f13e 100644
--- a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
+++ b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
@@ -22,6 +22,113 @@

SECTION .text

+;-------------------------------------------------------------------------------------
+;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
+;procedure serializes all the AP processors through an Init sequence. It must be
+;noted that APs arrive here very raw...ie: real mode, no stack.
+;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
+;IS IN MACHINE CODE.
+;-------------------------------------------------------------------------------------
+global ASM_PFX(RendezvousFunnelProc)
+ASM_PFX(RendezvousFunnelProc):
+RendezvousFunnelProcStart:
+; At this point CS = 0x(vv00) and ip= 0x0.
+BITS 16
+ mov ebp, eax ; save BIST information
+
+ mov ax, cs
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+ xor ax, ax
+ mov fs, ax
+ mov gs, ax
+
+ mov si, BufferStartLocation
+ mov ebx, [si]
+
+ mov di, PmodeOffsetLocation
+ mov eax, [di]
+ mov di, ax
+ sub di, 06h
+ add eax, ebx
+ mov [di],eax
+
+ mov si, GdtrLocation
+o32 lgdt [cs:si]
+
+ mov si, IdtrLocation
+o32 lidt [cs:si]
+
+ xor ax, ax
+ mov ds, ax
+
+ mov eax, cr0 ;Get control register 0
+ or eax, 000000003h ;Set PE bit (bit #0) & MP
+ mov cr0, eax
+
+ jmp PROTECT_MODE_CS:strict dword 0 ; far jump to protected mode
+BITS 32
+Flat32Start: ; protected mode entry point
+ mov ax, PROTECT_MODE_DS
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ mov esi, ebx
+ mov edi, esi
+ add edi, LockLocation
+ mov eax, NotVacantFlag
+
+TestLock:
+ xchg [edi], eax
+ cmp eax, NotVacantFlag
+ jz TestLock
+
+ mov edi, esi
+ add edi, NumApsExecutingLoction
+ inc dword [edi]
+ mov ebx, [edi]
+
+ProgramStack:
+ mov edi, esi
+ add edi, StackSizeLocation
+ mov eax, [edi]
+ mov edi, esi
+ add edi, StackStartAddressLocation
+ add eax, [edi]
+ mov esp, eax
+ mov [edi], eax
+
+Releaselock:
+ mov eax, VacantFlag
+ mov edi, esi
+ add edi, LockLocation
+ xchg [edi], eax
+
+CProcedureInvoke:
+ push ebp ; push BIST data at top of AP stack
+ xor ebp, ebp ; clear ebp for call stack trace
+ push ebp
+ mov ebp, esp
+
+
+ push ebx ; Push NumApsExecuting
+ mov eax, esi
+ add eax, LockLocation
+ push eax ; push address of exchange info data buffer
+
+ mov edi, esi
+ add edi, ApProcedureLocation
+ mov eax, [edi]
+
+ call eax ; invoke C function
+
+ jmp $ ; never reach here
+RendezvousFunnelProcEnd:
+

global ASM_PFX(AsmInitializeGdt)
ASM_PFX(AsmInitializeGdt):
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:09:55 UTC
Permalink
Load new GDT table and update segment accordingly.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/CpuMpPei.c | 28 ++++++++++++++++++
UefiCpuPkg/CpuMpPei/CpuMpPei.h | 30 +++++++++++++++++++
UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 11 +++++++
UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc | 24 +++++++++++++++
UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm | 55 +++++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm | 49 +++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/X64/MpEqu.inc | 25 ++++++++++++++++
UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm | 51 ++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm | 50 +++++++++++++++++++++++++++++++
9 files changed, 323 insertions(+)
create mode 100644 UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc
create mode 100644 UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
create mode 100644 UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
create mode 100644 UefiCpuPkg/CpuMpPei/X64/MpEqu.inc
create mode 100644 UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
create mode 100644 UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
index c1684c2..78299b3 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
@@ -14,6 +14,30 @@

#include "CpuMpPei.h"

+//
+// Global Descriptor Table (GDT)
+//
+GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = {
+/* selector { Global Segment Descriptor } */
+/* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //null descriptor
+/* 0x08 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear data segment descriptor
+/* 0x10 */ {{0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear code segment descriptor
+/* 0x18 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
+/* 0x20 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system code segment descriptor
+/* 0x28 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
+/* 0x30 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
+/* 0x38 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 1, 0, 1, 0}}, //system code segment descriptor
+/* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
+};
+
+//
+// IA32 Gdt register
+//
+GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR mGdt = {
+ sizeof (mGdtEntries) - 1,
+ (UINTN) mGdtEntries
+ };
+

/**
The Entry point of the MP CPU PEIM.
@@ -36,6 +60,10 @@ CpuMpPeimInit (
{


+ //
+ // Load new GDT table on BSP
+ //
+ AsmInitializeGdt (&mGdt);

return EFI_SUCCESS;
}
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
index 00e95cf..611a296 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
@@ -21,6 +21,36 @@
#include <Library/BaseLib.h>
#include <Library/PeimEntryPoint.h>

+#pragma pack(1)
+typedef union {
+ struct {
+ UINT32 LimitLow : 16;
+ UINT32 BaseLow : 16;
+ UINT32 BaseMid : 8;
+ UINT32 Type : 4;
+ UINT32 System : 1;
+ UINT32 Dpl : 2;
+ UINT32 Present : 1;
+ UINT32 LimitHigh : 4;
+ UINT32 Software : 1;
+ UINT32 Reserved : 1;
+ UINT32 DefaultSize : 1;
+ UINT32 Granularity : 1;
+ UINT32 BaseHigh : 8;
+ } Bits;
+ UINT64 Uint64;
+} IA32_GDT;
+#pragma pack()
+/**
+ Assembly code to load GDT table and update segment accordingly.
+
+ @param Gdtr Pointer to GDT descriptor
+**/
+VOID
+EFIAPI
+AsmInitializeGdt (
+ IN IA32_DESCRIPTOR *Gdtr
+ );


#endif
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
index 05db141..1dfee4e 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
@@ -31,6 +31,17 @@
CpuMpPei.h
CpuMpPei.c

+[Sources.IA32]
+ Ia32/MpEqu.inc
+ Ia32/MpFuncs.asm | MSFT
+ Ia32/MpFuncs.asm | INTEL
+ Ia32/MpFuncs.nasm | GCC
+
+[Sources.X64]
+ X64/MpEqu.inc
+ X64/MpFuncs.asm | MSFT
+ X64/MpFuncs.asm | INTEL
+ X64/MpFuncs.nasm | GCC

[Packages]
MdePkg/MdePkg.dec
diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc b/UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc
new file mode 100644
index 0000000..2d30db4
--- /dev/null
+++ b/UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc
@@ -0,0 +1,24 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+; Module Name:
+;
+; MpEqu.inc
+;
+; Abstract:
+;
+; This is the equates file for Multiple Processor support
+;
+;-------------------------------------------------------------------------------
+
+PROTECT_MODE_CS equ 10h
+PROTECT_MODE_DS equ 18h
+
+
diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
new file mode 100644
index 0000000..ca9c15a
--- /dev/null
+++ b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
@@ -0,0 +1,55 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+; Module Name:
+;
+; MpFuncs32.asm
+;
+; Abstract:
+;
+; This is the assembly code for MP support
+;
+;-------------------------------------------------------------------------------
+
+.686p
+.model flat
+
+include MpEqu.inc
+.code
+
+
+AsmInitializeGdt PROC near C PUBLIC
+ push ebp
+ mov ebp, esp
+ pushad
+ mov edi, [ebp + 8] ; Load GDT register
+
+ mov ax,cs ; Get the selector data from our code image
+ mov es,ax
+ lgdt FWORD PTR es:[edi] ; and update the GDTR
+
+ push PROTECT_MODE_CS
+ lea eax, SetCodeSelectorFarJump
+ push eax
+ retf
+SetCodeSelectorFarJump:
+ mov ax, PROTECT_MODE_DS ; Update the Base for the new selectors, too
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ popad
+ pop ebp
+ ret
+AsmInitializeGdt ENDP
+
+END
diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
new file mode 100644
index 0000000..180b637
--- /dev/null
+++ b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
@@ -0,0 +1,49 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+; Module Name:
+;
+; MpFuncs.nasm
+;
+; Abstract:
+;
+; This is the assembly code for MP support
+;
+;-------------------------------------------------------------------------------
+
+%include "MpEqu.inc"
+
+SECTION .text
+
+
+global ASM_PFX(AsmInitializeGdt)
+ASM_PFX(AsmInitializeGdt):
+ push ebp
+ mov ebp, esp
+ pushad
+ mov edi, [ebp + 8] ; Load GDT register
+
+ lgdt [edi] ; and update the GDTR
+
+ push PROTECT_MODE_CS
+ mov eax, ASM_PFX(SetCodeSelectorFarJump)
+ push eax
+ retf
+ASM_PFX(SetCodeSelectorFarJump):
+ mov ax, PROTECT_MODE_DS ; Update the Base for the new selectors, too
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ popad
+ pop ebp
+ ret
diff --git a/UefiCpuPkg/CpuMpPei/X64/MpEqu.inc b/UefiCpuPkg/CpuMpPei/X64/MpEqu.inc
new file mode 100644
index 0000000..f59b2c4
--- /dev/null
+++ b/UefiCpuPkg/CpuMpPei/X64/MpEqu.inc
@@ -0,0 +1,25 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+; Module Name:
+;
+; MpEqu.inc
+;
+; Abstract:
+;
+; This is the equates file for Multiple Processor support
+;
+;-------------------------------------------------------------------------------
+
+LONG_MODE_CS equ 38h
+LONG_MODE_DS equ 30h
+
+
+
diff --git a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
new file mode 100644
index 0000000..13a7b5f
--- /dev/null
+++ b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
@@ -0,0 +1,51 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+; Module Name:
+;
+; MpFuncs32.asm
+;
+; Abstract:
+;
+; This is the assembly code for MP support
+;
+;-------------------------------------------------------------------------------
+
+include MpEqu.inc
+.code
+
+
+AsmInitializeGdt PROC
+ push rbp
+ mov rbp, rsp
+
+ lgdt fword PTR [rcx] ; update the GDTR
+
+ sub rsp, 0x10
+ lea rax, SetCodeSelectorFarJump
+ mov [rsp], rax
+ mov rdx, LONG_MODE_CS
+ mov [rsp + 4], dx ; get new CS
+ jmp fword ptr [rsp]
+SetCodeSelectorFarJump:
+ add rsp, 0x10
+
+ mov rax, LONG_MODE_DS ; get new DS
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ pop rbp
+ ret
+AsmInitializeGdt ENDP
+
+END
diff --git a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm
new file mode 100644
index 0000000..bd59572
--- /dev/null
+++ b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm
@@ -0,0 +1,50 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+; Module Name:
+;
+; MpFuncs.nasm
+;
+; Abstract:
+;
+; This is the assembly code for MP support
+;
+;-------------------------------------------------------------------------------
+
+%include "MpEqu.inc"
+DEFAULT REL
+SECTION .text
+
+global ASM_PFX(AsmInitializeGdt)
+ASM_PFX(AsmInitializeGdt):
+ push rbp
+ mov rbp, rsp
+
+ lgdt [rcx] ; update the GDTR
+
+ sub rsp, 0x10
+ mov rax, ASM_PFX(SetCodeSelectorFarJump)
+ mov [rsp], rax
+ mov rdx, LONG_MODE_CS
+ mov [rsp + 4], dx ; get new CS
+ jmp far dword [rsp] ; far jump with new CS
+ASM_PFX(SetCodeSelectorFarJump):
+ add rsp, 0x10
+
+ mov rax, LONG_MODE_DS ; get new DS
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ pop rbp
+
+ ret
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:01 UTC
Permalink
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/CpuMpPei.h | 23 +++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm | 16 ++++++++++++++++
UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm | 16 ++++++++++++++++
UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm | 11 +++++++++++
UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm | 11 +++++++++++
5 files changed, 77 insertions(+)

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
index 146422c..7c96084 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
@@ -23,6 +23,16 @@
#include <Library/PeimEntryPoint.h>
#include <Library/UefiCpuLib.h>

+//
+// AP reset code information
+//
+typedef struct {
+ UINT8 *RendezvousFunnelAddress;
+ UINTN PModeEntryOffset;
+ UINTN LModeEntryOffset;
+ UINTN RendezvousFunnelSize;
+} MP_ASSEMBLY_ADDRESS_MAP;
+
#pragma pack(1)

typedef union {
@@ -62,6 +72,19 @@ typedef struct {
} MP_CPU_EXCHANGE_INFO;

#pragma pack()
+
+/**
+ Assembly code to get starting address and size of the rendezvous entry for APs.
+ Information for fixing a jump instruction in the code is also returned.
+
+ @param AddressMap Output buffer for address map information.
+**/
+VOID
+EFIAPI
+AsmGetAddressMap (
+ OUT MP_ASSEMBLY_ADDRESS_MAP *AddressMap
+ );
+
/**
Assembly code to load GDT table and update segment accordingly.

diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
index 4dc7191..9861472 100644
--- a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
+++ b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
@@ -144,6 +144,22 @@ CProcedureInvoke:
RendezvousFunnelProc ENDP
RendezvousFunnelProcEnd::

+;-------------------------------------------------------------------------------------
+; AsmGetAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+AsmGetAddressMap PROC near C PUBLIC
+ pushad
+ mov ebp,esp
+
+ mov ebx, dword ptr [ebp+24h]
+ mov dword ptr [ebx], RendezvousFunnelProcStart
+ mov dword ptr [ebx + 4h], Flat32Start - RendezvousFunnelProcStart
+ mov dword ptr [ebx + 8h], 0
+ mov dword ptr [ebx + 0ch], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
+
+ popad
+ ret
+AsmGetAddressMap ENDP

AsmInitializeGdt PROC near C PUBLIC
push ebp
diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
index 4a1aa71..a3c4ae9 100644
--- a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
+++ b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
@@ -132,6 +132,22 @@ CProcedureInvoke:
jmp $ ; never reach here
RendezvousFunnelProcEnd:

+;-------------------------------------------------------------------------------------
+; AsmGetAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmGetAddressMap)
+ASM_PFX(AsmGetAddressMap):
+ pushad
+ mov ebp,esp
+
+ mov ebx, [ebp + 24h]
+ mov dword [ebx], RendezvousFunnelProcStart
+ mov dword [ebx + 4h], Flat32Start - RendezvousFunnelProcStart
+ mov dword [ebx + 8h], 0
+ mov dword [ebx + 0ch], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
+
+ popad
+ ret

global ASM_PFX(AsmInitializeGdt)
ASM_PFX(AsmInitializeGdt):
diff --git a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
index 425bc20..9e85fac 100644
--- a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
+++ b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
@@ -181,6 +181,17 @@ CProcedureInvoke:
RendezvousFunnelProc ENDP
RendezvousFunnelProcEnd::

+;-------------------------------------------------------------------------------------
+; AsmGetAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+AsmGetAddressMap PROC
+ mov rax, offset RendezvousFunnelProcStart
+ mov qword ptr [rcx], rax
+ mov qword ptr [rcx + 8h], Flat32Start - RendezvousFunnelProcStart
+ mov qword ptr [rcx + 10h], LongModeStart - RendezvousFunnelProcStart
+ mov qword ptr [rcx + 18h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
+ ret
+AsmGetAddressMap ENDP

AsmInitializeGdt PROC
push rbp
diff --git a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm
index 3ddf26c..09c2fbc 100644
--- a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm
+++ b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm
@@ -175,6 +175,17 @@ CProcedureInvoke:

RendezvousFunnelProcEnd:

+;-------------------------------------------------------------------------------------
+; AsmGetAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmGetAddressMap)
+ASM_PFX(AsmGetAddressMap):
+ mov rax, ASM_PFX(RendezvousFunnelProc)
+ mov qword [rcx], rax
+ mov qword [rcx + 8h], Flat32Start - RendezvousFunnelProcStart
+ mov qword [rcx + 10h], LongModeStart - RendezvousFunnelProcStart
+ mov qword [rcx + 18h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
+ ret

global ASM_PFX(AsmInitializeGdt)
ASM_PFX(AsmInitializeGdt):
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:00 UTC
Permalink
Invoke InitializeFloatingPointUnits() to initialize FPU per UEFI specification
before call C function in assembly code.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/CpuMpPei.h | 1 +
UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 1 +
UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm | 3 +++
UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm | 3 +++
UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm | 6 ++++++
UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm | 5 +++++
6 files changed, 19 insertions(+)

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
index 3f4fa92..146422c 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
@@ -21,6 +21,7 @@
#include <Library/BaseLib.h>
#include <Library/HobLib.h>
#include <Library/PeimEntryPoint.h>
+#include <Library/UefiCpuLib.h>

#pragma pack(1)

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
index 7cf33d3..9fb9e94 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
@@ -51,6 +51,7 @@
BaseLib
HobLib
PeimEntryPoint
+ UefiCpuLib



diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
index c8bdc52..4dc7191 100644
--- a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
+++ b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
@@ -22,6 +22,7 @@
.model flat

include MpEqu.inc
+InitializeFloatingPointUnits PROTO C

.code

@@ -124,6 +125,8 @@ CProcedureInvoke:
push ebp
mov ebp, esp

+ mov eax, InitializeFloatingPointUnits
+ call eax ; Call assembly function to initialize FPU per UEFI spec

push ebx ; Push NumApsExecuting
mov eax, esi
diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
index 379f13e..4a1aa71 100644
--- a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
+++ b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
@@ -19,6 +19,7 @@
;-------------------------------------------------------------------------------

%include "MpEqu.inc"
+extern ASM_PFX(InitializeFloatingPointUnits)

SECTION .text

@@ -114,6 +115,8 @@ CProcedureInvoke:
push ebp
mov ebp, esp

+ mov eax, ASM_PFX(InitializeFloatingPointUnits)
+ call eax ; Call assembly function to initialize FPU per UEFI spec

push ebx ; Push NumApsExecuting
mov eax, esi
diff --git a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
index 5425547..425bc20 100644
--- a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
+++ b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
@@ -19,6 +19,8 @@
;-------------------------------------------------------------------------------

include MpEqu.inc
+extern InitializeFloatingPointUnits:PROC
+
.code
;-------------------------------------------------------------------------------------
;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
@@ -158,6 +160,10 @@ CProcedureInvoke:
push rbp
mov rbp, rsp

+ mov rax, InitializeFloatingPointUnits
+ sub rsp, 20h
+ call rax ; Call assembly function to initialize FPU per UEFI spec
+ add rsp, 20h

mov edx, ebx ; edx is NumApsExecuting
mov ecx, esi
diff --git a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm
index 99669ce..3ddf26c 100644
--- a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm
+++ b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm
@@ -19,6 +19,7 @@
;-------------------------------------------------------------------------------

%include "MpEqu.inc"
+extern ASM_PFX(InitializeFloatingPointUnits)

DEFAULT REL

@@ -155,6 +156,10 @@ CProcedureInvoke:
push rbp
mov rbp, rsp

+ mov rax, ASM_PFX(InitializeFloatingPointUnits)
+ sub rsp, 20h
+ call rax ; Call assembly function to initialize FPU per UEFI spec
+ add rsp, 20h

mov edx, ebx ; edx is NumApsExecuting
mov ecx, esi
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:09:59 UTC
Permalink
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/X64/MpEqu.inc | 17 ++++
UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm | 154 +++++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm | 149 +++++++++++++++++++++++++++++++++
3 files changed, 320 insertions(+)

diff --git a/UefiCpuPkg/CpuMpPei/X64/MpEqu.inc b/UefiCpuPkg/CpuMpPei/X64/MpEqu.inc
index f59b2c4..28a826c 100644
--- a/UefiCpuPkg/CpuMpPei/X64/MpEqu.inc
+++ b/UefiCpuPkg/CpuMpPei/X64/MpEqu.inc
@@ -18,8 +18,25 @@
;
;-------------------------------------------------------------------------------

+PROTECT_MODE_CS equ 10h
+PROTECT_MODE_DS equ 18h
LONG_MODE_CS equ 38h
LONG_MODE_DS equ 30h

+VacantFlag equ 00h
+NotVacantFlag equ 0ffh


+LockLocation equ (RendezvousFunnelProcEnd - RendezvousFunnelProcStart)
+StackStartAddressLocation equ LockLocation + 08h
+StackSizeLocation equ LockLocation + 10h
+ApProcedureLocation equ LockLocation + 18h
+GdtrLocation equ LockLocation + 20h
+IdtrLocation equ LockLocation + 2Ah
+BufferStartLocation equ LockLocation + 34h
+PmodeOffsetLocation equ LockLocation + 3Ch
+NumApsExecutingLoction equ LockLocation + 44h
+LmodeOffsetLocation equ LockLocation + 4Ch
+Cr3Location equ LockLocation + 54h
+
+;-------------------------------------------------------------------------------
diff --git a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
index 13a7b5f..5425547 100644
--- a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
+++ b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
@@ -20,6 +20,160 @@

include MpEqu.inc
.code
+;-------------------------------------------------------------------------------------
+;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
+;procedure serializes all the AP processors through an Init sequence. It must be
+;noted that APs arrive here very raw...ie: real mode, no stack.
+;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
+;IS IN MACHINE CODE.
+;-------------------------------------------------------------------------------------
+RendezvousFunnelProc PROC PUBLIC
+RendezvousFunnelProcStart::
+; At this point CS = 0x(vv00) and ip= 0x0.
+; Save BIST information to ebp firstly
+ db 66h, 08bh, 0e8h ; mov ebp, eax ; save BIST information
+
+ db 8ch,0c8h ; mov ax,cs
+ db 8eh,0d8h ; mov ds,ax
+ db 8eh,0c0h ; mov es,ax
+ db 8eh,0d0h ; mov ss,ax
+ db 33h,0c0h ; xor ax,ax
+ db 8eh,0e0h ; mov fs,ax
+ db 8eh,0e8h ; mov gs,ax
+
+ db 0BEh ; opcode of mov si, mem16
+ dw BufferStartLocation ; mov si, BufferStartLocation
+ db 66h, 8Bh, 1Ch ; mov ebx,dword ptr [si]
+
+ db 0BFh ; opcode of mov di, mem16
+ dw PmodeOffsetLocation ; mov di, PmodeOffsetLocation
+ db 66h, 8Bh, 05h ; mov eax,dword ptr [di]
+ db 8Bh, 0F8h ; mov di, ax
+ db 83h, 0EFh,06h ; sub di, 06h
+ db 66h, 03h, 0C3h ; add eax, ebx
+ db 66h, 89h, 05h ; mov dword ptr [di],eax
+
+ db 0BFh ; opcode of mov di, mem16
+ dw LmodeOffsetLocation ; mov di, LmodeOffsetLocation
+ db 66h, 8Bh, 05h ; mov eax,dword ptr [di]
+ db 8Bh, 0F8h ; mov di, ax
+ db 83h, 0EFh,06h ; sub di, 06h
+ db 66h, 03h, 0C3h ; add eax, ebx
+ db 66h, 89h, 05h ; mov dword ptr [di],eax
+
+ db 0BEh
+ dw Cr3Location ; mov si, Cr3Location
+ db 66h, 8Bh, 0Ch ; mov ecx,dword ptr [si] ; ECX is keeping the value of CR3
+
+ db 0BEh ; opcode of mov si, mem16
+ dw GdtrLocation ; mov si, GdtrLocation
+ db 66h ; db 66h
+ db 2Eh, 0Fh, 01h, 14h ; lgdt fword ptr cs:[si]
+
+ db 0BEh
+ dw IdtrLocation ; mov si, IdtrLocation
+ db 66h ; db 66h
+ db 2Eh,0Fh, 01h, 1Ch ; lidt fword ptr cs:[si]
+
+ db 33h, 0C0h ; xor ax, ax
+ db 8Eh, 0D8h ; mov ds, ax
+
+ db 0Fh, 20h, 0C0h ; mov eax, cr0 ;Get control register 0
+ db 66h, 83h, 0C8h, 03h ; or eax, 000000003h ;Set PE bit (bit #0) & MP
+ db 0Fh, 22h, 0C0h ; mov cr0, eax
+
+ db 66h, 67h, 0EAh ; far jump
+ dd 0h ; 32-bit offset
+ dw PROTECT_MODE_CS ; 16-bit selector
+
+Flat32Start:: ; protected mode entry point
+ mov ax, PROTECT_MODE_DS
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ db 0Fh, 20h, 0E0h ; mov eax, cr4
+ db 0Fh, 0BAh, 0E8h, 05h ; bts eax, 5
+ db 0Fh, 22h, 0E0h ; mov cr4, eax
+
+ db 0Fh, 22h, 0D9h ; mov cr3, ecx
+
+ db 0B9h
+ dd 0C0000080h ; mov ecx, 0c0000080h ; EFER MSR number.
+ db 0Fh, 32h ; rdmsr ; Read EFER.
+ db 0Fh, 0BAh, 0E8h, 08h ; bts eax, 8 ; Set LME=1.
+ db 0Fh, 30h ; wrmsr ; Write EFER.
+
+ db 0Fh, 20h, 0C0h ; mov eax, cr0 ; Read CR0.
+ db 0Fh, 0BAh, 0E8h, 1Fh ; bts eax, 31 ; Set PG=1.
+ db 0Fh, 22h, 0C0h ; mov cr0, eax ; Write CR0.
+
+LONG_JUMP:
+ db 67h, 0EAh ; far jump
+ dd 0h ; 32-bit offset
+ dw LONG_MODE_CS ; 16-bit selector
+
+LongModeStart::
+ mov ax, LONG_MODE_DS
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+
+ mov esi, ebx
+ mov edi, esi
+ add edi, LockLocation
+ mov rax, NotVacantFlag
+
+TestLock:
+ xchg qword ptr [edi], rax
+ cmp rax, NotVacantFlag
+ jz TestLock
+
+ mov edi, esi
+ add edi, NumApsExecutingLoction
+ inc dword ptr [edi]
+ mov ebx, dword ptr [edi]
+
+ProgramStack:
+ mov edi, esi
+ add edi, StackSizeLocation
+ mov rax, qword ptr [edi]
+ mov edi, esi
+ add edi, StackStartAddressLocation
+ add rax, qword ptr [edi]
+ mov rsp, rax
+ mov qword ptr [edi], rax
+
+Releaselock:
+ mov rax, VacantFlag
+ mov edi, esi
+ add edi, LockLocation
+ xchg qword ptr [edi], rax
+
+CProcedureInvoke:
+ push rbp ; push BIST data
+ xor rbp, rbp ; clear ebp for call stack trace
+ push rbp
+ mov rbp, rsp
+
+
+ mov edx, ebx ; edx is NumApsExecuting
+ mov ecx, esi
+ add ecx, LockLocation ; rcx is address of exchange info data buffer
+
+ mov edi, esi
+ add edi, ApProcedureLocation
+ mov rax, qword ptr [edi]
+
+ sub rsp, 20h
+ call rax ; invoke C function
+ add rsp, 20h
+ jmp $
+
+RendezvousFunnelProc ENDP
+RendezvousFunnelProcEnd::


AsmInitializeGdt PROC
diff --git a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm
index bd59572..99669ce 100644
--- a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm
+++ b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm
@@ -19,9 +19,158 @@
;-------------------------------------------------------------------------------

%include "MpEqu.inc"
+
DEFAULT REL
+
SECTION .text

+;-------------------------------------------------------------------------------------
+;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
+;procedure serializes all the AP processors through an Init sequence. It must be
+;noted that APs arrive here very raw...ie: real mode, no stack.
+;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
+;IS IN MACHINE CODE.
+;-------------------------------------------------------------------------------------
+global ASM_PFX(RendezvousFunnelProc)
+ASM_PFX(RendezvousFunnelProc):
+RendezvousFunnelProcStart:
+; At this point CS = 0x(vv00) and ip= 0x0.
+; Save BIST information to ebp firstly
+BITS 16
+
+ mov eax, 1234h
+ mov ebp, eax ; save BIST information
+
+ mov ax, cs
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+ xor ax, ax
+ mov fs, ax
+ mov gs, ax
+
+ mov si, BufferStartLocation
+ mov ebx, [si]
+
+ mov di, PmodeOffsetLocation
+ mov eax, [di]
+ mov di, ax
+ sub di, 06h
+ add eax, ebx
+ mov [di],eax
+
+ mov di, LmodeOffsetLocation
+ mov eax, [di]
+ mov di, ax
+ sub di, 06h
+ add eax, ebx
+ mov [di],eax
+
+
+ mov si, Cr3Location
+ mov ecx,[si] ; ECX is keeping the value of CR3
+
+ mov si, GdtrLocation
+o32 lgdt [cs:si]
+
+ mov si, IdtrLocation
+o32 lidt [cs:si]
+
+
+ xor ax, ax
+ mov ds, ax
+
+ mov eax, cr0 ;Get control register 0
+ or eax, 000000003h ;Set PE bit (bit #0) & MP
+ mov cr0, eax
+
+ jmp PROTECT_MODE_CS:strict dword 0 ; far jump to protected mode
+BITS 32
+Flat32Start: ; protected mode entry point
+ mov ax, PROTECT_MODE_DS
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ mov eax, cr4
+ bts eax, 5
+ mov cr4, eax
+
+ mov cr3, ecx
+
+
+ mov ecx, 0c0000080h ; EFER MSR number.
+ rdmsr ; Read EFER.
+ bts eax, 8 ; Set LME=1.
+ wrmsr ; Write EFER.
+
+ mov eax, cr0 ; Read CR0.
+ bts eax, 31 ; Set PG=1.
+ mov cr0, eax ; Write CR0.
+
+ jmp LONG_MODE_CS:strict dword 0 ; far jump to long mode
+BITS 64
+LongModeStart:
+ mov ax, LONG_MODE_DS
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+
+ mov esi, ebx
+ mov edi, esi
+ add edi, LockLocation
+ mov rax, NotVacantFlag
+
+TestLock:
+ xchg qword [edi], rax
+ cmp rax, NotVacantFlag
+ jz TestLock
+
+ mov edi, esi
+ add edi, NumApsExecutingLoction
+ inc dword [edi]
+ mov ebx, [edi]
+
+ProgramStack:
+ mov edi, esi
+ add edi, StackSizeLocation
+ mov rax, qword [edi]
+ mov edi, esi
+ add edi, StackStartAddressLocation
+ add rax, qword [edi]
+ mov rsp, rax
+ mov qword [edi], rax
+
+Releaselock:
+ mov rax, VacantFlag
+ mov edi, esi
+ add edi, LockLocation
+ xchg qword [edi], rax
+
+CProcedureInvoke:
+ push rbp ; push BIST data at top of AP stack
+ xor rbp, rbp ; clear ebp for call stack trace
+ push rbp
+ mov rbp, rsp
+
+
+ mov edx, ebx ; edx is NumApsExecuting
+ mov ecx, esi
+ add ecx, LockLocation ; rcx is address of exchange info data buffer
+
+ mov edi, esi
+ add edi, ApProcedureLocation
+ mov rax, qword [edi]
+
+ sub rsp, 20h
+ call rax ; invoke C function
+ add rsp, 20h
+
+RendezvousFunnelProcEnd:
+
+
global ASM_PFX(AsmInitializeGdt)
ASM_PFX(AsmInitializeGdt):
push rbp
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:05 UTC
Permalink
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/CpuMpPei.c | 60 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
index 8367f05..a2f25b9 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
@@ -39,6 +39,62 @@ GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR mGdt = {
};

/**
+ Sort the APIC ID of all processors.
+
+ This function sorts the APIC ID of all processors so that processor number is
+ assigned in the ascending order of APIC ID which eases MP debugging.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+**/
+VOID
+SortApicId (
+ IN PEI_CPU_MP_DATA *PeiCpuMpData
+ )
+{
+ UINTN Index1;
+ UINTN Index2;
+ UINTN Index3;
+ UINT32 ApicId;
+ EFI_HEALTH_FLAGS Health;
+ UINT32 ApCount;
+
+ ApCount = PeiCpuMpData->CpuCount - 1;
+
+ if (ApCount != 0) {
+ for (Index1 = 0; Index1 < ApCount; Index1++) {
+ Index3 = Index1;
+ //
+ // Sort key is the hardware default APIC ID
+ //
+ ApicId = PeiCpuMpData->CpuData[Index1].ApicId;
+ for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {
+ if (ApicId > PeiCpuMpData->CpuData[Index2].ApicId) {
+ Index3 = Index2;
+ ApicId = PeiCpuMpData->CpuData[Index2].ApicId;
+ }
+ }
+ if (Index3 != Index1) {
+ PeiCpuMpData->CpuData[Index3].ApicId = PeiCpuMpData->CpuData[Index1].ApicId;
+ PeiCpuMpData->CpuData[Index1].ApicId = ApicId;
+ Health = PeiCpuMpData->CpuData[Index3].Health;
+ PeiCpuMpData->CpuData[Index3].Health = PeiCpuMpData->CpuData[Index1].Health;
+ PeiCpuMpData->CpuData[Index1].Health = Health;
+ }
+ }
+
+ //
+ // Get the processor number for the BSP
+ //
+ ApicId = GetInitialApicId ();
+ for (Index1 = 0; Index1 < PeiCpuMpData->CpuCount; Index1++) {
+ if (PeiCpuMpData->CpuData[Index1].ApicId == ApicId) {
+ PeiCpuMpData->BspNumber = (UINT32) Index1;
+ break;
+ }
+ }
+ }
+}
+/**
This function will be called from AP reset code if BSP uses WakeUpAP.

@param ExchangeInfo Pointer to the MP exchange info buffer
@@ -240,6 +296,10 @@ CountProcessorNumber (
MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));
PeiCpuMpData->InitFlag = 0;
PeiCpuMpData->CpuCount += (UINT32) PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting;
+ //
+ // Sort BSP/Aps by CPU APIC ID in ascending order
+ //
+ SortApicId (PeiCpuMpData);

DEBUG ((EFI_D_INFO, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData->CpuCount));
return PeiCpuMpData->CpuCount;
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:02 UTC
Permalink
Get AP wakeup buffer and copy AP reset code into it. Allocate APs' stack and CPU
MP data buffer. Fill CPU MP data fields accordingly.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/CpuMpPei.c | 87 ++++++++++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/CpuMpPei.h | 41 ++++++++++++++++++-
UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 9 ++++-
3 files changed, 135 insertions(+), 2 deletions(-)

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
index 0e34f26..45243d8 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
@@ -111,6 +111,88 @@ GetWakeupBuffer (
}

/**
+ Get available system memory below 1MB by specified size.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+**/
+VOID
+BackupAndPrepareWakeupBuffer(
+ IN PEI_CPU_MP_DATA *PeiCpuMpData
+ )
+{
+ CopyMem (
+ (VOID *) PeiCpuMpData->BackupBuffer,
+ (VOID *) PeiCpuMpData->WakeupBuffer,
+ PeiCpuMpData->BackupBufferSize
+ );
+ CopyMem (
+ (VOID *) PeiCpuMpData->WakeupBuffer,
+ (VOID *) PeiCpuMpData->AddressMap.RendezvousFunnelAddress,
+ PeiCpuMpData->AddressMap.RendezvousFunnelSize
+ );
+}
+/**
+ Prepare for AP wakeup buffer and copy AP reset code into it.
+
+ Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.
+
+ @return Pointer to PEI CPU MP Data
+**/
+PEI_CPU_MP_DATA *
+PrepareAPStartupVector (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 MaxCpuCount;
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ EFI_PHYSICAL_ADDRESS Buffer;
+ UINTN BufferSize;
+ UINTN WakeupBuffer;
+ UINTN WakeupBufferSize;
+ MP_ASSEMBLY_ADDRESS_MAP AddressMap;
+
+ AsmGetAddressMap (&AddressMap);
+ WakeupBufferSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);
+ WakeupBuffer = GetWakeupBuffer ((WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1));
+ DEBUG ((EFI_D_INFO, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer));
+
+ //
+ // Allocate Pages for APs stack, CPU MP Data and backup buffer for wakeup buffer
+ //
+ MaxCpuCount = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
+ BufferSize = PcdGet32 (PcdCpuApStackSize) * MaxCpuCount + sizeof (PEI_CPU_MP_DATA)
+ + WakeupBufferSize + sizeof (PEI_CPU_DATA) * MaxCpuCount;
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &Buffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ PeiCpuMpData = (PEI_CPU_MP_DATA *) (UINTN) (Buffer + PcdGet32 (PcdCpuApStackSize) * MaxCpuCount);
+ PeiCpuMpData->Buffer = (UINTN) Buffer;
+ PeiCpuMpData->CpuApStackSize = PcdGet32 (PcdCpuApStackSize);
+ PeiCpuMpData->WakeupBuffer = WakeupBuffer;
+ PeiCpuMpData->BackupBuffer = (UINTN)PeiCpuMpData + sizeof (PEI_CPU_MP_DATA);
+ PeiCpuMpData->BackupBufferSize = WakeupBufferSize;
+ PeiCpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeupBuffer + AddressMap.RendezvousFunnelSize);
+
+ PeiCpuMpData->CpuCount = 1;
+ PeiCpuMpData->BspNumber = 0;
+ PeiCpuMpData->CpuData = (PEI_CPU_DATA *) (PeiCpuMpData->MpCpuExchangeInfo + 1);
+ PeiCpuMpData->CpuData[0].ApicId = GetInitialApicId ();
+ PeiCpuMpData->CpuData[0].Health.Uint32 = 0;
+ CopyMem (&PeiCpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));
+
+ //
+ // Backup original data and copy AP reset code in it
+ //
+ BackupAndPrepareWakeupBuffer(PeiCpuMpData);
+
+ return PeiCpuMpData;
+}
+/**
The Entry point of the MP CPU PEIM.

This function will wakeup APs and collect CPU AP count and install the
@@ -130,11 +212,16 @@ CpuMpPeimInit (
)
{

+ PEI_CPU_MP_DATA *PeiCpuMpData;

//
// Load new GDT table on BSP
//
AsmInitializeGdt (&mGdt);
+ //
+ // Get wakeup buffer and copy AP reset code in it
+ //
+ PeiCpuMpData = PrepareAPStartupVector ();

return EFI_SUCCESS;
}
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
index 7c96084..1219e4e 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
@@ -17,11 +17,25 @@

#include <PiPei.h>

+#include <Ppi/SecPlatformInformation.h>

#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
#include <Library/HobLib.h>
+#include <Library/LocalApicLib.h>
+#include <Library/PcdLib.h>
#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
#include <Library/UefiCpuLib.h>
+//
+// AP state
+//
+typedef enum {
+ CpuStateIdle,
+ CpuStateBusy,
+ CpuStateDisabled
+} CPU_STATE;

//
// AP reset code information
@@ -33,7 +47,9 @@ typedef struct {
UINTN RendezvousFunnelSize;
} MP_ASSEMBLY_ADDRESS_MAP;

-#pragma pack(1)
+typedef struct _PEI_CPU_MP_DATA PEI_CPU_MP_DATA;
+
+#pragma pack()

typedef union {
struct {
@@ -73,6 +89,29 @@ typedef struct {

#pragma pack()

+typedef struct {
+ UINT32 ApicId;
+ EFI_HEALTH_FLAGS Health;
+ CPU_STATE State;
+ BOOLEAN CpuHealthy;
+} PEI_CPU_DATA;
+
+//
+// PEI CPU MP Data save in memory
+//
+struct _PEI_CPU_MP_DATA {
+ UINT32 CpuCount;
+ UINT32 BspNumber;
+ UINTN Buffer;
+ UINTN CpuApStackSize;
+ MP_ASSEMBLY_ADDRESS_MAP AddressMap;
+ UINTN WakeupBuffer;
+ UINTN BackupBuffer;
+ UINTN BackupBufferSize;
+ PEI_CPU_DATA *CpuData;
+ volatile MP_CPU_EXCHANGE_INFO *MpCpuExchangeInfo;
+};
+
/**
Assembly code to get starting address and size of the rendezvous entry for APs.
Information for fixing a jump instruction in the code is also returned.
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
index 9fb9e94..a04556f 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
@@ -49,12 +49,19 @@

[LibraryClasses]
BaseLib
+ BaseMemoryLib
+ DebugLib
HobLib
+ LocalApicLib
+ PcdLib
PeimEntryPoint
+ PeiServicesLib
UefiCpuLib


-
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize

[Depex]
gEfiPeiMemoryDiscoveredPpiGuid
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:03 UTC
Permalink
This PCD is used to specify timeout value for BSP to detect all APs for the
first time.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/UefiCpuPkg.dec | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index 14a0bf2..b45774c 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -1,7 +1,7 @@
## @file UefiCpuPkg.dec
# This Package provides UEFI compatible CPU modules and libraries.
#
-# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials are licensed and made available under
# the terms and conditions of the BSD License which accompanies this distribution.
@@ -62,5 +62,10 @@
# @Prompt Configure stack size for Application Processor (AP)
gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize|0x8000|UINT32|0x00000003

+[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
+ ## Specifies timeout value in microseconds for the BSP to detect all APs for the first time.
+ # @Prompt Timeout for the BSP to detect all APs for the first time.
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds|50000|UINT32|0x00000004
+
[UserExtensions.TianoCore."ExtraFiles"]
UefiCpuPkgExtra.uni
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:06 UTC
Permalink
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/CpuMpPei.c | 8 ++++++++
UefiCpuPkg/CpuMpPei/CpuMpPei.h | 2 ++
UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 1 +
3 files changed, 11 insertions(+)

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
index a2f25b9..e39a813 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
@@ -118,6 +118,10 @@ ApCFunction (
BistData = *(UINTN *) (PeiCpuMpData->Buffer + NumApsExecuting * PeiCpuMpData->CpuApStackSize - sizeof (UINTN));
PeiCpuMpData->CpuData[NumApsExecuting].ApicId = GetInitialApicId ();
PeiCpuMpData->CpuData[NumApsExecuting].Health.Uint32 = (UINT32) BistData;
+ //
+ // Sync BSP's Mtrr table to all wakeup APs
+ //
+ MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable);
}

//
@@ -286,6 +290,10 @@ CountProcessorNumber (
{

//
+ // Store BSP's MTRR setting
+ //
+ MtrrGetAllMtrrs (&PeiCpuMpData->MtrrTable);
+ //
// Send broadcast IPI to APs to wakeup APs
//
PeiCpuMpData->InitFlag = 1;
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
index 3194f1f..466ddc0 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
@@ -24,6 +24,7 @@
#include <Library/DebugLib.h>
#include <Library/HobLib.h>
#include <Library/LocalApicLib.h>
+#include <Library/MtrrLib.h>
#include <Library/PcdLib.h>
#include <Library/PeimEntryPoint.h>
#include <Library/PeiServicesLib.h>
@@ -115,6 +116,7 @@ struct _PEI_CPU_MP_DATA {
UINTN ApFunctionArgument;
volatile UINT32 FinishedCount;
BOOLEAN InitFlag;
+ MTRR_SETTINGS MtrrTable;
PEI_CPU_DATA *CpuData;
volatile MP_CPU_EXCHANGE_INFO *MpCpuExchangeInfo;
};
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
index 4d7ba3e..e195f8c 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
@@ -53,6 +53,7 @@
DebugLib
HobLib
LocalApicLib
+ MtrrLib
PcdLib
PeimEntryPoint
PeiServicesLib
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:08 UTC
Permalink
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/Include/Register/LocalApic.h | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/UefiCpuPkg/Include/Register/LocalApic.h b/UefiCpuPkg/Include/Register/LocalApic.h
index f49e8f5..cf335a6 100644
--- a/UefiCpuPkg/Include/Register/LocalApic.h
+++ b/UefiCpuPkg/Include/Register/LocalApic.h
@@ -1,7 +1,7 @@
/** @file
IA32 Local APIC Definitions.

- Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
@@ -25,7 +25,11 @@
//
#define CPUID_SIGNATURE 0x0
#define CPUID_VERSION_INFO 0x1
+#define CPUID_CACHE_PARAMS 0x4
#define CPUID_EXTENDED_TOPOLOGY 0xB
+#define CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID 0x0
+#define CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT 0x1
+#define CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE 0x2
#define CPUID_EXTENDED_FUNCTION 0x80000000
#define CPUID_VIR_PHY_ADDRESS_SIZE 0x80000008
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:04 UTC
Permalink
BSP will send broadcast INIT Startup IPI to all APs and collect APs count and
BIST information.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/CpuMpPei.c | 119 +++++++++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/CpuMpPei.h | 7 +++
UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 3 +
3 files changed, 129 insertions(+)

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
index 45243d8..8367f05 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
@@ -39,6 +39,91 @@ GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR mGdt = {
};

/**
+ This function will be called from AP reset code if BSP uses WakeUpAP.
+
+ @param ExchangeInfo Pointer to the MP exchange info buffer
+ @param NumApsExecuting Number of curret executing AP
+**/
+VOID
+EFIAPI
+ApCFunction (
+ IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,
+ IN UINTN NumApsExecuting
+ )
+{
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINTN BistData;
+
+ PeiCpuMpData = ExchangeInfo->PeiCpuMpData;
+ if (PeiCpuMpData->InitFlag) {
+ //
+ // This is first time AP wakeup, get BIST inforamtion from AP stack
+ //
+ BistData = *(UINTN *) (PeiCpuMpData->Buffer + NumApsExecuting * PeiCpuMpData->CpuApStackSize - sizeof (UINTN));
+ PeiCpuMpData->CpuData[NumApsExecuting].ApicId = GetInitialApicId ();
+ PeiCpuMpData->CpuData[NumApsExecuting].Health.Uint32 = (UINT32) BistData;
+ }
+
+ //
+ // AP finished executing C code
+ //
+ InterlockedIncrement ((UINT32 *)&PeiCpuMpData->FinishedCount);
+
+}
+
+/**
+ This function will be called by BSP to wakeup AP.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+ @param Broadcast TRUE: Send broadcast IPI to all APs
+ FALSE: Send IPI to AP by ApicId
+ @param ApicId Apic ID for the processor to be waked
+ @param Procedure The function to be invoked by AP
+ @param ProcedureArgument The argument to be passed into AP function
+**/
+VOID
+WakeUpAP (
+ IN PEI_CPU_MP_DATA *PeiCpuMpData,
+ IN BOOLEAN Broadcast,
+ IN UINT32 ApicId,
+ IN EFI_AP_PROCEDURE Procedure, OPTIONAL
+ IN VOID *ProcedureArgument OPTIONAL
+ )
+{
+ volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+
+ PeiCpuMpData->ApFunction = (UINTN) Procedure;
+ PeiCpuMpData->ApFunctionArgument = (UINTN) ProcedureArgument;
+ PeiCpuMpData->FinishedCount = 0;
+
+ ExchangeInfo = PeiCpuMpData->MpCpuExchangeInfo;
+ ExchangeInfo->Lock = 0;
+ ExchangeInfo->StackStart = PeiCpuMpData->Buffer;
+ ExchangeInfo->StackSize = PeiCpuMpData->CpuApStackSize;
+ ExchangeInfo->BufferStart = PeiCpuMpData->WakeupBuffer;
+ ExchangeInfo->PmodeOffset = PeiCpuMpData->AddressMap.PModeEntryOffset;
+ ExchangeInfo->LmodeOffset = PeiCpuMpData->AddressMap.LModeEntryOffset;
+ ExchangeInfo->Cr3 = AsmReadCr3 ();
+ ExchangeInfo->CFunction = (UINTN) ApCFunction;
+ ExchangeInfo->NumApsExecuting = 0;
+ ExchangeInfo->PeiCpuMpData = PeiCpuMpData;
+
+ //
+ // Get the BSP's data of GDT and IDT
+ //
+ CopyMem ((VOID *)&ExchangeInfo->GdtrProfile, &mGdt, sizeof(mGdt));
+ AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);
+
+ if (Broadcast) {
+ SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
+ } else {
+ SendInitSipiSipi (ApicId, (UINT32) ExchangeInfo->BufferStart);
+ }
+
+ return ;
+}
+
+/**
Get available system memory below 1MB by specified size.

@param WakeupBufferSize Wakeup buffer size required
@@ -132,6 +217,35 @@ BackupAndPrepareWakeupBuffer(
);
}
/**
+ This function will get CPU count in the system.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+
+ @return AP processor count
+**/
+UINT32
+CountProcessorNumber (
+ IN PEI_CPU_MP_DATA *PeiCpuMpData
+ )
+{
+
+ //
+ // Send broadcast IPI to APs to wakeup APs
+ //
+ PeiCpuMpData->InitFlag = 1;
+ WakeUpAP (PeiCpuMpData, TRUE, 0, NULL, NULL);
+ //
+ // Wait for AP task to complete and then exit.
+ //
+ MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));
+ PeiCpuMpData->InitFlag = 0;
+ PeiCpuMpData->CpuCount += (UINT32) PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting;
+
+ DEBUG ((EFI_D_INFO, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData->CpuCount));
+ return PeiCpuMpData->CpuCount;
+}
+
+/**
Prepare for AP wakeup buffer and copy AP reset code into it.

Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.
@@ -213,6 +327,7 @@ CpuMpPeimInit (
{

PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINT32 ProcessorCount;

//
// Load new GDT table on BSP
@@ -222,6 +337,10 @@ CpuMpPeimInit (
// Get wakeup buffer and copy AP reset code in it
//
PeiCpuMpData = PrepareAPStartupVector ();
+ //
+ // Count processor number and collect processor information
+ //
+ ProcessorCount = CountProcessorNumber (PeiCpuMpData);

return EFI_SUCCESS;
}
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
index 1219e4e..3194f1f 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
@@ -27,6 +27,8 @@
#include <Library/PcdLib.h>
#include <Library/PeimEntryPoint.h>
#include <Library/PeiServicesLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/TimerLib.h>
#include <Library/UefiCpuLib.h>
//
// AP state
@@ -85,6 +87,7 @@ typedef struct {
UINTN NumApsExecuting;
UINTN LmodeOffset;
UINTN Cr3;
+ PEI_CPU_MP_DATA *PeiCpuMpData;
} MP_CPU_EXCHANGE_INFO;

#pragma pack()
@@ -108,6 +111,10 @@ struct _PEI_CPU_MP_DATA {
UINTN WakeupBuffer;
UINTN BackupBuffer;
UINTN BackupBufferSize;
+ UINTN ApFunction;
+ UINTN ApFunctionArgument;
+ volatile UINT32 FinishedCount;
+ BOOLEAN InitFlag;
PEI_CPU_DATA *CpuData;
volatile MP_CPU_EXCHANGE_INFO *MpCpuExchangeInfo;
};
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
index a04556f..4d7ba3e 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
@@ -56,11 +56,14 @@
PcdLib
PeimEntryPoint
PeiServicesLib
+ SynchronizationLib
+ TimerLib
UefiCpuLib


[Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds
gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize

[Depex]
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:07 UTC
Permalink
Add PCDs PcdCpuMicrocodePatchAddress and PcdCpuMicrocodePatchRegionSize that
are used to detect microcode patch from microcode region.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/UefiCpuPkg.dec | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec
index b45774c..202e719 100644
--- a/UefiCpuPkg/UefiCpuPkg.dec
+++ b/UefiCpuPkg/UefiCpuPkg.dec
@@ -66,6 +66,12 @@
## Specifies timeout value in microseconds for the BSP to detect all APs for the first time.
# @Prompt Timeout for the BSP to detect all APs for the first time.
gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds|50000|UINT32|0x00000004
+ ## Specifies the base address of the first microcode Patch in the microcode Region.
+ # @Prompt Microcode Region base address.
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchAddress|0x0|UINT64|0x00000005
+ ## Specifies the size of the microcode Region.
+ # @Prompt Microcode Region size.
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize|0x0|UINT64|0x00000006

[UserExtensions.TianoCore."ExtraFiles"]
UefiCpuPkgExtra.uni
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:10 UTC
Permalink
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/CpuMpPei.c | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
index d63b1ff..ae98c38 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
@@ -94,6 +94,31 @@ SortApicId (
}
}
}
+
+/**
+ Get CPU MP Data pointer from the Guided HOB.
+
+ @return Pointer to Pointer to PEI CPU MP Data
+**/
+PEI_CPU_MP_DATA *
+GetMpHobData (
+ VOID
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ VOID *DataInHob;
+ PEI_CPU_MP_DATA *CpuMpData;
+
+ CpuMpData = NULL;
+ GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
+ if (GuidHob != NULL) {
+ DataInHob = GET_GUID_HOB_DATA (GuidHob);
+ CpuMpData = (PEI_CPU_MP_DATA *)(*(UINTN *)DataInHob);
+ }
+ ASSERT (CpuMpData != NULL);
+ return CpuMpData;
+}
+
/**
This function will be called from AP reset code if BSP uses WakeUpAP.

@@ -413,6 +438,14 @@ CpuMpPeimInit (
// Count processor number and collect processor information
//
ProcessorCount = CountProcessorNumber (PeiCpuMpData);
+ //
+ // Build location of PEI CPU MP DATA buffer in HOB
+ //
+ BuildGuidDataHob (
+ &gEfiCallerIdGuid,
+ (VOID *)&PeiCpuMpData,
+ sizeof(UINT64)
+ );

return EFI_SUCCESS;
}
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:09 UTC
Permalink
Add DetectMicrocode() to load microcode on BSP and APs.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/CpuMpPei.c | 8 +-
UefiCpuPkg/CpuMpPei/CpuMpPei.h | 5 +
UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 4 +
UefiCpuPkg/CpuMpPei/Microcode.c | 200 +++++++++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/Microcode.h | 68 +++++++++++++
5 files changed, 283 insertions(+), 2 deletions(-)
create mode 100644 UefiCpuPkg/CpuMpPei/Microcode.c
create mode 100644 UefiCpuPkg/CpuMpPei/Microcode.h

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
index e39a813..d63b1ff 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
@@ -119,9 +119,10 @@ ApCFunction (
PeiCpuMpData->CpuData[NumApsExecuting].ApicId = GetInitialApicId ();
PeiCpuMpData->CpuData[NumApsExecuting].Health.Uint32 = (UINT32) BistData;
//
- // Sync BSP's Mtrr table to all wakeup APs
+ // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs.
//
MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable);
+ MicrocodeDetect ();
}

//
@@ -288,7 +289,10 @@ CountProcessorNumber (
IN PEI_CPU_MP_DATA *PeiCpuMpData
)
{
-
+ //
+ // Load Microcode on BSP
+ //
+ MicrocodeDetect ();
//
// Store BSP's MTRR setting
//
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
index 466ddc0..7a34a98 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
@@ -19,6 +19,8 @@

#include <Ppi/SecPlatformInformation.h>

+#include <Register/LocalApic.h>
+
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
@@ -31,6 +33,9 @@
#include <Library/SynchronizationLib.h>
#include <Library/TimerLib.h>
#include <Library/UefiCpuLib.h>
+
+#include "Microcode.h"
+
//
// AP state
//
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
index e195f8c..1bb4dae 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
@@ -30,6 +30,8 @@
[Sources]
CpuMpPei.h
CpuMpPei.c
+ Microcode.h
+ Microcode.c

[Sources.IA32]
Ia32/MpEqu.inc
@@ -66,6 +68,8 @@
gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds
gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchAddress
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize

[Depex]
gEfiPeiMemoryDiscoveredPpiGuid
diff --git a/UefiCpuPkg/CpuMpPei/Microcode.c b/UefiCpuPkg/CpuMpPei/Microcode.c
new file mode 100644
index 0000000..eb2e76b
--- /dev/null
+++ b/UefiCpuPkg/CpuMpPei/Microcode.c
@@ -0,0 +1,200 @@
+/** @file
+ Implementation of loading microcode on processors.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "CpuMpPei.h"
+
+/**
+ Get microcode update signature of currently loaded microcode update.
+
+ @return Microcode signature.
+
+**/
+UINT32
+GetCurrentMicrocodeSignature (
+ VOID
+ )
+{
+ UINT64 Signature;
+
+ AsmWriteMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID, 0);
+ AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);
+ Signature = AsmReadMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID);
+ return (UINT32) RShiftU64 (Signature, 32);
+}
+
+/**
+ Detect whether specified processor can find matching microcode patch and load it.
+
+**/
+VOID
+MicrocodeDetect (
+ VOID
+ )
+{
+ UINT64 MicrocodePatchAddress;
+ UINT64 MicrocodePatchRegionSize;
+ UINT32 ExtendedTableLength;
+ UINT32 ExtendedTableCount;
+ EFI_CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
+ EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
+ EFI_CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
+ UINTN MicrocodeEnd;
+ UINTN Index;
+ UINT8 PlatformId;
+ UINT32 RegEax;
+ UINT32 LatestRevision;
+ UINTN TotalSize;
+ UINT32 CheckSum32;
+ BOOLEAN CorrectMicrocode;
+ INT32 CurrentSignature;
+ MICROCODE_INFO MicrocodeInfo;
+
+ ZeroMem (&MicrocodeInfo, sizeof (MICROCODE_INFO));
+ MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);
+ MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);
+ if (MicrocodePatchRegionSize == 0) {
+ //
+ // There is no microcode patches
+ //
+ return;
+ }
+
+ ExtendedTableLength = 0;
+ //
+ // Here data of CPUID leafs have not been collected into context buffer, so
+ // GetProcessorCpuid() cannot be used here to retrieve CPUID data.
+ //
+ AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);
+
+ //
+ // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID
+ //
+ PlatformId = (UINT8) AsmMsrBitFieldRead64 (EFI_MSR_IA32_PLATFORM_ID, 50, 52);
+
+ LatestRevision = 0;
+ MicrocodeEnd = (UINTN) (MicrocodePatchAddress + MicrocodePatchRegionSize);
+ MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;
+ do {
+ //
+ // Check if the microcode is for the Cpu and the version is newer
+ // and the update can be processed on the platform
+ //
+ CorrectMicrocode = FALSE;
+ if (MicrocodeEntryPoint->HeaderVersion == 0x1) {
+ //
+ // It is the microcode header. It is not the padding data between microcode patches
+ // becasue the padding data should not include 0x00000001 and it should be the repeated
+ // byte format (like 0xXYXYXYXY....).
+ //
+ if (MicrocodeEntryPoint->ProcessorId == RegEax &&
+ MicrocodeEntryPoint->UpdateRevision > LatestRevision &&
+ (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))
+ ) {
+ if (MicrocodeEntryPoint->DataSize == 0) {
+ CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, 2048);
+ } else {
+ CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, MicrocodeEntryPoint->DataSize + sizeof(EFI_CPU_MICROCODE_HEADER));
+ }
+ if (CheckSum32 == 0) {
+ CorrectMicrocode = TRUE;
+ }
+ } else if ((MicrocodeEntryPoint->DataSize != 0) &&
+ (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {
+ ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));
+ if (ExtendedTableLength != 0) {
+ //
+ // Extended Table exist, check if the CPU in support list
+ //
+ ExtendedTableHeader = (EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));
+ //
+ // Calculate Extended Checksum
+ //
+ if ((ExtendedTableLength % 4) == 0) {
+ CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTableHeader, ExtendedTableLength);
+ if (CheckSum32 == 0) {
+ //
+ // Checksum correct
+ //
+ ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
+ ExtendedTable = (EFI_CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);
+ for (Index = 0; Index < ExtendedTableCount; Index ++) {
+ CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTable, sizeof(EFI_CPU_MICROCODE_EXTENDED_TABLE));
+ if (CheckSum32 == 0) {
+ //
+ // Verify Header
+ //
+ if ((ExtendedTable->ProcessorSignature == RegEax) &&
+ (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {
+ //
+ // Find one
+ //
+ CorrectMicrocode = TRUE;
+ break;
+ }
+ }
+ ExtendedTable ++;
+ }
+ }
+ }
+ }
+ }
+ } else {
+ //
+ // It is the padding data between the microcode patches for microcode patches alignment.
+ // Because the microcode patch is the multiple of 1-KByte, the padding data should not
+ // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
+ // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
+ // find the next possible microcode patch header.
+ //
+ MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
+ continue;
+ }
+ //
+ // Get the next patch.
+ //
+ if (MicrocodeEntryPoint->DataSize == 0) {
+ TotalSize = 2048;
+ } else {
+ TotalSize = MicrocodeEntryPoint->TotalSize;
+ }
+
+ if (CorrectMicrocode) {
+ LatestRevision = MicrocodeEntryPoint->UpdateRevision;
+ MicrocodeInfo.MicrocodeData = (VOID *)((UINTN)MicrocodeEntryPoint + sizeof (EFI_CPU_MICROCODE_HEADER));
+ MicrocodeInfo.MicrocodeSize = TotalSize;
+ MicrocodeInfo.ProcessorId = RegEax;
+ }
+
+ MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
+ } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
+
+ if (LatestRevision > 0) {
+ //
+ // Get microcode update signature of currently loaded microcode update
+ //
+ CurrentSignature = GetCurrentMicrocodeSignature ();
+ //
+ // If no microcode update has been loaded, then trigger microcode load.
+ //
+ if (CurrentSignature == 0) {
+ AsmWriteMsr64 (
+ EFI_MSR_IA32_BIOS_UPDT_TRIG,
+ (UINT64) (UINTN) MicrocodeInfo.MicrocodeData
+ );
+ MicrocodeInfo.Load = TRUE;
+ } else {
+ MicrocodeInfo.Load = FALSE;
+ }
+ }
+}
diff --git a/UefiCpuPkg/CpuMpPei/Microcode.h b/UefiCpuPkg/CpuMpPei/Microcode.h
new file mode 100644
index 0000000..6f93e2f
--- /dev/null
+++ b/UefiCpuPkg/CpuMpPei/Microcode.h
@@ -0,0 +1,68 @@
+/** @file
+ Definitions for loading microcode on processors.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _CPU_MICROCODE_H_
+#define _CPU_MICROCODE_H_
+
+#define EFI_MSR_IA32_PLATFORM_ID 0x17
+#define EFI_MSR_IA32_BIOS_UPDT_TRIG 0x79
+#define EFI_MSR_IA32_BIOS_SIGN_ID 0x8b
+
+#define MAX_MICROCODE_DESCRIPTOR_LENGTH 100
+
+typedef struct {
+ VOID *MicrocodeData;
+ UINTN MicrocodeSize;
+ UINT32 ProcessorId;
+ BOOLEAN Load;
+} MICROCODE_INFO;
+
+//
+// Definition for IA32 microcode format
+//
+typedef struct {
+ UINT32 HeaderVersion;
+ UINT32 UpdateRevision;
+ UINT32 Date;
+ UINT32 ProcessorId;
+ UINT32 Checksum;
+ UINT32 LoaderRevision;
+ UINT32 ProcessorFlags;
+ UINT32 DataSize;
+ UINT32 TotalSize;
+ UINT8 Reserved[12];
+} EFI_CPU_MICROCODE_HEADER;
+
+typedef struct {
+ UINT32 ExtendedSignatureCount;
+ UINT32 ExtendedTableChecksum;
+ UINT8 Reserved[12];
+} EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER;
+
+typedef struct {
+ UINT32 ProcessorSignature;
+ UINT32 ProcessorFlag;
+ UINT32 ProcessorChecksum;
+} EFI_CPU_MICROCODE_EXTENDED_TABLE;
+
+/**
+ Detect whether specified processor can find matching microcode patch and load it.
+
+**/
+VOID
+MicrocodeDetect (
+ VOID
+ );
+
+#endif
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:13 UTC
Permalink
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/PeiMpServices.c | 82 +++++++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/PeiMpServices.h | 46 +++++++++++++++++++++
2 files changed, 128 insertions(+)

diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.c b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
index c411b15..de3e6d8 100644
--- a/UefiCpuPkg/CpuMpPei/PeiMpServices.c
+++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
@@ -44,6 +44,88 @@ GetProcessorNumber (
return EFI_NOT_FOUND;
}

+/**
+ This service retrieves the number of logical processor in the platform
+ and the number of those logical processors that are enabled on this boot.
+ This service may only be called from the BSP.
+
+ This function is used to retrieve the following information:
+ - The number of logical processors that are present in the system.
+ - The number of enabled logical processors in the system at the instant
+ this call is made.
+
+ Because MP Service Ppi provides services to enable and disable processors
+ dynamically, the number of enabled logical processors may vary during the
+ course of a boot session.
+
+ If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
+ If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
+ EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
+ is returned in NumberOfProcessors, the number of currently enabled processor
+ is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI
+ instance.
+ @param[out] NumberOfProcessors Pointer to the total number of logical
+ processors in the system, including the BSP
+ and disabled APs.
+ @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
+ processors that exist in system, including
+ the BSP.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
+ @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNumberOfProcessors (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ OUT UINTN *NumberOfProcessors,
+ OUT UINTN *NumberOfEnabledProcessors
+ )
+{
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINTN CallerNumber;
+ UINTN ProcessorNumber;
+ UINTN EnabledProcessorNumber;
+ UINTN Index;
+
+ PeiCpuMpData = GetMpHobData ();
+ if (PeiCpuMpData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ PeiWhoAmI (PeiServices, This, &CallerNumber);
+ if (CallerNumber != PeiCpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ProcessorNumber = PeiCpuMpData->CpuCount;
+ EnabledProcessorNumber = 0;
+ for (Index = 0; Index < ProcessorNumber; Index++) {
+ if (PeiCpuMpData->CpuData[Index].State != CpuStateDisabled) {
+ EnabledProcessorNumber ++;
+ }
+ }
+
+ *NumberOfProcessors = ProcessorNumber;
+ *NumberOfEnabledProcessors = EnabledProcessorNumber;
+
+ return EFI_SUCCESS;
+}

/**
This return the handle number for the calling processor. This service may be
diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.h b/UefiCpuPkg/CpuMpPei/PeiMpServices.h
index 5958fd8..a2eb708 100644
--- a/UefiCpuPkg/CpuMpPei/PeiMpServices.h
+++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.h
@@ -17,6 +17,52 @@

#include "CpuMpPei.h"

+/**
+ This service retrieves the number of logical processor in the platform
+ and the number of those logical processors that are enabled on this boot.
+ This service may only be called from the BSP.
+
+ This function is used to retrieve the following information:
+ - The number of logical processors that are present in the system.
+ - The number of enabled logical processors in the system at the instant
+ this call is made.
+
+ Because MP Service Ppi provides services to enable and disable processors
+ dynamically, the number of enabled logical processors may vary during the
+ course of a boot session.
+
+ If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
+ If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
+ EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
+ is returned in NumberOfProcessors, the number of currently enabled processor
+ is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI
+ instance.
+ @param[out] NumberOfProcessors Pointer to the total number of logical
+ processors in the system, including the BSP
+ and disabled APs.
+ @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
+ processors that exist in system, including
+ the BSP.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
+ @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNumberOfProcessors (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ OUT UINTN *NumberOfProcessors,
+ OUT UINTN *NumberOfEnabledProcessors
+ );
+

/**
This return the handle number for the calling processor. This service may be
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:12 UTC
Permalink
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/CpuMpPei.h | 1 +
UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 2 +
UefiCpuPkg/CpuMpPei/PeiMpServices.c | 94 +++++++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/PeiMpServices.h | 54 +++++++++++++++++++++
4 files changed, 151 insertions(+)
create mode 100644 UefiCpuPkg/CpuMpPei/PeiMpServices.c
create mode 100644 UefiCpuPkg/CpuMpPei/PeiMpServices.h

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
index aa926ab..8e83dc7 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
@@ -17,6 +17,7 @@

#include <PiPei.h>

+#include <Ppi/MpServices.h>
#include <Ppi/SecPlatformInformation.h>
#include <Ppi/SecPlatformInformation2.h>

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
index 36126af..faf999a 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
@@ -33,6 +33,8 @@
CpuBist.c
Microcode.h
Microcode.c
+ PeiMpServices.h
+ PeiMpServices.c

[Sources.IA32]
Ia32/MpEqu.inc
diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.c b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
new file mode 100644
index 0000000..c411b15
--- /dev/null
+++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
@@ -0,0 +1,94 @@
+/** @file
+ Implementation of Multiple Processor PPI services.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PeiMpServices.h"
+
+
+
+/**
+ Find the current Processor number by APIC ID.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+ @param ProcessorNumber Return the pocessor number found
+
+ @retval EFI_SUCCESS ProcessorNumber is found and returned.
+ @retval EFI_NOT_FOUND ProcessorNumber is not found.
+**/
+EFI_STATUS
+GetProcessorNumber (
+ IN PEI_CPU_MP_DATA *PeiCpuMpData,
+ OUT UINTN *ProcessorNumber
+ )
+{
+ UINTN TotalProcessorNumber;
+ UINTN Index;
+
+ TotalProcessorNumber = PeiCpuMpData->CpuCount;
+ for (Index = 0; Index < TotalProcessorNumber; Index ++) {
+ if (PeiCpuMpData->CpuData[Index].ApicId == GetInitialApicId ()) {
+ *ProcessorNumber = Index;
+ return EFI_SUCCESS;
+ }
+ }
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ This return the handle number for the calling processor. This service may be
+ called from the BSP and APs.
+
+ This service returns the processor handle number for the calling processor.
+ The returned value is in the range from 0 to the total number of logical
+ processors minus 1. The total number of logical processors can be retrieved
+ with EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors(). This service may be
+ called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
+ is returned. Otherwise, the current processors handle number is returned in
+ ProcessorNumber, and EFI_SUCCESS is returned.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
+
+ @retval EFI_SUCCESS The current processor handle number was returned
+ in ProcessorNumber.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiWhoAmI (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ OUT UINTN *ProcessorNumber
+ )
+{
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+
+ PeiCpuMpData = GetMpHobData ();
+ if (PeiCpuMpData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (ProcessorNumber == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return GetProcessorNumber (PeiCpuMpData, ProcessorNumber);
+}
+
diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.h b/UefiCpuPkg/CpuMpPei/PeiMpServices.h
new file mode 100644
index 0000000..5958fd8
--- /dev/null
+++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.h
@@ -0,0 +1,54 @@
+/** @file
+ Functions prototype of Multiple Processor PPI services.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PEI_MP_SERVICES_H_
+#define _PEI_MP_SERVICES_H_
+
+#include "CpuMpPei.h"
+
+
+/**
+ This return the handle number for the calling processor. This service may be
+ called from the BSP and APs.
+
+ This service returns the processor handle number for the calling processor.
+ The returned value is in the range from 0 to the total number of logical
+ processors minus 1. The total number of logical processors can be retrieved
+ with EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors(). This service may be
+ called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
+ is returned. Otherwise, the current processors handle number is returned in
+ ProcessorNumber, and EFI_SUCCESS is returned.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
+
+ @retval EFI_SUCCESS The current processor handle number was returned
+ in ProcessorNumber.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiWhoAmI (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ OUT UINTN *ProcessorNumber
+ );
+
+#endif
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:14 UTC
Permalink
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/PeiMpServices.c | 191 ++++++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/PeiMpServices.h | 36 +++++++
2 files changed, 227 insertions(+)

diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.c b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
index de3e6d8..6eff772 100644
--- a/UefiCpuPkg/CpuMpPei/PeiMpServices.c
+++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
@@ -15,6 +15,115 @@
#include "PeiMpServices.h"


+/**
+ Get CPU Package/Core/Thread location information.
+
+ @param InitialApicId CPU APIC ID
+ @param Location Pointer to CPU location information
+**/
+VOID
+ExtractProcessorLocation (
+ IN UINT32 InitialApicId,
+ OUT EFI_CPU_PHYSICAL_LOCATION *Location
+ )
+{
+ BOOLEAN TopologyLeafSupported;
+ UINTN ThreadBits;
+ UINTN CoreBits;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+ UINT32 RegEdx;
+ UINT32 MaxCpuIdIndex;
+ UINT32 SubIndex;
+ UINTN LevelType;
+ UINT32 MaxLogicProcessorsPerPackage;
+ UINT32 MaxCoresPerPackage;
+
+ //
+ // Check if the processor is capable of supporting more than one logical processor.
+ //
+ AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx);
+ if ((RegEdx & BIT28) == 0) {
+ Location->Thread = 0;
+ Location->Core = 0;
+ Location->Package = 0;
+ return;
+ }
+
+ ThreadBits = 0;
+ CoreBits = 0;
+
+ //
+ // Assume three-level mapping of APIC ID: Package:Core:SMT.
+ //
+
+ TopologyLeafSupported = FALSE;
+ //
+ // Get the max index of basic CPUID
+ //
+ AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
+
+ //
+ // If the extended topology enumeration leaf is available, it
+ // is the preferred mechanism for enumerating topology.
+ //
+ if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
+ AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, &RegEax, &RegEbx, &RegEcx, NULL);
+ //
+ // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for
+ // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not
+ // supported on that processor.
+ //
+ if (RegEbx != 0) {
+ TopologyLeafSupported = TRUE;
+
+ //
+ // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract
+ // the SMT sub-field of x2APIC ID.
+ //
+ LevelType = (RegEcx >> 8) & 0xff;
+ ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);
+ ThreadBits = RegEax & 0x1f;
+
+ //
+ // Software must not assume any "level type" encoding
+ // value to be related to any sub-leaf index, except sub-leaf 0.
+ //
+ SubIndex = 1;
+ do {
+ AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, SubIndex, &RegEax, NULL, &RegEcx, NULL);
+ LevelType = (RegEcx >> 8) & 0xff;
+ if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {
+ CoreBits = (RegEax & 0x1f) - ThreadBits;
+ break;
+ }
+ SubIndex++;
+ } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);
+ }
+ }
+
+ if (!TopologyLeafSupported) {
+ AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
+ MaxLogicProcessorsPerPackage = (RegEbx >> 16) & 0xff;
+ if (MaxCpuIdIndex >= CPUID_CACHE_PARAMS) {
+ AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &RegEax, NULL, NULL, NULL);
+ MaxCoresPerPackage = (RegEax >> 26) + 1;
+ } else {
+ //
+ // Must be a single-core processor.
+ //
+ MaxCoresPerPackage = 1;
+ }
+
+ ThreadBits = (UINTN) (HighBitSet32 (MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);
+ CoreBits = (UINTN) (HighBitSet32 (MaxCoresPerPackage - 1) + 1);
+ }
+
+ Location->Thread = InitialApicId & ~((-1) << ThreadBits);
+ Location->Core = (InitialApicId >> ThreadBits) & ~((-1) << CoreBits);
+ Location->Package = (InitialApicId >> (ThreadBits + CoreBits));
+}

/**
Find the current Processor number by APIC ID.
@@ -128,6 +237,88 @@ PeiGetNumberOfProcessors (
}

/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ This service retrieves detailed MP-related information about any processor
+ on the platform. Note the following:
+ - The processor information may change during the course of a boot session.
+ - The information presented here is entirely MP related.
+
+ Information regarding the number of caches and their sizes, frequency of operation,
+ slot numbers is all considered platform-related information and is not provided
+ by this service.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI
+ instance.
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
+ the requested processor is deposited.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetProcessorInfo (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ )
+{
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINTN CallerNumber;
+
+ PeiCpuMpData = GetMpHobData ();
+ if (PeiCpuMpData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ PeiWhoAmI (PeiServices, This, &CallerNumber);
+ if (CallerNumber != PeiCpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ProcessorInfoBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ProcessorNumber >= PeiCpuMpData->CpuCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ ProcessorInfoBuffer->ProcessorId = (UINT64) PeiCpuMpData->CpuData[ProcessorNumber].ApicId;
+ ProcessorInfoBuffer->StatusFlag = 0;
+ if (PeiCpuMpData->CpuData[ProcessorNumber].ApicId == GetInitialApicId()) {
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;
+ }
+ if (PeiCpuMpData->CpuData[ProcessorNumber].Health.Uint32 == 0) {
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;
+ }
+ if (PeiCpuMpData->CpuData[ProcessorNumber].State == CpuStateDisabled) {
+ ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT;
+ } else {
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;
+ }
+
+ //
+ // Get processor location information
+ //
+ ExtractProcessorLocation (PeiCpuMpData->CpuData[ProcessorNumber].ApicId, &ProcessorInfoBuffer->Location);
+
+ return EFI_SUCCESS;
+}
+
+/**
This return the handle number for the calling processor. This service may be
called from the BSP and APs.

diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.h b/UefiCpuPkg/CpuMpPei/PeiMpServices.h
index a2eb708..4ac5d93 100644
--- a/UefiCpuPkg/CpuMpPei/PeiMpServices.h
+++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.h
@@ -63,6 +63,42 @@ PeiGetNumberOfProcessors (
OUT UINTN *NumberOfEnabledProcessors
);

+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ This service retrieves detailed MP-related information about any processor
+ on the platform. Note the following:
+ - The processor information may change during the course of a boot session.
+ - The information presented here is entirely MP related.
+
+ Information regarding the number of caches and their sizes, frequency of operation,
+ slot numbers is all considered platform-related information and is not provided
+ by this service.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI
+ instance.
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
+ the requested processor is deposited.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiGetProcessorInfo (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ );
+

/**
This return the handle number for the calling processor. This service may be
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:15 UTC
Permalink
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/CpuMpPei.c | 14 +++
UefiCpuPkg/CpuMpPei/CpuMpPei.h | 34 +++++++
UefiCpuPkg/CpuMpPei/PeiMpServices.c | 188 ++++++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/PeiMpServices.h | 82 ++++++++++++++++
4 files changed, 318 insertions(+)

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
index d218313..bfcf816 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
@@ -133,6 +133,8 @@ ApCFunction (
)
{
PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINTN ProcessorNumber;
+ EFI_AP_PROCEDURE Procedure;
UINTN BistData;

PeiCpuMpData = ExchangeInfo->PeiCpuMpData;
@@ -148,6 +150,18 @@ ApCFunction (
//
MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable);
MicrocodeDetect ();
+ } else {
+ //
+ // Execute AP function if AP is not disabled
+ //
+ GetProcessorNumber (PeiCpuMpData, &ProcessorNumber);
+ if ((PeiCpuMpData->CpuData[ProcessorNumber].State != CpuStateDisabled) &&
+ (PeiCpuMpData->ApFunction != 0)) {
+ PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateBusy;
+ Procedure = (EFI_AP_PROCEDURE)(UINTN)PeiCpuMpData->ApFunction;
+ Procedure ((VOID *)(UINTN)PeiCpuMpData->ApFunctionArgument);
+ PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;
+ }
}

//
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
index 8e83dc7..ed6cf05 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
@@ -154,6 +154,25 @@ AsmInitializeGdt (


/**
+ This function will be called by BSP to wakeup AP.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+ @param Broadcast TRUE: Send broadcast IPI to all APs
+ FALSE: Send IPI to AP by ApicId
+ @param ApicId Apic ID for the processor to be waked
+ @param Procedure The function to be invoked by AP
+ @param ProcedureArgument The argument to be passed into AP function
+**/
+VOID
+WakeUpAP (
+ IN PEI_CPU_MP_DATA *PeiCpuMpData,
+ IN BOOLEAN Broadcast,
+ IN UINT32 ApicId,
+ IN EFI_AP_PROCEDURE Procedure, OPTIONAL
+ IN VOID *ProcedureArgument OPTIONAL
+ );
+
+/**
Get CPU MP Data pointer from the Guided HOB.

@return Pointer to Pointer to PEI CPU MP Data
@@ -164,6 +183,21 @@ GetMpHobData (
);

/**
+ Find the current Processor number by APIC ID.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+ @param ProcessorNumber Return the pocessor number found
+
+ @retval EFI_SUCCESS ProcessorNumber is found and returned.
+ @retval EFI_NOT_FOUND ProcessorNumber is not found.
+**/
+EFI_STATUS
+GetProcessorNumber (
+ IN PEI_CPU_MP_DATA *PeiCpuMpData,
+ OUT UINTN *ProcessorNumber
+ );
+
+/**
Collects BIST data from PPI.

This function collects BIST data from Sec Platform Information2 PPI
diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.c b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
index 6eff772..50145b3 100644
--- a/UefiCpuPkg/CpuMpPei/PeiMpServices.c
+++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
@@ -319,6 +319,194 @@ PeiGetProcessorInfo (
}

/**
+ This service executes a caller provided function on all enabled APs. APs can
+ run either simultaneously or one at a time in sequence. This service supports
+ both blocking requests only. This service may only
+ be called from the BSP.
+
+ This function is used to dispatch all the enabled APs to the function specified
+ by Procedure. If any enabled AP is busy, then EFI_NOT_READY is returned
+ immediately and Procedure is not started on any AP.
+
+ If SingleThread is TRUE, all the enabled APs execute the function specified by
+ Procedure one by one, in ascending order of processor handle number. Otherwise,
+ all the enabled APs execute the function specified by Procedure simultaneously.
+
+ If the timeout specified by TimeoutInMicroseconds expires before all APs return
+ from Procedure, then Procedure on the failed APs is terminated. All enabled APs
+ are always available for further calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ and EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If FailedCpuList is not NULL, its
+ content points to the list of processor handle numbers in which Procedure was
+ terminated.
+
+ Note: It is the responsibility of the consumer of the EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ to make sure that the nature of the code that is executed on the BSP and the
+ dispatched APs is well controlled. The MP Services Ppi does not guarantee
+ that the Procedure function is MP-safe. Hence, the tasks that can be run in
+ parallel are limited to certain independent tasks and well-controlled exclusive
+ code. PEI services and Ppis may not be called by APs unless otherwise
+ specified.
+
+ In blocking execution mode, BSP waits until all APs finish or
+ TimeoutInMicroSeconds expires.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] SingleThread If TRUE, then all the enabled APs execute
+ the function specified by Procedure one by
+ one, in ascending order of processor handle
+ number. If FALSE, then all the enabled APs
+ execute the function specified by Procedure
+ simultaneously.
+ @param[in] TimeoutInMicrosecsond Indicates the time limit in microseconds for
+ APs to return from Procedure, for
+ blocking mode only. Zero means
+ infinity. If the timeout expires before
+ all APs return from Procedure, then Procedure
+ on the failed APs is terminated. All enabled
+ APs are available for next function assigned
+ by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ or EFI_PEI_MP_SERVICES_PPI.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT.
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before
+ the timeout expired.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_STARTED No enabled APs exist in the system.
+ @retval EFI_NOT_READY Any enabled APs are busy.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ all enabled APs have finished.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiStartupAllAPs (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN UINTN TimeoutInMicroSeconds,
+ IN VOID *ProcedureArgument OPTIONAL
+ )
+{
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINTN ProcessorNumber;
+ UINTN Index;
+ UINTN CallerNumber;
+ BOOLEAN HasEnabledAp;
+ BOOLEAN HasEnabledIdleAp;
+ volatile UINT32 *FinishedCount;
+ EFI_STATUS Status;
+ UINTN WaitCountIndex;
+ UINTN WaitCountNumber;
+
+ PeiCpuMpData = GetMpHobData ();
+ if (PeiCpuMpData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ PeiWhoAmI (PeiServices, This, &CallerNumber);
+ if (CallerNumber != PeiCpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ProcessorNumber = PeiCpuMpData->CpuCount;
+
+ HasEnabledAp = FALSE;
+ HasEnabledIdleAp = FALSE;
+ for (Index = 0; Index < ProcessorNumber; Index ++) {
+ if (Index == CallerNumber) {
+ //
+ // Skip BSP
+ //
+ continue;
+ }
+ if (PeiCpuMpData->CpuData[Index].State != CpuStateDisabled) {
+ HasEnabledAp = TRUE;
+ if (PeiCpuMpData->CpuData[Index].State != CpuStateBusy) {
+ HasEnabledIdleAp = TRUE;
+ }
+ }
+ }
+ if (!HasEnabledAp) {
+ //
+ // If no enabled AP exists, return EFI_NOT_STARTED.
+ //
+ return EFI_NOT_STARTED;
+ }
+ if (!HasEnabledIdleAp) {
+ //
+ // If any enabled APs are busy, return EFI_NOT_READY.
+ //
+ return EFI_NOT_READY;
+ }
+
+ WaitCountNumber = TimeoutInMicroSeconds / CPU_CHECK_AP_INTERVAL + 1;
+ WaitCountIndex = 0;
+ FinishedCount = &PeiCpuMpData->FinishedCount;
+ if (!SingleThread) {
+ WakeUpAP (PeiCpuMpData, TRUE, 0, Procedure, ProcedureArgument);
+ //
+ // Wait to finish
+ //
+ if (TimeoutInMicroSeconds == 0) {
+ while (*FinishedCount < ProcessorNumber - 1) {
+ CpuPause ();
+ }
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_TIMEOUT;
+ for (WaitCountIndex = 0; WaitCountIndex < WaitCountNumber; WaitCountIndex++) {
+ MicroSecondDelay (CPU_CHECK_AP_INTERVAL);
+ if (*FinishedCount >= ProcessorNumber - 1) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+ }
+ } else {
+ Status = EFI_SUCCESS;
+ for (Index = 0; Index < ProcessorNumber; Index++) {
+ if (Index == CallerNumber) {
+ continue;
+ }
+ WakeUpAP (PeiCpuMpData, FALSE, PeiCpuMpData->CpuData[Index].ApicId, Procedure, ProcedureArgument);
+ //
+ // Wait to finish
+ //
+ if (TimeoutInMicroSeconds == 0) {
+ while (*FinishedCount < 1) {
+ CpuPause ();
+ }
+ } else {
+ for (WaitCountIndex = 0; WaitCountIndex < WaitCountNumber; WaitCountIndex++) {
+ MicroSecondDelay (CPU_CHECK_AP_INTERVAL);
+ if (*FinishedCount >= 1) {
+ break;
+ }
+ }
+ if (WaitCountIndex == WaitCountNumber) {
+ Status = EFI_TIMEOUT;
+ }
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
This return the handle number for the calling processor. This service may be
called from the BSP and APs.

diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.h b/UefiCpuPkg/CpuMpPei/PeiMpServices.h
index 4ac5d93..71f5a04 100644
--- a/UefiCpuPkg/CpuMpPei/PeiMpServices.h
+++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.h
@@ -17,6 +17,9 @@

#include "CpuMpPei.h"

+
+#define CPU_CHECK_AP_INTERVAL 0x100 // 100 microseconds
+
/**
This service retrieves the number of logical processor in the platform
and the number of those logical processors that are enabled on this boot.
@@ -99,6 +102,85 @@ PeiGetProcessorInfo (
OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
);

+/**
+ This service executes a caller provided function on all enabled APs. APs can
+ run either simultaneously or one at a time in sequence. This service supports
+ both blocking requests only. This service may only
+ be called from the BSP.
+
+ This function is used to dispatch all the enabled APs to the function specified
+ by Procedure. If any enabled AP is busy, then EFI_NOT_READY is returned
+ immediately and Procedure is not started on any AP.
+
+ If SingleThread is TRUE, all the enabled APs execute the function specified by
+ Procedure one by one, in ascending order of processor handle number. Otherwise,
+ all the enabled APs execute the function specified by Procedure simultaneously.
+
+ If the timeout specified by TimeoutInMicroseconds expires before all APs return
+ from Procedure, then Procedure on the failed APs is terminated. All enabled APs
+ are always available for further calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ and EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If FailedCpuList is not NULL, its
+ content points to the list of processor handle numbers in which Procedure was
+ terminated.
+
+ Note: It is the responsibility of the consumer of the EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ to make sure that the nature of the code that is executed on the BSP and the
+ dispatched APs is well controlled. The MP Services Ppi does not guarantee
+ that the Procedure function is MP-safe. Hence, the tasks that can be run in
+ parallel are limited to certain independent tasks and well-controlled exclusive
+ code. PEI services and Ppis may not be called by APs unless otherwise
+ specified.
+
+ In blocking execution mode, BSP waits until all APs finish or
+ TimeoutInMicroSeconds expires.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] SingleThread If TRUE, then all the enabled APs execute
+ the function specified by Procedure one by
+ one, in ascending order of processor handle
+ number. If FALSE, then all the enabled APs
+ execute the function specified by Procedure
+ simultaneously.
+ @param[in] TimeoutInMicrosecsond Indicates the time limit in microseconds for
+ APs to return from Procedure, for
+ blocking mode only. Zero means
+ infinity. If the timeout expires before
+ all APs return from Procedure, then Procedure
+ on the failed APs is terminated. All enabled
+ APs are available for next function assigned
+ by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ or EFI_PEI_MP_SERVICES_PPI.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT.
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before
+ the timeout expired.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_STARTED No enabled APs exist in the system.
+ @retval EFI_NOT_READY Any enabled APs are busy.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ all enabled APs have finished.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiStartupAllAPs (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN UINTN TimeoutInMicroSeconds,
+ IN VOID *ProcedureArgument OPTIONAL
+ );
+

/**
This return the handle number for the calling processor. This service may be
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:16 UTC
Permalink
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/PeiMpServices.c | 126 ++++++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/PeiMpServices.h | 62 ++++++++++++++++++
2 files changed, 188 insertions(+)

diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.c b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
index 50145b3..bf10a48 100644
--- a/UefiCpuPkg/CpuMpPei/PeiMpServices.c
+++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
@@ -507,6 +507,132 @@ PeiStartupAllAPs (
}

/**
+ This service lets the caller get one enabled AP to execute a caller-provided
+ function. The caller can request the BSP to wait for the completion
+ of the AP. This service may only be called from the BSP.
+
+ This function is used to dispatch one enabled AP to the function specified by
+ Procedure passing in the argument specified by ProcedureArgument.
+ The execution is in blocking mode. The BSP waits until the AP finishes or
+ TimeoutInMicroSecondss expires.
+
+ If the timeout specified by TimeoutInMicroseconds expires before the AP returns
+ from Procedure, then execution of Procedure by the AP is terminated. The AP is
+ available for subsequent calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs() and
+ EFI_PEI_MP_SERVICES_PPI.StartupThisAP().
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] ProcessorNumber The handle number of the AP. The range is
+ from 0 to the total number of logical
+ processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
+ @param[in] TimeoutInMicrosecsond Indicates the time limit in microseconds for
+ APs to return from Procedure, for
+ blocking mode only. Zero means
+ infinity. If the timeout expires before
+ all APs return from Procedure, then Procedure
+ on the failed APs is terminated. All enabled
+ APs are available for next function assigned
+ by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ or EFI_PEI_MP_SERVICES_PPI.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT.
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+
+ @retval EFI_SUCCESS In blocking mode, specified AP finished before
+ the timeout expires.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ the specified AP has finished.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiStartupThisAP (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL
+ )
+{
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINTN CallerNumber;
+ volatile UINT32 *FinishedCount;
+ EFI_STATUS Status;
+ UINTN WaitCountIndex;
+ UINTN WaitCountNumber;
+
+ PeiCpuMpData = GetMpHobData ();
+ if (PeiCpuMpData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ PeiWhoAmI (PeiServices, This, &CallerNumber);
+ if (CallerNumber != PeiCpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ProcessorNumber >= PeiCpuMpData->CpuCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (ProcessorNumber == PeiCpuMpData->BspNumber || Procedure == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether specified AP is disabled
+ //
+ if (PeiCpuMpData->CpuData[ProcessorNumber].State == CpuStateDisabled) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ WaitCountNumber = TimeoutInMicroseconds / CPU_CHECK_AP_INTERVAL + 1;
+ WaitCountIndex = 0;
+ FinishedCount = &PeiCpuMpData->FinishedCount;
+
+ WakeUpAP (PeiCpuMpData, FALSE, PeiCpuMpData->CpuData[ProcessorNumber].ApicId, Procedure, ProcedureArgument);
+
+ //
+ // Wait to finish
+ //
+ if (TimeoutInMicroseconds == 0) {
+ while (*FinishedCount < 1) {
+ CpuPause() ;
+ }
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_TIMEOUT;
+ for (WaitCountIndex = 0; WaitCountIndex < WaitCountNumber; WaitCountIndex++) {
+ MicroSecondDelay (CPU_CHECK_AP_INTERVAL);
+ if (*FinishedCount >= 1) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+ }
+
+ return Status;
+}
+
+
+/**
This return the handle number for the calling processor. This service may be
called from the BSP and APs.

diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.h b/UefiCpuPkg/CpuMpPei/PeiMpServices.h
index 71f5a04..cafa783 100644
--- a/UefiCpuPkg/CpuMpPei/PeiMpServices.h
+++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.h
@@ -181,6 +181,68 @@ PeiStartupAllAPs (
IN VOID *ProcedureArgument OPTIONAL
);

+/**
+ This service lets the caller get one enabled AP to execute a caller-provided
+ function. The caller can request the BSP to wait for the completion
+ of the AP. This service may only be called from the BSP.
+
+ This function is used to dispatch one enabled AP to the function specified by
+ Procedure passing in the argument specified by ProcedureArgument.
+ The execution is in blocking mode. The BSP waits until the AP finishes or
+ TimeoutInMicroSecondss expires.
+
+ If the timeout specified by TimeoutInMicroseconds expires before the AP returns
+ from Procedure, then execution of Procedure by the AP is terminated. The AP is
+ available for subsequent calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs() and
+ EFI_PEI_MP_SERVICES_PPI.StartupThisAP().
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] ProcessorNumber The handle number of the AP. The range is
+ from 0 to the total number of logical
+ processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
+ @param[in] TimeoutInMicrosecsond Indicates the time limit in microseconds for
+ APs to return from Procedure, for
+ blocking mode only. Zero means
+ infinity. If the timeout expires before
+ all APs return from Procedure, then Procedure
+ on the failed APs is terminated. All enabled
+ APs are available for next function assigned
+ by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ or EFI_PEI_MP_SERVICES_PPI.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT.
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+
+ @retval EFI_SUCCESS In blocking mode, specified AP finished before
+ the timeout expires.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ the specified AP has finished.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiStartupThisAP (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL
+ );
+

/**
This return the handle number for the calling processor. This service may be
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:11 UTC
Permalink
Get CPU BIST information from SEC Platform Information(2) PPIs and update them
accordingly. Install(Reinstall) SEC Platform Information2 PPI to published the
new CPU BIST.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/CpuBist.c | 260 +++++++++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/CpuMpPei.c | 4 +
UefiCpuPkg/CpuMpPei/CpuMpPei.h | 48 ++++++++
UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 7 ++
4 files changed, 319 insertions(+)
create mode 100644 UefiCpuPkg/CpuMpPei/CpuBist.c

diff --git a/UefiCpuPkg/CpuMpPei/CpuBist.c b/UefiCpuPkg/CpuMpPei/CpuBist.c
new file mode 100644
index 0000000..579b6b0
--- /dev/null
+++ b/UefiCpuPkg/CpuMpPei/CpuBist.c
@@ -0,0 +1,260 @@
+/** @file
+ Update and publish processors' BIST information.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "CpuMpPei.h"
+
+EFI_SEC_PLATFORM_INFORMATION2_PPI mSecPlatformInformation2Ppi = {
+ SecPlatformInformation2
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPeiSecPlatformInformation2Ppi = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiSecPlatformInformation2PpiGuid,
+ &mSecPlatformInformation2Ppi
+};
+
+/**
+ Implementation of the PlatformInformation2 service in EFI_SEC_PLATFORM_INFORMATION2_PPI.
+
+ @param PeiServices The pointer to the PEI Services Table.
+ @param StructureSize The pointer to the variable describing size of the input buffer.
+ @param PlatformInformationRecord2 The pointer to the EFI_SEC_PLATFORM_INFORMATION_RECORD2.
+
+ @retval EFI_SUCCESS The data was successfully returned.
+ @retval EFI_BUFFER_TOO_SMALL The buffer was too small. The current buffer size needed to
+ hold the record is returned in StructureSize.
+
+**/
+EFI_STATUS
+EFIAPI
+SecPlatformInformation2 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN OUT UINT64 *StructureSize,
+ OUT EFI_SEC_PLATFORM_INFORMATION_RECORD2 *PlatformInformationRecord2
+ )
+{
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINTN BistInformationSize;
+ UINTN CpuIndex;
+ EFI_SEC_PLATFORM_INFORMATION_CPU *CpuInstance;
+
+ PeiCpuMpData = GetMpHobData ();
+
+ BistInformationSize = sizeof (EFI_SEC_PLATFORM_INFORMATION_RECORD2) +
+ sizeof (EFI_SEC_PLATFORM_INFORMATION_CPU) * PeiCpuMpData->CpuCount;
+ //
+ // return the information size if input buffer size is too small
+ //
+ if ((*StructureSize) < (UINT64) BistInformationSize) {
+ *StructureSize = (UINT64) BistInformationSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ PlatformInformationRecord2->NumberOfCpus = PeiCpuMpData->CpuCount;
+ CpuInstance = PlatformInformationRecord2->CpuInstance;
+ for (CpuIndex = 0; CpuIndex < PeiCpuMpData->CpuCount; CpuIndex ++) {
+ CpuInstance[CpuIndex].CpuLocation = PeiCpuMpData->CpuData[CpuIndex].ApicId;
+ CpuInstance[CpuIndex].InfoRecord.IA32HealthFlags = PeiCpuMpData->CpuData[CpuIndex].Health;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Worker function to get CPUs' BIST by calling SecPlatformInformationPpi
+ or SecPlatformInformation2Ppi.
+
+ @param PeiServices Pointer to PEI Services Table
+ @param Guid PPI Guid
+ @param PpiDescriptor Return a pointer to instance of the
+ EFI_PEI_PPI_DESCRIPTOR
+ @param BistInformationData Pointer to BIST information data
+
+ @retval EFI_SUCCESS Retrieve of the BIST data successfully
+ @retval EFI_NOT_FOUND No sec platform information(2) ppi export
+ @retval EFI_DEVICE_ERROR Failed to get CPU Information
+
+**/
+EFI_STATUS
+GetBistInfoFromPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_GUID *Guid,
+ OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor,
+ OUT VOID **BistInformationData
+ )
+{
+ EFI_STATUS Status;
+ EFI_SEC_PLATFORM_INFORMATION2_PPI *SecPlatformInformation2Ppi;
+ EFI_SEC_PLATFORM_INFORMATION_RECORD2 *SecPlatformInformation2;
+ UINT64 InformationSize;
+
+ Status = PeiServicesLocatePpi (
+ Guid, // GUID
+ 0, // INSTANCE
+ PpiDescriptor, // EFI_PEI_PPI_DESCRIPTOR
+ (VOID **)&SecPlatformInformation2Ppi // PPI
+ );
+ if (Status == EFI_NOT_FOUND) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Status == EFI_SUCCESS) {
+ //
+ // Get the size of the sec platform information2(BSP/APs' BIST data)
+ //
+ InformationSize = 0;
+ SecPlatformInformation2 = NULL;
+ Status = SecPlatformInformation2Ppi->PlatformInformation2 (
+ PeiServices,
+ &InformationSize,
+ SecPlatformInformation2
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Status = PeiServicesAllocatePool (
+ (UINTN) InformationSize,
+ (VOID **) &SecPlatformInformation2
+ );
+ if (Status == EFI_SUCCESS) {
+ //
+ // Retrieve BIST data
+ //
+ Status = SecPlatformInformation2Ppi->PlatformInformation2 (
+ PeiServices,
+ &InformationSize,
+ SecPlatformInformation2
+ );
+ if (Status == EFI_SUCCESS) {
+ *BistInformationData = SecPlatformInformation2;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Collects BIST data from PPI.
+
+ This function collects BIST data from Sec Platform Information2 PPI
+ or SEC Platform Information PPI.
+
+ @param PeiServices Pointer to PEI Services Table
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+
+**/
+VOID
+CollectBistDataFromPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN PEI_CPU_MP_DATA *PeiCpuMpData
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_PPI_DESCRIPTOR *SecInformationDescriptor;
+ EFI_SEC_PLATFORM_INFORMATION_RECORD2 *SecPlatformInformation2;
+ EFI_SEC_PLATFORM_INFORMATION_RECORD *SecPlatformInformation;
+ UINTN NumberOfData;
+ EFI_SEC_PLATFORM_INFORMATION_CPU *CpuInstance;
+ EFI_SEC_PLATFORM_INFORMATION_CPU BspCpuInstance;
+ UINTN ProcessorNumber;
+ UINTN CpuIndex;
+ PEI_CPU_DATA *CpuData;
+
+ SecPlatformInformation2 = NULL;
+ SecPlatformInformation = NULL;
+ NumberOfData = 0;
+ CpuInstance = NULL;
+
+ //
+ // Get BIST information from Sec Platform Information2 Ppi firstly
+ //
+ Status = GetBistInfoFromPpi (
+ PeiServices,
+ &gEfiSecPlatformInformation2PpiGuid,
+ &SecInformationDescriptor,
+ (VOID *) &SecPlatformInformation2
+ );
+ if (Status == EFI_SUCCESS) {
+ //
+ // Sec Platform Information2 PPI includes BSP/APs' BIST information
+ //
+ NumberOfData = SecPlatformInformation2->NumberOfCpus;
+ CpuInstance = SecPlatformInformation2->CpuInstance;
+ } else {
+ //
+ // Otherwise, get BIST information from Sec Platform Information Ppi
+ //
+ Status = GetBistInfoFromPpi (
+ PeiServices,
+ &gEfiSecPlatformInformationPpiGuid,
+ &SecInformationDescriptor,
+ (VOID *) &SecPlatformInformation
+ );
+ if (Status == EFI_SUCCESS) {
+ NumberOfData = 1;
+ //
+ // SEC Platform Information only includes BSP's BIST information
+ // and does not have BSP's APIC ID
+ //
+ BspCpuInstance.CpuLocation = GetInitialApicId ();
+ BspCpuInstance.InfoRecord.IA32HealthFlags.Uint32 = SecPlatformInformation->IA32HealthFlags.Uint32;
+ CpuInstance = &BspCpuInstance;
+ } else {
+ DEBUG ((EFI_D_INFO, "Does not find any stored CPU BIST information from PPI!\n"));
+ }
+ }
+ for (ProcessorNumber = 0; ProcessorNumber < PeiCpuMpData->CpuCount; ProcessorNumber ++) {
+ CpuData = &PeiCpuMpData->CpuData[ProcessorNumber];
+ for (CpuIndex = 0; CpuIndex < NumberOfData; CpuIndex ++) {
+ ASSERT (CpuInstance != NULL);
+ if (CpuData->ApicId == CpuInstance[CpuIndex].CpuLocation) {
+ //
+ // Update processor's BIST data if it is already stored before
+ //
+ CpuData->Health = CpuInstance[CpuIndex].InfoRecord.IA32HealthFlags;
+ }
+ }
+ if (CpuData->Health.Uint32 != 0) {
+ //
+ // Report Status Code that self test is failed
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MAJOR,
+ (EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_EC_SELF_TEST)
+ );
+ }
+ DEBUG ((EFI_D_INFO, " APICID - 0x%08x, BIST - 0x%08x\n",
+ PeiCpuMpData->CpuData[ProcessorNumber].ApicId,
+ PeiCpuMpData->CpuData[ProcessorNumber].Health.Uint32
+ ));
+ }
+
+ if (SecPlatformInformation2 != NULL && NumberOfData < PeiCpuMpData->CpuCount) {
+ //
+ // Reinstall SecPlatformInformation2 PPI to include new BIST inforamtion
+ //
+ Status = PeiServicesReInstallPpi (
+ SecInformationDescriptor,
+ &mPeiSecPlatformInformation2Ppi
+ );
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ //
+ // Install SecPlatformInformation2 PPI to include new BIST inforamtion
+ //
+ Status = PeiServicesInstallPpi (&mPeiSecPlatformInformation2Ppi);
+ ASSERT_EFI_ERROR(Status);
+ }
+}
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
index ae98c38..d218313 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
@@ -446,6 +446,10 @@ CpuMpPeimInit (
(VOID *)&PeiCpuMpData,
sizeof(UINT64)
);
+ //
+ // Update and publish CPU BIST information
+ //
+ CollectBistDataFromPpi (PeiServices, PeiCpuMpData);

return EFI_SUCCESS;
}
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
index 7a34a98..aa926ab 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
@@ -18,6 +18,7 @@
#include <PiPei.h>

#include <Ppi/SecPlatformInformation.h>
+#include <Ppi/SecPlatformInformation2.h>

#include <Register/LocalApic.h>

@@ -30,6 +31,7 @@
#include <Library/PcdLib.h>
#include <Library/PeimEntryPoint.h>
#include <Library/PeiServicesLib.h>
+#include <Library/ReportStatusCodeLib.h>
#include <Library/SynchronizationLib.h>
#include <Library/TimerLib.h>
#include <Library/UefiCpuLib.h>
@@ -150,4 +152,50 @@ AsmInitializeGdt (
);


+/**
+ Get CPU MP Data pointer from the Guided HOB.
+
+ @return Pointer to Pointer to PEI CPU MP Data
+**/
+PEI_CPU_MP_DATA *
+GetMpHobData (
+ VOID
+ );
+
+/**
+ Collects BIST data from PPI.
+
+ This function collects BIST data from Sec Platform Information2 PPI
+ or SEC Platform Information PPI.
+
+ @param PeiServices Pointer to PEI Services Table
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+
+**/
+VOID
+CollectBistDataFromPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN PEI_CPU_MP_DATA *PeiCpuMpData
+ );
+
+/**
+ Implementation of the PlatformInformation2 service in EFI_SEC_PLATFORM_INFORMATION2_PPI.
+
+ @param PeiServices The pointer to the PEI Services Table.
+ @param StructureSize The pointer to the variable describing size of the input buffer.
+ @param PlatformInformationRecord2 The pointer to the EFI_SEC_PLATFORM_INFORMATION_RECORD2.
+
+ @retval EFI_SUCCESS The data was successfully returned.
+ @retval EFI_BUFFER_TOO_SMALL The buffer was too small. The current buffer size needed to
+ hold the record is returned in StructureSize.
+
+**/
+EFI_STATUS
+EFIAPI
+SecPlatformInformation2 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN OUT UINT64 *StructureSize,
+ OUT EFI_SEC_PLATFORM_INFORMATION_RECORD2 *PlatformInformationRecord2
+ );
+
#endif
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
index 1bb4dae..36126af 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
@@ -30,6 +30,7 @@
[Sources]
CpuMpPei.h
CpuMpPei.c
+ CpuBist.c
Microcode.h
Microcode.c

@@ -59,10 +60,16 @@
PcdLib
PeimEntryPoint
PeiServicesLib
+ ReportStatusCodeLib
SynchronizationLib
TimerLib
UefiCpuLib

+[Ppis]
+ gEfiSecPlatformInformationPpiGuid ## SOMETIMES_CONSUMES
+ ## SOMETIMES_CONSUMES
+ ## SOMETIMES_PRODUCES
+ gEfiSecPlatformInformation2PpiGuid

[Pcd]
gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:18 UTC
Permalink
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/PeiMpServices.c | 87 +++++++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/PeiMpServices.h | 50 +++++++++++++++++++++
2 files changed, 137 insertions(+)

diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.c b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
index 9a89045..960c228 100644
--- a/UefiCpuPkg/CpuMpPei/PeiMpServices.c
+++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
@@ -763,6 +763,93 @@ PeiSwitchBSP (
return EFI_SUCCESS;
}

+/**
+ This service lets the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+
+ This service allows the caller enable or disable an AP from this point onward.
+ The caller can optionally specify the health status of the AP by Health. If
+ an AP is being disabled, then the state of the disabled AP is implementation
+ dependent. If an AP is enabled, then the implementation must guarantee that a
+ complete initialization sequence is performed on the AP, so the AP is in a state
+ that is compatible with an MP operating system.
+
+ If the enable or disable AP operation cannot be completed prior to the return
+ from this service, then EFI_UNSUPPORTED must be returned.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
+ @param[in] EnableAP Specifies the new state for the processor for
+ enabled, FALSE for disabled.
+ @param[in] HealthFlag If not NULL, a pointer to a value that specifies
+ the new health status of the AP. This flag
+ corresponds to StatusFlag defined in
+ EFI_PEI_MP_SERVICES_PPI.GetProcessorInfo(). Only
+ the PROCESSOR_HEALTH_STATUS_BIT is used. All other
+ bits are ignored. If it is NULL, this parameter
+ is ignored.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
+ prior to this service returning.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
+ does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiEnableDisableAP (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ )
+{
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINTN CallerNumber;
+
+ PeiCpuMpData = GetMpHobData ();
+ if (PeiCpuMpData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ PeiWhoAmI (PeiServices, This, &CallerNumber);
+ if (CallerNumber != PeiCpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ProcessorNumber == PeiCpuMpData->BspNumber) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ProcessorNumber >= PeiCpuMpData->CpuCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (!EnableAP) {
+ PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateDisabled;
+ } else {
+ PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;
+ }
+
+ if (HealthFlag != NULL) {
+ PeiCpuMpData->CpuData[ProcessorNumber].CpuHealthy =
+ (BOOLEAN) ((*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT) != 0);
+ }
+ return EFI_SUCCESS;
+}

/**
This return the handle number for the calling processor. This service may be
diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.h b/UefiCpuPkg/CpuMpPei/PeiMpServices.h
index fe8b459..bf8244c 100644
--- a/UefiCpuPkg/CpuMpPei/PeiMpServices.h
+++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.h
@@ -308,6 +308,56 @@ PeiSwitchBSP (
IN BOOLEAN EnableOldBSP
);

+/**
+ This service lets the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+
+ This service allows the caller enable or disable an AP from this point onward.
+ The caller can optionally specify the health status of the AP by Health. If
+ an AP is being disabled, then the state of the disabled AP is implementation
+ dependent. If an AP is enabled, then the implementation must guarantee that a
+ complete initialization sequence is performed on the AP, so the AP is in a state
+ that is compatible with an MP operating system.
+
+ If the enable or disable AP operation cannot be completed prior to the return
+ from this service, then EFI_UNSUPPORTED must be returned.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
+ @param[in] EnableAP Specifies the new state for the processor for
+ enabled, FALSE for disabled.
+ @param[in] HealthFlag If not NULL, a pointer to a value that specifies
+ the new health status of the AP. This flag
+ corresponds to StatusFlag defined in
+ EFI_PEI_MP_SERVICES_PPI.GetProcessorInfo(). Only
+ the PROCESSOR_HEALTH_STATUS_BIT is used. All other
+ bits are ignored. If it is NULL, this parameter
+ is ignored.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
+ prior to this service returning.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
+ does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiEnableDisableAP (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ );

/**
This return the handle number for the calling processor. This service may be
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:17 UTC
Permalink
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/CpuMpPei.h | 12 ++++
UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc | 4 ++
UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm | 79 ++++++++++++++++++++
UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm | 74 +++++++++++++++++++
UefiCpuPkg/CpuMpPei/PeiMpServices.c | 132 ++++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/PeiMpServices.h | 65 +++++++++++++++++
UefiCpuPkg/CpuMpPei/X64/MpEqu.inc | 3 +
UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm | 106 +++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm | 106 +++++++++++++++++++++++++++
9 files changed, 581 insertions(+)

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
index ed6cf05..d8ee2ee 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
@@ -58,6 +58,16 @@ typedef struct {
UINTN RendezvousFunnelSize;
} MP_ASSEMBLY_ADDRESS_MAP;

+//
+// CPU exchange information for switch BSP
+//
+typedef struct {
+ UINT8 State; // offset 0
+ UINTN StackPointer; // offset 4 / 8
+ IA32_DESCRIPTOR Gdtr; // offset 8 / 16
+ IA32_DESCRIPTOR Idtr; // offset 14 / 26
+} CPU_EXCHANGE_ROLE_INFO;
+
typedef struct _PEI_CPU_MP_DATA PEI_CPU_MP_DATA;

#pragma pack()
@@ -124,6 +134,8 @@ struct _PEI_CPU_MP_DATA {
UINTN ApFunctionArgument;
volatile UINT32 FinishedCount;
BOOLEAN InitFlag;
+ CPU_EXCHANGE_ROLE_INFO BSPInfo;
+ CPU_EXCHANGE_ROLE_INFO APInfo;
MTRR_SETTINGS MtrrTable;
PEI_CPU_DATA *CpuData;
volatile MP_CPU_EXCHANGE_INFO *MpCpuExchangeInfo;
diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc b/UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc
index 1f02dad..50ec8c9 100644
--- a/UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc
+++ b/UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc
@@ -24,6 +24,10 @@ PROTECT_MODE_DS equ 18h
VacantFlag equ 00h
NotVacantFlag equ 0ffh

+CPU_SWITCH_STATE_IDLE equ 0
+CPU_SWITCH_STATE_STORED equ 1
+CPU_SWITCH_STATE_LOADED equ 2
+
LockLocation equ (RendezvousFunnelProcEnd - RendezvousFunnelProcStart)
StackStartAddressLocation equ LockLocation + 04h
StackSizeLocation equ LockLocation + 08h
diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
index 9861472..63c8048 100644
--- a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
+++ b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
@@ -161,6 +161,85 @@ AsmGetAddressMap PROC near C PUBLIC
ret
AsmGetAddressMap ENDP

+PAUSE32 MACRO
+ DB 0F3h
+ DB 090h
+ ENDM
+
+;-------------------------------------------------------------------------------------
+;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
+;about to become an AP. It switches it'stack with the current AP.
+;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
+;-------------------------------------------------------------------------------------
+AsmExchangeRole PROC near C PUBLIC
+ ; DO NOT call other functions in this function, since 2 CPU may use 1 stack
+ ; at the same time. If 1 CPU try to call a function, stack will be corrupted.
+ pushad
+ mov ebp,esp
+
+ ; esi contains MyInfo pointer
+ mov esi, dword ptr [ebp+24h]
+
+ ; edi contains OthersInfo pointer
+ mov edi, dword ptr [ebp+28h]
+
+ ;Store EFLAGS, GDTR and IDTR register to stack
+ pushfd
+ mov eax, cr4
+ push eax ; push cr4 firstly
+ mov eax, cr0
+ push eax
+
+ sgdt fword ptr [esi+8]
+ sidt fword ptr [esi+14]
+
+ ; Store the its StackPointer
+ mov dword ptr [esi+4],esp
+
+ ; update its switch state to STORED
+ mov byte ptr [esi], CPU_SWITCH_STATE_STORED
+
+WaitForOtherStored:
+ ; wait until the other CPU finish storing its state
+ cmp byte ptr [edi], CPU_SWITCH_STATE_STORED
+ jz OtherStored
+ PAUSE32
+ jmp WaitForOtherStored
+
+OtherStored:
+ ; Since another CPU already stored its state, load them
+ ; load GDTR value
+ lgdt fword ptr [edi+8]
+
+ ; load IDTR value
+ lidt fword ptr [edi+14]
+
+ ; load its future StackPointer
+ mov esp, dword ptr [edi+4]
+
+ ; update the other CPU's switch state to LOADED
+ mov byte ptr [edi], CPU_SWITCH_STATE_LOADED
+
+WaitForOtherLoaded:
+ ; wait until the other CPU finish loading new state,
+ ; otherwise the data in stack may corrupt
+ cmp byte ptr [esi], CPU_SWITCH_STATE_LOADED
+ jz OtherLoaded
+ PAUSE32
+ jmp WaitForOtherLoaded
+
+OtherLoaded:
+ ; since the other CPU already get the data it want, leave this procedure
+ pop eax
+ mov cr0, eax
+ pop eax
+ mov cr4, eax
+ popfd
+
+ popad
+ ret
+AsmExchangeRole ENDP
+
AsmInitializeGdt PROC near C PUBLIC
push ebp
mov ebp, esp
diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
index a3c4ae9..fe45cf1 100644
--- a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
+++ b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
@@ -149,6 +149,80 @@ ASM_PFX(AsmGetAddressMap):
popad
ret

+;-------------------------------------------------------------------------------------
+;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
+;about to become an AP. It switches it'stack with the current AP.
+;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmExchangeRole)
+ASM_PFX(AsmExchangeRole):
+ ; DO NOT call other functions in this function, since 2 CPU may use 1 stack
+ ; at the same time. If 1 CPU try to call a function, stack will be corrupted.
+ pushad
+ mov ebp,esp
+
+ ; esi contains MyInfo pointer
+ mov esi, [ebp + 24h]
+
+ ; edi contains OthersInfo pointer
+ mov edi, [ebp + 28h]
+
+ ;Store EFLAGS, GDTR and IDTR register to stack
+ pushfd
+ mov eax, cr4
+ push eax ; push cr4 firstly
+ mov eax, cr0
+ push eax
+
+ sgdt [esi + 8]
+ sidt [esi + 14]
+
+ ; Store the its StackPointer
+ mov [esi + 4],esp
+
+ ; update its switch state to STORED
+ mov byte [esi], CPU_SWITCH_STATE_STORED
+
+WaitForOtherStored:
+ ; wait until the other CPU finish storing its state
+ cmp byte [edi], CPU_SWITCH_STATE_STORED
+ jz OtherStored
+ pause
+ jmp WaitForOtherStored
+
+OtherStored:
+ ; Since another CPU already stored its state, load them
+ ; load GDTR value
+ lgdt [edi + 8]
+
+ ; load IDTR value
+ lidt [edi + 14]
+
+ ; load its future StackPointer
+ mov esp, [edi + 4]
+
+ ; update the other CPU's switch state to LOADED
+ mov byte [edi], CPU_SWITCH_STATE_LOADED
+
+WaitForOtherLoaded:
+ ; wait until the other CPU finish loading new state,
+ ; otherwise the data in stack may corrupt
+ cmp byte [esi], CPU_SWITCH_STATE_LOADED
+ jz OtherLoaded
+ pause
+ jmp WaitForOtherLoaded
+
+OtherLoaded:
+ ; since the other CPU already get the data it want, leave this procedure
+ pop eax
+ mov cr0, eax
+ pop eax
+ mov cr4, eax
+ popfd
+
+ popad
+ ret
+
global ASM_PFX(AsmInitializeGdt)
ASM_PFX(AsmInitializeGdt):
push ebp
diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.c b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
index bf10a48..9a89045 100644
--- a/UefiCpuPkg/CpuMpPei/PeiMpServices.c
+++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
@@ -154,6 +154,25 @@ GetProcessorNumber (
}

/**
+ Worker function for SwitchBSP().
+
+ Worker function for SwitchBSP(), assigned to the AP which is intended to become BSP.
+
+ @param Buffer Pointer to CPU MP Data
+**/
+VOID
+EFIAPI
+FutureBSPProc (
+ IN VOID *Buffer
+ )
+{
+ PEI_CPU_MP_DATA *DataInHob;
+
+ DataInHob = (PEI_CPU_MP_DATA *) Buffer;
+ AsmExchangeRole (&DataInHob->APInfo, &DataInHob->BSPInfo);
+}
+
+/**
This service retrieves the number of logical processor in the platform
and the number of those logical processors that are enabled on this boot.
This service may only be called from the BSP.
@@ -631,6 +650,119 @@ PeiStartupThisAP (
return Status;
}

+/**
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. This call can only be performed
+ by the current BSP.
+
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. The new BSP can take over the
+ execution of the old BSP and continue seamlessly from where the old one left
+ off.
+
+ If the BSP cannot be switched prior to the return from this service, then
+ EFI_UNSUPPORTED must be returned.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
+ @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
+ enabled AP. Otherwise, it will be disabled.
+
+ @retval EFI_SUCCESS BSP successfully switched.
+ @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
+ this service returning.
+ @retval EFI_UNSUPPORTED Switching the BSP is not supported.
+ @retval EFI_SUCCESS The calling processor is an AP.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
+ a disabled AP.
+ @retval EFI_NOT_READY The specified AP is busy.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiSwitchBSP (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ )
+{
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINTN CallerNumber;
+ MSR_IA32_APIC_BASE ApicBaseMsr;
+
+ PeiCpuMpData = GetMpHobData ();
+ if (PeiCpuMpData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ PeiWhoAmI (PeiServices, This, &CallerNumber);
+ if (CallerNumber != PeiCpuMpData->BspNumber) {
+ return EFI_SUCCESS;
+ }
+
+ if (ProcessorNumber >= PeiCpuMpData->CpuCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether specified AP is disabled
+ //
+ if (PeiCpuMpData->CpuData[ProcessorNumber].State == CpuStateDisabled) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether ProcessorNumber specifies the current BSP
+ //
+ if (ProcessorNumber == PeiCpuMpData->BspNumber) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether specified AP is busy
+ //
+ if (PeiCpuMpData->CpuData[ProcessorNumber].State == CpuStateBusy) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Clear the BSP bit of MSR_IA32_APIC_BASE
+ //
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);
+ ApicBaseMsr.Bits.Bsp = 0;
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);
+
+ PeiCpuMpData->BSPInfo.State = CPU_SWITCH_STATE_IDLE;
+ PeiCpuMpData->APInfo.State = CPU_SWITCH_STATE_IDLE;
+
+ //
+ // Need to wakeUp AP (future BSP).
+ //
+ WakeUpAP (PeiCpuMpData, FALSE, PeiCpuMpData->CpuData[ProcessorNumber].ApicId, FutureBSPProc, PeiCpuMpData);
+
+ AsmExchangeRole (&PeiCpuMpData->BSPInfo, &PeiCpuMpData->APInfo);
+
+ //
+ // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP
+ //
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);
+ ApicBaseMsr.Bits.Bsp = 1;
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);
+
+ return EFI_SUCCESS;
+}
+

/**
This return the handle number for the calling processor. This service may be
diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.h b/UefiCpuPkg/CpuMpPei/PeiMpServices.h
index cafa783..fe8b459 100644
--- a/UefiCpuPkg/CpuMpPei/PeiMpServices.h
+++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.h
@@ -17,10 +17,31 @@

#include "CpuMpPei.h"

+//
+// The MP data for switch BSP
+//
+#define CPU_SWITCH_STATE_IDLE 0
+#define CPU_SWITCH_STATE_STORED 1
+#define CPU_SWITCH_STATE_LOADED 2

#define CPU_CHECK_AP_INTERVAL 0x100 // 100 microseconds

/**
+ This function is called by both the BSP and the AP which is to become the BSP to
+ Exchange execution context including stack between them. After return from this
+ function, the BSP becomes AP and the AP becomes the BSP.
+
+ @param MyInfo Pointer to buffer holding the exchanging information for the executing processor.
+ @param OthersInfo Pointer to buffer holding the exchanging information for the peer.
+**/
+VOID
+EFIAPI
+AsmExchangeRole (
+ IN CPU_EXCHANGE_ROLE_INFO *MyInfo,
+ IN CPU_EXCHANGE_ROLE_INFO *OthersInfo
+ );
+
+/**
This service retrieves the number of logical processor in the platform
and the number of those logical processors that are enabled on this boot.
This service may only be called from the BSP.
@@ -243,6 +264,50 @@ PeiStartupThisAP (
IN VOID *ProcedureArgument OPTIONAL
);

+/**
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. This call can only be performed
+ by the current BSP.
+
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. The new BSP can take over the
+ execution of the old BSP and continue seamlessly from where the old one left
+ off.
+
+ If the BSP cannot be switched prior to the return from this service, then
+ EFI_UNSUPPORTED must be returned.
+
+ @param[in] PeiServices General purpose services available to every PEIM.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
+ @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
+ enabled AP. Otherwise, it will be disabled.
+
+ @retval EFI_SUCCESS BSP successfully switched.
+ @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
+ this service returning.
+ @retval EFI_UNSUPPORTED Switching the BSP is not supported.
+ @retval EFI_SUCCESS The calling processor is an AP.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
+ a disabled AP.
+ @retval EFI_NOT_READY The specified AP is busy.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiSwitchBSP (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ );
+

/**
This return the handle number for the calling processor. This service may be
diff --git a/UefiCpuPkg/CpuMpPei/X64/MpEqu.inc b/UefiCpuPkg/CpuMpPei/X64/MpEqu.inc
index 28a826c..946fe50 100644
--- a/UefiCpuPkg/CpuMpPei/X64/MpEqu.inc
+++ b/UefiCpuPkg/CpuMpPei/X64/MpEqu.inc
@@ -26,6 +26,9 @@ LONG_MODE_DS equ 30h
VacantFlag equ 00h
NotVacantFlag equ 0ffh

+CPU_SWITCH_STATE_IDLE equ 0
+CPU_SWITCH_STATE_STORED equ 1
+CPU_SWITCH_STATE_LOADED equ 2

LockLocation equ (RendezvousFunnelProcEnd - RendezvousFunnelProcStart)
StackStartAddressLocation equ LockLocation + 08h
diff --git a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
index 9e85fac..6622c43 100644
--- a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
+++ b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
@@ -193,6 +193,112 @@ AsmGetAddressMap PROC
ret
AsmGetAddressMap ENDP

+;-------------------------------------------------------------------------------------
+;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
+;about to become an AP. It switches it'stack with the current AP.
+;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
+;-------------------------------------------------------------------------------------
+AsmExchangeRole PROC
+ ; DO NOT call other functions in this function, since 2 CPU may use 1 stack
+ ; at the same time. If 1 CPU try to call a function, stack will be corrupted.
+
+ push rax
+ push rbx
+ push rcx
+ push rdx
+ push rsi
+ push rdi
+ push rbp
+ push r8
+ push r9
+ push r10
+ push r11
+ push r12
+ push r13
+ push r14
+ push r15
+
+ mov rax, cr0
+ push rax
+
+ mov rax, cr4
+ push rax
+
+ ; rsi contains MyInfo pointer
+ mov rsi, rcx
+
+ ; rdi contains OthersInfo pointer
+ mov rdi, rdx
+
+ ;Store EFLAGS, GDTR and IDTR regiter to stack
+ pushfq
+ sgdt fword ptr [rsi + 16]
+ sidt fword ptr [rsi + 26]
+
+ ; Store the its StackPointer
+ mov qword ptr [rsi + 8], rsp
+
+ ; update its switch state to STORED
+ mov byte ptr [rsi], CPU_SWITCH_STATE_STORED
+
+WaitForOtherStored:
+ ; wait until the other CPU finish storing its state
+ cmp byte ptr [rdi], CPU_SWITCH_STATE_STORED
+ jz OtherStored
+ pause
+ jmp WaitForOtherStored
+
+OtherStored:
+ ; Since another CPU already stored its state, load them
+ ; load GDTR value
+ lgdt fword ptr [rdi + 16]
+
+ ; load IDTR value
+ lidt fword ptr [rdi + 26]
+
+ ; load its future StackPointer
+ mov rsp, qword ptr [rdi + 8]
+
+ ; update the other CPU's switch state to LOADED
+ mov byte ptr [rdi], CPU_SWITCH_STATE_LOADED
+
+WaitForOtherLoaded:
+ ; wait until the other CPU finish loading new state,
+ ; otherwise the data in stack may corrupt
+ cmp byte ptr [rsi], CPU_SWITCH_STATE_LOADED
+ jz OtherLoaded
+ pause
+ jmp WaitForOtherLoaded
+
+OtherLoaded:
+ ; since the other CPU already get the data it want, leave this procedure
+ popfq
+
+ pop rax
+ mov cr4, rax
+
+ pop rax
+ mov cr0, rax
+
+ pop r15
+ pop r14
+ pop r13
+ pop r12
+ pop r11
+ pop r10
+ pop r9
+ pop r8
+ pop rbp
+ pop rdi
+ pop rsi
+ pop rdx
+ pop rcx
+ pop rbx
+ pop rax
+
+ ret
+AsmExchangeRole ENDP
+
AsmInitializeGdt PROC
push rbp
mov rbp, rsp
diff --git a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm
index 09c2fbc..8b93c0d 100644
--- a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm
+++ b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm
@@ -187,6 +187,112 @@ ASM_PFX(AsmGetAddressMap):
mov qword [rcx + 18h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
ret

+;-------------------------------------------------------------------------------------
+;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
+;about to become an AP. It switches it'stack with the current AP.
+;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmExchangeRole)
+ASM_PFX(AsmExchangeRole):
+ ; DO NOT call other functions in this function, since 2 CPU may use 1 stack
+ ; at the same time. If 1 CPU try to call a function, stack will be corrupted.
+
+ push rax
+ push rbx
+ push rcx
+ push rdx
+ push rsi
+ push rdi
+ push rbp
+ push r8
+ push r9
+ push r10
+ push r11
+ push r12
+ push r13
+ push r14
+ push r15
+
+ mov rax, cr0
+ push rax
+
+ mov rax, cr4
+ push rax
+
+ ; rsi contains MyInfo pointer
+ mov rsi, rcx
+
+ ; rdi contains OthersInfo pointer
+ mov rdi, rdx
+
+ ;Store EFLAGS, GDTR and IDTR regiter to stack
+ pushfq
+ sgdt [rsi + 16]
+ sidt [rsi + 26]
+
+ ; Store the its StackPointer
+ mov [rsi + 8], rsp
+
+ ; update its switch state to STORED
+ mov byte [rsi], CPU_SWITCH_STATE_STORED
+
+WaitForOtherStored:
+ ; wait until the other CPU finish storing its state
+ cmp byte [rdi], CPU_SWITCH_STATE_STORED
+ jz OtherStored
+ pause
+ jmp WaitForOtherStored
+
+OtherStored:
+ ; Since another CPU already stored its state, load them
+ ; load GDTR value
+ lgdt [rdi + 16]
+
+ ; load IDTR value
+ lidt [rdi + 26]
+
+ ; load its future StackPointer
+ mov rsp, [rdi + 8]
+
+ ; update the other CPU's switch state to LOADED
+ mov byte [rdi], CPU_SWITCH_STATE_LOADED
+
+WaitForOtherLoaded:
+ ; wait until the other CPU finish loading new state,
+ ; otherwise the data in stack may corrupt
+ cmp byte [rsi], CPU_SWITCH_STATE_LOADED
+ jz OtherLoaded
+ pause
+ jmp WaitForOtherLoaded
+
+OtherLoaded:
+ ; since the other CPU already get the data it want, leave this procedure
+ popfq
+
+ pop rax
+ mov cr4, rax
+
+ pop rax
+ mov cr0, rax
+
+ pop r15
+ pop r14
+ pop r13
+ pop r12
+ pop r11
+ pop r10
+ pop r9
+ pop r8
+ pop rbp
+ pop rdi
+ pop rsi
+ pop rdx
+ pop rcx
+ pop rbx
+ pop rax
+
+ ret
+
global ASM_PFX(AsmInitializeGdt)
ASM_PFX(AsmInitializeGdt):
push rbp
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:19 UTC
Permalink
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/CpuMpPei.c | 9 +++++++--
UefiCpuPkg/CpuMpPei/CpuMpPei.h | 2 ++
UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 1 +
UefiCpuPkg/CpuMpPei/PeiMpServices.c | 18 ++++++++++++++++++
4 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
index bfcf816..7b75d35 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
@@ -436,7 +436,7 @@ CpuMpPeimInit (
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
-
+ EFI_STATUS Status;
PEI_CPU_MP_DATA *PeiCpuMpData;
UINT32 ProcessorCount;

@@ -464,6 +464,11 @@ CpuMpPeimInit (
// Update and publish CPU BIST information
//
CollectBistDataFromPpi (PeiServices, PeiCpuMpData);
+ //
+ // Install CPU MP PPI
+ //
+ Status = PeiServicesInstallPpi(&mPeiCpuMpPpiDesc);
+ ASSERT_EFI_ERROR (Status);

- return EFI_SUCCESS;
+ return Status;
}
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
index d8ee2ee..97d52bf 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
@@ -140,6 +140,8 @@ struct _PEI_CPU_MP_DATA {
PEI_CPU_DATA *CpuData;
volatile MP_CPU_EXCHANGE_INFO *MpCpuExchangeInfo;
};
+extern EFI_PEI_PPI_DESCRIPTOR mPeiCpuMpPpiDesc;
+

/**
Assembly code to get starting address and size of the rendezvous entry for APs.
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
index faf999a..7160c0e 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
@@ -68,6 +68,7 @@
UefiCpuLib

[Ppis]
+ gEfiPeiMpServicesPpiGuid ## PRODUCES
gEfiSecPlatformInformationPpiGuid ## SOMETIMES_CONSUMES
## SOMETIMES_CONSUMES
## SOMETIMES_PRODUCES
diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.c b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
index 960c228..bd77f58 100644
--- a/UefiCpuPkg/CpuMpPei/PeiMpServices.c
+++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
@@ -14,6 +14,24 @@

#include "PeiMpServices.h"

+//
+// CPU MP PPI to be installed
+//
+EFI_PEI_MP_SERVICES_PPI mMpServicesPpi = {
+ PeiGetNumberOfProcessors,
+ PeiGetProcessorInfo,
+ PeiStartupAllAPs,
+ PeiStartupThisAP,
+ PeiSwitchBSP,
+ PeiEnableDisableAP,
+ PeiWhoAmI,
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPeiCpuMpPpiDesc = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiMpServicesPpiGuid,
+ &mMpServicesPpi
+};

/**
Get CPU Package/Core/Thread location information.
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:20 UTC
Permalink
Add AsmHltLoop () in assembly code, it will not be copied into AP wakeup
buffer and invoked at end of ApCFunction (). To make sure AP work in case
AP wakeup buffer is restored to original data.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/CpuMpPei.c | 1 +
UefiCpuPkg/CpuMpPei/CpuMpPei.h | 9 +++++++++
UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm | 6 ++++++
UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm | 6 ++++++
UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm | 6 ++++++
UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm | 6 ++++++
6 files changed, 34 insertions(+)

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
index 7b75d35..40e62e0 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
@@ -169,6 +169,7 @@ ApCFunction (
//
InterlockedIncrement ((UINT32 *)&PeiCpuMpData->FinishedCount);

+ AsmCliHltLoop ();
}

/**
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
index 97d52bf..c241349 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
@@ -166,6 +166,15 @@ AsmInitializeGdt (
IN IA32_DESCRIPTOR *Gdtr
);

+/**
+ Assembly code to do CLI-HALT loop.
+
+**/
+VOID
+EFIAPI
+AsmCliHltLoop (
+ VOID
+ );

/**
This function will be called by BSP to wakeup AP.
diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
index 63c8048..060f467 100644
--- a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
+++ b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
@@ -144,6 +144,12 @@ CProcedureInvoke:
RendezvousFunnelProc ENDP
RendezvousFunnelProcEnd::

+AsmCliHltLoop PROC near C PUBLIC
+ cli
+ hlt
+ jmp $-2
+AsmCliHltLoop ENDP
+
;-------------------------------------------------------------------------------------
; AsmGetAddressMap (&AddressMap);
;-------------------------------------------------------------------------------------
diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
index fe45cf1..3a8e91f 100644
--- a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
+++ b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
@@ -132,6 +132,12 @@ CProcedureInvoke:
jmp $ ; never reach here
RendezvousFunnelProcEnd:

+global ASM_PFX(AsmCliHltLoop)
+ASM_PFX(AsmCliHltLoop):
+ cli
+ hlt
+ jmp $-2
+
;-------------------------------------------------------------------------------------
; AsmGetAddressMap (&AddressMap);
;-------------------------------------------------------------------------------------
diff --git a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
index 6622c43..18c8b72 100644
--- a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
+++ b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
@@ -181,6 +181,12 @@ CProcedureInvoke:
RendezvousFunnelProc ENDP
RendezvousFunnelProcEnd::

+AsmCliHltLoop PROC
+ cli
+ hlt
+ jmp $-2
+AsmCliHltLoop ENDP
+
;-------------------------------------------------------------------------------------
; AsmGetAddressMap (&AddressMap);
;-------------------------------------------------------------------------------------
diff --git a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm
index 8b93c0d..4683543 100644
--- a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm
+++ b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm
@@ -175,6 +175,12 @@ CProcedureInvoke:

RendezvousFunnelProcEnd:

+global ASM_PFX(AsmCliHltLoop)
+ASM_PFX(AsmCliHltLoop):
+ cli
+ hlt
+ jmp $-2
+
;-------------------------------------------------------------------------------------
; AsmGetAddressMap (&AddressMap);
;-------------------------------------------------------------------------------------
--
1.9.5.msysgit.0
Jeff Fan
2015-07-03 15:10:21 UTC
Permalink
Add CpuMpEndOfPeiCallback () to restore wakeup buffer data on S3 path and flag
flag wakeup buffer to be un-used type on normal boot path. Set one EndOfPei
flag save/restore wakeup buffer when wakeup APs every time.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <***@intel.com>
CC: Feng Tian <***@intel.com>
CC: Jiewen Yao <***@intel.com>
CC: Michael Kinney <***@intel.com>
---
UefiCpuPkg/CpuMpPei/CpuMpPei.c | 90 +++++++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/CpuMpPei.h | 43 ++++++++++++++++++
UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 1 +
UefiCpuPkg/CpuMpPei/PeiMpServices.c | 42 +++++++++++++++++
4 files changed, 176 insertions(+)

diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
index 40e62e0..c047804 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c
@@ -38,6 +38,12 @@ GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR mGdt = {
(UINTN) mGdtEntries
};

+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiEndOfPeiSignalPpiGuid,
+ CpuMpEndOfPeiCallback
+};
+
/**
Sort the APIC ID of all processors.

@@ -317,6 +323,20 @@ BackupAndPrepareWakeupBuffer(
PeiCpuMpData->AddressMap.RendezvousFunnelSize
);
}
+
+/**
+ Restore wakeup buffer data.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+**/
+VOID
+RestoreWakeupBuffer(
+ IN PEI_CPU_MP_DATA *PeiCpuMpData
+ )
+{
+ CopyMem ((VOID *) PeiCpuMpData->WakeupBuffer, (VOID *) PeiCpuMpData->BackupBuffer, PeiCpuMpData->BackupBufferSize);
+}
+
/**
This function will get CPU count in the system.

@@ -409,6 +429,7 @@ PrepareAPStartupVector (
PeiCpuMpData->CpuData = (PEI_CPU_DATA *) (PeiCpuMpData->MpCpuExchangeInfo + 1);
PeiCpuMpData->CpuData[0].ApicId = GetInitialApicId ();
PeiCpuMpData->CpuData[0].Health.Uint32 = 0;
+ PeiCpuMpData->EndOfPeiFlag = FALSE;
CopyMem (&PeiCpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));

//
@@ -418,6 +439,70 @@ PrepareAPStartupVector (

return PeiCpuMpData;
}
+
+/**
+ Notify function on End Of Pei PPI.
+
+ On S3 boot, this function will restore wakeup buffer data.
+ On normal boot, this function will flag wakeup buffer to be un-used type.
+
+ @param PeiServices The pointer to the PEI Services Table.
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS When everything is OK.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuMpEndOfPeiCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MODE BootMode;
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
+
+ DEBUG ((EFI_D_INFO, "CpuMpPei: CpuMpEndOfPeiCallback () invokded\n"));
+
+ Status = PeiServicesGetBootMode (&BootMode);
+ ASSERT_EFI_ERROR (Status);
+
+ PeiCpuMpData = GetMpHobData ();
+ ASSERT (PeiCpuMpData != NULL);
+
+ if (BootMode != BOOT_ON_S3_RESUME) {
+ //
+ // Get the HOB list for processing
+ //
+ Hob.Raw = GetHobList ();
+ //
+ // Collect memory ranges
+ //
+ while (!END_OF_HOB_LIST (Hob)) {
+ if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
+ MemoryHob = Hob.MemoryAllocation;
+ if(MemoryHob->AllocDescriptor.MemoryBaseAddress == PeiCpuMpData->WakeupBuffer) {
+ //
+ // Flag this HOB type to un-used
+ //
+ GET_HOB_TYPE (Hob) = EFI_HOB_TYPE_UNUSED;
+ break;
+ }
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+ } else {
+ RestoreWakeupBuffer (PeiCpuMpData);
+ PeiCpuMpData->EndOfPeiFlag = TRUE;
+ }
+ return EFI_SUCCESS;
+}
+
/**
The Entry point of the MP CPU PEIM.

@@ -466,6 +551,11 @@ CpuMpPeimInit (
//
CollectBistDataFromPpi (PeiServices, PeiCpuMpData);
//
+ // register an event for EndOfPei
+ //
+ Status = PeiServicesNotifyPpi (&mNotifyList);
+ ASSERT_EFI_ERROR (Status);
+ //
// Install CPU MP PPI
//
Status = PeiServicesInstallPpi(&mPeiCpuMpPpiDesc);
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
index c241349..8d01ac6 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h
@@ -20,6 +20,7 @@
#include <Ppi/MpServices.h>
#include <Ppi/SecPlatformInformation.h>
#include <Ppi/SecPlatformInformation2.h>
+#include <Ppi/EndOfPeiPhase.h>

#include <Register/LocalApic.h>

@@ -133,6 +134,7 @@ struct _PEI_CPU_MP_DATA {
UINTN ApFunction;
UINTN ApFunctionArgument;
volatile UINT32 FinishedCount;
+ BOOLEAN EndOfPeiFlag;
BOOLEAN InitFlag;
CPU_EXCHANGE_ROLE_INFO BSPInfo;
CPU_EXCHANGE_ROLE_INFO APInfo;
@@ -177,6 +179,47 @@ AsmCliHltLoop (
);

/**
+ Get available system memory below 1MB by specified size.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+**/
+VOID
+BackupAndPrepareWakeupBuffer(
+ IN PEI_CPU_MP_DATA *PeiCpuMpData
+ );
+
+/**
+ Restore wakeup buffer data.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+**/
+VOID
+RestoreWakeupBuffer(
+ IN PEI_CPU_MP_DATA *PeiCpuMpData
+ );
+
+/**
+ Notify function on End Of Pei PPI.
+
+ On S3 boot, this function will restore wakeup buffer data.
+ On normal boot, this function will flag wakeup buffer to be un-used type.
+
+ @param PeiServices The pointer to the PEI Services Table.
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS When everything is OK.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuMpEndOfPeiCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+/**
This function will be called by BSP to wakeup AP.

@param PeiCpuMpData Pointer to PEI CPU MP Data
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
index 7160c0e..92c64f9 100644
--- a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
+++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf
@@ -69,6 +69,7 @@

[Ppis]
gEfiPeiMpServicesPpiGuid ## PRODUCES
+ gEfiEndOfPeiSignalPpiGuid ## NOTIFY
gEfiSecPlatformInformationPpiGuid ## SOMETIMES_CONSUMES
## SOMETIMES_CONSUMES
## SOMETIMES_PRODUCES
diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.c b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
index bd77f58..6f8d662 100644
--- a/UefiCpuPkg/CpuMpPei/PeiMpServices.c
+++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.c
@@ -489,6 +489,13 @@ PeiStartupAllAPs (
return EFI_NOT_READY;
}

+ if (PeiCpuMpData->EndOfPeiFlag) {
+ //
+ // Backup original data and copy AP reset vector in it
+ //
+ BackupAndPrepareWakeupBuffer(PeiCpuMpData);
+ }
+
WaitCountNumber = TimeoutInMicroSeconds / CPU_CHECK_AP_INTERVAL + 1;
WaitCountIndex = 0;
FinishedCount = &PeiCpuMpData->FinishedCount;
@@ -540,6 +547,13 @@ PeiStartupAllAPs (
}
}

+ if (PeiCpuMpData->EndOfPeiFlag) {
+ //
+ // Restore original data
+ //
+ RestoreWakeupBuffer(PeiCpuMpData);
+ }
+
return Status;
}

@@ -640,6 +654,13 @@ PeiStartupThisAP (
return EFI_INVALID_PARAMETER;
}

+ if (PeiCpuMpData->EndOfPeiFlag) {
+ //
+ // Backup original data and copy AP reset vector in it
+ //
+ BackupAndPrepareWakeupBuffer(PeiCpuMpData);
+ }
+
WaitCountNumber = TimeoutInMicroseconds / CPU_CHECK_AP_INTERVAL + 1;
WaitCountIndex = 0;
FinishedCount = &PeiCpuMpData->FinishedCount;
@@ -665,6 +686,13 @@ PeiStartupThisAP (
}
}

+ if (PeiCpuMpData->EndOfPeiFlag) {
+ //
+ // Backup original data and copy AP reset vector in it
+ //
+ RestoreWakeupBuffer(PeiCpuMpData);
+ }
+
return Status;
}

@@ -764,6 +792,13 @@ PeiSwitchBSP (
PeiCpuMpData->BSPInfo.State = CPU_SWITCH_STATE_IDLE;
PeiCpuMpData->APInfo.State = CPU_SWITCH_STATE_IDLE;

+ if (PeiCpuMpData->EndOfPeiFlag) {
+ //
+ // Backup original data and copy AP reset vector in it
+ //
+ BackupAndPrepareWakeupBuffer(PeiCpuMpData);
+ }
+
//
// Need to wakeUp AP (future BSP).
//
@@ -771,6 +806,13 @@ PeiSwitchBSP (

AsmExchangeRole (&PeiCpuMpData->BSPInfo, &PeiCpuMpData->APInfo);

+ if (PeiCpuMpData->EndOfPeiFlag) {
+ //
+ // Backup original data and copy AP reset vector in it
+ //
+ RestoreWakeupBuffer(PeiCpuMpData);
+ }
+
//
// Set the BSP bit of MSR_IA32_APIC_BASE on new BSP
//
--
1.9.5.msysgit.0
Tian, Feng
2015-07-14 03:02:04 UTC
Permalink
Shall you allow shadow in CpuMpPei driver entry point like below?
//
// Shadow this PEIM to run from memory
//
if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
return EFI_SUCCESS;
}

Others look good to me

Reviewed-by: Feng Tian <***@intel.com>

-----Original Message-----
From: Jeff Fan [mailto:***@intel.com]
Sent: Friday, July 03, 2015 11:10 PM
To: edk2-***@lists.sourceforge.net
Subject: [edk2] [Patch 00/28] UefiCpuPkg: Add CpuMpPei install PI CPU MP PPI

PI 1.4 introduced CPU MP PPI to provide MP service in PEI.
This serial patches include:
A. Added three PCDs in UefiCpuPkg: PcdCpuApInitTimeOutInMicroSeconds,
PcdCpuMicrocodePatchAddress and PcdCpuMicrocodePatchRegionSize.
B. Added some CPU ID definitions in Include\Register\LocalApic.h.
C. Added CpuMpPei driver in UefiCpuPkg.
1. Prepare wakeup buffer and wakeup Aps to collect Aps count.
2. Load GDT on BSP/Aps.
3. Load microcode on BSP/Aps.
4. Sync BSP's mtrr setting to Aps.
5. Install CPU MP PPI to provide MP service in PEI defined in PI 1.4.
6. Collect and publish Aps BIST information.

Jeff Fan (28):
UefiCpuPkg: Add CpuMpPei module
UefiCpuPkg/CpuMpPei: Load GDT table on BSP
UefiCpuPkg/CpuMpPei: Find available memory < 1MB for AP reset code
UefiCpuPkg/CpuMpPei: Add MP exchange structure definition
UefiCpuPkg/CpuMpPei: Add AP reset IA32 assembly code
UefiCpuPkg/CpuMpPei: Add AP reset x64 assembly code
UefiCpuPkg/CpuMpPei: Initialize FPU per UEFI specification
UefiCpuPkg/CpuMpPei: Get AP reset code size and far jump information
UefiCpuPkg/CpuMpPei: Prepare for buffer for AP wakeup and CPU MP data
UefiCpuPkg: Add PcdCpuApInitTimeOutInMicroSeconds
UefiCpuPkg/CpuMpPei: Wakeup APs and collect AP count
UefiCpuPkg/CpuMpPei: Sort APIC ID in ascending order
UefiCpuPkg/CpuMpPei: Sync BPS's mtrr setting to APs
UefiCpuPkg: Add microcode PCDs
UefiCpuPkg: Add some CPUID definitions
UefiCpuPkg/CpuMpPei: Load microcode on BSP and APs
UefiCpuPkg/CpuMpPei: Build one GUIDed HOB to save CPU MP Data
UefiCpuPkg/CpuMpPei: Update and publish CPU BIST information
UefiCpuPkg/CpuMpPei: Implementation of PeiWhoAmI ()
UefiCpuPkg/CpuMpPei: Implementation of PeiGetNumberOfProcessors ()
UefiCpuPkg/CpuMpPei: Implementation of PeiGetProcessorInfo ()
UefiCpuPkg/CpuMpPei: Implementation of PeiStartupAllAPs ()
UefiCpuPkg/CpuMpPei: Implementation of PeiStartupThisAP ()
UefiCpuPkg/CpuMpPei: Implementation of PeiSwitchBSP ()
UefiCpuPkg/CpuMpPei: Implementation of PeiEnableDisableAP ()
UefiCpuPkg/CpuMpPei: Install PI CPU MP PPI
UefiCpuPkg/CpuMpPei: Add AsmHltLoop ()
UefiCpuPkg/CpuMpPei: Register callback on End Of Pei PPI

UefiCpuPkg/CpuMpPei/CpuBist.c | 260 +++++++++
UefiCpuPkg/CpuMpPei/CpuMpPei.c | 565 +++++++++++++++++++
UefiCpuPkg/CpuMpPei/CpuMpPei.h | 302 ++++++++++
UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 90 +++
UefiCpuPkg/CpuMpPei/CpuMpPei.uni | Bin 0 -> 1706 bytes
UefiCpuPkg/CpuMpPei/CpuMpPeiExtra.uni | Bin 0 -> 1344 bytes
UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc | 40 ++
UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm | 276 +++++++++
UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm | 255 +++++++++
UefiCpuPkg/CpuMpPei/Microcode.c | 200 +++++++
UefiCpuPkg/CpuMpPei/Microcode.h | 68 +++
UefiCpuPkg/CpuMpPei/PeiMpServices.c | 960 ++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/PeiMpServices.h | 395 +++++++++++++
UefiCpuPkg/CpuMpPei/X64/MpEqu.inc | 45 ++
UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm | 334 +++++++++++
UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm | 327 +++++++++++
UefiCpuPkg/Include/Register/LocalApic.h | 6 +-
UefiCpuPkg/UefiCpuPkg.dec | 13 +-
UefiCpuPkg/UefiCpuPkg.dsc | 1 +
19 files changed, 4135 insertions(+), 2 deletions(-) create mode 100644 UefiCpuPkg/CpuMpPei/CpuBist.c create mode 100644 UefiCpuPkg/CpuMpPei/CpuMpPei.c create mode 100644 UefiCpuPkg/CpuMpPei/CpuMpPei.h create mode 100644 UefiCpuPkg/CpuMpPei/CpuMpPei.inf create mode 100644 UefiCpuPkg/CpuMpPei/CpuMpPei.uni create mode 100644 UefiCpuPkg/CpuMpPei/CpuMpPeiExtra.uni
create mode 100644 UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc
create mode 100644 UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
create mode 100644 UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
create mode 100644 UefiCpuPkg/CpuMpPei/Microcode.c create mode 100644 UefiCpuPkg/CpuMpPei/Microcode.h create mode 100644 UefiCpuPkg/CpuMpPei/PeiMpServices.c
create mode 100644 UefiCpuPkg/CpuMpPei/PeiMpServices.h
create mode 100644 UefiCpuPkg/CpuMpPei/X64/MpEqu.inc create mode 100644 UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
create mode 100644 UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm

--
1.9.5.msysgit.0


------------------------------------------------------------------------------
Don't Limit Your Business. Reach for the Cloud.
GigeNET's Cloud Solutions provide you with the tools and support that you need to offload your IT needs and focus on growing your business.
Configured For All Businesses. Start Your Cloud Today.
https://www.gigenetcloud.com/
_______________________________________________
edk2-devel mailing list
edk2-***@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel
Fan, Jeff
2015-07-14 03:17:10 UTC
Permalink
Feng,

Good point.
This module will be dispatched after memory is ready. Actually, Pei Core will shadow the PEI module (dispatched after memory is initialized) into memory automatically.
PeiServicesRegisterForShadow () is not required more.

Best Regards,
Jeff
-----Original Message-----
From: Tian, Feng
Sent: Tuesday, July 14, 2015 11:02 AM
To: Fan, Jeff; edk2-***@lists.sourceforge.net
Cc: Tian, Feng
Subject: RE: [edk2] [Patch 00/28] UefiCpuPkg: Add CpuMpPei install PI CPU MP PPI

Shall you allow shadow in CpuMpPei driver entry point like below?
//
// Shadow this PEIM to run from memory
//
if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
return EFI_SUCCESS;
}

Others look good to me

Reviewed-by: Feng Tian <***@intel.com>

-----Original Message-----
From: Jeff Fan [mailto:***@intel.com]
Sent: Friday, July 03, 2015 11:10 PM
To: edk2-***@lists.sourceforge.net
Subject: [edk2] [Patch 00/28] UefiCpuPkg: Add CpuMpPei install PI CPU MP PPI

PI 1.4 introduced CPU MP PPI to provide MP service in PEI.
This serial patches include:
A. Added three PCDs in UefiCpuPkg: PcdCpuApInitTimeOutInMicroSeconds,
PcdCpuMicrocodePatchAddress and PcdCpuMicrocodePatchRegionSize.
B. Added some CPU ID definitions in Include\Register\LocalApic.h.
C. Added CpuMpPei driver in UefiCpuPkg.
1. Prepare wakeup buffer and wakeup Aps to collect Aps count.
2. Load GDT on BSP/Aps.
3. Load microcode on BSP/Aps.
4. Sync BSP's mtrr setting to Aps.
5. Install CPU MP PPI to provide MP service in PEI defined in PI 1.4.
6. Collect and publish Aps BIST information.

Jeff Fan (28):
UefiCpuPkg: Add CpuMpPei module
UefiCpuPkg/CpuMpPei: Load GDT table on BSP
UefiCpuPkg/CpuMpPei: Find available memory < 1MB for AP reset code
UefiCpuPkg/CpuMpPei: Add MP exchange structure definition
UefiCpuPkg/CpuMpPei: Add AP reset IA32 assembly code
UefiCpuPkg/CpuMpPei: Add AP reset x64 assembly code
UefiCpuPkg/CpuMpPei: Initialize FPU per UEFI specification
UefiCpuPkg/CpuMpPei: Get AP reset code size and far jump information
UefiCpuPkg/CpuMpPei: Prepare for buffer for AP wakeup and CPU MP data
UefiCpuPkg: Add PcdCpuApInitTimeOutInMicroSeconds
UefiCpuPkg/CpuMpPei: Wakeup APs and collect AP count
UefiCpuPkg/CpuMpPei: Sort APIC ID in ascending order
UefiCpuPkg/CpuMpPei: Sync BPS's mtrr setting to APs
UefiCpuPkg: Add microcode PCDs
UefiCpuPkg: Add some CPUID definitions
UefiCpuPkg/CpuMpPei: Load microcode on BSP and APs
UefiCpuPkg/CpuMpPei: Build one GUIDed HOB to save CPU MP Data
UefiCpuPkg/CpuMpPei: Update and publish CPU BIST information
UefiCpuPkg/CpuMpPei: Implementation of PeiWhoAmI ()
UefiCpuPkg/CpuMpPei: Implementation of PeiGetNumberOfProcessors ()
UefiCpuPkg/CpuMpPei: Implementation of PeiGetProcessorInfo ()
UefiCpuPkg/CpuMpPei: Implementation of PeiStartupAllAPs ()
UefiCpuPkg/CpuMpPei: Implementation of PeiStartupThisAP ()
UefiCpuPkg/CpuMpPei: Implementation of PeiSwitchBSP ()
UefiCpuPkg/CpuMpPei: Implementation of PeiEnableDisableAP ()
UefiCpuPkg/CpuMpPei: Install PI CPU MP PPI
UefiCpuPkg/CpuMpPei: Add AsmHltLoop ()
UefiCpuPkg/CpuMpPei: Register callback on End Of Pei PPI

UefiCpuPkg/CpuMpPei/CpuBist.c | 260 +++++++++
UefiCpuPkg/CpuMpPei/CpuMpPei.c | 565 +++++++++++++++++++
UefiCpuPkg/CpuMpPei/CpuMpPei.h | 302 ++++++++++
UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 90 +++
UefiCpuPkg/CpuMpPei/CpuMpPei.uni | Bin 0 -> 1706 bytes
UefiCpuPkg/CpuMpPei/CpuMpPeiExtra.uni | Bin 0 -> 1344 bytes
UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc | 40 ++
UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm | 276 +++++++++
UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm | 255 +++++++++
UefiCpuPkg/CpuMpPei/Microcode.c | 200 +++++++
UefiCpuPkg/CpuMpPei/Microcode.h | 68 +++
UefiCpuPkg/CpuMpPei/PeiMpServices.c | 960 ++++++++++++++++++++++++++++++++
UefiCpuPkg/CpuMpPei/PeiMpServices.h | 395 +++++++++++++
UefiCpuPkg/CpuMpPei/X64/MpEqu.inc | 45 ++
UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm | 334 +++++++++++
UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm | 327 +++++++++++
UefiCpuPkg/Include/Register/LocalApic.h | 6 +-
UefiCpuPkg/UefiCpuPkg.dec | 13 +-
UefiCpuPkg/UefiCpuPkg.dsc | 1 +
19 files changed, 4135 insertions(+), 2 deletions(-) create mode 100644 UefiCpuPkg/CpuMpPei/CpuBist.c create mode 100644 UefiCpuPkg/CpuMpPei/CpuMpPei.c create mode 100644 UefiCpuPkg/CpuMpPei/CpuMpPei.h create mode 100644 UefiCpuPkg/CpuMpPei/CpuMpPei.inf create mode 100644 UefiCpuPkg/CpuMpPei/CpuMpPei.uni create mode 100644 UefiCpuPkg/CpuMpPei/CpuMpPeiExtra.uni
create mode 100644 UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc
create mode 100644 UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm
create mode 100644 UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm
create mode 100644 UefiCpuPkg/CpuMpPei/Microcode.c create mode 100644 UefiCpuPkg/CpuMpPei/Microcode.h create mode 100644 UefiCpuPkg/CpuMpPei/PeiMpServices.c
create mode 100644 UefiCpuPkg/CpuMpPei/PeiMpServices.h
create mode 100644 UefiCpuPkg/CpuMpPei/X64/MpEqu.inc create mode 100644 UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm
create mode 100644 UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm

--
1.9.5.msysgit.0


------------------------------------------------------------------------------
Don't Limit Your Business. Reach for the Cloud.
GigeNET's Cloud Solutions provide you with the tools and support that you need to offload your IT needs and focus on growing your business.
Configured For All Businesses. Start Your Cloud Today.
https://www.gigenetcloud.com/
_______________________________________________
edk2-devel mailing list
edk2-***@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Loading...