]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/PiSmmCpuDxeSmm/X64/SmmFuncsArch.c
6844c3fc499d810bb041a38ae04084f934f090e7
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / X64 / SmmFuncsArch.c
1 /** @file
2 SMM CPU misc functions for x64 arch specific.
3
4 Copyright (c) 2015 - 2016, 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
9
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.
12
13 **/
14
15 #include "PiSmmCpuDxeSmm.h"
16
17 /**
18 Initialize Gdt for all processors.
19
20 @param[in] Cr3 CR3 value.
21 @param[out] GdtStepSize The step size for GDT table.
22
23 @return GdtBase for processor 0.
24 GdtBase for processor X is: GdtBase + (GdtStepSize * X)
25 **/
26 VOID *
27 InitGdt (
28 IN UINTN Cr3,
29 OUT UINTN *GdtStepSize
30 )
31 {
32 UINTN Index;
33 IA32_SEGMENT_DESCRIPTOR *GdtDescriptor;
34 UINTN TssBase;
35 UINTN GdtTssTableSize;
36 UINT8 *GdtTssTables;
37 UINTN GdtTableStepSize;
38
39 //
40 // For X64 SMM, we allocate separate GDT/TSS for each CPUs to avoid TSS load contention
41 // on each SMI entry.
42 //
43 GdtTssTableSize = (gcSmiGdtr.Limit + 1 + TSS_SIZE + 7) & ~7; // 8 bytes aligned
44 GdtTssTables = (UINT8*)AllocatePages (EFI_SIZE_TO_PAGES (GdtTssTableSize * gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus));
45 ASSERT (GdtTssTables != NULL);
46 GdtTableStepSize = GdtTssTableSize;
47
48 for (Index = 0; Index < gSmmCpuPrivate->SmmCoreEntryContext.NumberOfCpus; Index++) {
49 CopyMem (GdtTssTables + GdtTableStepSize * Index, (VOID*)(UINTN)gcSmiGdtr.Base, gcSmiGdtr.Limit + 1 + TSS_SIZE);
50
51 //
52 // Fixup TSS descriptors
53 //
54 TssBase = (UINTN)(GdtTssTables + GdtTableStepSize * Index + gcSmiGdtr.Limit + 1);
55 GdtDescriptor = (IA32_SEGMENT_DESCRIPTOR *)(TssBase) - 2;
56 GdtDescriptor->Bits.BaseLow = (UINT16)(UINTN)TssBase;
57 GdtDescriptor->Bits.BaseMid = (UINT8)((UINTN)TssBase >> 16);
58 GdtDescriptor->Bits.BaseHigh = (UINT8)((UINTN)TssBase >> 24);
59
60 if (FeaturePcdGet (PcdCpuSmmStackGuard)) {
61 //
62 // Setup top of known good stack as IST1 for each processor.
63 //
64 *(UINTN *)(TssBase + TSS_X64_IST1_OFFSET) = (mSmmStackArrayBase + EFI_PAGE_SIZE + Index * mSmmStackSize);
65 }
66 }
67
68 *GdtStepSize = GdtTableStepSize;
69 return GdtTssTables;
70 }
71
72 /**
73 Get Protected mode code segment from current GDT table.
74
75 @return Protected mode code segment value.
76 **/
77 UINT16
78 GetProtectedModeCS (
79 VOID
80 )
81 {
82 IA32_DESCRIPTOR GdtrDesc;
83 IA32_SEGMENT_DESCRIPTOR *GdtEntry;
84 UINTN GdtEntryCount;
85 UINT16 Index;
86
87 Index = (UINT16) -1;
88 AsmReadGdtr (&GdtrDesc);
89 GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);
90 GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;
91 for (Index = 0; Index < GdtEntryCount; Index++) {
92 if (GdtEntry->Bits.L == 0) {
93 if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.L == 0) {
94 break;
95 }
96 }
97 GdtEntry++;
98 }
99 ASSERT (Index != -1);
100 return Index * 8;
101 }
102
103 /**
104 Transfer AP to safe hlt-loop after it finished restore CPU features on S3 patch.
105
106 @param[in] ApHltLoopCode The 32-bit address of the safe hlt-loop function.
107 @param[in] TopOfStack A pointer to the new stack to use for the ApHltLoopCode.
108 @param[in] NumberToFinish Semaphore of APs finish count.
109
110 **/
111 VOID
112 TransferApToSafeState (
113 IN UINT32 ApHltLoopCode,
114 IN UINT32 TopOfStack,
115 IN UINT32 *NumberToFinish
116 )
117 {
118 AsmDisablePaging64 (
119 GetProtectedModeCS (),
120 (UINT32) (UINTN) ApHltLoopCode,
121 (UINT32) (UINTN) NumberToFinish,
122 0,
123 TopOfStack
124 );
125 //
126 // It should never reach here
127 //
128 ASSERT (FALSE);
129 }
130
131