1.Port Platform driver override protocol utility application in MdeModulePkg.dsc.
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Library / DxePlatDriOverLib / PlatDriOverLib.c
1 /** @file\r
2 \r
3 Copyright (c) 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     PlatDriOverLib.c\r
15 \r
16 Abstract:\r
17 \r
18 \r
19 **/\r
20 \r
21 #include "PlatDriOver.h"\r
22 \r
23 STATIC LIST_ENTRY   mDevicePathStack = INITIALIZE_LIST_HEAD_VARIABLE (mDevicePathStack);\r
24 \r
25 \r
26 /**\r
27   Install the Platform Driver Override Protocol, and ensure there is only one Platform Driver Override Protocol\r
28   in the system.\r
29 \r
30   @param  gPlatformDriverOverride  PlatformDriverOverride protocol interface which\r
31                                    needs to be installed\r
32 \r
33   @retval EFI_ALREADY_STARTED      There has been a Platform Driver Override\r
34                                    Protocol in the system, cannot install it again.\r
35   @retval Other                    Returned by InstallProtocolInterface\r
36 \r
37 **/\r
38 EFI_STATUS\r
39 EFIAPI\r
40 InstallPlatformDriverOverrideProtocol (\r
41   EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL *gPlatformDriverOverride\r
42   )\r
43 {\r
44   EFI_HANDLE          Handle;\r
45   EFI_STATUS          Status;\r
46   UINTN               HandleCount;\r
47   EFI_HANDLE          *HandleBuffer;\r
48 \r
49   //\r
50   // There will be only one platform driver override protocol in the system\r
51   // If there is another out there, someone is trying to install us again,\r
52   // Fail that scenario.\r
53   //\r
54   Status = gBS->LocateHandleBuffer (\r
55                   ByProtocol,\r
56                   &gEfiPlatformDriverOverrideProtocolGuid,\r
57                   NULL,\r
58                   &HandleCount,\r
59                   &HandleBuffer\r
60                   );\r
61   //\r
62   // If there was no error, assume there is an installation and return error\r
63   //\r
64   if (!EFI_ERROR (Status)) {\r
65     if (HandleBuffer != NULL) {\r
66       FreePool (HandleBuffer);\r
67     }\r
68     return EFI_ALREADY_STARTED;\r
69   }\r
70 \r
71   //\r
72   // Install platform driver override protocol\r
73   //\r
74   Handle = NULL;\r
75   Status = gBS->InstallProtocolInterface (\r
76                   &Handle,\r
77                   &gEfiPlatformDriverOverrideProtocolGuid,\r
78                   EFI_NATIVE_INTERFACE,\r
79                   gPlatformDriverOverride\r
80                   );\r
81   return Status;\r
82 }\r
83 \r
84 \r
85 /**\r
86   Free all the mapping database memory resource and initialize the mapping list entry\r
87 \r
88   @param  MappingDataBase          Mapping database list entry pointer\r
89 \r
90   @retval EFI_INVALID_PARAMETER    mapping database list entry is NULL\r
91   @retval EFI_SUCCESS              Free success\r
92 \r
93 **/\r
94 EFI_STATUS\r
95 EFIAPI\r
96 FreeMappingDatabase (\r
97   IN  OUT  LIST_ENTRY            *MappingDataBase\r
98   )\r
99 {\r
100   LIST_ENTRY                  *OverrideItemListIndex;\r
101   LIST_ENTRY                  *ImageInfoListIndex;\r
102   PLATFORM_OVERRIDE_ITEM      *OverrideItem;\r
103   DRIVER_IMAGE_INFO           *DriverImageInfo;\r
104 \r
105   if (MappingDataBase == NULL) {\r
106     return EFI_INVALID_PARAMETER;\r
107   }\r
108 \r
109   OverrideItemListIndex = MappingDataBase->ForwardLink;\r
110   while (OverrideItemListIndex != MappingDataBase){\r
111     OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);\r
112     //\r
113     // Free PLATFORM_OVERRIDE_ITEM.ControllerDevicePath[]\r
114     //\r
115     if (OverrideItem->ControllerDevicePath != NULL){\r
116       FreePool(OverrideItem->ControllerDevicePath);\r
117     }\r
118 \r
119     ImageInfoListIndex =  OverrideItem->DriverInfoList.ForwardLink;\r
120     while (ImageInfoListIndex != &OverrideItem->DriverInfoList){\r
121       //\r
122       // Free all DRIVER_IMAGE_INFO.DriverImagePath[]\r
123       //\r
124       DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);\r
125       if (DriverImageInfo->DriverImagePath != NULL) {\r
126         FreePool(DriverImageInfo->DriverImagePath);\r
127       }\r
128       //\r
129       // Free DRIVER_IMAGE_INFO itself\r
130       //\r
131       ImageInfoListIndex = ImageInfoListIndex->ForwardLink;\r
132       RemoveEntryList (&DriverImageInfo->Link);\r
133       FreePool (DriverImageInfo);\r
134     }\r
135     //\r
136     // Free PLATFORM_OVERRIDE_ITEM itself\r
137     //\r
138     OverrideItemListIndex =  OverrideItemListIndex->ForwardLink;\r
139     RemoveEntryList (&OverrideItem->Link);\r
140     FreePool (OverrideItem);\r
141   }\r
142 \r
143   InitializeListHead (MappingDataBase);\r
144   return EFI_SUCCESS;\r
145 }\r
146 \r
147 \r
148 /**\r
149   Read the environment variable(s) that contain the override mappings from Controller Device Path to\r
150   a set of Driver Device Paths, and create the mapping database in memory with those variable info.\r
151   VariableLayout{\r
152   //\r
153   // NotEnd indicate whether the variable is the last one, and has no subsequent variable need to load.\r
154   // Each variable has MaximumVariableSize limitation, so  we maybe need multi variables to store\r
155   // large mapping infos.\r
156   // The variable(s) name rule is PlatDriOver, PlatDriOver1, PlatDriOver2, ....\r
157   //\r
158   UINT32                         NotEnd;\r
159   //\r
160   // The entry which contains the mapping that Controller Device Path to a set of Driver Device Paths\r
161   // There are often multi mapping entries in a variable.\r
162   //\r
163   UINT32                         SIGNATURE;            //EFI_SIGNATURE_32('p','d','o','i')\r
164   UINT32                         DriverNum;\r
165   EFI_DEVICE_PATH_PROTOCOL       ControllerDevicePath[];\r
166   EFI_DEVICE_PATH_PROTOCOL       DriverDevicePath[];\r
167   EFI_DEVICE_PATH_PROTOCOL       DriverDevicePath[];\r
168   EFI_DEVICE_PATH_PROTOCOL       DriverDevicePath[];\r
169   ......\r
170   UINT32                         SIGNATURE;\r
171   UINT32                         DriverNum;\r
172   EFI_DEVICE_PATH_PROTOCOL       ControllerDevicePath[];\r
173   EFI_DEVICE_PATH_PROTOCOL       DriverDevicePath[];\r
174   EFI_DEVICE_PATH_PROTOCOL       DriverDevicePath[];\r
175   EFI_DEVICE_PATH_PROTOCOL       DriverDevicePath[];\r
176   ......\r
177   }\r
178   typedef struct _PLATFORM_OVERRIDE_ITEM{\r
179   UINTN                          Signature;                  //EFI_SIGNATURE_32('p','d','o','i')\r
180   LIST_ENTRY                     Link;\r
181   UINT32                         DriverInfoNum;\r
182   EFI_DEVICE_PATH_PROTOCOL       *ControllerDevicePath;\r
183   LIST_ENTRY                     DriverInfoList;         //DRIVER_IMAGE_INFO List\r
184   } PLATFORM_OVERRIDE_ITEM;\r
185   typedef struct _DRIVER_IMAGE_INFO{\r
186   UINTN                          Signature;                  //EFI_SIGNATURE_32('p','d','i','i')\r
187   LIST_ENTRY                     Link;\r
188   EFI_HANDLE                     ImageHandle;\r
189   EFI_DEVICE_PATH_PROTOCOL       *DriverImagePath;\r
190   BOOLEAN                        UnLoadable;\r
191   BOOLEAN                        UnStartable;\r
192   } DRIVER_IMAGE_INFO;\r
193 \r
194   @param  MappingDataBase          Mapping database list entry pointer\r
195 \r
196   @retval EFI_INVALID_PARAMETER    MappingDataBase pointer is null\r
197   @retval EFI_NOT_FOUND            Cannot find the 'PlatDriOver' NV variable\r
198   @retval EFI_VOLUME_CORRUPTED     The found NV variable is corrupted\r
199   @retval EFI_SUCCESS              Create the mapping database in memory\r
200                                    successfully\r
201 \r
202 **/\r
203 EFI_STATUS\r
204 EFIAPI\r
205 InitOverridesMapping (\r
206   OUT  LIST_ENTRY            *MappingDataBase\r
207   )\r
208 {\r
209   UINTN                       BufferSize;\r
210   VOID                        *VariableBuffer;\r
211   UINT8                       *VariableIndex;\r
212   UINTN                       VariableNum;\r
213   CHAR16                      OverrideVariableName[40];\r
214   UINT32                      NotEnd;\r
215   UINT32                      DriverNumber;\r
216   PLATFORM_OVERRIDE_ITEM      *OverrideItem;\r
217   DRIVER_IMAGE_INFO           *DriverImageInfo;\r
218   BOOLEAN                     Corrupted;\r
219   UINT32                      Signature;\r
220   EFI_DEVICE_PATH_PROTOCOL    *ControllerDevicePath;\r
221   EFI_DEVICE_PATH_PROTOCOL    *DriverDevicePath;\r
222   UINTN                       Index;\r
223 \r
224   if (MappingDataBase == NULL) {\r
225     return EFI_INVALID_PARAMETER;\r
226   }\r
227 \r
228   VariableNum = 0;\r
229   Corrupted = FALSE;\r
230   //\r
231   // Check the environment variable(s) that contain the override mappings .\r
232   //\r
233   VariableBuffer = GetVariableAndSize (L"PlatDriOver", &gEfiOverrideVariableGuid, &BufferSize);\r
234   ASSERT ((UINTN) VariableBuffer % sizeof(UINTN) == 0);\r
235   VariableNum ++;\r
236   if (VariableBuffer == NULL) {\r
237     return EFI_NOT_FOUND;\r
238   }\r
239 \r
240   do {\r
241     VariableIndex = VariableBuffer;\r
242     NotEnd = *(UINT32*) VariableIndex;\r
243     VariableIndex = VariableIndex + sizeof (UINT32);\r
244     while (VariableIndex < ((UINT8 *)VariableBuffer + BufferSize)) {\r
245       OverrideItem = AllocateZeroPool (sizeof (PLATFORM_OVERRIDE_ITEM));\r
246       ASSERT (OverrideItem != NULL);\r
247       OverrideItem->Signature = PLATFORM_OVERRIDE_ITEM_SIGNATURE;\r
248       InitializeListHead (&OverrideItem->DriverInfoList);\r
249       //\r
250       // Check SIGNATURE\r
251       //\r
252       Signature = *(UINT32 *) VariableIndex;\r
253       VariableIndex = VariableIndex + sizeof (UINT32);\r
254       if (Signature != PLATFORM_OVERRIDE_ITEM_SIGNATURE) {\r
255         FreePool (OverrideItem);\r
256         Corrupted = TRUE;\r
257         break;\r
258       }\r
259       //\r
260       // Get DriverNum\r
261       //\r
262       DriverNumber = *(UINT32*) VariableIndex;\r
263       OverrideItem->DriverInfoNum = DriverNumber;\r
264       VariableIndex = VariableIndex + sizeof (UINT32);\r
265       //\r
266       // Get ControllerDevicePath[]\r
267       //\r
268       ControllerDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) VariableIndex;\r
269       OverrideItem->ControllerDevicePath = DuplicateDevicePath (ControllerDevicePath);\r
270       VariableIndex = VariableIndex + GetDevicePathSize (ControllerDevicePath);\r
271       //\r
272       // Align the VariableIndex since the controller device path may not be aligned, refer to the SaveOverridesMapping()\r
273       //\r
274       VariableIndex += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));\r
275 \r
276       //\r
277       // Get all DriverDevicePath[]\r
278       //\r
279       for (Index = 0; Index < DriverNumber; Index++) {\r
280         DriverImageInfo = AllocateZeroPool (sizeof (DRIVER_IMAGE_INFO));\r
281         ASSERT (DriverImageInfo != NULL);\r
282         DriverImageInfo->Signature = DRIVER_IMAGE_INFO_SIGNATURE;\r
283 \r
284         DriverDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) VariableIndex;\r
285         DriverImageInfo->DriverImagePath = DuplicateDevicePath (DriverDevicePath);\r
286         VariableIndex = VariableIndex + GetDevicePathSize (DriverDevicePath);\r
287         //\r
288         // Align the VariableIndex since the driver image device path may not be aligned, refer to the SaveOverridesMapping()\r
289         //\r
290         VariableIndex += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));\r
291 \r
292         InsertTailList (&OverrideItem->DriverInfoList, &DriverImageInfo->Link);\r
293       }\r
294       InsertTailList (MappingDataBase, &OverrideItem->Link);\r
295     }\r
296 \r
297     FreePool (VariableBuffer);\r
298     if (Corrupted) {\r
299       FreeMappingDatabase (MappingDataBase);\r
300       return EFI_VOLUME_CORRUPTED;\r
301     }\r
302 \r
303     //\r
304     // If has other variable(PlatDriOver1, PlatDriOver2, PlatDriOver3.....), get them.\r
305     // NotEnd indicate whether current variable is the end variable.\r
306     //\r
307     if (NotEnd != 0) {\r
308       UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver%d", VariableNum);\r
309       VariableBuffer = GetVariableAndSize (OverrideVariableName, &gEfiOverrideVariableGuid, &BufferSize);\r
310       ASSERT ((UINTN) VariableBuffer % sizeof(UINTN) == 0);\r
311       VariableNum ++;\r
312       if (VariableBuffer == NULL) {\r
313         FreeMappingDatabase (MappingDataBase);\r
314         return EFI_VOLUME_CORRUPTED;\r
315       }\r
316     }\r
317 \r
318   } while (NotEnd != 0);\r
319 \r
320   return EFI_SUCCESS;\r
321 }\r
322 \r
323 \r
324 /**\r
325   Calculate the needed size in NV variable for recording a specific PLATFORM_OVERRIDE_ITEM info\r
326 \r
327   @param  OverrideItemListIndex    a list entry point to a specific\r
328                                    PLATFORM_OVERRIDE_ITEM\r
329 \r
330   @return The needed size number\r
331 \r
332 **/\r
333 UINTN\r
334 EFIAPI\r
335 GetOneItemNeededSize (\r
336   IN  LIST_ENTRY            *OverrideItemListIndex\r
337   )\r
338 {\r
339   UINTN                       NeededSize;\r
340   PLATFORM_OVERRIDE_ITEM      *OverrideItem;\r
341   LIST_ENTRY                  *ImageInfoListIndex;\r
342   DRIVER_IMAGE_INFO           *DriverImageInfo;\r
343 \r
344 \r
345   NeededSize = 0;\r
346   OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);\r
347   NeededSize += sizeof (UINT32); //UINT32  SIGNATURE;\r
348   NeededSize += sizeof (UINT32); //UINT32  DriverNum;\r
349   NeededSize += GetDevicePathSize (OverrideItem->ControllerDevicePath); // ControllerDevicePath\r
350   //\r
351   // Align the controller device path\r
352   //\r
353   NeededSize += ((sizeof(UINT32) - ((UINTN) GetDevicePathSize (OverrideItem->ControllerDevicePath))) \\r
354                   & (sizeof(UINT32) - 1));\r
355   ImageInfoListIndex =  OverrideItem->DriverInfoList.ForwardLink;\r
356   while (ImageInfoListIndex != &OverrideItem->DriverInfoList){\r
357     DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);\r
358     NeededSize += GetDevicePathSize (DriverImageInfo->DriverImagePath); //DriverDevicePath\r
359     //\r
360     // Align the driver image device path\r
361     //\r
362     NeededSize += ((sizeof(UINT32) - ((UINTN) GetDevicePathSize (DriverImageInfo->DriverImagePath))) \\r
363                     & (sizeof(UINT32) - 1));\r
364     ImageInfoListIndex = ImageInfoListIndex->ForwardLink;\r
365   }\r
366 \r
367   return NeededSize;\r
368 }\r
369 \r
370 \r
371 \r
372 /**\r
373   Save the memory mapping database into NV environment variable(s)\r
374 \r
375   @param  MappingDataBase          Mapping database list entry pointer\r
376 \r
377   @retval EFI_INVALID_PARAMETER    MappingDataBase pointer is null\r
378   @retval EFI_SUCCESS              Save memory mapping database successfully\r
379 \r
380 **/\r
381 EFI_STATUS\r
382 EFIAPI\r
383 SaveOverridesMapping (\r
384   IN  LIST_ENTRY              *MappingDataBase\r
385   )\r
386 {\r
387   EFI_STATUS                  Status;\r
388   VOID                        *VariableBuffer;\r
389   UINT8                       *VariableIndex;\r
390   UINTN                       NumIndex;\r
391   CHAR16                      OverrideVariableName[40];\r
392   UINT32                      NotEnd;\r
393   PLATFORM_OVERRIDE_ITEM      *OverrideItem;\r
394   DRIVER_IMAGE_INFO           *DriverImageInfo;\r
395   LIST_ENTRY                  *OverrideItemListIndex;\r
396   LIST_ENTRY                  *ItemIndex;\r
397   LIST_ENTRY                  *ImageInfoListIndex;\r
398   UINTN                       VariableNeededSize;\r
399   UINTN                       SavedSize;\r
400   UINT64                      MaximumVariableStorageSize;\r
401   UINT64                      RemainingVariableStorageSize;\r
402   UINT64                      MaximumVariableSize;\r
403   UINTN                       OneItemNeededSize;\r
404 \r
405   if (MappingDataBase == NULL) {\r
406     return EFI_INVALID_PARAMETER;\r
407   }\r
408 \r
409   if (MappingDataBase->ForwardLink == MappingDataBase) {\r
410     Status = DeleteOverridesVariables ();\r
411     return EFI_SUCCESS;\r
412   }\r
413 \r
414   //\r
415   // Get the the maximum size of an individual EFI variable in current system\r
416   //\r
417   gRT->QueryVariableInfo (\r
418           EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
419           &MaximumVariableStorageSize,\r
420           &RemainingVariableStorageSize,\r
421           &MaximumVariableSize\r
422           );\r
423 \r
424   NumIndex = 0;\r
425   OverrideItemListIndex = MappingDataBase->ForwardLink;\r
426   while (OverrideItemListIndex != MappingDataBase) {\r
427     //\r
428     // Try to find the most proper variable size which <= MaximumVariableSize, but can contain mapping info as much as possible\r
429     //\r
430     VariableNeededSize = 0;\r
431     VariableNeededSize += sizeof (UINT32); //BOOLEAN  NotEnd;\r
432     ItemIndex = OverrideItemListIndex;\r
433     NotEnd = FALSE;\r
434 \r
435     while (ItemIndex != MappingDataBase){\r
436       OneItemNeededSize = GetOneItemNeededSize (ItemIndex);\r
437       if ((VariableNeededSize +\r
438            OneItemNeededSize +\r
439            sizeof (VARIABLE_HEADER) +\r
440            StrSize (L"PlatDriOver ")\r
441            ) >= MaximumVariableSize\r
442           ) {\r
443         NotEnd = TRUE;\r
444         break;\r
445       }\r
446 \r
447       VariableNeededSize += GetOneItemNeededSize (ItemIndex);\r
448       ItemIndex =  ItemIndex->ForwardLink;\r
449     }\r
450 \r
451     if (NotEnd) {\r
452       if (VariableNeededSize == sizeof (UINT32)) {\r
453         //\r
454         // If an individual EFI variable cannot contain a single Item, return error\r
455         //\r
456         return EFI_OUT_OF_RESOURCES;\r
457       }\r
458     }\r
459 \r
460     //\r
461     // VariableNeededSize is the most proper variable size, allocate variable buffer\r
462     // ItemIndex now points to the next PLATFORM_OVERRIDE_ITEM which is not covered by VariableNeededSize\r
463     //\r
464     VariableBuffer = AllocateZeroPool (VariableNeededSize);\r
465     ASSERT ((UINTN) VariableBuffer % sizeof(UINTN) == 0);\r
466 \r
467     //\r
468     // Fill the variable buffer according to MappingDataBase\r
469     //\r
470     SavedSize = 0;\r
471     VariableIndex = VariableBuffer;\r
472     *(UINT32 *) VariableIndex = NotEnd;\r
473     VariableIndex += sizeof (UINT32); // pass NoEnd\r
474     SavedSize += sizeof (UINT32);\r
475     //\r
476     // ItemIndex points to the next PLATFORM_OVERRIDE_ITEM which is not covered by VariableNeededSize\r
477     //\r
478     while (OverrideItemListIndex != ItemIndex){\r
479       *(UINT32 *) VariableIndex = PLATFORM_OVERRIDE_ITEM_SIGNATURE;\r
480       VariableIndex += sizeof (UINT32); // pass SIGNATURE\r
481       SavedSize += sizeof (UINT32);\r
482 \r
483       OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);\r
484       *(UINT32 *) VariableIndex = OverrideItem->DriverInfoNum;\r
485       VariableIndex += sizeof (UINT32); // pass DriverNum\r
486       SavedSize += sizeof (UINT32);\r
487 \r
488       CopyMem (VariableIndex, OverrideItem->ControllerDevicePath, GetDevicePathSize (OverrideItem->ControllerDevicePath));\r
489       VariableIndex += GetDevicePathSize (OverrideItem->ControllerDevicePath); // pass ControllerDevicePath\r
490       SavedSize += GetDevicePathSize (OverrideItem->ControllerDevicePath);\r
491 \r
492       //\r
493       // Align the VariableIndex since the controller device path may not be aligned\r
494       //\r
495       SavedSize += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));\r
496       VariableIndex += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));\r
497 \r
498       ImageInfoListIndex =  OverrideItem->DriverInfoList.ForwardLink;\r
499       while (ImageInfoListIndex != &OverrideItem->DriverInfoList){\r
500         DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);\r
501         CopyMem (VariableIndex, DriverImageInfo->DriverImagePath, GetDevicePathSize (DriverImageInfo->DriverImagePath));\r
502         VariableIndex += GetDevicePathSize (DriverImageInfo->DriverImagePath); // pass DriverImageDevicePath\r
503         SavedSize += GetDevicePathSize (DriverImageInfo->DriverImagePath);\r
504         //\r
505         // Align the VariableIndex since the driver image device path may not be aligned\r
506         //\r
507         SavedSize += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));\r
508         VariableIndex += ((sizeof(UINT32) - ((UINTN) (VariableIndex))) & (sizeof(UINT32) - 1));\r
509         ImageInfoListIndex = ImageInfoListIndex->ForwardLink;\r
510       }\r
511 \r
512       OverrideItemListIndex =  OverrideItemListIndex->ForwardLink;\r
513     }\r
514 \r
515     ASSERT (SavedSize == VariableNeededSize);\r
516 \r
517     if (NumIndex == 0) {\r
518       UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver");\r
519     } else {\r
520       UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver%d", NumIndex );\r
521     }\r
522 \r
523     Status = gRT->SetVariable (\r
524                     OverrideVariableName,\r
525                     &gEfiOverrideVariableGuid,\r
526                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
527                     VariableNeededSize,\r
528                     VariableBuffer\r
529                     );\r
530     ASSERT (!EFI_ERROR(Status));\r
531 \r
532     NumIndex ++;\r
533     FreePool (VariableBuffer);\r
534   }\r
535 \r
536   return EFI_SUCCESS;\r
537 }\r
538 \r
539 /**\r
540   Get the first Binding protocol which has the specific image handle\r
541 \r
542   @param  Image          Image handle\r
543 \r
544   @return Pointer into the Binding Protocol interface\r
545 \r
546 **/\r
547 EFI_DRIVER_BINDING_PROTOCOL *\r
548 EFIAPI\r
549 GetBindingProtocolFromImageHandle (\r
550   IN  EFI_HANDLE   ImageHandle,\r
551   OUT EFI_HANDLE   *BindingHandle\r
552   )\r
553 {\r
554   EFI_STATUS                        Status;\r
555   UINTN                             Index;\r
556   UINTN                             DriverBindingHandleCount;\r
557   EFI_HANDLE                        *DriverBindingHandleBuffer;\r
558   EFI_DRIVER_BINDING_PROTOCOL       *DriverBindingInterface;\r
559 \r
560   if (BindingHandle == NULL || ImageHandle == NULL) {\r
561     return NULL;\r
562   }\r
563   //\r
564   // Get all driver which support binding protocol in second page\r
565   //\r
566   DriverBindingHandleCount  = 0;\r
567   Status = gBS->LocateHandleBuffer (\r
568                   ByProtocol,\r
569                   &gEfiDriverBindingProtocolGuid,\r
570                   NULL,\r
571                   &DriverBindingHandleCount,\r
572                   &DriverBindingHandleBuffer\r
573                   );\r
574   if (EFI_ERROR (Status) || (DriverBindingHandleCount == 0)) {\r
575     return NULL;\r
576   }\r
577 \r
578   for (Index = 0; Index < DriverBindingHandleCount; Index++) {\r
579     DriverBindingInterface =NULL;\r
580     Status = gBS->OpenProtocol (\r
581                     DriverBindingHandleBuffer[Index],\r
582                     &gEfiDriverBindingProtocolGuid,\r
583                     (VOID **) &DriverBindingInterface,\r
584                     NULL,\r
585                     NULL,\r
586                     EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
587                     );\r
588     if (EFI_ERROR (Status)) {\r
589       continue;\r
590     }\r
591 \r
592     if (DriverBindingInterface->ImageHandle == ImageHandle) {\r
593       *BindingHandle = DriverBindingHandleBuffer[Index];\r
594       FreePool (DriverBindingHandleBuffer);\r
595       return DriverBindingInterface;\r
596     }\r
597   }\r
598 \r
599   FreePool (DriverBindingHandleBuffer);\r
600   *BindingHandle = NULL;\r
601   return NULL;\r
602 }\r
603 \r
604 /**\r
605   return the current TPL, copied from the EDKII glue lib\r
606 \r
607   @param  VOID\r
608 \r
609   @return Current TPL\r
610 \r
611 **/\r
612 EFI_TPL\r
613 GetCurrentTpl (\r
614   VOID\r
615   )\r
616 {\r
617   EFI_TPL                 Tpl;\r
618 \r
619   Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
620   gBS->RestoreTPL (Tpl);\r
621 \r
622   return Tpl;\r
623 }\r
624 \r
625 \r
626 /**\r
627   Retrieves the image handle of the platform override driver for a controller in the system from the memory mapping database.\r
628 \r
629   @param  This                     A pointer to the\r
630                                    EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL instance.\r
631   @param  ControllerHandle         The device handle of the controller to check if\r
632                                    a driver override exists.\r
633   @param  DriverImageHandle        On output, a pointer to the next driver handle.\r
634                                    Passing in a pointer to NULL, will return the\r
635                                    first driver handle for ControllerHandle.\r
636   @param  MappingDataBase          MappingDataBase - Mapping database list entry\r
637                                    pointer\r
638   @param  CallerImageHandle        The caller driver's image handle, for\r
639                                    UpdateFvFileDevicePath use.\r
640 \r
641   @retval EFI_INVALID_PARAMETER    The handle specified by ControllerHandle is not\r
642                                    a valid handle.  Or DriverImagePath is not a\r
643                                    device path that was returned on a previous call\r
644                                    to GetDriverPath().\r
645   @retval EFI_NOT_FOUND            A driver override for ControllerHandle was not\r
646                                    found.\r
647   @retval EFI_UNSUPPORTED          The operation is not supported.\r
648   @retval EFI_SUCCESS              The driver override for ControllerHandle was\r
649                                    returned in DriverImagePath.\r
650 \r
651 **/\r
652 EFI_STATUS\r
653 EFIAPI\r
654 GetDriverFromMapping (\r
655   IN EFI_PLATFORM_DRIVER_OVERRIDE_PROTOCOL              * This,\r
656   IN     EFI_HANDLE                                     ControllerHandle,\r
657   IN OUT EFI_HANDLE                                     * DriverImageHandle,\r
658   IN     LIST_ENTRY                                     * MappingDataBase,\r
659   IN     EFI_HANDLE                                     CallerImageHandle\r
660   )\r
661 {\r
662   EFI_STATUS                  Status;\r
663   EFI_DEVICE_PATH_PROTOCOL    *ControllerDevicePath;\r
664   BOOLEAN                     ControllerFound;\r
665   BOOLEAN                     ImageFound;\r
666   EFI_HANDLE                  *ImageHandleBuffer;\r
667   UINTN                       ImageHandleCount;\r
668   UINTN                       Index;\r
669   EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;\r
670   EFI_HANDLE                  DriverBindingHandle;\r
671   BOOLEAN                     FoundLastReturned;\r
672   PLATFORM_OVERRIDE_ITEM      *OverrideItem;\r
673   DRIVER_IMAGE_INFO           *DriverImageInfo;\r
674   LIST_ENTRY                  *OverrideItemListIndex;\r
675   LIST_ENTRY                  *ImageInfoListIndex;\r
676   EFI_DEVICE_PATH_PROTOCOL    *TempDriverImagePath;\r
677   EFI_HANDLE                  ImageHandle;\r
678   EFI_HANDLE                  Handle;\r
679   EFI_DEVICE_PATH_PROTOCOL    *LoadedImageDevicePath;\r
680   EFI_BUS_SPECIFIC_DRIVER_OVERRIDE_PROTOCOL  *BusSpecificDriverOverride;\r
681   UINTN                       DevicePathSize;\r
682 \r
683   //\r
684   // Check that ControllerHandle is a valid handle\r
685   //\r
686   if (ControllerHandle == NULL) {\r
687     return EFI_INVALID_PARAMETER;\r
688   }\r
689 \r
690   Status = gBS->HandleProtocol (\r
691               ControllerHandle,\r
692               &gEfiDevicePathProtocolGuid,\r
693               (VOID **) &ControllerDevicePath\r
694               );\r
695   if (EFI_ERROR (Status) || ControllerDevicePath == NULL) {\r
696     return EFI_INVALID_PARAMETER;\r
697   }\r
698 \r
699   //\r
700   // Search ControllerDevicePath in MappingDataBase\r
701   //\r
702   OverrideItem = NULL;\r
703   ControllerFound = FALSE;\r
704   OverrideItemListIndex = MappingDataBase->ForwardLink;\r
705   while (OverrideItemListIndex != MappingDataBase){\r
706     OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);\r
707     DevicePathSize = GetDevicePathSize (ControllerDevicePath);\r
708     if (DevicePathSize == GetDevicePathSize (OverrideItem->ControllerDevicePath)) {\r
709       if (CompareMem (\r
710             ControllerDevicePath,\r
711             OverrideItem->ControllerDevicePath,\r
712             GetDevicePathSize (OverrideItem->ControllerDevicePath)\r
713             ) == 0\r
714           ) {\r
715         ControllerFound = TRUE;\r
716         break;\r
717       }\r
718 \r
719     }\r
720     OverrideItemListIndex =  OverrideItemListIndex->ForwardLink;\r
721   }\r
722 \r
723   if (!ControllerFound) {\r
724     return EFI_NOT_FOUND;\r
725   }\r
726   //\r
727   // Passing in a pointer to NULL, will return the first driver device path for ControllerHandle.\r
728   // Check whether the driverImagePath is not a device path that was returned on a previous call to GetDriverPath().\r
729   //\r
730   if (*DriverImageHandle != NULL) {\r
731     if (*DriverImageHandle != OverrideItem->LastReturnedImageHandle) {\r
732       return EFI_INVALID_PARAMETER;\r
733     }\r
734   }\r
735   //\r
736   // The GetDriverPath() maybe called recursively, because it use ConnectDevicePath() internally,\r
737   //  so should check whether there is a dead loop.\r
738   //  Here use a controller device path stack to record all processed controller device path during a GetDriverPath() call,\r
739   //  and check the  controller device path whether appear again during the  GetDriverPath() call.\r
740   //\r
741   if (CheckExistInStack(OverrideItem->ControllerDevicePath)) {\r
742     //\r
743     // There is a dependecy dead loop if the ControllerDevicePath appear in stack twice\r
744     //\r
745     return EFI_UNSUPPORTED;\r
746   }\r
747   PushDevPathStack (OverrideItem->ControllerDevicePath);\r
748 \r
749   //\r
750   // Check every override driver, try to load and start them\r
751   //\r
752   ImageInfoListIndex =  OverrideItem->DriverInfoList.ForwardLink;\r
753   while (ImageInfoListIndex != &OverrideItem->DriverInfoList){\r
754     DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);\r
755     if (DriverImageInfo->ImageHandle == NULL) {\r
756       //\r
757       // Skip if the image is unloadable or unstartable\r
758       //\r
759       if ((!DriverImageInfo->UnLoadable) && ((!DriverImageInfo->UnStartable))) {\r
760         TempDriverImagePath = DriverImageInfo->DriverImagePath;\r
761         //\r
762         // If the image device path contain a FV node, check the Fv file device path is valid. If it is invalid, try to return the valid device path.\r
763         // FV address maybe changes for memory layout adjust from time to time, use this funciton could promise the Fv file device path is right.\r
764         //\r
765         Status = UpdateFvFileDevicePath (&TempDriverImagePath, NULL, CallerImageHandle);\r
766         if (!EFI_ERROR (Status)) {\r
767           FreePool(DriverImageInfo->DriverImagePath);\r
768           DriverImageInfo->DriverImagePath = TempDriverImagePath;\r
769         }\r
770         //\r
771         // Get all Loaded Image protocol to check whether the driver image has been loaded and started\r
772         //\r
773         ImageFound = FALSE;\r
774         ImageHandleCount  = 0;\r
775         Status = gBS->LocateHandleBuffer (\r
776                         ByProtocol,\r
777                         &gEfiLoadedImageProtocolGuid,\r
778                         NULL,\r
779                         &ImageHandleCount,\r
780                         &ImageHandleBuffer\r
781                         );\r
782         if (EFI_ERROR (Status) || (ImageHandleCount == 0)) {\r
783           return EFI_NOT_FOUND;\r
784         }\r
785 \r
786         for(Index = 0; Index < ImageHandleCount; Index ++) {\r
787           //\r
788           // Get the EFI Loaded Image Device Path Protocol\r
789           //\r
790           LoadedImageDevicePath = NULL;\r
791           Status = gBS->HandleProtocol (\r
792                               ImageHandleBuffer[Index],\r
793                               &gEfiLoadedImageDevicePathProtocolGuid,\r
794                               (VOID **) &LoadedImageDevicePath\r
795                               );\r
796           if (EFI_ERROR (Status)) {\r
797             //\r
798             // Maybe Not all EFI Loaded Image Device Path Protocol existed.\r
799             //\r
800             continue;\r
801           }\r
802 \r
803           DevicePathSize = GetDevicePathSize (DriverImageInfo->DriverImagePath);\r
804           if (DevicePathSize == GetDevicePathSize (LoadedImageDevicePath)) {\r
805             if (CompareMem (\r
806                   DriverImageInfo->DriverImagePath,\r
807                   LoadedImageDevicePath,\r
808                   GetDevicePathSize (LoadedImageDevicePath)\r
809                   ) == 0\r
810                 ) {\r
811               ImageFound = TRUE;\r
812               break;\r
813             }\r
814           }\r
815         }\r
816 \r
817         if (ImageFound) {\r
818           //\r
819           // Find its related driver binding protocol\r
820           // Driver binding handle may be different with its driver's Image handle,\r
821           //\r
822           DriverBindingHandle = NULL;\r
823           DriverBinding = GetBindingProtocolFromImageHandle (\r
824                                       ImageHandleBuffer[Index],\r
825                                       &DriverBindingHandle\r
826                                       );\r
827           ASSERT (DriverBinding != NULL);\r
828           DriverImageInfo->ImageHandle = ImageHandleBuffer[Index];\r
829         } else if (GetCurrentTpl() <= TPL_CALLBACK){\r
830           //\r
831           // The driver image has not been loaded and started, need try to load and start it now\r
832           // Try to connect all device in the driver image path\r
833           //\r
834           // Note: LoadImage() and  StartImage() should be called under CALLBACK TPL in theory, but\r
835           // since many device need to be connected in  CALLBACK level environment( e.g. Usb devices )\r
836           // and the Fat and Patition driver can endure executing in CALLBACK level in fact, so here permit\r
837           // to use LoadImage() and  StartImage() in CALLBACK TPL.\r
838           //\r
839           Status = ConnectDevicePath (DriverImageInfo->DriverImagePath);\r
840           //\r
841           // check whether it points to a PCI Option Rom image, and try to use bus override protocol to get its first option rom image driver\r
842           //\r
843           TempDriverImagePath = DriverImageInfo->DriverImagePath;\r
844           gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &TempDriverImagePath, &Handle);\r
845           //\r
846           // Get the Bus Specific Driver Override Protocol instance on the Controller Handle\r
847           //\r
848           Status = gBS->HandleProtocol(\r
849                            Handle,\r
850                            &gEfiBusSpecificDriverOverrideProtocolGuid,\r
851                            (VOID **) &BusSpecificDriverOverride\r
852                            );\r
853           if (!EFI_ERROR (Status) && (BusSpecificDriverOverride != NULL)) {\r
854             ImageHandle = NULL;\r
855             Status = BusSpecificDriverOverride->GetDriver (\r
856                                                   BusSpecificDriverOverride,\r
857                                                   &ImageHandle\r
858                                                   );\r
859             if (!EFI_ERROR (Status)) {\r
860               //\r
861               // Find its related driver binding protocol\r
862               // Driver binding handle may be different with its driver's Image handle\r
863               //\r
864               DriverBindingHandle = NULL;\r
865               DriverBinding = GetBindingProtocolFromImageHandle (\r
866                                           ImageHandle,\r
867                                           &DriverBindingHandle\r
868                                           );\r
869               ASSERT (DriverBinding != NULL);\r
870               DriverImageInfo->ImageHandle = ImageHandle;\r
871             }\r
872           }\r
873           //\r
874           // Skip if any device cannot be connected now, future passes through GetDriver() may be able to load that driver.\r
875           // Only file path media or FwVol Device Path Node remain if all device is connected\r
876           //\r
877           TempDriverImagePath = DriverImageInfo->DriverImagePath;\r
878           gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &TempDriverImagePath, &Handle);\r
879           if (((DevicePathType (TempDriverImagePath) == MEDIA_DEVICE_PATH) &&\r
880                (DevicePathSubType (TempDriverImagePath) == MEDIA_FILEPATH_DP)) ||\r
881               (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) TempDriverImagePath) != NULL)\r
882              ) {\r
883             //\r
884             // Try to load the driver\r
885             //\r
886             TempDriverImagePath = DriverImageInfo->DriverImagePath;\r
887             Status = gBS->LoadImage (\r
888                             FALSE,\r
889                             CallerImageHandle,\r
890                             TempDriverImagePath,\r
891                             NULL,\r
892                             0,\r
893                             &ImageHandle\r
894                             );\r
895             if (!EFI_ERROR (Status)) {\r
896               //\r
897               // Try to start the driver\r
898               //\r
899               Status = gBS->StartImage (ImageHandle, NULL, NULL);\r
900               if (EFI_ERROR (Status)){\r
901                 DriverImageInfo->UnStartable = TRUE;\r
902                 DriverImageInfo->ImageHandle = NULL;\r
903               } else {\r
904                 //\r
905                 // Find its related driver binding protocol\r
906                 // Driver binding handle may be different with its driver's Image handle\r
907                 //\r
908                 DriverBindingHandle = NULL;\r
909                 DriverBinding = GetBindingProtocolFromImageHandle (\r
910                                             ImageHandle,\r
911                                             &DriverBindingHandle\r
912                                             );\r
913                 ASSERT (DriverBinding != NULL);\r
914                 DriverImageInfo->ImageHandle = ImageHandle;\r
915               }\r
916             } else {\r
917               DriverImageInfo->UnLoadable = TRUE;\r
918               DriverImageInfo->ImageHandle = NULL;\r
919             }\r
920           }\r
921         }\r
922         FreePool (ImageHandleBuffer);\r
923       }\r
924     }\r
925     ImageInfoListIndex = ImageInfoListIndex->ForwardLink;\r
926   }\r
927   //\r
928   // Finish try to load and start the override driver of a controller, popup the controller's device path\r
929   //\r
930   PopDevPathStack (NULL);\r
931 \r
932   //\r
933   // return the DriverImageHandle for ControllerHandle\r
934   //\r
935   FoundLastReturned = FALSE;\r
936   ImageInfoListIndex =  OverrideItem->DriverInfoList.ForwardLink;\r
937   while (ImageInfoListIndex != &OverrideItem->DriverInfoList){\r
938     DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);\r
939     if (DriverImageInfo->ImageHandle != NULL) {\r
940       if ((*DriverImageHandle == NULL) || FoundLastReturned) {\r
941         OverrideItem->LastReturnedImageHandle = DriverImageInfo->ImageHandle;\r
942         *DriverImageHandle = DriverImageInfo->ImageHandle;\r
943         return EFI_SUCCESS;\r
944       } else if (*DriverImageHandle == DriverImageInfo->ImageHandle){\r
945         FoundLastReturned = TRUE;\r
946       }\r
947     }\r
948     ImageInfoListIndex = ImageInfoListIndex->ForwardLink;\r
949   }\r
950 \r
951   return EFI_NOT_FOUND;\r
952 }\r
953 \r
954 \r
955 /**\r
956   Check mapping database whether already has the  mapping info which\r
957   records the input Controller to input DriverImage.\r
958   If has, the controller's total override driver number and input DriverImage's order number is return.\r
959 \r
960   @param  ControllerDevicePath     The controller device path need to add a\r
961                                    override driver image item\r
962   @param  DriverImageDevicePath    The driver image device path need to be insert\r
963   @param  MappingDataBase          Mapping database list entry pointer\r
964   @param  DriverInfoNum            the controller's total override driver number\r
965   @param  DriverImageNO            The inserted order number\r
966 \r
967   @return EFI_INVALID_PARAMETER\r
968   @return EFI_NOT_FOUND\r
969   @return EFI_SUCCESS\r
970 \r
971 **/\r
972 EFI_STATUS\r
973 EFIAPI\r
974 CheckMapping (\r
975   IN     EFI_DEVICE_PATH_PROTOCOL                       *ControllerDevicePath,\r
976   IN     EFI_DEVICE_PATH_PROTOCOL                       *DriverImageDevicePath,\r
977   IN     LIST_ENTRY                                     * MappingDataBase,\r
978   OUT    UINT32                                         *DriverInfoNum,\r
979   OUT    UINT32                                         *DriverImageNO\r
980   )\r
981 {\r
982   LIST_ENTRY                  *OverrideItemListIndex;\r
983   PLATFORM_OVERRIDE_ITEM      *OverrideItem;\r
984   LIST_ENTRY                  *ImageInfoListIndex;\r
985   DRIVER_IMAGE_INFO           *DriverImageInfo;\r
986   BOOLEAN                     Found;\r
987   UINT32                      ImageNO;\r
988   UINTN                       DevicePathSize;\r
989 \r
990   //\r
991   // Check that ControllerHandle is a valid handle\r
992   //\r
993   if (ControllerDevicePath == NULL) {\r
994     return EFI_INVALID_PARAMETER;\r
995   }\r
996   if (MappingDataBase == NULL) {\r
997     return EFI_INVALID_PARAMETER;\r
998   }\r
999   //\r
1000   // Search ControllerDevicePath in MappingDataBase\r
1001   //\r
1002   Found = FALSE;\r
1003   OverrideItem = NULL;\r
1004   OverrideItemListIndex = MappingDataBase->ForwardLink;\r
1005   while (OverrideItemListIndex != MappingDataBase){\r
1006     OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);\r
1007     DevicePathSize = GetDevicePathSize (ControllerDevicePath);\r
1008     if (DevicePathSize == GetDevicePathSize (OverrideItem->ControllerDevicePath)) {\r
1009       if (CompareMem (\r
1010             ControllerDevicePath,\r
1011             OverrideItem->ControllerDevicePath,\r
1012             GetDevicePathSize (OverrideItem->ControllerDevicePath)\r
1013             ) == 0\r
1014           ) {\r
1015         Found = TRUE;\r
1016         break;\r
1017       }\r
1018     }\r
1019     OverrideItemListIndex =  OverrideItemListIndex->ForwardLink;\r
1020   }\r
1021 \r
1022   if (!Found) {\r
1023     return EFI_NOT_FOUND;\r
1024   }\r
1025 \r
1026   ASSERT (OverrideItem->DriverInfoNum != 0);\r
1027   if (DriverInfoNum != NULL) {\r
1028     *DriverInfoNum = OverrideItem->DriverInfoNum;\r
1029   }\r
1030 \r
1031 \r
1032   if (DriverImageDevicePath == NULL) {\r
1033     return EFI_SUCCESS;\r
1034   }\r
1035   //\r
1036   // return the DriverImageHandle for ControllerHandle\r
1037   //\r
1038   ImageNO = 0;\r
1039   Found = FALSE;\r
1040   ImageInfoListIndex =  OverrideItem->DriverInfoList.ForwardLink;\r
1041   while (ImageInfoListIndex != &OverrideItem->DriverInfoList){\r
1042     DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);\r
1043     ImageNO++;\r
1044     DevicePathSize = GetDevicePathSize (DriverImageDevicePath);\r
1045     if (DevicePathSize == GetDevicePathSize (DriverImageInfo->DriverImagePath)) {\r
1046       if (CompareMem (\r
1047             DriverImageDevicePath,\r
1048             DriverImageInfo->DriverImagePath,\r
1049             GetDevicePathSize (DriverImageInfo->DriverImagePath)\r
1050             ) == 0\r
1051           ) {\r
1052         Found = TRUE;\r
1053         break;\r
1054       }\r
1055     }\r
1056     ImageInfoListIndex = ImageInfoListIndex->ForwardLink;\r
1057   }\r
1058 \r
1059   if (!Found) {\r
1060     return EFI_NOT_FOUND;\r
1061   } else {\r
1062     if (DriverImageNO != NULL) {\r
1063       *DriverImageNO = ImageNO;\r
1064     }\r
1065     return EFI_SUCCESS;\r
1066   }\r
1067 \r
1068 }\r
1069 \r
1070 \r
1071 /**\r
1072   Insert a driver image as a controller's override driver into the mapping database.\r
1073   The driver image's order number is indicated by DriverImageNO.\r
1074 \r
1075   @param  ControllerDevicePath     The controller device path need to add a\r
1076                                    override driver image item\r
1077   @param  DriverImageDevicePath    The driver image device path need to be insert\r
1078   @param  MappingDataBase          Mapping database list entry pointer\r
1079   @param  DriverImageNO            The inserted order number\r
1080 \r
1081   @return EFI_INVALID_PARAMETER\r
1082   @return EFI_ALREADY_STARTED\r
1083   @return EFI_SUCCESS\r
1084 \r
1085 **/\r
1086 EFI_STATUS\r
1087 EFIAPI\r
1088 InsertDriverImage (\r
1089   IN     EFI_DEVICE_PATH_PROTOCOL                       *ControllerDevicePath,\r
1090   IN     EFI_DEVICE_PATH_PROTOCOL                       *DriverImageDevicePath,\r
1091   IN     LIST_ENTRY                                     *MappingDataBase,\r
1092   IN     UINT32                                         DriverImageNO\r
1093   )\r
1094 {\r
1095   EFI_STATUS                  Status;\r
1096   LIST_ENTRY                  *OverrideItemListIndex;\r
1097   PLATFORM_OVERRIDE_ITEM      *OverrideItem;\r
1098   LIST_ENTRY                  *ImageInfoListIndex;\r
1099   DRIVER_IMAGE_INFO           *DriverImageInfo;\r
1100   BOOLEAN                     Found;\r
1101   UINT32                      ImageNO;\r
1102   UINTN                       DevicePathSize;\r
1103 \r
1104   //\r
1105   // Check that ControllerHandle is a valid handle\r
1106   //\r
1107   if (ControllerDevicePath == NULL) {\r
1108     return EFI_INVALID_PARAMETER;\r
1109   }\r
1110   if (DriverImageDevicePath == NULL) {\r
1111     return EFI_INVALID_PARAMETER;\r
1112   }\r
1113   if (MappingDataBase == NULL) {\r
1114     return EFI_INVALID_PARAMETER;\r
1115   }\r
1116 \r
1117   Status = CheckMapping (\r
1118             ControllerDevicePath,\r
1119             DriverImageDevicePath,\r
1120             MappingDataBase,\r
1121             NULL,\r
1122             NULL\r
1123             );\r
1124   if (Status == EFI_SUCCESS) {\r
1125     return EFI_ALREADY_STARTED;\r
1126   }\r
1127 \r
1128   //\r
1129   // Search the input ControllerDevicePath in MappingDataBase\r
1130   //\r
1131   Found = FALSE;\r
1132   OverrideItem = NULL;\r
1133   OverrideItemListIndex = MappingDataBase->ForwardLink;\r
1134   while (OverrideItemListIndex != MappingDataBase){\r
1135     OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);\r
1136     DevicePathSize = GetDevicePathSize (ControllerDevicePath);\r
1137     if (DevicePathSize == GetDevicePathSize (OverrideItem->ControllerDevicePath)) {\r
1138       if (CompareMem (\r
1139             ControllerDevicePath,\r
1140             OverrideItem->ControllerDevicePath,\r
1141             GetDevicePathSize (OverrideItem->ControllerDevicePath)\r
1142             ) == 0\r
1143           ) {\r
1144         Found = TRUE;\r
1145         break;\r
1146       }\r
1147     }\r
1148     OverrideItemListIndex =  OverrideItemListIndex->ForwardLink;\r
1149   }\r
1150   //\r
1151   // If cannot find, this is a new controller item\r
1152   // Add the Controller related PLATFORM_OVERRIDE_ITEM structrue in mapping data base\r
1153   //\r
1154   if (!Found) {\r
1155     OverrideItem = AllocateZeroPool (sizeof (PLATFORM_OVERRIDE_ITEM));\r
1156     ASSERT (OverrideItem != NULL);\r
1157     OverrideItem->Signature = PLATFORM_OVERRIDE_ITEM_SIGNATURE;\r
1158     OverrideItem->ControllerDevicePath = DuplicateDevicePath (ControllerDevicePath);\r
1159     InitializeListHead (&OverrideItem->DriverInfoList);\r
1160     InsertTailList (MappingDataBase, &OverrideItem->Link);\r
1161   }\r
1162 \r
1163   //\r
1164   // Prepare the driver image related DRIVER_IMAGE_INFO structure.\r
1165   //\r
1166   DriverImageInfo = AllocateZeroPool (sizeof (DRIVER_IMAGE_INFO));\r
1167   ASSERT (DriverImageInfo != NULL);\r
1168   DriverImageInfo->Signature = DRIVER_IMAGE_INFO_SIGNATURE;\r
1169   DriverImageInfo->DriverImagePath = DuplicateDevicePath (DriverImageDevicePath);\r
1170   //\r
1171   // Find the driver image wantted order location\r
1172   //\r
1173   ImageNO = 0;\r
1174   Found = FALSE;\r
1175   ImageInfoListIndex =  OverrideItem->DriverInfoList.ForwardLink;\r
1176   while (ImageInfoListIndex != &OverrideItem->DriverInfoList){\r
1177     if (ImageNO == (DriverImageNO - 1)) {\r
1178       //\r
1179       // find the wantted order location, insert it\r
1180       //\r
1181       InsertTailList (ImageInfoListIndex, &DriverImageInfo->Link);\r
1182       OverrideItem->DriverInfoNum ++;\r
1183       Found = TRUE;\r
1184       break;\r
1185     }\r
1186     //DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);\r
1187     ImageNO++;\r
1188     ImageInfoListIndex = ImageInfoListIndex->ForwardLink;\r
1189   }\r
1190 \r
1191   if (!Found) {\r
1192     //\r
1193     // if not find the wantted order location, add it as last item of the controller mapping item\r
1194     //\r
1195     InsertTailList (&OverrideItem->DriverInfoList, &DriverImageInfo->Link);\r
1196     OverrideItem->DriverInfoNum ++;\r
1197   }\r
1198 \r
1199   return EFI_SUCCESS;\r
1200 }\r
1201 \r
1202 \r
1203 /**\r
1204   Delete a controller's override driver from the mapping database.\r
1205 \r
1206   @param  ControllerDevicePath     The controller device path need to add a\r
1207                                    override driver image item\r
1208   @param  DriverImageDevicePath    The driver image device path need to be insert\r
1209   @param  MappingDataBase          Mapping database list entry pointer\r
1210   @param  DriverImageNO            The inserted order number\r
1211 \r
1212   @return EFI_INVALID_PARAMETER\r
1213   @return EFI_NOT_FOUND\r
1214   @return EFI_SUCCESS\r
1215 \r
1216 **/\r
1217 EFI_STATUS\r
1218 EFIAPI\r
1219 DeleteDriverImage (\r
1220   IN     EFI_DEVICE_PATH_PROTOCOL                       *ControllerDevicePath,\r
1221   IN     EFI_DEVICE_PATH_PROTOCOL                       *DriverImageDevicePath,\r
1222   IN     LIST_ENTRY                                     *MappingDataBase\r
1223   )\r
1224 {\r
1225   EFI_STATUS                  Status;\r
1226   LIST_ENTRY                  *OverrideItemListIndex;\r
1227   PLATFORM_OVERRIDE_ITEM      *OverrideItem;\r
1228   LIST_ENTRY                  *ImageInfoListIndex;\r
1229   DRIVER_IMAGE_INFO           *DriverImageInfo;\r
1230   BOOLEAN                     Found;\r
1231   UINTN                       DevicePathSize;\r
1232 \r
1233   //\r
1234   // Check that ControllerHandle is a valid handle\r
1235   //\r
1236   if (ControllerDevicePath == NULL) {\r
1237     return EFI_INVALID_PARAMETER;\r
1238   }\r
1239 \r
1240   if (MappingDataBase == NULL) {\r
1241     return EFI_INVALID_PARAMETER;\r
1242   }\r
1243 \r
1244    Status = CheckMapping (\r
1245               ControllerDevicePath,\r
1246               DriverImageDevicePath,\r
1247               MappingDataBase,\r
1248               NULL,\r
1249               NULL\r
1250               );\r
1251   if (Status == EFI_NOT_FOUND) {\r
1252     return EFI_NOT_FOUND;\r
1253   }\r
1254 \r
1255   //\r
1256   // Search ControllerDevicePath in MappingDataBase\r
1257   //\r
1258   Found = FALSE;\r
1259   OverrideItem = NULL;\r
1260   OverrideItemListIndex = MappingDataBase->ForwardLink;\r
1261   while (OverrideItemListIndex != MappingDataBase){\r
1262     OverrideItem = CR(OverrideItemListIndex, PLATFORM_OVERRIDE_ITEM, Link, PLATFORM_OVERRIDE_ITEM_SIGNATURE);\r
1263     DevicePathSize = GetDevicePathSize (ControllerDevicePath);\r
1264     if (DevicePathSize == GetDevicePathSize (OverrideItem->ControllerDevicePath)) {\r
1265       if (CompareMem (\r
1266             ControllerDevicePath,\r
1267             OverrideItem->ControllerDevicePath,\r
1268             GetDevicePathSize (OverrideItem->ControllerDevicePath)\r
1269             ) == 0\r
1270           ) {\r
1271         Found = TRUE;\r
1272         break;\r
1273       }\r
1274     }\r
1275     OverrideItemListIndex =  OverrideItemListIndex->ForwardLink;\r
1276   }\r
1277 \r
1278   ASSERT (Found);\r
1279   ASSERT (OverrideItem->DriverInfoNum != 0);\r
1280   //\r
1281   //\r
1282   //\r
1283   Found = FALSE;\r
1284   ImageInfoListIndex =  OverrideItem->DriverInfoList.ForwardLink;\r
1285   while (ImageInfoListIndex != &OverrideItem->DriverInfoList){\r
1286     DriverImageInfo = CR(ImageInfoListIndex, DRIVER_IMAGE_INFO, Link, DRIVER_IMAGE_INFO_SIGNATURE);\r
1287     ImageInfoListIndex = ImageInfoListIndex->ForwardLink;\r
1288     if (DriverImageDevicePath != NULL) {\r
1289       DevicePathSize = GetDevicePathSize (DriverImageDevicePath);\r
1290       if (DevicePathSize == GetDevicePathSize (DriverImageInfo->DriverImagePath)) {\r
1291         if (CompareMem (\r
1292               DriverImageDevicePath,\r
1293               DriverImageInfo->DriverImagePath,\r
1294               GetDevicePathSize (DriverImageInfo->DriverImagePath)\r
1295               ) == 0\r
1296             ) {\r
1297           Found = TRUE;\r
1298           FreePool(DriverImageInfo->DriverImagePath);\r
1299           RemoveEntryList (&DriverImageInfo->Link);\r
1300           OverrideItem->DriverInfoNum --;\r
1301           break;\r
1302         }\r
1303       }\r
1304     } else {\r
1305       Found = TRUE;\r
1306       FreePool(DriverImageInfo->DriverImagePath);\r
1307       RemoveEntryList (&DriverImageInfo->Link);\r
1308       OverrideItem->DriverInfoNum --;\r
1309     }\r
1310   }\r
1311 \r
1312   if (DriverImageDevicePath == NULL) {\r
1313     ASSERT (OverrideItem->DriverInfoNum == 0);\r
1314   }\r
1315 \r
1316   if (OverrideItem->DriverInfoNum == 0) {\r
1317     FreePool(OverrideItem->ControllerDevicePath);\r
1318     RemoveEntryList (&OverrideItem->Link);\r
1319     FreePool (OverrideItem);\r
1320   }\r
1321 \r
1322   if (!Found) {\r
1323     return EFI_NOT_FOUND;\r
1324   }\r
1325 \r
1326   return EFI_SUCCESS;\r
1327 }\r
1328 \r
1329 \r
1330 /**\r
1331   Deletes all environment variable(s) that contain the override mappings from Controller Device Path to\r
1332   a set of Driver Device Paths.\r
1333 \r
1334   None\r
1335 \r
1336   @return EFI_SUCCESS\r
1337 \r
1338 **/\r
1339 EFI_STATUS\r
1340 EFIAPI\r
1341 DeleteOverridesVariables (\r
1342   VOID\r
1343   )\r
1344 {\r
1345   EFI_STATUS                  Status;\r
1346   VOID                        *VariableBuffer;\r
1347   UINTN                       VariableNum;\r
1348   UINTN                       BufferSize;\r
1349   UINTN                       Index;\r
1350   CHAR16                      OverrideVariableName[40];\r
1351 \r
1352   //\r
1353   // Get environment variable(s)  number\r
1354   //\r
1355   VariableNum =0;\r
1356   VariableBuffer = GetVariableAndSize (L"PlatDriOver", &gEfiOverrideVariableGuid, &BufferSize);\r
1357   VariableNum ++;\r
1358   if (VariableBuffer == NULL) {\r
1359     return EFI_NOT_FOUND;\r
1360   }\r
1361   //\r
1362   // Check NotEnd to get all PlatDriOverX variable(s)\r
1363   //\r
1364   while (*(UINT32*)VariableBuffer) {\r
1365     UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver%d", VariableNum);\r
1366     VariableBuffer = GetVariableAndSize (OverrideVariableName, &gEfiOverrideVariableGuid, &BufferSize);\r
1367     VariableNum ++;\r
1368     ASSERT (VariableBuffer != NULL);\r
1369   }\r
1370 \r
1371   Status = gRT->SetVariable (\r
1372                   L"PlatDriOver",\r
1373                   &gEfiOverrideVariableGuid,\r
1374                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
1375                   0,\r
1376                   NULL\r
1377                   );\r
1378   ASSERT (!EFI_ERROR (Status));\r
1379   for (Index = 1; Index < VariableNum; Index++) {\r
1380     UnicodeSPrint (OverrideVariableName, sizeof (OverrideVariableName), L"PlatDriOver%d", Index);\r
1381     Status = gRT->SetVariable (\r
1382                     OverrideVariableName,\r
1383                     &gEfiOverrideVariableGuid,\r
1384                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
1385                     0,\r
1386                     NULL\r
1387                     );\r
1388     ASSERT (!EFI_ERROR (Status));\r
1389   }\r
1390   return EFI_SUCCESS;\r
1391 }\r
1392 \r
1393 \r
1394 /**\r
1395   Push a controller device path into a globle device path list\r
1396 \r
1397   @param  ControllerDevicePath     The controller device path need to push into\r
1398                                    stack\r
1399 \r
1400   @return EFI_SUCCESS\r
1401 \r
1402 **/\r
1403 EFI_STATUS\r
1404 EFIAPI\r
1405 PushDevPathStack (\r
1406   IN  EFI_DEVICE_PATH_PROTOCOL    *DevicePath\r
1407   )\r
1408 {\r
1409   DEVICE_PATH_STACK_ITEM  *DevicePathStackItem;\r
1410 \r
1411   DevicePathStackItem = AllocateZeroPool (sizeof (DEVICE_PATH_STACK_ITEM));\r
1412   ASSERT (DevicePathStackItem != NULL);\r
1413   DevicePathStackItem->Signature = DEVICE_PATH_STACK_ITEM_SIGNATURE;\r
1414   DevicePathStackItem->DevicePath = DuplicateDevicePath (DevicePath);\r
1415   InsertTailList (&mDevicePathStack, &DevicePathStackItem->Link);\r
1416   return EFI_SUCCESS;\r
1417 }\r
1418 \r
1419 \r
1420 /**\r
1421   Pop a controller device path from a globle device path list\r
1422 \r
1423   @param  ControllerDevicePath     The controller device path retrieved from stack\r
1424 \r
1425   @return EFI_SUCCESS\r
1426   @return EFI_NOT_FOUND\r
1427 \r
1428 **/\r
1429 EFI_STATUS\r
1430 EFIAPI\r
1431 PopDevPathStack (\r
1432   OUT  EFI_DEVICE_PATH_PROTOCOL    **DevicePath\r
1433   )\r
1434 {\r
1435   DEVICE_PATH_STACK_ITEM  *DevicePathStackItem;\r
1436   LIST_ENTRY              *ItemListIndex;\r
1437 \r
1438   ItemListIndex = mDevicePathStack.BackLink;\r
1439   if (ItemListIndex != &mDevicePathStack){\r
1440     DevicePathStackItem = CR(ItemListIndex, DEVICE_PATH_STACK_ITEM, Link, DEVICE_PATH_STACK_ITEM_SIGNATURE);\r
1441     if (DevicePath != NULL) {\r
1442       *DevicePath = DuplicateDevicePath (DevicePathStackItem->DevicePath);\r
1443     }\r
1444     FreePool (DevicePathStackItem->DevicePath);\r
1445     RemoveEntryList (&DevicePathStackItem->Link);\r
1446     FreePool (DevicePathStackItem);\r
1447     return EFI_SUCCESS;\r
1448   }\r
1449   return EFI_NOT_FOUND;\r
1450 }\r
1451 \r
1452 \r
1453 /**\r
1454   Check whether a controller device path is in a globle device path list\r
1455 \r
1456   @param  ControllerDevicePath     The controller device path need to check\r
1457 \r
1458   @return True\r
1459   @return False\r
1460 \r
1461 **/\r
1462 BOOLEAN\r
1463 EFIAPI\r
1464 CheckExistInStack (\r
1465   IN  EFI_DEVICE_PATH_PROTOCOL    *DevicePath\r
1466   )\r
1467 {\r
1468   DEVICE_PATH_STACK_ITEM  *DevicePathStackItem;\r
1469   LIST_ENTRY              *ItemListIndex;\r
1470   BOOLEAN                 Found;\r
1471   UINTN                   DevicePathSize;\r
1472 \r
1473   Found = FALSE;\r
1474   ItemListIndex = mDevicePathStack.BackLink;\r
1475   while (ItemListIndex != &mDevicePathStack){\r
1476     DevicePathStackItem = CR(ItemListIndex, DEVICE_PATH_STACK_ITEM, Link, DEVICE_PATH_STACK_ITEM_SIGNATURE);\r
1477     DevicePathSize = GetDevicePathSize (DevicePath);\r
1478     if (DevicePathSize == GetDevicePathSize (DevicePathStackItem->DevicePath)) {\r
1479       if (CompareMem (\r
1480             DevicePath,\r
1481             DevicePathStackItem->DevicePath,\r
1482             GetDevicePathSize (DevicePathStackItem->DevicePath)\r
1483             ) == 0\r
1484           ) {\r
1485         Found = TRUE;\r
1486         break;\r
1487       }\r
1488     }\r
1489     ItemListIndex = ItemListIndex->BackLink;\r
1490   }\r
1491 \r
1492   return Found;\r
1493 }\r
1494 \r
1495 \r
1496 /**\r
1497   According to a file guild, check a Fv file device path is valid. If it is invalid,\r
1498   try to return the valid device path.\r
1499   FV address maybe changes for memory layout adjust from time to time, use this funciton\r
1500   could promise the Fv file device path is right.\r
1501 \r
1502   @param  DevicePath               on input, the Fv file device path need to check\r
1503                                    on output, the updated valid Fv file device path\r
1504   @param  FileGuid                 the Fv file guild\r
1505   @param  CallerImageHandle\r
1506 \r
1507   @retval EFI_INVALID_PARAMETER    the input DevicePath or FileGuid is invalid\r
1508                                    parameter\r
1509   @retval EFI_UNSUPPORTED          the input DevicePath does not contain Fv file\r
1510                                    guild at all\r
1511   @retval EFI_ALREADY_STARTED      the input DevicePath has pointed to Fv file, it\r
1512                                    is valid\r
1513   @retval EFI_SUCCESS              has successfully updated the invalid DevicePath,\r
1514                                    and return the updated device path in DevicePath\r
1515 \r
1516 **/\r
1517 EFI_STATUS\r
1518 EFIAPI\r
1519 UpdateFvFileDevicePath (\r
1520   IN  OUT EFI_DEVICE_PATH_PROTOCOL      ** DevicePath,\r
1521   IN  EFI_GUID                          *FileGuid,\r
1522   IN  EFI_HANDLE                        CallerImageHandle\r
1523   )\r
1524 {\r
1525   EFI_DEVICE_PATH_PROTOCOL      *TempDevicePath;\r
1526   EFI_DEVICE_PATH_PROTOCOL      *LastDeviceNode;\r
1527   EFI_STATUS                    Status;\r
1528   EFI_GUID                      *GuidPoint;\r
1529   UINTN                         Index;\r
1530   UINTN                         FvHandleCount;\r
1531   EFI_HANDLE                    *FvHandleBuffer;\r
1532   EFI_FV_FILETYPE               Type;\r
1533   UINTN                         Size;\r
1534   EFI_FV_FILE_ATTRIBUTES        Attributes;\r
1535   UINT32                        AuthenticationStatus;\r
1536   BOOLEAN                       FindFvFile;\r
1537   EFI_LOADED_IMAGE_PROTOCOL     *LoadedImage;\r
1538   EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
1539   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;\r
1540   EFI_HANDLE                    FoundFvHandle;\r
1541   EFI_DEVICE_PATH_PROTOCOL      *NewDevicePath;\r
1542   BOOLEAN                       HasFVNode;\r
1543 \r
1544   if ((DevicePath == NULL) || (*DevicePath == NULL)) {\r
1545     return EFI_INVALID_PARAMETER;\r
1546   }\r
1547 \r
1548   //\r
1549   // Check whether the device path point to the default the input Fv file\r
1550   //\r
1551   TempDevicePath = *DevicePath;\r
1552   LastDeviceNode = TempDevicePath;\r
1553   while (!EfiIsDevicePathEnd (TempDevicePath)) {\r
1554      LastDeviceNode = TempDevicePath;\r
1555      TempDevicePath = EfiNextDevicePathNode (TempDevicePath);\r
1556   }\r
1557   GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode (\r
1558                 (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode\r
1559                 );\r
1560   if (GuidPoint == NULL) {\r
1561     //\r
1562     // if this option does not points to a Fv file, just return EFI_UNSUPPORTED\r
1563     //\r
1564     return EFI_UNSUPPORTED;\r
1565   }\r
1566 \r
1567   if (FileGuid != NULL) {\r
1568     if (!CompareGuid (GuidPoint, FileGuid)) {\r
1569       //\r
1570       // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED\r
1571       //\r
1572       return EFI_UNSUPPORTED;\r
1573     }\r
1574   } else {\r
1575     FileGuid = GuidPoint;\r
1576   }\r
1577 \r
1578   //\r
1579   // Check to see if the device path contain memory map node\r
1580   //\r
1581   TempDevicePath = *DevicePath;\r
1582   HasFVNode = FALSE;\r
1583   while (!EfiIsDevicePathEnd (TempDevicePath)) {\r
1584     //\r
1585     // Use old Device Path\r
1586     //\r
1587     if (DevicePathType (TempDevicePath) == HARDWARE_DEVICE_PATH &&\r
1588         DevicePathSubType (TempDevicePath) == HW_MEMMAP_DP) {\r
1589       HasFVNode = TRUE;\r
1590       break;\r
1591     }\r
1592     TempDevicePath = EfiNextDevicePathNode (TempDevicePath);\r
1593   }\r
1594 \r
1595   if (!HasFVNode) {\r
1596     return EFI_UNSUPPORTED;\r
1597   }\r
1598 \r
1599   //\r
1600   // Check whether the input Fv file device path is valid\r
1601   //\r
1602   TempDevicePath = *DevicePath;\r
1603   FoundFvHandle = NULL;\r
1604   Status = gBS->LocateDevicePath (\r
1605                   &gEfiFirmwareVolume2ProtocolGuid,\r
1606                   &TempDevicePath,\r
1607                   &FoundFvHandle\r
1608                   );\r
1609   if (!EFI_ERROR (Status)) {\r
1610     Status = gBS->HandleProtocol (\r
1611                     FoundFvHandle,\r
1612                     &gEfiFirmwareVolume2ProtocolGuid,\r
1613                     (VOID **) &Fv\r
1614                     );\r
1615     if (!EFI_ERROR (Status)) {\r
1616       //\r
1617       // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there\r
1618       //\r
1619       Status = Fv->ReadFile (\r
1620                     Fv,\r
1621                     FileGuid,\r
1622                     NULL,\r
1623                     &Size,\r
1624                     &Type,\r
1625                     &Attributes,\r
1626                     &AuthenticationStatus\r
1627                     );\r
1628       if (!EFI_ERROR (Status)) {\r
1629         return EFI_ALREADY_STARTED;\r
1630       }\r
1631     }\r
1632   }\r
1633 \r
1634   //\r
1635   // Look for the input wanted FV file in current FV\r
1636   // First, try to look for in Caller own FV. Caller and input wanted FV file usually are in the same FV\r
1637   //\r
1638   FindFvFile = FALSE;\r
1639   FoundFvHandle = NULL;\r
1640   Status = gBS->HandleProtocol (\r
1641              CallerImageHandle,\r
1642              &gEfiLoadedImageProtocolGuid,\r
1643              (VOID **) &LoadedImage\r
1644              );\r
1645   if (!EFI_ERROR (Status)) {\r
1646     Status = gBS->HandleProtocol (\r
1647                     LoadedImage->DeviceHandle,\r
1648                     &gEfiFirmwareVolume2ProtocolGuid,\r
1649                     (VOID **) &Fv\r
1650                     );\r
1651     if (!EFI_ERROR (Status)) {\r
1652       Status = Fv->ReadFile (\r
1653                     Fv,\r
1654                     FileGuid,\r
1655                     NULL,\r
1656                     &Size,\r
1657                     &Type,\r
1658                     &Attributes,\r
1659                     &AuthenticationStatus\r
1660                     );\r
1661       if (!EFI_ERROR (Status)) {\r
1662         FindFvFile = TRUE;\r
1663         FoundFvHandle = LoadedImage->DeviceHandle;\r
1664       }\r
1665     }\r
1666   }\r
1667   //\r
1668   // Second, if fail to find, try to enumerate all FV\r
1669   //\r
1670   if (!FindFvFile) {\r
1671     gBS->LocateHandleBuffer (\r
1672           ByProtocol,\r
1673           &gEfiFirmwareVolume2ProtocolGuid,\r
1674           NULL,\r
1675           &FvHandleCount,\r
1676           &FvHandleBuffer\r
1677           );\r
1678     for (Index = 0; Index < FvHandleCount; Index++) {\r
1679       gBS->HandleProtocol (\r
1680             FvHandleBuffer[Index],\r
1681             &gEfiFirmwareVolume2ProtocolGuid,\r
1682             (VOID **) &Fv\r
1683             );\r
1684 \r
1685       Status = Fv->ReadFile (\r
1686                     Fv,\r
1687                     FileGuid,\r
1688                     NULL,\r
1689                     &Size,\r
1690                     &Type,\r
1691                     &Attributes,\r
1692                     &AuthenticationStatus\r
1693                     );\r
1694       if (EFI_ERROR (Status)) {\r
1695         //\r
1696         // Skip if input Fv file not in the FV\r
1697         //\r
1698         continue;\r
1699       }\r
1700       FindFvFile = TRUE;\r
1701       FoundFvHandle = FvHandleBuffer[Index];\r
1702       break;\r
1703     }\r
1704   }\r
1705 \r
1706   if (FindFvFile) {\r
1707     //\r
1708     // Build the shell device path\r
1709     //\r
1710     NewDevicePath = DevicePathFromHandle (FoundFvHandle);\r
1711     EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);\r
1712     NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);\r
1713     *DevicePath = NewDevicePath;\r
1714     return EFI_SUCCESS;\r
1715   }\r
1716   return EFI_NOT_FOUND;\r
1717 }\r
1718 \r
1719 \r
1720 /**\r
1721   Read the EFI variable (VendorGuid/Name) and return a dynamically allocated\r
1722   buffer, and the size of the buffer. If failure return NULL.\r
1723 \r
1724   @param  Name                     String part of EFI variable name\r
1725   @param  VendorGuid               GUID part of EFI variable name\r
1726   @param  VariableSize             Returns the size of the EFI variable that was\r
1727                                    read\r
1728 \r
1729   @return Dynamically allocated memory that contains a copy of the EFI variable.\r
1730   @return Caller is responsible freeing the buffer.\r
1731   @retval NULL                     Variable was not read\r
1732 \r
1733 **/\r
1734 VOID *\r
1735 EFIAPI\r
1736 GetVariableAndSize (\r
1737   IN  CHAR16              *Name,\r
1738   IN  EFI_GUID            *VendorGuid,\r
1739   OUT UINTN               *VariableSize\r
1740   )\r
1741 {\r
1742   EFI_STATUS  Status;\r
1743   UINTN       BufferSize;\r
1744   VOID        *Buffer;\r
1745 \r
1746   Buffer = NULL;\r
1747 \r
1748   //\r
1749   // Pass in a zero size buffer to find the required buffer size.\r
1750   //\r
1751   BufferSize  = 0;\r
1752   Status      = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);\r
1753   if (Status == EFI_BUFFER_TOO_SMALL) {\r
1754     //\r
1755     // Allocate the buffer to return\r
1756     //\r
1757     Buffer = AllocateZeroPool (BufferSize);\r
1758     if (Buffer == NULL) {\r
1759       return NULL;\r
1760     }\r
1761     //\r
1762     // Read variable into the allocated buffer.\r
1763     //\r
1764     Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);\r
1765     if (EFI_ERROR (Status)) {\r
1766       BufferSize = 0;\r
1767     }\r
1768   }\r
1769 \r
1770   *VariableSize = BufferSize;\r
1771   return Buffer;\r
1772 }\r
1773 \r
1774 \r
1775 /**\r
1776   This function will create all handles associate with every device\r
1777   path node. If the handle associate with one device path node can not\r
1778   be created success, then still give one chance to do the dispatch,\r
1779   which load the missing drivers if possible.\r
1780 \r
1781   @param  DevicePathToConnect      The device path which will be connected, it can\r
1782                                    be a multi-instance device path\r
1783 \r
1784   @retval EFI_SUCCESS              All handles associate with every device path\r
1785                                    node have been created\r
1786   @retval EFI_OUT_OF_RESOURCES     There is no resource to create new handles\r
1787   @retval EFI_NOT_FOUND            Create the handle associate with one device\r
1788                                    path node failed\r
1789 \r
1790 **/\r
1791 EFI_STATUS\r
1792 EFIAPI\r
1793 ConnectDevicePath (\r
1794   IN EFI_DEVICE_PATH_PROTOCOL  *DevicePathToConnect\r
1795   )\r
1796 {\r
1797   EFI_STATUS                Status;\r
1798   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
1799   EFI_DEVICE_PATH_PROTOCOL  *CopyOfDevicePath;\r
1800   EFI_DEVICE_PATH_PROTOCOL  *Instance;\r
1801   EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath;\r
1802   EFI_DEVICE_PATH_PROTOCOL  *Next;\r
1803   EFI_HANDLE                Handle;\r
1804   EFI_HANDLE                PreviousHandle;\r
1805   UINTN                     Size;\r
1806 \r
1807   if (DevicePathToConnect == NULL) {\r
1808     return EFI_SUCCESS;\r
1809   }\r
1810 \r
1811   DevicePath        = DuplicateDevicePath (DevicePathToConnect);\r
1812   CopyOfDevicePath  = DevicePath;\r
1813   if (DevicePath == NULL) {\r
1814     return EFI_OUT_OF_RESOURCES;\r
1815   }\r
1816 \r
1817   do {\r
1818     //\r
1819     // The outer loop handles multi instance device paths.\r
1820     // Only console variables contain multiple instance device paths.\r
1821     //\r
1822     // After this call DevicePath points to the next Instance\r
1823     //\r
1824     Instance  = GetNextDevicePathInstance (&DevicePath, &Size);\r
1825     Next      = Instance;\r
1826     while (!IsDevicePathEndType (Next)) {\r
1827       Next = NextDevicePathNode (Next);\r
1828     }\r
1829 \r
1830     SetDevicePathEndNode (Next);\r
1831 \r
1832     //\r
1833     // Start the real work of connect with RemainingDevicePath\r
1834     //\r
1835     PreviousHandle = NULL;\r
1836     do {\r
1837       //\r
1838       // Find the handle that best matches the Device Path. If it is only a\r
1839       // partial match the remaining part of the device path is returned in\r
1840       // RemainingDevicePath.\r
1841       //\r
1842       RemainingDevicePath = Instance;\r
1843       Status              = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle);\r
1844 \r
1845       if (!EFI_ERROR (Status)) {\r
1846         if (Handle == PreviousHandle) {\r
1847           //\r
1848           // If no forward progress is made try invoking the Dispatcher.\r
1849           // A new FV may have been added to the system an new drivers\r
1850           // may now be found.\r
1851           // Status == EFI_SUCCESS means a driver was dispatched\r
1852           // Status == EFI_NOT_FOUND means no new drivers were dispatched\r
1853           //\r
1854           Status = gDS->Dispatch ();\r
1855         }\r
1856 \r
1857         if (!EFI_ERROR (Status)) {\r
1858           PreviousHandle = Handle;\r
1859           //\r
1860           // Connect all drivers that apply to Handle and RemainingDevicePath,\r
1861           // the Recursive flag is FALSE so only one level will be expanded.\r
1862           //\r
1863           // Do not check the connect status here, if the connect controller fail,\r
1864           // then still give the chance to do dispatch, because partial\r
1865           // RemainingDevicepath may be in the new FV\r
1866           //\r
1867           // 1. If the connect fail, RemainingDevicepath and handle will not\r
1868           //    change, so next time will do the dispatch, then dispatch's status\r
1869           //    will take effect\r
1870           // 2. If the connect success, the RemainingDevicepath and handle will\r
1871           //    change, then avoid the dispatch, we have chance to continue the\r
1872           //    next connection\r
1873           //\r
1874           gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE);\r
1875         }\r
1876       }\r
1877       //\r
1878       // Loop until RemainingDevicePath is an empty device path\r
1879       //\r
1880     } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath));\r
1881 \r
1882   } while (DevicePath != NULL);\r
1883 \r
1884   if (CopyOfDevicePath != NULL) {\r
1885     FreePool (CopyOfDevicePath);\r
1886   }\r
1887   //\r
1888   // All handle with DevicePath exists in the handle database\r
1889   //\r
1890   return Status;\r
1891 }\r