]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleService.c
Revert "Capsule-on-Disk entire Patch
[mirror_edk2.git] / MdeModulePkg / Universal / CapsuleRuntimeDxe / CapsuleService.c
CommitLineData
13d40edd 1/** @file\r
58612f24 2 Capsule Runtime Driver produces two UEFI capsule runtime services.\r
5d69642d 3 (UpdateCapsule, QueryCapsuleCapabilities)\r
d1102dba 4 It installs the Capsule Architectural Protocol defined in PI1.0a to signify\r
109e9a61 5 the capsule runtime services are ready.\r
74fea867 6\r
57ec204e 7Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 8SPDX-License-Identifier: BSD-2-Clause-Patent\r
74fea867 9\r
13d40edd 10**/\r
74fea867 11\r
e077a93d
AB
12#include "CapsuleService.h"\r
13\r
3f42faa7 14//\r
15// Handle for the installation of Capsule Architecture Protocol.\r
16//\r
17EFI_HANDLE mNewHandle = NULL;\r
18\r
f03ccf59 19//\r
20// The times of calling UpdateCapsule ()\r
21//\r
22UINTN mTimes = 0;\r
23\r
f67eb9d8
SZ
24UINT32 mMaxSizePopulateCapsule = 0;\r
25UINT32 mMaxSizeNonPopulateCapsule = 0;\r
26\r
5d69642d
LG
27/**\r
28 Passes capsules to the firmware with both virtual and physical mapping. Depending on the intended\r
29 consumption, the firmware may process the capsule immediately. If the payload should persist\r
30 across a system reset, the reset value returned from EFI_QueryCapsuleCapabilities must\r
31 be passed into ResetSystem() and will cause the capsule to be processed by the firmware as\r
32 part of the reset process.\r
33\r
34 @param CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules\r
35 being passed into update capsule.\r
36 @param CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in\r
37 CaspuleHeaderArray.\r
38 @param ScatterGatherList Physical pointer to a set of\r
39 EFI_CAPSULE_BLOCK_DESCRIPTOR that describes the\r
40 location in physical memory of a set of capsules.\r
41\r
42 @retval EFI_SUCCESS Valid capsule was passed. If\r
43 CAPSULE_FLAGS_PERSIT_ACROSS_RESET is not set, the\r
44 capsule has been successfully processed by the firmware.\r
45 @retval EFI_DEVICE_ERROR The capsule update was started, but failed due to a device error.\r
3f42faa7 46 @retval EFI_INVALID_PARAMETER CapsuleSize is NULL, or an incompatible set of flags were\r
47 set in the capsule header.\r
48 @retval EFI_INVALID_PARAMETER CapsuleCount is Zero.\r
49 @retval EFI_INVALID_PARAMETER For across reset capsule image, ScatterGatherList is NULL.\r
5d69642d 50 @retval EFI_UNSUPPORTED CapsuleImage is not recognized by the firmware.\r
d1102dba
LG
51 @retval EFI_OUT_OF_RESOURCES When ExitBootServices() has been previously called this error indicates the capsule\r
52 is compatible with this platform but is not capable of being submitted or processed\r
ad3f3656 53 in runtime. The caller may resubmit the capsule prior to ExitBootServices().\r
d1102dba 54 @retval EFI_OUT_OF_RESOURCES When ExitBootServices() has not been previously called then this error indicates\r
ad3f3656 55 the capsule is compatible with this platform but there are insufficient resources to process.\r
5d69642d
LG
56\r
57**/\r
74fea867 58EFI_STATUS\r
59EFIAPI\r
60UpdateCapsule (\r
61 IN EFI_CAPSULE_HEADER **CapsuleHeaderArray,\r
62 IN UINTN CapsuleCount,\r
63 IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL\r
64 )\r
74fea867 65{\r
74fea867 66 UINTN ArrayNumber;\r
74fea867 67 EFI_STATUS Status;\r
74fea867 68 EFI_CAPSULE_HEADER *CapsuleHeader;\r
409d47b4 69 BOOLEAN NeedReset;\r
3f42faa7 70 BOOLEAN InitiateReset;\r
f03ccf59 71 CHAR16 CapsuleVarName[30];\r
d1102dba
LG
72 CHAR16 *TempVarName;\r
73\r
5d69642d
LG
74 //\r
75 // Capsule Count can't be less than one.\r
76 //\r
74fea867 77 if (CapsuleCount < 1) {\r
78 return EFI_INVALID_PARAMETER;\r
79 }\r
3f42faa7 80\r
f03ccf59 81 NeedReset = FALSE;\r
82 InitiateReset = FALSE;\r
83 CapsuleHeader = NULL;\r
84 CapsuleVarName[0] = 0;\r
74fea867 85\r
86 for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {\r
d12f75fe
LG
87 //\r
88 // A capsule which has the CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag must have\r
89 // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.\r
90 //\r
74fea867 91 CapsuleHeader = CapsuleHeaderArray[ArrayNumber];\r
92 if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {\r
93 return EFI_INVALID_PARAMETER;\r
94 }\r
d12f75fe 95 //\r
3f42faa7 96 // A capsule which has the CAPSULE_FLAGS_INITIATE_RESET flag must have\r
97 // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.\r
98 //\r
99 if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) {\r
100 return EFI_INVALID_PARAMETER;\r
101 }\r
566771b0 102\r
103 //\r
d1102dba 104 // Check FMP capsule flag\r
566771b0 105 //\r
106 if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)\r
107 && (CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0 ) {\r
108 return EFI_INVALID_PARAMETER;\r
109 }\r
110\r
3f42faa7 111 //\r
d1102dba 112 // Check Capsule image without populate flag by firmware support capsule function\r
6ee65722 113 //\r
566771b0 114 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {\r
115 Status = SupportCapsuleImage (CapsuleHeader);\r
116 if (EFI_ERROR(Status)) {\r
117 return Status;\r
118 }\r
6ee65722 119 }\r
74fea867 120 }\r
121\r
d12f75fe 122 //\r
3f42faa7 123 // Walk through all capsules, record whether there is a capsule needs reset\r
124 // or initiate reset. And then process capsules which has no reset flag directly.\r
5d69642d 125 //\r
409d47b4
LG
126 for (ArrayNumber = 0; ArrayNumber < CapsuleCount ; ArrayNumber++) {\r
127 CapsuleHeader = CapsuleHeaderArray[ArrayNumber];\r
d12f75fe 128 //\r
409d47b4
LG
129 // Here should be in the boot-time for non-reset capsule image\r
130 // Platform specific update for the non-reset capsule image.\r
d12f75fe 131 //\r
409d47b4 132 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) == 0) {\r
d1102dba 133 if (EfiAtRuntime ()) {\r
ad3f3656 134 Status = EFI_OUT_OF_RESOURCES;\r
409d47b4
LG
135 } else {\r
136 Status = ProcessCapsuleImage(CapsuleHeader);\r
137 }\r
138 if (EFI_ERROR(Status)) {\r
d12f75fe 139 return Status;\r
74fea867 140 }\r
409d47b4
LG
141 } else {\r
142 NeedReset = TRUE;\r
3f42faa7 143 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_INITIATE_RESET) != 0) {\r
144 InitiateReset = TRUE;\r
145 }\r
74fea867 146 }\r
74fea867 147 }\r
d1102dba 148\r
409d47b4
LG
149 //\r
150 // After launching all capsules who has no reset flag, if no more capsules claims\r
151 // for a system reset just return.\r
152 //\r
153 if (!NeedReset) {\r
154 return EFI_SUCCESS;\r
155 }\r
74fea867 156\r
157 //\r
409d47b4 158 // ScatterGatherList is only referenced if the capsules are defined to persist across\r
d1102dba 159 // system reset.\r
74fea867 160 //\r
409d47b4
LG
161 if (ScatterGatherList == (EFI_PHYSICAL_ADDRESS) (UINTN) NULL) {\r
162 return EFI_INVALID_PARAMETER;\r
74fea867 163 }\r
164\r
165 //\r
409d47b4 166 // Check if the platform supports update capsule across a system reset\r
74fea867 167 //\r
e077a93d 168 if (!IsPersistAcrossResetCapsuleSupported ()) {\r
409d47b4 169 return EFI_UNSUPPORTED;\r
74fea867 170 }\r
171\r
e077a93d
AB
172 CapsuleCacheWriteBack (ScatterGatherList);\r
173\r
f03ccf59 174 //\r
175 // Construct variable name CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...\r
176 // if user calls UpdateCapsule multiple times.\r
177 //\r
931d4d82 178 StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16), EFI_CAPSULE_VARIABLE_NAME);\r
f03ccf59 179 TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
180 if (mTimes > 0) {\r
9f4048f7
HW
181 UnicodeValueToStringS (\r
182 TempVarName,\r
183 sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName),\r
184 0,\r
185 mTimes,\r
186 0\r
187 );\r
f03ccf59 188 }\r
189\r
409d47b4
LG
190 //\r
191 // ScatterGatherList is only referenced if the capsules are defined to persist across\r
d1102dba 192 // system reset. Set its value into NV storage to let pre-boot driver to pick it up\r
409d47b4
LG
193 // after coming through a system reset.\r
194 //\r
b3b1a4cf 195 Status = EfiSetVariable (\r
f03ccf59 196 CapsuleVarName,\r
b3b1a4cf 197 &gEfiCapsuleVendorGuid,\r
198 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
199 sizeof (UINTN),\r
200 (VOID *) &ScatterGatherList\r
201 );\r
f03ccf59 202 if (!EFI_ERROR (Status)) {\r
203 //\r
204 // Variable has been set successfully, increase variable index.\r
205 //\r
206 mTimes++;\r
207 if(InitiateReset) {\r
208 //\r
209 // Firmware that encounters a capsule which has the CAPSULE_FLAGS_INITIATE_RESET Flag set in its header\r
d1102dba 210 // will initiate a reset of the platform which is compatible with the passed-in capsule request and will\r
f03ccf59 211 // not return back to the caller.\r
212 //\r
213 EfiResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);\r
214 }\r
3f42faa7 215 }\r
409d47b4 216 return Status;\r
74fea867 217}\r
218\r
5d69642d
LG
219/**\r
220 Returns if the capsule can be supported via UpdateCapsule().\r
221\r
222 @param CapsuleHeaderArray Virtual pointer to an array of virtual pointers to the capsules\r
223 being passed into update capsule.\r
224 @param CapsuleCount Number of pointers to EFI_CAPSULE_HEADER in\r
225 CaspuleHeaderArray.\r
226 @param MaxiumCapsuleSize On output the maximum size that UpdateCapsule() can\r
227 support as an argument to UpdateCapsule() via\r
228 CapsuleHeaderArray and ScatterGatherList.\r
229 @param ResetType Returns the type of reset required for the capsule update.\r
74fea867 230\r
5d69642d
LG
231 @retval EFI_SUCCESS Valid answer returned.\r
232 @retval EFI_UNSUPPORTED The capsule image is not supported on this platform, and\r
233 MaximumCapsuleSize and ResetType are undefined.\r
234 @retval EFI_INVALID_PARAMETER MaximumCapsuleSize is NULL, or ResetTyep is NULL,\r
235 Or CapsuleCount is Zero, or CapsuleImage is not valid.\r
74fea867 236\r
5d69642d 237**/\r
74fea867 238EFI_STATUS\r
239EFIAPI\r
240QueryCapsuleCapabilities (\r
241 IN EFI_CAPSULE_HEADER **CapsuleHeaderArray,\r
242 IN UINTN CapsuleCount,\r
243 OUT UINT64 *MaxiumCapsuleSize,\r
244 OUT EFI_RESET_TYPE *ResetType\r
245 )\r
74fea867 246{\r
566771b0 247 EFI_STATUS Status;\r
74fea867 248 UINTN ArrayNumber;\r
249 EFI_CAPSULE_HEADER *CapsuleHeader;\r
0ef42f88 250 BOOLEAN NeedReset;\r
74fea867 251\r
5d69642d
LG
252 //\r
253 // Capsule Count can't be less than one.\r
254 //\r
74fea867 255 if (CapsuleCount < 1) {\r
256 return EFI_INVALID_PARAMETER;\r
257 }\r
d1102dba 258\r
5d69642d 259 //\r
3f42faa7 260 // Check whether input parameter is valid\r
5d69642d 261 //\r
74fea867 262 if ((MaxiumCapsuleSize == NULL) ||(ResetType == NULL)) {\r
263 return EFI_INVALID_PARAMETER;\r
264 }\r
265\r
266 CapsuleHeader = NULL;\r
0ef42f88 267 NeedReset = FALSE;\r
74fea867 268\r
269 for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {\r
270 CapsuleHeader = CapsuleHeaderArray[ArrayNumber];\r
d12f75fe
LG
271 //\r
272 // A capsule which has the CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag must have\r
273 // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.\r
274 //\r
74fea867 275 if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {\r
276 return EFI_INVALID_PARAMETER;\r
277 }\r
d12f75fe 278 //\r
3f42faa7 279 // A capsule which has the CAPSULE_FLAGS_INITIATE_RESET flag must have\r
280 // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.\r
281 //\r
282 if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) {\r
283 return EFI_INVALID_PARAMETER;\r
284 }\r
566771b0 285\r
286 //\r
d1102dba 287 // Check FMP capsule flag\r
566771b0 288 //\r
289 if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)\r
290 && (CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0 ) {\r
291 return EFI_INVALID_PARAMETER;\r
292 }\r
293\r
3f42faa7 294 //\r
5d69642d 295 // Check Capsule image without populate flag is supported by firmware\r
6ee65722 296 //\r
566771b0 297 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {\r
298 Status = SupportCapsuleImage (CapsuleHeader);\r
299 if (EFI_ERROR(Status)) {\r
300 return Status;\r
301 }\r
6ee65722 302 }\r
74fea867 303 }\r
304\r
305 //\r
d1102dba 306 // Find out whether there is any capsule defined to persist across system reset.\r
74fea867 307 //\r
0ef42f88 308 for (ArrayNumber = 0; ArrayNumber < CapsuleCount ; ArrayNumber++) {\r
309 CapsuleHeader = CapsuleHeaderArray[ArrayNumber];\r
310 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
311 NeedReset = TRUE;\r
312 break;\r
313 }\r
314 }\r
566771b0 315\r
0ef42f88 316 if (NeedReset) {\r
74fea867 317 //\r
318 //Check if the platform supports update capsule across a system reset\r
319 //\r
e077a93d 320 if (!IsPersistAcrossResetCapsuleSupported ()) {\r
74fea867 321 return EFI_UNSUPPORTED;\r
322 }\r
0ef42f88 323 *ResetType = EfiResetWarm;\r
f67eb9d8 324 *MaxiumCapsuleSize = (UINT64) mMaxSizePopulateCapsule;\r
74fea867 325 } else {\r
5d69642d
LG
326 //\r
327 // For non-reset capsule image.\r
328 //\r
74fea867 329 *ResetType = EfiResetCold;\r
f67eb9d8 330 *MaxiumCapsuleSize = (UINT64) mMaxSizeNonPopulateCapsule;\r
74fea867 331 }\r
5c526736 332\r
74fea867 333 return EFI_SUCCESS;\r
334}\r
335\r
336\r
5d69642d
LG
337/**\r
338\r
109e9a61 339 This code installs UEFI capsule runtime service.\r
5d69642d 340\r
d1102dba 341 @param ImageHandle The firmware allocated handle for the EFI image.\r
5d69642d
LG
342 @param SystemTable A pointer to the EFI System Table.\r
343\r
d1102dba 344 @retval EFI_SUCCESS UEFI Capsule Runtime Services are installed successfully.\r
5d69642d
LG
345\r
346**/\r
74fea867 347EFI_STATUS\r
348EFIAPI\r
349CapsuleServiceInitialize (\r
350 IN EFI_HANDLE ImageHandle,\r
351 IN EFI_SYSTEM_TABLE *SystemTable\r
352 )\r
74fea867 353{\r
354 EFI_STATUS Status;\r
f67eb9d8
SZ
355\r
356 mMaxSizePopulateCapsule = PcdGet32(PcdMaxSizePopulateCapsule);\r
357 mMaxSizeNonPopulateCapsule = PcdGet32(PcdMaxSizeNonPopulateCapsule);\r
358\r
ab7017fe 359 //\r
d1102dba 360 // When PEI phase is IA32, DXE phase is X64, it is possible that capsule data are\r
ab7017fe 361 // put above 4GB, so capsule PEI will transfer to long mode to get capsule data.\r
362 // The page table and stack is used to transfer processor mode from IA32 to long mode.\r
363 // Create the base address of page table and stack, and save them into variable.\r
364 // This is not needed when capsule with reset type is not supported.\r
365 //\r
366 SaveLongModeContext ();\r
d1102dba 367\r
5d69642d
LG
368 //\r
369 // Install capsule runtime services into UEFI runtime service tables.\r
370 //\r
109e9a61
LG
371 gRT->UpdateCapsule = UpdateCapsule;\r
372 gRT->QueryCapsuleCapabilities = QueryCapsuleCapabilities;\r
74fea867 373\r
374 //\r
5d69642d
LG
375 // Install the Capsule Architectural Protocol on a new handle\r
376 // to signify the capsule runtime services are ready.\r
74fea867 377 //\r
74fea867 378 Status = gBS->InstallMultipleProtocolInterfaces (\r
3f42faa7 379 &mNewHandle,\r
74fea867 380 &gEfiCapsuleArchProtocolGuid,\r
381 NULL,\r
382 NULL\r
383 );\r
384 ASSERT_EFI_ERROR (Status);\r
385\r
3f42faa7 386 return Status;\r
74fea867 387}\r