]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[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
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
43VOID*\r
fd9abd04 44AllocateReservedMemoryBelow4G (\r
ab7017fe 45 IN UINTN Size\r
46 )\r
47{\r
48 UINTN Pages;\r
49 EFI_PHYSICAL_ADDRESS Address;\r
50 EFI_STATUS Status;\r
51 VOID* Buffer;\r
52\r
53 Pages = EFI_SIZE_TO_PAGES (Size);\r
54 Address = 0xffffffff;\r
55\r
56 Status = gBS->AllocatePages (\r
57 AllocateMaxAddress,\r
fd9abd04 58 EfiReservedMemoryType,\r
ab7017fe 59 Pages,\r
60 &Address\r
61 );\r
62 ASSERT_EFI_ERROR (Status);\r
63\r
64 Buffer = (VOID *) (UINTN) Address;\r
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
EL
79VariableLockCapsuleLongModeBufferVariable (\r
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
ab7017fe 86 //\r
b5040e4c 87 // Mark EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to read-only if the Variable Lock protocol exists\r
ab7017fe 88 //\r
b5040e4c 89 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
ab7017fe 90 if (!EFI_ERROR (Status)) {\r
b5040e4c
EL
91 Status = VariableLock->RequestToLock (VariableLock, EFI_CAPSULE_LONG_MODE_BUFFER_NAME, &gEfiCapsuleVendorGuid);\r
92 ASSERT_EFI_ERROR (Status);\r
ab7017fe 93 }\r
b5040e4c
EL
94}\r
95\r
96/**\r
fd9abd04
EL
97 1. Allocate Reserved memory for capsule PEIM to establish a 1:1 Virtual to Physical mapping.\r
98 2. Allocate Reserved memroy as a stack for capsule PEIM to transfer from 32-bit mdoe to 64-bit mode.\r
b5040e4c
EL
99\r
100**/\r
101VOID\r
102EFIAPI\r
103PrepareContextForCapsulePei (\r
104 VOID\r
105 )\r
106{\r
b2d2a7f3 107 UINTN ExtraPageTablePages;\r
b5040e4c
EL
108 UINT32 RegEax;\r
109 UINT32 RegEdx;\r
110 UINTN TotalPagesNum;\r
111 UINT8 PhysicalAddressBits;\r
b5040e4c
EL
112 UINT32 NumberOfPml4EntriesNeeded;\r
113 UINT32 NumberOfPdpEntriesNeeded;\r
114 BOOLEAN Page1GSupport;\r
115 EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer;\r
116 EFI_STATUS Status;\r
117 VOID *Registration;\r
b2d2a7f3
SZ
118\r
119 //\r
120 // Calculate the size of page table, allocate the memory.\r
121 //\r
122 Page1GSupport = FALSE;\r
123 if (PcdGetBool(PcdUse1GPageTable)) {\r
124 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
125 if (RegEax >= 0x80000001) {\r
126 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
127 if ((RegEdx & BIT26) != 0) {\r
128 Page1GSupport = TRUE;\r
b5040e4c 129 }\r
ab7017fe 130 }\r
ab7017fe 131 }\r
b2d2a7f3
SZ
132\r
133 //\r
134 // Create 4G page table by default,\r
135 // and let PF handler to handle > 4G request.\r
136 //\r
137 PhysicalAddressBits = 32;\r
138 ExtraPageTablePages = EXTRA_PAGE_TABLE_PAGES;\r
139\r
140 //\r
141 // Calculate the table entries needed.\r
142 //\r
143 if (PhysicalAddressBits <= 39 ) {\r
144 NumberOfPml4EntriesNeeded = 1;\r
145 NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));\r
146 } else {\r
147 NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));\r
148 NumberOfPdpEntriesNeeded = 512;\r
149 }\r
150\r
151 if (!Page1GSupport) {\r
152 TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;\r
153 } else {\r
154 TotalPagesNum = NumberOfPml4EntriesNeeded + 1;\r
155 }\r
156 TotalPagesNum += ExtraPageTablePages;\r
558f58e3 157 DEBUG ((DEBUG_INFO, "CapsuleRuntimeDxe X64 TotalPagesNum - 0x%x pages\n", TotalPagesNum));\r
b2d2a7f3
SZ
158\r
159 LongModeBuffer.PageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedMemoryBelow4G (EFI_PAGES_TO_SIZE (TotalPagesNum));\r
160 ASSERT (LongModeBuffer.PageTableAddress != 0);\r
d1102dba 161\r
b5040e4c
EL
162 //\r
163 // Allocate stack\r
164 //\r
165 LongModeBuffer.StackSize = PcdGet32 (PcdCapsulePeiLongModeStackSize);\r
fd9abd04 166 LongModeBuffer.StackBaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedMemoryBelow4G (PcdGet32 (PcdCapsulePeiLongModeStackSize));\r
d1102dba
LG
167 ASSERT (LongModeBuffer.StackBaseAddress != 0);\r
168\r
ab7017fe 169 Status = gRT->SetVariable (\r
170 EFI_CAPSULE_LONG_MODE_BUFFER_NAME,\r
171 &gEfiCapsuleVendorGuid,\r
b5040e4c 172 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
ab7017fe 173 sizeof (EFI_CAPSULE_LONG_MODE_BUFFER),\r
174 &LongModeBuffer\r
175 );\r
b5040e4c
EL
176 if (!EFI_ERROR (Status)) {\r
177 //\r
178 // Register callback function upon VariableLockProtocol\r
179 // to lock EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to avoid malicious code to update it.\r
180 //\r
181 EfiCreateProtocolNotifyEvent (\r
182 &gEdkiiVariableLockProtocolGuid,\r
183 TPL_CALLBACK,\r
184 VariableLockCapsuleLongModeBufferVariable,\r
185 NULL,\r
186 &Registration\r
d1102dba 187 );\r
b5040e4c
EL
188 } else {\r
189 DEBUG ((EFI_D_ERROR, "FATAL ERROR: CapsuleLongModeBuffer cannot be saved: %r. Capsule in PEI may fail!\n", Status));\r
190 gBS->FreePages (LongModeBuffer.StackBaseAddress, EFI_SIZE_TO_PAGES (LongModeBuffer.StackSize));\r
191 }\r
ab7017fe 192}\r
193\r
194/**\r
195 Create the variable to save the base address of page table and stack\r
196 for transferring into long mode in IA32 capsule PEI.\r
197**/\r
198VOID\r
199SaveLongModeContext (\r
200 VOID\r
201 )\r
202{\r
ab7017fe 203 if ((FeaturePcdGet(PcdSupportUpdateCapsuleReset)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode))) {\r
204 //\r
b5040e4c 205 // Allocate memory for Capsule IA32 PEIM, it will create page table to transfer to long mode to access capsule above 4GB.\r
ab7017fe 206 //\r
b5040e4c 207 PrepareContextForCapsulePei ();\r
ab7017fe 208 }\r
209}\r