Add CapsuleInfo guid to store the list of capsule image guid.
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Universal / CapsuleRuntimeDxe / CapsuleService.c
1 /*++\r
2 \r
3 Copyright (c) 2006 - 2007, Intel Corporation\r
4 All rights reserved. This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 \r
12 Module Name:\r
13 \r
14   CapsuleService.c\r
15 \r
16 Abstract:\r
17 \r
18   Capsule Runtime Service.\r
19 \r
20 --*/\r
21 \r
22 #include "CapsuleService.h"\r
23 \r
24 EFI_STATUS\r
25 EFIAPI\r
26 UpdateCapsule (\r
27   IN EFI_CAPSULE_HEADER      **CapsuleHeaderArray,\r
28   IN UINTN                   CapsuleCount,\r
29   IN EFI_PHYSICAL_ADDRESS    ScatterGatherList OPTIONAL\r
30   )\r
31 /*++\r
32 \r
33 Routine Description:\r
34 \r
35   This code finds whether the capsules need reset to update, if not, update immediately.\r
36 \r
37 Arguments:\r
38 \r
39   CapsuleHeaderArray             A array of pointers to capsule headers passed in\r
40   CapsuleCount                   The number of capsule\r
41   ScatterGatherList              Physical address of datablock list points to capsule\r
42 \r
43 Returns:\r
44 \r
45   EFI STATUS\r
46   EFI_SUCCESS                    Valid capsule was passed.If CAPSULE_FLAG_PERSIT_ACROSS_RESET is\r
47                                  not set, the capsule has been successfully processed by the firmware.\r
48                                  If it set, the ScattlerGatherList is successfully to be set.\r
49   EFI_INVALID_PARAMETER          CapsuleCount is less than 1,CapsuleGuid is not supported.\r
50   EFI_DEVICE_ERROR               Failed to SetVariable or AllocatePool or ProcessFirmwareVolume.\r
51 \r
52 --*/\r
53 {\r
54   UINTN                     CapsuleSize;\r
55   UINTN                     ArrayNumber;\r
56   VOID                      *BufferPtr;\r
57   EFI_STATUS                Status;\r
58   EFI_HANDLE                FvHandle;\r
59   EFI_CAPSULE_HEADER        *CapsuleHeader;\r
60 \r
61   if (CapsuleCount < 1) {\r
62     return EFI_INVALID_PARAMETER;\r
63   }\r
64 \r
65   BufferPtr       = NULL;\r
66   CapsuleHeader   = NULL;\r
67 \r
68   for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {\r
69     //\r
70     // A capsule which has the CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag must have\r
71     // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.\r
72     //\r
73     CapsuleHeader = CapsuleHeaderArray[ArrayNumber];\r
74     if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {\r
75       return EFI_INVALID_PARAMETER;\r
76     }\r
77     //\r
78     // To remove this check. Capsule update supports non reset image.\r
79     // \r
80     //    if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {\r
81     //      return EFI_UNSUPPORTED;\r
82     //    }\r
83   }\r
84 \r
85   //\r
86   // Check capsule guid is suppored by this platform. To do\r
87   //\r
88 \r
89   //\r
90   //Assume that capsules have the same flags on reseting or not.\r
91   //\r
92   CapsuleHeader = CapsuleHeaderArray[0];\r
93 \r
94   if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
95     //\r
96     //Check if the platform supports update capsule across a system reset\r
97     //\r
98     if (!FeaturePcdGet(PcdSupportUpdateCapsuleRest)) {\r
99       return EFI_UNSUPPORTED;\r
100     }\r
101     //\r
102     // ScatterGatherList is only referenced if the capsules are defined to persist across\r
103     // system reset. \r
104     //\r
105     if (ScatterGatherList == (EFI_PHYSICAL_ADDRESS) NULL) {\r
106       return EFI_INVALID_PARAMETER;\r
107     } else {\r
108       //\r
109       // ScatterGatherList is only referenced if the capsules are defined to persist across\r
110       // system reset. Set its value into NV storage to let pre-boot driver to pick it up \r
111       // after coming through a system reset.\r
112       //\r
113       Status = EfiSetVariable (\r
114                  EFI_CAPSULE_VARIABLE_NAME,\r
115                  &gEfiCapsuleVendorGuid,\r
116                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
117                  sizeof (UINTN),\r
118                  (VOID *) &ScatterGatherList\r
119                  );\r
120       if (Status != EFI_SUCCESS) {\r
121         return Status;\r
122       }\r
123     }\r
124     return EFI_SUCCESS;\r
125   }\r
126 \r
127   //\r
128   // The rest occurs in the condition of non-reset mode\r
129   // Current Runtime mode doesn't support the non-reset capsule image.\r
130   //\r
131   if (EfiAtRuntime ()) {\r
132     return EFI_INVALID_PARAMETER;\r
133   }\r
134 \r
135   //\r
136   // Here should be in the boot-time for non-reset capsule image\r
137   // Default process to Update Capsule image into Flash for any guid image.\r
138   //\r
139   for (ArrayNumber = 0; ArrayNumber < CapsuleCount ; ArrayNumber++) {\r
140     CapsuleHeader = CapsuleHeaderArray[ArrayNumber];\r
141     CapsuleSize = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;\r
142 \r
143     BufferPtr = AllocatePool (CapsuleSize);\r
144     if (BufferPtr == NULL) {\r
145       return EFI_OUT_OF_RESOURCES;\r
146     }\r
147 \r
148     CopyMem (BufferPtr, (UINT8*)CapsuleHeader+ CapsuleHeader->HeaderSize, CapsuleSize);\r
149 \r
150     //\r
151     //Call DXE service ProcessFirmwareVolume to process immediatelly\r
152     //\r
153     Status = gDS->ProcessFirmwareVolume (BufferPtr, CapsuleSize, &FvHandle);\r
154     if (Status != EFI_SUCCESS) {\r
155       FreePool (BufferPtr);\r
156       return Status;\r
157     }\r
158     gDS->Dispatch ();\r
159     FreePool (BufferPtr);\r
160   }\r
161 \r
162   return EFI_SUCCESS;\r
163 }\r
164 \r
165 \r
166 \r
167 EFI_STATUS\r
168 EFIAPI\r
169 QueryCapsuleCapabilities (\r
170   IN  EFI_CAPSULE_HEADER   **CapsuleHeaderArray,\r
171   IN  UINTN                CapsuleCount,\r
172   OUT UINT64               *MaxiumCapsuleSize,\r
173   OUT EFI_RESET_TYPE       *ResetType\r
174   )\r
175 /*++\r
176 \r
177 Routine Description:\r
178 \r
179   This code is to query about capsule capability.\r
180 \r
181 Arguments:\r
182 \r
183   CapsuleHeaderArray              A array of pointers to capsule headers passed in\r
184   CapsuleCount                    The number of capsule\r
185   MaxiumCapsuleSize               Max capsule size is supported\r
186   ResetType                       Reset type the capsule indicates, if reset is not needed,return EfiResetCold.\r
187                                   If reset is needed, return EfiResetWarm.\r
188 \r
189 Returns:\r
190 \r
191   EFI STATUS\r
192   EFI_SUCCESS                     Valid answer returned\r
193   EFI_INVALID_PARAMETER           MaxiumCapsuleSize is NULL,ResetType is NULL.CapsuleCount is less than 1,CapsuleGuid is not supported.\r
194   EFI_UNSUPPORTED                 The capsule type is not supported.\r
195 \r
196 --*/\r
197 {\r
198   UINTN                     ArrayNumber;\r
199   EFI_CAPSULE_HEADER        *CapsuleHeader;\r
200 \r
201   if (CapsuleCount < 1) {\r
202     return EFI_INVALID_PARAMETER;\r
203   }\r
204 \r
205   if ((MaxiumCapsuleSize == NULL) ||(ResetType == NULL)) {\r
206     return EFI_INVALID_PARAMETER;\r
207   }\r
208 \r
209   CapsuleHeader = NULL;\r
210 \r
211   for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) {\r
212     CapsuleHeader = CapsuleHeaderArray[ArrayNumber];\r
213     //\r
214     // A capsule which has the CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag must have\r
215     // CAPSULE_FLAGS_PERSIST_ACROSS_RESET set in its header as well.\r
216     //\r
217     if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) {\r
218       return EFI_INVALID_PARAMETER;\r
219     }\r
220     //\r
221     // To remove this check. Capsule update supports non reset image.\r
222     // \r
223     //    if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {\r
224     //      return EFI_UNSUPPORTED;\r
225     //    }\r
226   }\r
227 \r
228   //\r
229   //Assume that capsules have the same flags on reseting or not.\r
230   //\r
231   CapsuleHeader = CapsuleHeaderArray[0];\r
232   if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
233     //\r
234     //Check if the platform supports update capsule across a system reset\r
235     //\r
236     if (!FeaturePcdGet(PcdSupportUpdateCapsuleRest)) {\r
237       return EFI_UNSUPPORTED;\r
238     }\r
239     *ResetType = EfiResetWarm;\r
240     *MaxiumCapsuleSize = FixedPcdGet32(PcdMaxSizePopulateCapsule);\r
241   } else {\r
242     *ResetType = EfiResetCold;\r
243     *MaxiumCapsuleSize = FixedPcdGet32(PcdMaxSizeNonPopulateCapsule);\r
244   }\r
245   return EFI_SUCCESS;\r
246 }\r
247 \r
248 \r
249 EFI_STATUS\r
250 EFIAPI\r
251 CapsuleServiceInitialize (\r
252   IN EFI_HANDLE         ImageHandle,\r
253   IN EFI_SYSTEM_TABLE   *SystemTable\r
254   )\r
255 /*++\r
256 \r
257 Routine Description:\r
258 \r
259   This code is capsule runtime service initialization.\r
260 \r
261 Arguments:\r
262 \r
263   ImageHandle          The image handle\r
264   SystemTable          The system table.\r
265 \r
266 Returns:\r
267 \r
268   EFI STATUS\r
269 \r
270 --*/\r
271 {\r
272   EFI_STATUS  Status;\r
273   EFI_HANDLE  NewHandle;\r
274 \r
275   SystemTable->RuntimeServices->UpdateCapsule                    = UpdateCapsule;\r
276   SystemTable->RuntimeServices->QueryCapsuleCapabilities         = QueryCapsuleCapabilities;\r
277 \r
278   //\r
279   // Now install the Capsule Architectural Protocol on a new handle\r
280   //\r
281   NewHandle = NULL;\r
282 \r
283   Status = gBS->InstallMultipleProtocolInterfaces (\r
284                   &NewHandle,\r
285                   &gEfiCapsuleArchProtocolGuid,\r
286                   NULL,\r
287                   NULL\r
288                   );\r
289   ASSERT_EFI_ERROR (Status);\r
290 \r
291   return EFI_SUCCESS;\r
292 }\r