]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / CapsuleRuntimeDxe / X64 / SaveLongModeContext.c
CommitLineData
ab7017fe 1/** @file\r
2 Create the variable to save the base address of page table and stack\r
3 for transferring into long mode in IA32 capsule PEI.\r
4\r
d1102dba 5Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
ab7017fe 7\r
8**/\r
9\r
10#include <Uefi.h>\r
11\r
12#include <Protocol/Capsule.h>\r
13#include <Protocol/DxeSmmReadyToLock.h>\r
b5040e4c 14#include <Protocol/VariableLock.h>\r
ab7017fe 15\r
16#include <Guid/CapsuleVendor.h>\r
17#include <Guid/AcpiS3Context.h>\r
18\r
19#include <Library/DebugLib.h>\r
20#include <Library/PcdLib.h>\r
21#include <Library/UefiBootServicesTableLib.h>\r
22#include <Library/UefiRuntimeServicesTableLib.h>\r
23#include <Library/UefiRuntimeLib.h>\r
24#include <Library/BaseLib.h>\r
ab7017fe 25#include <Library/UefiLib.h>\r
26#include <Library/BaseMemoryLib.h>\r
b2d2a7f3
SZ
27\r
28//\r
29// 8 extra pages for PF handler.\r
30//\r
1436aea4 31#define EXTRA_PAGE_TABLE_PAGES 8\r
ab7017fe 32\r
33/**\r
fd9abd04 34 Allocate EfiReservedMemoryType below 4G memory address.\r
ab7017fe 35\r
fd9abd04 36 This function allocates EfiReservedMemoryType below 4G memory address.\r
ab7017fe 37\r
fd9abd04 38 @param Size Size of memory to allocate.\r
d1102dba 39\r
fd9abd04 40 @return Allocated Address for output.\r
ab7017fe 41\r
42**/\r
1436aea4 43VOID *\r
fd9abd04 44AllocateReservedMemoryBelow4G (\r
1436aea4 45 IN UINTN Size\r
ab7017fe 46 )\r
47{\r
48 UINTN Pages;\r
49 EFI_PHYSICAL_ADDRESS Address;\r
50 EFI_STATUS Status;\r
1436aea4 51 VOID *Buffer;\r
ab7017fe 52\r
1436aea4 53 Pages = EFI_SIZE_TO_PAGES (Size);\r
ab7017fe 54 Address = 0xffffffff;\r
55\r
1436aea4
MK
56 Status = gBS->AllocatePages (\r
57 AllocateMaxAddress,\r
58 EfiReservedMemoryType,\r
59 Pages,\r
60 &Address\r
61 );\r
ab7017fe 62 ASSERT_EFI_ERROR (Status);\r
63\r
1436aea4 64 Buffer = (VOID *)(UINTN)Address;\r
ab7017fe 65 ZeroMem (Buffer, Size);\r
66\r
67 return Buffer;\r
68}\r
69\r
70/**\r
b5040e4c
EL
71 Register callback function upon VariableLockProtocol\r
72 to lock EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to avoid malicious code to update it.\r
ab7017fe 73\r
74 @param[in] Event Event whose notification function is being invoked.\r
75 @param[in] Context Pointer to the notification function's context.\r
76**/\r
77VOID\r
78EFIAPI\r
b5040e4c 79VariableLockCapsuleLongModeBufferVariable (\r
1436aea4
MK
80 IN EFI_EVENT Event,\r
81 IN VOID *Context\r
ab7017fe 82 )\r
83{\r
84 EFI_STATUS Status;\r
b5040e4c 85 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
1436aea4 86\r
ab7017fe 87 //\r
b5040e4c 88 // Mark EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to read-only if the Variable Lock protocol exists\r
ab7017fe 89 //\r
1436aea4 90 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);\r
ab7017fe 91 if (!EFI_ERROR (Status)) {\r
b5040e4c
EL
92 Status = VariableLock->RequestToLock (VariableLock, EFI_CAPSULE_LONG_MODE_BUFFER_NAME, &gEfiCapsuleVendorGuid);\r
93 ASSERT_EFI_ERROR (Status);\r
ab7017fe 94 }\r
b5040e4c
EL
95}\r
96\r
97/**\r
fd9abd04
EL
98 1. Allocate Reserved memory for capsule PEIM to establish a 1:1 Virtual to Physical mapping.\r
99 2. Allocate Reserved memroy as a stack for capsule PEIM to transfer from 32-bit mdoe to 64-bit mode.\r
b5040e4c
EL
100\r
101**/\r
102VOID\r
103EFIAPI\r
104PrepareContextForCapsulePei (\r
105 VOID\r
106 )\r
107{\r
1436aea4
MK
108 UINTN ExtraPageTablePages;\r
109 UINT32 RegEax;\r
110 UINT32 RegEdx;\r
111 UINTN TotalPagesNum;\r
112 UINT8 PhysicalAddressBits;\r
113 UINT32 NumberOfPml4EntriesNeeded;\r
114 UINT32 NumberOfPdpEntriesNeeded;\r
115 BOOLEAN Page1GSupport;\r
116 EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer;\r
117 EFI_STATUS Status;\r
118 VOID *Registration;\r
b2d2a7f3
SZ
119\r
120 //\r
121 // Calculate the size of page table, allocate the memory.\r
122 //\r
123 Page1GSupport = FALSE;\r
1436aea4 124 if (PcdGetBool (PcdUse1GPageTable)) {\r
b2d2a7f3
SZ
125 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
126 if (RegEax >= 0x80000001) {\r
127 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
128 if ((RegEdx & BIT26) != 0) {\r
129 Page1GSupport = TRUE;\r
b5040e4c 130 }\r
ab7017fe 131 }\r
ab7017fe 132 }\r
b2d2a7f3
SZ
133\r
134 //\r
135 // Create 4G page table by default,\r
136 // and let PF handler to handle > 4G request.\r
137 //\r
138 PhysicalAddressBits = 32;\r
139 ExtraPageTablePages = EXTRA_PAGE_TABLE_PAGES;\r
140\r
141 //\r
142 // Calculate the table entries needed.\r
143 //\r
144 if (PhysicalAddressBits <= 39 ) {\r
145 NumberOfPml4EntriesNeeded = 1;\r
1436aea4 146 NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));\r
b2d2a7f3
SZ
147 } else {\r
148 NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));\r
1436aea4 149 NumberOfPdpEntriesNeeded = 512;\r
b2d2a7f3
SZ
150 }\r
151\r
152 if (!Page1GSupport) {\r
153 TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;\r
154 } else {\r
155 TotalPagesNum = NumberOfPml4EntriesNeeded + 1;\r
156 }\r
1436aea4 157\r
b2d2a7f3 158 TotalPagesNum += ExtraPageTablePages;\r
558f58e3 159 DEBUG ((DEBUG_INFO, "CapsuleRuntimeDxe X64 TotalPagesNum - 0x%x pages\n", TotalPagesNum));\r
b2d2a7f3
SZ
160\r
161 LongModeBuffer.PageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedMemoryBelow4G (EFI_PAGES_TO_SIZE (TotalPagesNum));\r
162 ASSERT (LongModeBuffer.PageTableAddress != 0);\r
d1102dba 163\r
b5040e4c
EL
164 //\r
165 // Allocate stack\r
166 //\r
167 LongModeBuffer.StackSize = PcdGet32 (PcdCapsulePeiLongModeStackSize);\r
fd9abd04 168 LongModeBuffer.StackBaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedMemoryBelow4G (PcdGet32 (PcdCapsulePeiLongModeStackSize));\r
d1102dba
LG
169 ASSERT (LongModeBuffer.StackBaseAddress != 0);\r
170\r
ab7017fe 171 Status = gRT->SetVariable (\r
172 EFI_CAPSULE_LONG_MODE_BUFFER_NAME,\r
173 &gEfiCapsuleVendorGuid,\r
b5040e4c 174 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
ab7017fe 175 sizeof (EFI_CAPSULE_LONG_MODE_BUFFER),\r
176 &LongModeBuffer\r
177 );\r
b5040e4c 178 if (!EFI_ERROR (Status)) {\r
1436aea4
MK
179 //\r
180 // Register callback function upon VariableLockProtocol\r
181 // to lock EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to avoid malicious code to update it.\r
182 //\r
183 EfiCreateProtocolNotifyEvent (\r
184 &gEdkiiVariableLockProtocolGuid,\r
185 TPL_CALLBACK,\r
186 VariableLockCapsuleLongModeBufferVariable,\r
187 NULL,\r
188 &Registration\r
189 );\r
b5040e4c 190 } else {\r
1436aea4
MK
191 DEBUG ((DEBUG_ERROR, "FATAL ERROR: CapsuleLongModeBuffer cannot be saved: %r. Capsule in PEI may fail!\n", Status));\r
192 gBS->FreePages (LongModeBuffer.StackBaseAddress, EFI_SIZE_TO_PAGES (LongModeBuffer.StackSize));\r
b5040e4c 193 }\r
ab7017fe 194}\r
195\r
196/**\r
197 Create the variable to save the base address of page table and stack\r
198 for transferring into long mode in IA32 capsule PEI.\r
199**/\r
200VOID\r
201SaveLongModeContext (\r
202 VOID\r
203 )\r
204{\r
1436aea4 205 if ((FeaturePcdGet (PcdSupportUpdateCapsuleReset)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode))) {\r
ab7017fe 206 //\r
b5040e4c 207 // Allocate memory for Capsule IA32 PEIM, it will create page table to transfer to long mode to access capsule above 4GB.\r
ab7017fe 208 //\r
b5040e4c 209 PrepareContextForCapsulePei ();\r
ab7017fe 210 }\r
211}\r