TianoCore EDK2 master
Loading...
Searching...
No Matches
CapsuleService.c
Go to the documentation of this file.
1
12#include "CapsuleService.h"
13
14//
15// Handle for the installation of Capsule Architecture Protocol.
16//
17EFI_HANDLE mNewHandle = NULL;
18
19//
20// The times of calling UpdateCapsule ()
21//
22UINTN mTimes = 0;
23
24UINT32 mMaxSizePopulateCapsule = 0;
25UINT32 mMaxSizeNonPopulateCapsule = 0;
26
62EFIAPI
64 IN EFI_CAPSULE_HEADER **CapsuleHeaderArray,
65 IN UINTN CapsuleCount,
66 IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL
67 )
68{
69 UINTN ArrayNumber;
70 EFI_STATUS Status;
71 EFI_CAPSULE_HEADER *CapsuleHeader;
72 BOOLEAN NeedReset;
73 BOOLEAN InitiateReset;
74 CHAR16 CapsuleVarName[30];
75 CHAR16 *TempVarName;
76
77 //
78 // Check if platform support Capsule In RAM or not.
79 // Platform could choose to drop CapsulePei/CapsuleX64 and do not support Capsule In RAM.
80 //
81 if (!PcdGetBool (PcdCapsuleInRamSupport)) {
82 return EFI_UNSUPPORTED;
83 }
84
85 //
86 // Capsule Count can't be less than one.
87 //
88 if (CapsuleCount < 1) {
89 return EFI_INVALID_PARAMETER;
90 }
91
92 NeedReset = FALSE;
93 InitiateReset = FALSE;
94 CapsuleHeader = NULL;
95 CapsuleVarName[0] = 0;
96
97 for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {
98 //
99 // A capsule which has the CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag must have
100 // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.
101 //
102 CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
103 if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {
104 return EFI_INVALID_PARAMETER;
105 }
106
107 //
108 // A capsule which has the CAPSULE_FLAGS_INITIATE_RESET flag must have
109 // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.
110 //
111 if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) {
112 return EFI_INVALID_PARAMETER;
113 }
114
115 //
116 // Check FMP capsule flag
117 //
118 if ( CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)
119 && ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0))
120 {
121 return EFI_INVALID_PARAMETER;
122 }
123
124 //
125 // Check Capsule image without populate flag by firmware support capsule function
126 //
127 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {
128 Status = SupportCapsuleImage (CapsuleHeader);
129 if (EFI_ERROR (Status)) {
130 return Status;
131 }
132 }
133 }
134
135 //
136 // Walk through all capsules, record whether there is a capsule needs reset
137 // or initiate reset. And then process capsules which has no reset flag directly.
138 //
139 for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {
140 CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
141 //
142 // Here should be in the boot-time for non-reset capsule image
143 // Platform specific update for the non-reset capsule image.
144 //
145 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) == 0) {
146 if (EfiAtRuntime () && !FeaturePcdGet (PcdSupportProcessCapsuleAtRuntime)) {
147 Status = EFI_OUT_OF_RESOURCES;
148 } else {
149 Status = ProcessCapsuleImage (CapsuleHeader);
150 }
151
152 if (EFI_ERROR (Status)) {
153 return Status;
154 }
155 } else {
156 NeedReset = TRUE;
157 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_INITIATE_RESET) != 0) {
158 InitiateReset = TRUE;
159 }
160 }
161 }
162
163 //
164 // After launching all capsules who has no reset flag, if no more capsules claims
165 // for a system reset just return.
166 //
167 if (!NeedReset) {
168 return EFI_SUCCESS;
169 }
170
171 //
172 // ScatterGatherList is only referenced if the capsules are defined to persist across
173 // system reset.
174 //
175 if (ScatterGatherList == (EFI_PHYSICAL_ADDRESS)(UINTN)NULL) {
176 return EFI_INVALID_PARAMETER;
177 }
178
179 //
180 // Check if the platform supports update capsule across a system reset
181 //
183 return EFI_UNSUPPORTED;
184 }
185
186 CapsuleCacheWriteBack (ScatterGatherList);
187
188 //
189 // Construct variable name CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
190 // if user calls UpdateCapsule multiple times.
191 //
192 StrCpyS (CapsuleVarName, sizeof (CapsuleVarName)/sizeof (CHAR16), EFI_CAPSULE_VARIABLE_NAME);
193 TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
194 if (mTimes > 0) {
196 TempVarName,
197 sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName),
198 0,
199 mTimes,
200 0
201 );
202 }
203
204 //
205 // ScatterGatherList is only referenced if the capsules are defined to persist across
206 // system reset. Set its value into NV storage to let pre-boot driver to pick it up
207 // after coming through a system reset.
208 //
209 Status = EfiSetVariable (
210 CapsuleVarName,
211 &gEfiCapsuleVendorGuid,
212 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
213 sizeof (UINTN),
214 (VOID *)&ScatterGatherList
215 );
216 if (!EFI_ERROR (Status)) {
217 //
218 // Variable has been set successfully, increase variable index.
219 //
220 mTimes++;
221 if (InitiateReset) {
222 //
223 // Firmware that encounters a capsule which has the CAPSULE_FLAGS_INITIATE_RESET Flag set in its header
224 // will initiate a reset of the platform which is compatible with the passed-in capsule request and will
225 // not return back to the caller.
226 //
228 }
229 }
230
231 return Status;
232}
233
266EFIAPI
268 IN EFI_CAPSULE_HEADER **CapsuleHeaderArray,
269 IN UINTN CapsuleCount,
270 OUT UINT64 *MaxiumCapsuleSize,
271 OUT EFI_RESET_TYPE *ResetType
272 )
273{
274 EFI_STATUS Status;
275 UINTN ArrayNumber;
276 EFI_CAPSULE_HEADER *CapsuleHeader;
277 BOOLEAN NeedReset;
278
279 //
280 // Capsule Count can't be less than one.
281 //
282 if (CapsuleCount < 1) {
283 return EFI_INVALID_PARAMETER;
284 }
285
286 //
287 // Check whether input parameter is valid
288 //
289 if ((MaxiumCapsuleSize == NULL) || (ResetType == NULL)) {
290 return EFI_INVALID_PARAMETER;
291 }
292
293 CapsuleHeader = NULL;
294 NeedReset = FALSE;
295
296 for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {
297 CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
298 //
299 // A capsule which has the CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag must have
300 // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.
301 //
302 if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {
303 return EFI_INVALID_PARAMETER;
304 }
305
306 //
307 // A capsule which has the CAPSULE_FLAGS_INITIATE_RESET flag must have
308 // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.
309 //
310 if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_INITIATE_RESET)) == CAPSULE_FLAGS_INITIATE_RESET) {
311 return EFI_INVALID_PARAMETER;
312 }
313
314 //
315 // Check FMP capsule flag
316 //
317 if ( CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)
318 && ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0))
319 {
320 return EFI_INVALID_PARAMETER;
321 }
322
323 //
324 // Check Capsule image without populate flag is supported by firmware
325 //
326 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {
327 Status = SupportCapsuleImage (CapsuleHeader);
328 if (EFI_ERROR (Status)) {
329 return Status;
330 }
331 }
332 }
333
334 //
335 // Find out whether there is any capsule defined to persist across system reset.
336 //
337 for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {
338 CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
339 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
340 NeedReset = TRUE;
341 break;
342 }
343 }
344
345 if (NeedReset) {
346 //
347 // Check if the platform supports update capsule across a system reset
348 //
350 return EFI_UNSUPPORTED;
351 }
352
353 *ResetType = EfiResetWarm;
354 *MaxiumCapsuleSize = (UINT64)mMaxSizePopulateCapsule;
355 } else {
356 //
357 // For non-reset capsule image.
358 //
359 *ResetType = EfiResetCold;
360 *MaxiumCapsuleSize = (UINT64)mMaxSizeNonPopulateCapsule;
361 }
362
363 return EFI_SUCCESS;
364}
365
377EFIAPI
379 IN EFI_HANDLE ImageHandle,
380 IN EFI_SYSTEM_TABLE *SystemTable
381 )
382{
383 EFI_STATUS Status;
384
385 mMaxSizePopulateCapsule = PcdGet32 (PcdMaxSizePopulateCapsule);
386 mMaxSizeNonPopulateCapsule = PcdGet32 (PcdMaxSizeNonPopulateCapsule);
387
388 //
389 // When PEI phase is IA32, DXE phase is X64, it is possible that capsule data are
390 // put above 4GB, so capsule PEI will transfer to long mode to get capsule data.
391 // The page table and stack is used to transfer processor mode from IA32 to long mode.
392 // Create the base address of page table and stack, and save them into variable.
393 // This is not needed when capsule with reset type is not supported.
394 //
396
397 //
398 // Install capsule runtime services into UEFI runtime service tables.
399 //
400 gRT->UpdateCapsule = UpdateCapsule;
401 gRT->QueryCapsuleCapabilities = QueryCapsuleCapabilities;
402
403 //
404 // Install the Capsule Architectural Protocol on a new handle
405 // to signify the capsule runtime services are ready.
406 //
407 Status = gBS->InstallMultipleProtocolInterfaces (
408 &mNewHandle,
409 &gEfiCapsuleArchProtocolGuid,
410 NULL,
411 NULL
412 );
413 ASSERT_EFI_ERROR (Status);
414
415 return Status;
416}
UINT64 UINTN
BOOLEAN IsPersistAcrossResetCapsuleSupported(VOID)
Definition: CapsuleReset.c:23
RETURN_STATUS EFIAPI StrCpyS(OUT CHAR16 *Destination, IN UINTN DestMax, IN CONST CHAR16 *Source)
Definition: SafeString.c:226
UINTN EFIAPI StrLen(IN CONST CHAR16 *String)
Definition: String.c:30
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
Definition: MemLibGuid.c:73
VOID CapsuleCacheWriteBack(IN EFI_PHYSICAL_ADDRESS ScatterGatherList)
Definition: CapsuleCache.c:26
EFI_STATUS EFIAPI ProcessCapsuleImage(IN EFI_CAPSULE_HEADER *CapsuleHeader)
EFI_STATUS EFIAPI SupportCapsuleImage(IN EFI_CAPSULE_HEADER *CapsuleHeader)
EFI_STATUS EFIAPI QueryCapsuleCapabilities(IN EFI_CAPSULE_HEADER **CapsuleHeaderArray, IN UINTN CapsuleCount, OUT UINT64 *MaxiumCapsuleSize, OUT EFI_RESET_TYPE *ResetType)
EFI_STATUS EFIAPI CapsuleServiceInitialize(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
EFI_STATUS EFIAPI UpdateCapsule(IN EFI_CAPSULE_HEADER **CapsuleHeaderArray, IN UINTN CapsuleCount, IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL)
VOID SaveLongModeContext(VOID)
#define EFI_CAPSULE_VARIABLE_NAME
Definition: CapsuleVendor.h:33
RETURN_STATUS EFIAPI UnicodeValueToStringS(IN OUT CHAR16 *Buffer, IN UINTN BufferSize, IN UINTN Flags, IN INT64 Value, IN UINTN Width)
Definition: PrintLib.c:652
EFI_RUNTIME_SERVICES * gRT
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define PcdGet32(TokenName)
Definition: PcdLib.h:362
#define PcdGetBool(TokenName)
Definition: PcdLib.h:401
#define FeaturePcdGet(TokenName)
Definition: PcdLib.h:50
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
EFI_RESET_TYPE
@ EfiResetCold
@ EfiResetWarm
#define EFI_VARIABLE_NON_VOLATILE
BOOLEAN EFIAPI EfiAtRuntime(VOID)
Definition: RuntimeLib.c:167
VOID EFIAPI EfiResetSystem(IN EFI_RESET_TYPE ResetType, IN EFI_STATUS ResetStatus, IN UINTN DataSize, IN VOID *ResetData OPTIONAL)
Definition: RuntimeLib.c:226
EFI_STATUS EFIAPI EfiSetVariable(IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN UINT32 Attributes, IN UINTN DataSize, IN VOID *Data)
Definition: RuntimeLib.c:498
EFI_GUID CapsuleGuid
Definition: UefiSpec.h:1682