1 /** @file
2   Generic Capsule services
3 
4   Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
5 
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include <Common/CapsuleName.h>
17 
18 
19 //
20 //Max size capsule services support are platform policy,to populate capsules we just need
21 //memory to maintain them across reset,it is not a problem. And to special capsules ,for
22 //example,update flash,it is mostly decided by the platform. Here is a sample size for
23 //different type capsules.
24 //
25 #define MAX_SIZE_POPULATE              (0)
26 #define MAX_SIZE_NON_POPULATE          (0)
27 #define MAX_SUPPORT_CAPSULE_NUM        0x10
28 
29 
30 BOOLEAN
31 EFIAPI
SupportUpdateCapsuleRest(VOID)32 SupportUpdateCapsuleRest (
33   VOID
34   )
35 {
36   //
37   //If the platform has a way to guarantee the memory integrity across a system reset, return
38   //TRUE, else FALSE.
39   //
40   return FALSE;
41 }
42 
43 
44 
45 VOID
46 EFIAPI
SupportCapsuleSize(IN OUT UINT32 * MaxSizePopulate,IN OUT UINT32 * MaxSizeNonPopulate)47 SupportCapsuleSize (
48   IN OUT UINT32 *MaxSizePopulate,
49   IN OUT UINT32 *MaxSizeNonPopulate
50   )
51 {
52   //
53   //Here is a sample size, different platforms have different sizes.
54   //
55   *MaxSizePopulate    = MAX_SIZE_POPULATE;
56   *MaxSizeNonPopulate = MAX_SIZE_NON_POPULATE;
57   return;
58 }
59 
60 
61 
62 
63 EFI_STATUS
LibUpdateCapsule(IN UEFI_CAPSULE_HEADER ** CapsuleHeaderArray,IN UINTN CapsuleCount,IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL)64 LibUpdateCapsule (
65   IN UEFI_CAPSULE_HEADER     **CapsuleHeaderArray,
66   IN UINTN                   CapsuleCount,
67   IN EFI_PHYSICAL_ADDRESS    ScatterGatherList OPTIONAL
68   )
69 /*++
70 
71 Routine Description:
72 
73   This code finds if the capsule needs reset to update, if no, update immediately.
74 
75 Arguments:
76 
77   CapsuleHeaderArray             A array of pointers to capsule headers passed in
78   CapsuleCount                   The number of capsule
79   ScatterGatherList              Physical address of datablock list points to capsule
80 
81 Returns:
82 
83   EFI STATUS
84   EFI_SUCCESS                    Valid capsule was passed.If CAPSULE_FLAG_PERSIT_ACROSS_RESET is
85                                  not set, the capsule has been successfully processed by the firmware.
86                                  If it set, the ScattlerGatherList is successfully to be set.
87   EFI_INVALID_PARAMETER          CapsuleCount is less than 1,CapsuleGuid is not supported.
88   EFI_DEVICE_ERROR               Failed to SetVariable or AllocatePool or ProcessFirmwareVolume.
89 
90 --*/
91 {
92   UINTN                     CapsuleSize;
93   UINTN                     ArrayNumber;
94   VOID                      *BufferPtr;
95   EFI_STATUS                Status;
96   EFI_HANDLE                FvHandle;
97   UEFI_CAPSULE_HEADER       *CapsuleHeader;
98 
99   if ((CapsuleCount < 1) || (CapsuleCount > MAX_SUPPORT_CAPSULE_NUM)){
100     return EFI_INVALID_PARAMETER;
101   }
102 
103   BufferPtr       = NULL;
104   CapsuleHeader   = NULL;
105 
106   //
107   //Compare GUIDs with EFI_CAPSULE_GUID, if capsule header contains CAPSULE_FLAGS_PERSIST_ACROSS_RESET
108   //and CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flags,whatever the GUID is ,the service supports.
109   //
110   for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {
111     CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
112     if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {
113       return EFI_INVALID_PARAMETER;
114     }
115     if (!CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiCapsuleGuid)) {
116       if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {
117         return EFI_UNSUPPORTED;
118       }
119     }
120   }
121 
122   //
123   //Assume that capsules have the same flags on resetting or not.
124   //
125   CapsuleHeader = CapsuleHeaderArray[0];
126 
127   if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
128     //
129     //Check if the platform supports update capsule across a system reset
130     //
131     if (!SupportUpdateCapsuleRest()) {
132       return EFI_UNSUPPORTED;
133     }
134 
135     if (ScatterGatherList == 0) {
136       return EFI_INVALID_PARAMETER;
137     } else {
138       Status = EfiSetVariable (
139                  EFI_CAPSULE_VARIABLE_NAME,
140                  &gEfiCapsuleVendorGuid,
141                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
142                  sizeof (UINTN),
143                  (VOID *) &ScatterGatherList
144                  );
145       if (Status != EFI_SUCCESS) {
146         return EFI_DEVICE_ERROR;
147       }
148     }
149     return EFI_SUCCESS;
150   }
151 
152   //
153   //The rest occurs in the condition of non-reset mode
154   //
155   if (EfiAtRuntime ()) {
156     return EFI_INVALID_PARAMETER;
157   }
158 
159   //
160   //Here should be in the boot-time
161   //
162   for (ArrayNumber = 0; ArrayNumber < CapsuleCount ; ArrayNumber++) {
163     CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
164     CapsuleSize = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
165     Status = gBS->AllocatePool (EfiBootServicesData, CapsuleSize, &BufferPtr);
166     if (Status != EFI_SUCCESS) {
167       goto Done;
168     }
169     gBS->CopyMem (BufferPtr, (UINT8*)CapsuleHeader+ CapsuleHeader->HeaderSize, CapsuleSize);
170 
171     //
172     //Call DXE service ProcessFirmwareVolume to process immediatelly
173     //
174     Status = gDS->ProcessFirmwareVolume (BufferPtr, CapsuleSize, &FvHandle);
175     if (Status != EFI_SUCCESS) {
176       gBS->FreePool (BufferPtr);
177       return EFI_DEVICE_ERROR;
178     }
179     gDS->Dispatch ();
180     gBS->FreePool (BufferPtr);
181   }
182   return EFI_SUCCESS;
183 
184 Done:
185   if (BufferPtr != NULL) {
186     gBS->FreePool (BufferPtr);
187   }
188   return EFI_DEVICE_ERROR;
189 }
190 
191 
192 EFI_STATUS
QueryCapsuleCapabilities(IN UEFI_CAPSULE_HEADER ** CapsuleHeaderArray,IN UINTN CapsuleCount,OUT UINT64 * MaxiumCapsuleSize,OUT EFI_RESET_TYPE * ResetType)193 QueryCapsuleCapabilities (
194   IN  UEFI_CAPSULE_HEADER  **CapsuleHeaderArray,
195   IN  UINTN                CapsuleCount,
196   OUT UINT64               *MaxiumCapsuleSize,
197   OUT EFI_RESET_TYPE       *ResetType
198   )
199 /*++
200 
201 Routine Description:
202 
203   This code is query about capsule capability.
204 
205 Arguments:
206 
207   CapsuleHeaderArray              A array of pointers to capsule headers passed in
208   CapsuleCount                    The number of capsule
209   MaxiumCapsuleSize               Max capsule size is supported
210   ResetType                       Reset type the capsule indicates, if reset is not needed,return EfiResetCold.
211                                   If reset is needed, return EfiResetWarm.
212 
213 Returns:
214 
215   EFI STATUS
216   EFI_SUCCESS                     Valid answer returned
217   EFI_INVALID_PARAMETER           MaxiumCapsuleSize is NULL,ResetType is NULL.CapsuleCount is less than 1,CapsuleGuid is not supported.
218   EFI_UNSUPPORTED                 The capsule type is not supported.
219 
220 --*/
221 {
222   UINTN                     ArrayNumber;
223   UEFI_CAPSULE_HEADER       *CapsuleHeader;
224   UINT32                    MaxSizePopulate;
225   UINT32                    MaxSizeNonPopulate;
226 
227 
228   if ((CapsuleCount < 1) || (CapsuleCount > MAX_SUPPORT_CAPSULE_NUM)){
229     return EFI_INVALID_PARAMETER;
230   }
231 
232   if ((MaxiumCapsuleSize == NULL) ||(ResetType == NULL)) {
233     return EFI_INVALID_PARAMETER;
234   }
235 
236   CapsuleHeader = NULL;
237 
238   //
239   //Compare GUIDs with EFI_CAPSULE_GUID, if capsule header contains CAPSULE_FLAGS_PERSIST_ACROSS_RESET
240   //and CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flags,whatever the GUID is ,the service supports.
241   //
242   for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {
243     CapsuleHeader = CapsuleHeaderArray[ArrayNumber];
244     if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {
245       return EFI_INVALID_PARAMETER;
246     }
247     if (!CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiCapsuleGuid)) {
248       if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {
249         return EFI_UNSUPPORTED;
250       }
251     }
252   }
253 
254   SupportCapsuleSize(&MaxSizePopulate,&MaxSizeNonPopulate);
255   //
256   //Assume that capsules have the same flags on resetting or not.
257   //
258   CapsuleHeader = CapsuleHeaderArray[0];
259   if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
260     //
261     //Check if the platform supports update capsule across a system reset
262     //
263     if (!SupportUpdateCapsuleRest()) {
264       return EFI_UNSUPPORTED;
265     }
266     *ResetType = EfiResetWarm;
267     *MaxiumCapsuleSize = MaxSizePopulate;
268   } else {
269     *ResetType = EfiResetCold;
270     *MaxiumCapsuleSize = MaxSizeNonPopulate;
271   }
272   return EFI_SUCCESS;
273 }
274 
275 
276 VOID
LibCapsuleVirtualAddressChangeEvent(VOID)277 LibCapsuleVirtualAddressChangeEvent (
278   VOID
279   )
280 {
281 }
282 
283 VOID
LibCapsuleInitialize(VOID)284 LibCapsuleInitialize (
285   VOID
286   )
287 {
288 }
289