2 SMM CPU misc functions for x64 arch specific.
4 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "PiSmmCpuDxeSmm.h"
17 EFI_PHYSICAL_ADDRESS mGdtBuffer
;
21 Initialize IDT for SMM Stack Guard.
26 InitializeIDTSmmStackGuard (
30 IA32_IDT_GATE_DESCRIPTOR
*IdtGate
;
33 // If SMM Stack Guard feature is enabled, set the IST field of
34 // the interrupt gate for Page Fault Exception to be 1
36 IdtGate
= (IA32_IDT_GATE_DESCRIPTOR
*)gcSmiIdtr
.Base
;
37 IdtGate
+= EXCEPT_IA32_PAGE_FAULT
;
38 IdtGate
->Bits
.Reserved_0
= 1;
42 Initialize Gdt for all processors.
44 @param[in] Cr3 CR3 value.
45 @param[out] GdtStepSize The step size for GDT table.
47 @return GdtBase for processor 0.
48 GdtBase for processor X is: GdtBase + (GdtStepSize * X)
53 OUT UINTN
*GdtStepSize
57 IA32_SEGMENT_DESCRIPTOR
*GdtDescriptor
;
59 UINTN GdtTssTableSize
;
61 UINTN GdtTableStepSize
;
64 // For X64 SMM, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention
67 GdtTssTableSize
= (gcSmiGdtr
.Limit
+ 1 + TSS_SIZE
+ 7) & ~7; // 8 bytes aligned
68 mGdtBufferSize
= GdtTssTableSize
* gSmmCpuPrivate
->SmmCoreEntryContext
.NumberOfCpus
;
69 GdtTssTables
= (UINT8
*)AllocateCodePages (EFI_SIZE_TO_PAGES (mGdtBufferSize
));
70 ASSERT (GdtTssTables
!= NULL
);
71 mGdtBuffer
= (UINTN
)GdtTssTables
;
72 GdtTableStepSize
= GdtTssTableSize
;
74 for (Index
= 0; Index
< gSmmCpuPrivate
->SmmCoreEntryContext
.NumberOfCpus
; Index
++) {
75 CopyMem (GdtTssTables
+ GdtTableStepSize
* Index
, (VOID
*)(UINTN
)gcSmiGdtr
.Base
, gcSmiGdtr
.Limit
+ 1 + TSS_SIZE
);
78 // Fixup TSS descriptors
80 TssBase
= (UINTN
)(GdtTssTables
+ GdtTableStepSize
* Index
+ gcSmiGdtr
.Limit
+ 1);
81 GdtDescriptor
= (IA32_SEGMENT_DESCRIPTOR
*)(TssBase
) - 2;
82 GdtDescriptor
->Bits
.BaseLow
= (UINT16
)(UINTN
)TssBase
;
83 GdtDescriptor
->Bits
.BaseMid
= (UINT8
)((UINTN
)TssBase
>> 16);
84 GdtDescriptor
->Bits
.BaseHigh
= (UINT8
)((UINTN
)TssBase
>> 24);
86 if (FeaturePcdGet (PcdCpuSmmStackGuard
)) {
88 // Setup top of known good stack as IST1 for each processor.
90 *(UINTN
*)(TssBase
+ TSS_X64_IST1_OFFSET
) = (mSmmStackArrayBase
+ EFI_PAGE_SIZE
+ Index
* mSmmStackSize
);
94 *GdtStepSize
= GdtTableStepSize
;
99 Get Protected mode code segment from current GDT table.
101 @return Protected mode code segment value.
108 IA32_DESCRIPTOR GdtrDesc
;
109 IA32_SEGMENT_DESCRIPTOR
*GdtEntry
;
114 AsmReadGdtr (&GdtrDesc
);
115 GdtEntryCount
= (GdtrDesc
.Limit
+ 1) / sizeof (IA32_SEGMENT_DESCRIPTOR
);
116 GdtEntry
= (IA32_SEGMENT_DESCRIPTOR
*) GdtrDesc
.Base
;
117 for (Index
= 0; Index
< GdtEntryCount
; Index
++) {
118 if (GdtEntry
->Bits
.L
== 0) {
119 if (GdtEntry
->Bits
.Type
> 8 && GdtEntry
->Bits
.L
== 0) {
125 ASSERT (Index
!= -1);
130 Transfer AP to safe hlt-loop after it finished restore CPU features on S3 patch.
132 @param[in] ApHltLoopCode The address of the safe hlt-loop function.
133 @param[in] TopOfStack A pointer to the new stack to use for the ApHltLoopCode.
134 @param[in] NumberToFinishAddress Address of Semaphore of APs finish count.
138 TransferApToSafeState (
139 IN UINTN ApHltLoopCode
,
141 IN UINTN NumberToFinishAddress
145 GetProtectedModeCS (),
146 (UINT32
)ApHltLoopCode
,
147 (UINT32
)NumberToFinishAddress
,
152 // It should never reach here