Correct data print format.
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Universal / BdsDxe / BootMaint / BBSsupport.c
1 /** @file\r
2   This function deal with the legacy boot option, it create, delete\r
3   and manage the legacy boot option, all legacy boot option is getting from\r
4   the legacy BBS table.\r
5 \r
6 Copyright (c) 2004 - 2008, Intel Corporation. <BR>\r
7 All rights reserved. This program and the accompanying materials\r
8 are licensed and made available under the terms and conditions of the BSD License\r
9 which accompanies this distribution.  The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php\r
11 \r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14 \r
15 **/\r
16 \r
17 #include "BBSsupport.h"\r
18 \r
19 EFI_DEVICE_PATH_PROTOCOL  EndDevicePath[] = {\r
20   END_DEVICE_PATH_TYPE,\r
21   END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
22   END_DEVICE_PATH_LENGTH,\r
23   0\r
24 };\r
25 \r
26 VOID\r
27 AsciiToUnicodeSize (\r
28   IN UINT8              *a,\r
29   IN UINTN              Size,\r
30   OUT UINT16            *u\r
31   )\r
32 /*++\r
33 \r
34   Routine Description:\r
35 \r
36     Translate the first n characters of an Ascii string to\r
37     Unicode characters. The count n is indicated by parameter\r
38     Size. If Size is greater than the length of string, then\r
39     the entire string is translated.\r
40 \r
41   Arguments:\r
42 \r
43     a         - Pointer to input Ascii string.\r
44     Size      - The number of characters to translate.\r
45     u         - Pointer to output Unicode string buffer.\r
46 \r
47   Returns:\r
48 \r
49     None\r
50 \r
51 --*/\r
52 {\r
53   UINTN i;\r
54 \r
55   i = 0;\r
56   while (a[i] != 0) {\r
57     u[i] = (CHAR16) a[i];\r
58     if (i == Size) {\r
59       break;\r
60     }\r
61 \r
62     i++;\r
63   }\r
64   u[i] = 0;\r
65 }\r
66 \r
67 UINTN\r
68 UnicodeToAscii (\r
69   IN  CHAR16  *UStr,\r
70   IN  UINTN   Length,\r
71   OUT CHAR8   *AStr\r
72   )\r
73 /*++\r
74 Routine Description:\r
75 \r
76   change a Unicode string t ASCII string\r
77 \r
78 Arguments:\r
79 \r
80   UStr   - Unicode string\r
81   Lenght - most possible length of AStr\r
82   AStr   - ASCII string to pass out\r
83 \r
84 Returns:\r
85 \r
86   Actuall length\r
87 \r
88 --*/\r
89 {\r
90   UINTN Index;\r
91 \r
92   //\r
93   // just buffer copy, not character copy\r
94   //\r
95   for (Index = 0; Index < Length; Index++) {\r
96     *AStr++ = (CHAR8) *UStr++;\r
97   }\r
98 \r
99   return Index;\r
100 }\r
101 \r
102 VOID\r
103 BdsBuildLegacyDevNameString (\r
104   IN BBS_TABLE                 *CurBBSEntry,\r
105   IN UINTN                     Index,\r
106   IN UINTN                     BufSize,\r
107   OUT CHAR16                   *BootString\r
108   )\r
109 {\r
110   CHAR16  *Fmt;\r
111   CHAR16  *Type;\r
112   UINT8   *StringDesc;\r
113   CHAR16  temp[80];\r
114 \r
115   switch (Index) {\r
116   //\r
117   // Primary Master\r
118   //\r
119   case 1:\r
120     Fmt = L"Primary Master %s";\r
121     break;\r
122 \r
123  //\r
124  // Primary Slave\r
125  //\r
126   case 2:\r
127     Fmt = L"Primary Slave %s";\r
128     break;\r
129 \r
130   //\r
131   // Secondary Master\r
132   //\r
133   case 3:\r
134     Fmt = L"Secondary Master %s";\r
135     break;\r
136 \r
137   //\r
138   // Secondary Slave\r
139   //\r
140   case 4:\r
141     Fmt = L"Secondary Slave %s";\r
142     break;\r
143 \r
144   default:\r
145     Fmt = L"%s";\r
146     break;\r
147   }\r
148 \r
149   switch (CurBBSEntry->DeviceType) {\r
150   case BBS_FLOPPY:\r
151     Type = L"Floppy";\r
152     break;\r
153 \r
154   case BBS_HARDDISK:\r
155     Type = L"Harddisk";\r
156     break;\r
157 \r
158   case BBS_CDROM:\r
159     Type = L"CDROM";\r
160     break;\r
161 \r
162   case BBS_PCMCIA:\r
163     Type = L"PCMCIAe";\r
164     break;\r
165 \r
166   case BBS_USB:\r
167     Type = L"USB";\r
168     break;\r
169 \r
170   case BBS_EMBED_NETWORK:\r
171     Type = L"Network";\r
172     break;\r
173 \r
174   case BBS_BEV_DEVICE:\r
175     Type = L"BEVe";\r
176     break;\r
177 \r
178   case BBS_UNKNOWN:\r
179   default:\r
180     Type = L"Unknown";\r
181     break;\r
182   }\r
183   //\r
184   // If current BBS entry has its description then use it.\r
185   //\r
186   StringDesc = (UINT8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset);\r
187   if (NULL != StringDesc) {\r
188     //\r
189     // Only get fisrt 32 characters, this is suggested by BBS spec\r
190     //\r
191     AsciiToUnicodeSize (StringDesc, 32, temp);\r
192     Fmt   = L"%s";\r
193     Type  = temp;\r
194   }\r
195 \r
196   //\r
197   // BbsTable 16 entries are for onboard IDE.\r
198   // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11\r
199   //\r
200   if (Index >= 5 && Index <= 16 && CurBBSEntry->DeviceType == BBS_HARDDISK) {\r
201     Fmt = L"%s %d";\r
202     UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5);\r
203   } else {\r
204     UnicodeSPrint (BootString, BufSize, Fmt, Type);\r
205   }\r
206 }\r
207 \r
208 EFI_STATUS\r
209 BdsCreateLegacyBootOption (\r
210   IN BBS_TABLE                        *CurrentBbsEntry,\r
211   IN EFI_DEVICE_PATH_PROTOCOL         *CurrentBbsDevPath,\r
212   IN UINTN                            Index,\r
213   IN OUT UINT16                       **BootOrderList,\r
214   IN OUT UINTN                        *BootOrderListSize\r
215   )\r
216 /*++\r
217 \r
218   Routine Description:\r
219 \r
220     Create a legacy boot option for the specified entry of\r
221     BBS table, save it as variable, and append it to the boot\r
222     order list.\r
223 \r
224   Arguments:\r
225 \r
226     CurrentBbsEntry        - Pointer to current BBS table.\r
227     CurrentBbsDevPath      - Pointer to the Device Path Protocol instance of BBS\r
228     Index                  - Index of the specified entry in BBS table.\r
229     BootOrderList          - On input, the original boot order list.\r
230                              On output, the new boot order list attached with the\r
231                              created node.\r
232     BootOrderListSize      - On input, the original size of boot order list.\r
233                            - On output, the size of new boot order list.\r
234 \r
235   Returns:\r
236 \r
237     EFI_SUCCESS            - Boot Option successfully created.\r
238     EFI_OUT_OF_RESOURCES   - Fail to allocate necessary memory.\r
239     Other                  - Error occurs while setting variable.\r
240 \r
241 --*/\r
242 {\r
243   EFI_STATUS           Status;\r
244   UINT16               CurrentBootOptionNo;\r
245   UINT16               BootString[10];\r
246   UINT16               BootDesc[100];\r
247   CHAR8                HelpString[100];\r
248   UINT16               *NewBootOrderList;\r
249   UINTN                BufferSize;\r
250   UINTN                StringLen;\r
251   VOID                 *Buffer;\r
252   UINT8                *Ptr;\r
253   UINT16               CurrentBbsDevPathSize;\r
254   UINTN                BootOrderIndex;\r
255   UINTN                BootOrderLastIndex;\r
256   UINTN                ArrayIndex;\r
257   BOOLEAN              IndexNotFound;\r
258   BBS_BBS_DEVICE_PATH  *NewBbsDevPathNode;\r
259 \r
260   if (NULL == (*BootOrderList)) {\r
261     CurrentBootOptionNo = 0;\r
262   } else {\r
263     for (ArrayIndex = 0; ArrayIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); ArrayIndex++) {\r
264       IndexNotFound = TRUE;\r
265       for (BootOrderIndex = 0; BootOrderIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); BootOrderIndex++) {\r
266         if ((*BootOrderList)[BootOrderIndex] == ArrayIndex) {\r
267           IndexNotFound = FALSE;\r
268           break;\r
269         }\r
270       }\r
271 \r
272       if (!IndexNotFound) {\r
273         continue;\r
274       } else {\r
275         break;\r
276       }\r
277     }\r
278 \r
279     CurrentBootOptionNo = (UINT16) ArrayIndex;\r
280   }\r
281 \r
282   UnicodeSPrint (\r
283     BootString,\r
284     sizeof (BootString),\r
285     L"Boot%04x",\r
286     CurrentBootOptionNo\r
287     );\r
288 \r
289   BdsBuildLegacyDevNameString (CurrentBbsEntry, Index, sizeof (BootDesc), BootDesc);\r
290 \r
291   //\r
292   // Create new BBS device path node with description string\r
293   //\r
294   UnicodeToAscii (BootDesc, StrSize (BootDesc), HelpString);\r
295   StringLen = AsciiStrLen (HelpString);\r
296   NewBbsDevPathNode = EfiAllocateZeroPool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen);\r
297   if (NewBbsDevPathNode == NULL) {\r
298     return EFI_OUT_OF_RESOURCES;\r
299   }\r
300   CopyMem (NewBbsDevPathNode, CurrentBbsDevPath, sizeof (BBS_BBS_DEVICE_PATH));\r
301   CopyMem (NewBbsDevPathNode->String, HelpString, StringLen + 1);\r
302   SetDevicePathNodeLength (&(NewBbsDevPathNode->Header), sizeof (BBS_BBS_DEVICE_PATH) + StringLen);\r
303 \r
304   //\r
305   // Create entire new CurrentBbsDevPath with end node\r
306   //\r
307   CurrentBbsDevPath = AppendDevicePathNode (\r
308                         EndDevicePath,\r
309                         (EFI_DEVICE_PATH_PROTOCOL *) NewBbsDevPathNode\r
310                         );\r
311    if (CurrentBbsDevPath == NULL) {\r
312     FreePool (NewBbsDevPathNode);\r
313     return EFI_OUT_OF_RESOURCES;\r
314   }\r
315 \r
316   CurrentBbsDevPathSize = (UINT16) (GetDevicePathSize (CurrentBbsDevPath));\r
317 \r
318   BufferSize = sizeof (UINT32) +\r
319     sizeof (UINT16) +\r
320     StrSize (BootDesc) +\r
321     CurrentBbsDevPathSize +\r
322     sizeof (BBS_TABLE) +\r
323     sizeof (UINT16);\r
324 \r
325   Buffer = EfiAllocateZeroPool (BufferSize);\r
326   if (Buffer == NULL) {\r
327     FreePool (NewBbsDevPathNode);\r
328     FreePool (CurrentBbsDevPath);\r
329     return EFI_OUT_OF_RESOURCES;\r
330   }\r
331 \r
332   Ptr               = (UINT8 *) Buffer;\r
333 \r
334   *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE;\r
335   Ptr += sizeof (UINT32);\r
336 \r
337   *((UINT16 *) Ptr) = CurrentBbsDevPathSize;\r
338   Ptr += sizeof (UINT16);\r
339 \r
340   CopyMem (\r
341     Ptr,\r
342     BootDesc,\r
343     StrSize (BootDesc)\r
344     );\r
345   Ptr += StrSize (BootDesc);\r
346 \r
347   CopyMem (\r
348     Ptr,\r
349     CurrentBbsDevPath,\r
350     CurrentBbsDevPathSize\r
351     );\r
352   Ptr += CurrentBbsDevPathSize;\r
353 \r
354   CopyMem (\r
355     Ptr,\r
356     CurrentBbsEntry,\r
357     sizeof (BBS_TABLE)\r
358     );\r
359 \r
360   Ptr += sizeof (BBS_TABLE);\r
361   *((UINT16 *) Ptr) = (UINT16) Index;\r
362 \r
363   Status = gRT->SetVariable (\r
364                   BootString,\r
365                   &gEfiGlobalVariableGuid,\r
366                   VAR_FLAG,\r
367                   BufferSize,\r
368                   Buffer\r
369                   );\r
370 \r
371   SafeFreePool (Buffer);\r
372   Buffer = NULL;\r
373 \r
374   NewBootOrderList = EfiAllocateZeroPool (*BootOrderListSize + sizeof (UINT16));\r
375   if (NULL == NewBootOrderList) {\r
376     FreePool (NewBbsDevPathNode);\r
377     FreePool (CurrentBbsDevPath);\r
378     return EFI_OUT_OF_RESOURCES;\r
379   }\r
380 \r
381   if (NULL != *BootOrderList) {\r
382     CopyMem (NewBootOrderList, *BootOrderList, *BootOrderListSize);\r
383   }\r
384 \r
385   SafeFreePool (*BootOrderList);\r
386 \r
387   BootOrderLastIndex                    = (UINTN) (*BootOrderListSize / sizeof (UINT16));\r
388   NewBootOrderList[BootOrderLastIndex]  = CurrentBootOptionNo;\r
389   *BootOrderListSize += sizeof (UINT16);\r
390   *BootOrderList = NewBootOrderList;\r
391 \r
392   FreePool (NewBbsDevPathNode);\r
393   FreePool (CurrentBbsDevPath);\r
394   return Status;\r
395 }\r
396 \r
397 BOOLEAN\r
398 BdsIsLegacyBootOption (\r
399   IN UINT8                 *BootOptionVar,\r
400   OUT BBS_TABLE            **BbsEntry,\r
401   OUT UINT16               *BbsIndex\r
402   )\r
403 {\r
404   UINT8                     *Ptr;\r
405   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;\r
406   BOOLEAN                   Ret;\r
407   UINT16                    DevPathLen;\r
408 \r
409   Ptr = BootOptionVar;\r
410   Ptr += sizeof (UINT32);\r
411   DevPathLen = *(UINT16 *) Ptr;\r
412   Ptr += sizeof (UINT16);\r
413   Ptr += StrSize ((UINT16 *) Ptr);\r
414   DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;\r
415   if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {\r
416     Ptr += DevPathLen;\r
417     *BbsEntry = (BBS_TABLE *) Ptr;\r
418     Ptr += sizeof (BBS_TABLE);\r
419     *BbsIndex = *(UINT16 *) Ptr;\r
420     Ret       = TRUE;\r
421   } else {\r
422     *BbsEntry = NULL;\r
423     Ret       = FALSE;\r
424   }\r
425 \r
426   return Ret;\r
427 }\r
428 \r
429 EFI_STATUS\r
430 BdsDeleteBootOption (\r
431   IN UINTN                       OptionNumber,\r
432   IN OUT UINT16                  *BootOrder,\r
433   IN OUT UINTN                   *BootOrderSize\r
434   )\r
435 {\r
436   UINT16      BootOption[100];\r
437   UINTN       Index;\r
438   EFI_STATUS  Status;\r
439   UINTN       Index2Del;\r
440 \r
441   Status    = EFI_SUCCESS;\r
442   Index2Del = 0;\r
443 \r
444   UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", OptionNumber);\r
445   Status = EfiLibDeleteVariable (BootOption, &gEfiGlobalVariableGuid);\r
446   //\r
447   // adjust boot order array\r
448   //\r
449   for (Index = 0; Index < *BootOrderSize / sizeof (UINT16); Index++) {\r
450     if (BootOrder[Index] == OptionNumber) {\r
451       Index2Del = Index;\r
452       break;\r
453     }\r
454   }\r
455 \r
456   if (Index != *BootOrderSize / sizeof (UINT16)) {\r
457     for (Index = 0; Index < *BootOrderSize / sizeof (UINT16) - 1; Index++) {\r
458       if (Index >= Index2Del) {\r
459         BootOrder[Index] = BootOrder[Index + 1];\r
460       }\r
461     }\r
462 \r
463     *BootOrderSize -= sizeof (UINT16);\r
464   }\r
465 \r
466   return Status;\r
467 \r
468 }\r
469 \r
470 EFI_STATUS\r
471 BdsDeleteAllInvalidLegacyBootOptions (\r
472   VOID\r
473   )\r
474 /*++\r
475 \r
476   Routine Description:\r
477 \r
478     Delete all the invalid legacy boot options.\r
479 \r
480   Arguments:\r
481 \r
482     None.\r
483 \r
484   Returns:\r
485 \r
486     EFI_SUCCESS            - All invalide legacy boot options are deleted.\r
487     EFI_OUT_OF_RESOURCES   - Fail to allocate necessary memory.\r
488     EFI_NOT_FOUND          - Fail to retrive variable of boot order.\r
489     Other                  - Error occurs while setting variable or locating\r
490                              protocol.\r
491 \r
492 --*/\r
493 {\r
494   UINT16                    *BootOrder;\r
495   UINT8                     *BootOptionVar;\r
496   UINTN                     BootOrderSize;\r
497   UINTN                     BootOptionSize;\r
498   EFI_STATUS                Status;\r
499   UINT16                    HddCount;\r
500   UINT16                    BbsCount;\r
501   HDD_INFO                  *LocalHddInfo;\r
502   BBS_TABLE                 *LocalBbsTable;\r
503   BBS_TABLE                 *BbsEntry;\r
504   UINT16                    BbsIndex;\r
505   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
506   UINTN                     Index;\r
507   UINT16                    BootOption[10];\r
508   UINT16                    BootDesc[100];\r
509   BOOLEAN                   DescStringMatch;\r
510 \r
511   Status        = EFI_SUCCESS;\r
512   BootOrder     = NULL;\r
513   BootOrderSize = 0;\r
514   HddCount      = 0;\r
515   BbsCount      = 0;\r
516   LocalHddInfo  = NULL;\r
517   LocalBbsTable = NULL;\r
518   BbsEntry      = NULL;\r
519 \r
520   Status        = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);\r
521   if (EFI_ERROR (Status)) {\r
522     return Status;\r
523   }\r
524 \r
525   LegacyBios->GetBbsInfo (\r
526                 LegacyBios,\r
527                 &HddCount,\r
528                 &LocalHddInfo,\r
529                 &BbsCount,\r
530                 &LocalBbsTable\r
531                 );\r
532 \r
533   BootOrder = BdsLibGetVariableAndSize (\r
534                 L"BootOrder",\r
535                 &gEfiGlobalVariableGuid,\r
536                 &BootOrderSize\r
537                 );\r
538   if (NULL == BootOrder) {\r
539     return EFI_NOT_FOUND;\r
540   }\r
541 \r
542   Index = 0;\r
543   while (Index < BootOrderSize / sizeof (UINT16)) {\r
544     UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
545     BootOptionVar = BdsLibGetVariableAndSize (\r
546                       BootOption,\r
547                       &gEfiGlobalVariableGuid,\r
548                       &BootOptionSize\r
549                       );\r
550     if (NULL == BootOptionVar) {\r
551       SafeFreePool (BootOrder);\r
552       return EFI_OUT_OF_RESOURCES;\r
553     }\r
554 \r
555     if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, &BbsIndex)) {\r
556       SafeFreePool (BootOptionVar);\r
557       Index++;\r
558       continue;\r
559     }\r
560 \r
561     //\r
562     // Check if BBS Description String is changed\r
563     //\r
564     DescStringMatch = FALSE;\r
565 \r
566     BdsBuildLegacyDevNameString (\r
567       &LocalBbsTable[BbsIndex],\r
568       BbsIndex,\r
569       sizeof(BootDesc),\r
570       BootDesc\r
571       );\r
572 \r
573     if (StrCmp (BootDesc, (UINT16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) == 0) {\r
574       DescStringMatch = TRUE;\r
575     }\r
576 \r
577     if (!((LocalBbsTable[BbsIndex].BootPriority == BBS_IGNORE_ENTRY) ||\r
578           (LocalBbsTable[BbsIndex].BootPriority == BBS_DO_NOT_BOOT_FROM)) &&\r
579         (LocalBbsTable[BbsIndex].DeviceType == BbsEntry->DeviceType) &&\r
580         DescStringMatch) {\r
581       Index++;\r
582       continue;\r
583     }\r
584 \r
585     SafeFreePool (BootOptionVar);\r
586     //\r
587     // should delete\r
588     //\r
589     BdsDeleteBootOption (\r
590       BootOrder[Index],\r
591       BootOrder,\r
592       &BootOrderSize\r
593       );\r
594   }\r
595 \r
596   if (BootOrderSize) {\r
597     Status = gRT->SetVariable (\r
598                     L"BootOrder",\r
599                     &gEfiGlobalVariableGuid,\r
600                     VAR_FLAG,\r
601                     BootOrderSize,\r
602                     BootOrder\r
603                     );\r
604   } else {\r
605     EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);\r
606   }\r
607 \r
608   SafeFreePool (BootOrder);\r
609 \r
610   return Status;\r
611 }\r
612 \r
613 BOOLEAN\r
614 BdsFindLegacyBootOptionByDevType (\r
615   IN UINT16                 *BootOrder,\r
616   IN UINTN                  BootOptionNum,\r
617   IN UINT16                 DevType,\r
618   OUT UINT32                *Attribute,\r
619   OUT UINT16                *BbsIndex,\r
620   OUT UINTN                 *OptionNumber\r
621   )\r
622 {\r
623   UINTN     Index;\r
624   UINTN     BootOrderIndex;\r
625   UINT16    BootOption[100];\r
626   UINTN     BootOptionSize;\r
627   UINT8     *BootOptionVar;\r
628   BBS_TABLE *BbsEntry;\r
629   BOOLEAN   Found;\r
630 \r
631   BbsEntry  = NULL;\r
632   Found     = FALSE;\r
633 \r
634   if (NULL == BootOrder) {\r
635     return Found;\r
636   }\r
637 \r
638   for (BootOrderIndex = 0; BootOrderIndex < BootOptionNum; BootOrderIndex++) {\r
639     Index = (UINTN) BootOrder[BootOrderIndex];\r
640     UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", Index);\r
641     BootOptionVar = BdsLibGetVariableAndSize (\r
642                       BootOption,\r
643                       &gEfiGlobalVariableGuid,\r
644                       &BootOptionSize\r
645                       );\r
646     if (NULL == BootOptionVar) {\r
647       continue;\r
648     }\r
649 \r
650     if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, BbsIndex)) {\r
651       SafeFreePool (BootOptionVar);\r
652       continue;\r
653     }\r
654 \r
655     if (BbsEntry->DeviceType != DevType) {\r
656       SafeFreePool (BootOptionVar);\r
657       continue;\r
658     }\r
659 \r
660     *Attribute    = *(UINT32 *) BootOptionVar;\r
661     *OptionNumber = Index;\r
662     Found         = TRUE;\r
663     SafeFreePool (BootOptionVar);\r
664     break;\r
665   }\r
666 \r
667   return Found;\r
668 }\r
669 \r
670 EFI_STATUS\r
671 BdsCreateOneLegacyBootOption (\r
672   IN BBS_TABLE              *BbsItem,\r
673   IN UINTN                  Index,\r
674   IN OUT UINT16             **BootOrderList,\r
675   IN OUT UINTN              *BootOrderListSize\r
676   )\r
677 {\r
678   BBS_BBS_DEVICE_PATH       BbsDevPathNode;\r
679   EFI_STATUS                Status;\r
680   EFI_DEVICE_PATH_PROTOCOL  *DevPath;\r
681 \r
682   DevPath                       = NULL;\r
683 \r
684   BbsDevPathNode.Header.Type    = BBS_DEVICE_PATH;\r
685   BbsDevPathNode.Header.SubType = BBS_BBS_DP;\r
686   SetDevicePathNodeLength (&BbsDevPathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));\r
687   BbsDevPathNode.DeviceType = BbsItem->DeviceType;\r
688   CopyMem (&BbsDevPathNode.StatusFlag, &BbsItem->StatusFlags, sizeof (UINT16));\r
689 \r
690   DevPath = AppendDevicePathNode (\r
691               EndDevicePath,\r
692               (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevPathNode\r
693               );\r
694   if (NULL == DevPath) {\r
695     return EFI_OUT_OF_RESOURCES;\r
696   }\r
697 \r
698   Status = BdsCreateLegacyBootOption (\r
699             BbsItem,\r
700             DevPath,\r
701             Index,\r
702             BootOrderList,\r
703             BootOrderListSize\r
704             );\r
705   BbsItem->BootPriority = 0x00;\r
706 \r
707   FreePool (DevPath);\r
708 \r
709   return Status;\r
710 }\r
711 \r
712 EFI_STATUS\r
713 BdsAddNonExistingLegacyBootOptions (\r
714   VOID\r
715   )\r
716 /*++\r
717 \r
718 Routine Description:\r
719 \r
720   Add the legacy boot options from BBS table if they do not exist.\r
721 \r
722 Arguments:\r
723 \r
724   None.\r
725 \r
726 Returns:\r
727 \r
728   EFI_SUCCESS       - The boot options are added successfully or they are already in boot options.\r
729   others            - An error occurred when creating legacy boot options.\r
730 \r
731 --*/\r
732 {\r
733   UINT16                    *BootOrder;\r
734   UINTN                     BootOrderSize;\r
735   EFI_STATUS                Status;\r
736   UINT16                    HddCount;\r
737   UINT16                    BbsCount;\r
738   HDD_INFO                  *LocalHddInfo;\r
739   BBS_TABLE                 *LocalBbsTable;\r
740   UINT16                    BbsIndex;\r
741   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
742   UINTN                     Index;\r
743   UINT32                    Attribute;\r
744   UINTN                     OptionNumber;\r
745   BOOLEAN                   Ret;\r
746 \r
747   BootOrder     = NULL;\r
748   HddCount      = 0;\r
749   BbsCount      = 0;\r
750   LocalHddInfo  = NULL;\r
751   LocalBbsTable = NULL;\r
752 \r
753   Status        = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);\r
754   if (EFI_ERROR (Status)) {\r
755     return Status;\r
756   }\r
757 \r
758   LegacyBios->GetBbsInfo (\r
759                 LegacyBios,\r
760                 &HddCount,\r
761                 &LocalHddInfo,\r
762                 &BbsCount,\r
763                 &LocalBbsTable\r
764                 );\r
765 \r
766   BootOrder = BdsLibGetVariableAndSize (\r
767                 L"BootOrder",\r
768                 &gEfiGlobalVariableGuid,\r
769                 &BootOrderSize\r
770                 );\r
771   if (NULL == BootOrder) {\r
772     BootOrderSize = 0;\r
773   }\r
774 \r
775   for (Index = 0; Index < BbsCount; Index++) {\r
776     if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||\r
777         (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)\r
778         ) {\r
779       continue;\r
780     }\r
781 \r
782     Ret = BdsFindLegacyBootOptionByDevType (\r
783             BootOrder,\r
784             BootOrderSize / sizeof (UINT16),\r
785             LocalBbsTable[Index].DeviceType,\r
786             &Attribute,\r
787             &BbsIndex,\r
788             &OptionNumber\r
789             );\r
790     if (Ret) {\r
791       continue;\r
792     }\r
793 \r
794     //\r
795     // Not found such type of legacy device in boot options or we found but it's disabled\r
796     // so we have to create one and put it to the tail of boot order list\r
797     //\r
798     Status = BdsCreateOneLegacyBootOption (\r
799               &LocalBbsTable[Index],\r
800               Index,\r
801               &BootOrder,\r
802               &BootOrderSize\r
803               );\r
804     if (EFI_ERROR (Status)) {\r
805       break;\r
806     }\r
807   }\r
808 \r
809   if (BootOrderSize > 0) {\r
810     Status = gRT->SetVariable (\r
811                     L"BootOrder",\r
812                     &gEfiGlobalVariableGuid,\r
813                     VAR_FLAG,\r
814                     BootOrderSize,\r
815                     BootOrder\r
816                     );\r
817   } else {\r
818     EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);\r
819   }\r
820 \r
821   if (BootOrder != NULL) {\r
822     SafeFreePool (BootOrder);\r
823   }\r
824 \r
825   return Status;\r
826 }\r
827 \r
828 UINT16 *\r
829 BdsFillDevOrderBuf (\r
830   IN BBS_TABLE                    *BbsTable,\r
831   IN BBS_TYPE                     BbsType,\r
832   IN UINTN                        BbsCount,\r
833   IN UINT16                       *Buf\r
834   )\r
835 {\r
836   UINTN Index;\r
837 \r
838   for (Index = 0; Index < BbsCount; Index++) {\r
839     if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {\r
840       continue;\r
841     }\r
842 \r
843     if (BbsTable[Index].DeviceType != BbsType) {\r
844       continue;\r
845     }\r
846 \r
847     *Buf = (UINT16) (Index & 0xFF);\r
848     Buf++;\r
849   }\r
850 \r
851   return Buf;\r
852 }\r
853 \r
854 EFI_STATUS\r
855 BdsCreateDevOrder (\r
856   IN BBS_TABLE                  *BbsTable,\r
857   IN UINT16                     BbsCount\r
858   )\r
859 {\r
860   UINTN       Index;\r
861   UINTN       FDCount;\r
862   UINTN       HDCount;\r
863   UINTN       CDCount;\r
864   UINTN       NETCount;\r
865   UINTN       BEVCount;\r
866   UINTN       TotalSize;\r
867   UINTN       HeaderSize;\r
868   UINT8       *DevOrder;\r
869   UINT8       *Ptr;\r
870   EFI_STATUS  Status;\r
871 \r
872   FDCount     = 0;\r
873   HDCount     = 0;\r
874   CDCount     = 0;\r
875   NETCount    = 0;\r
876   BEVCount    = 0;\r
877   TotalSize   = 0;\r
878   HeaderSize  = sizeof (BBS_TYPE) + sizeof (UINT16);\r
879   DevOrder    = NULL;\r
880   Ptr         = NULL;\r
881   Status      = EFI_SUCCESS;\r
882 \r
883   for (Index = 0; Index < BbsCount; Index++) {\r
884     if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {\r
885       continue;\r
886     }\r
887 \r
888     switch (BbsTable[Index].DeviceType) {\r
889     case BBS_FLOPPY:\r
890       FDCount++;\r
891       break;\r
892 \r
893     case BBS_HARDDISK:\r
894       HDCount++;\r
895       break;\r
896 \r
897     case BBS_CDROM:\r
898       CDCount++;\r
899       break;\r
900 \r
901     case BBS_EMBED_NETWORK:\r
902       NETCount++;\r
903       break;\r
904 \r
905     case BBS_BEV_DEVICE:\r
906       BEVCount++;\r
907       break;\r
908 \r
909     default:\r
910       break;\r
911     }\r
912   }\r
913 \r
914   TotalSize += (HeaderSize + sizeof (UINT16) * FDCount);\r
915   TotalSize += (HeaderSize + sizeof (UINT16) * HDCount);\r
916   TotalSize += (HeaderSize + sizeof (UINT16) * CDCount);\r
917   TotalSize += (HeaderSize + sizeof (UINT16) * NETCount);\r
918   TotalSize += (HeaderSize + sizeof (UINT16) * BEVCount);\r
919 \r
920   DevOrder = EfiAllocateZeroPool (TotalSize);\r
921   if (NULL == DevOrder) {\r
922     return EFI_OUT_OF_RESOURCES;\r
923   }\r
924 \r
925   Ptr                 = DevOrder;\r
926 \r
927   *((BBS_TYPE *) Ptr) = BBS_FLOPPY;\r
928   Ptr += sizeof (BBS_TYPE);\r
929   *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));\r
930   Ptr += sizeof (UINT16);\r
931   if (FDCount) {\r
932     Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_FLOPPY, BbsCount, (UINT16 *) Ptr);\r
933   }\r
934 \r
935   *((BBS_TYPE *) Ptr) = BBS_HARDDISK;\r
936   Ptr += sizeof (BBS_TYPE);\r
937   *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));\r
938   Ptr += sizeof (UINT16);\r
939   if (HDCount) {\r
940     Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_HARDDISK, BbsCount, (UINT16 *) Ptr);\r
941   }\r
942 \r
943   *((BBS_TYPE *) Ptr) = BBS_CDROM;\r
944   Ptr += sizeof (BBS_TYPE);\r
945   *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));\r
946   Ptr += sizeof (UINT16);\r
947   if (CDCount) {\r
948     Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_CDROM, BbsCount, (UINT16 *) Ptr);\r
949   }\r
950 \r
951   *((BBS_TYPE *) Ptr) = BBS_EMBED_NETWORK;\r
952   Ptr += sizeof (BBS_TYPE);\r
953   *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));\r
954   Ptr += sizeof (UINT16);\r
955   if (NETCount) {\r
956     Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_EMBED_NETWORK, BbsCount, (UINT16 *) Ptr);\r
957   }\r
958 \r
959   *((BBS_TYPE *) Ptr) = BBS_BEV_DEVICE;\r
960   Ptr += sizeof (BBS_TYPE);\r
961   *((UINT16 *) Ptr) = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));\r
962   Ptr += sizeof (UINT16);\r
963   if (BEVCount) {\r
964     Ptr = (UINT8 *) BdsFillDevOrderBuf (BbsTable, BBS_BEV_DEVICE, BbsCount, (UINT16 *) Ptr);\r
965   }\r
966 \r
967   Status = gRT->SetVariable (\r
968                   VarLegacyDevOrder,\r
969                   &EfiLegacyDevOrderGuid,\r
970                   VAR_FLAG,\r
971                   TotalSize,\r
972                   DevOrder\r
973                   );\r
974   SafeFreePool (DevOrder);\r
975 \r
976   return Status;\r
977 }\r
978 \r
979 EFI_STATUS\r
980 BdsUpdateLegacyDevOrder (\r
981   VOID\r
982   )\r
983 /*++\r
984 Format of LegacyDevOrder variable:\r
985 |-----------------------------------------------------------------------------------------------------------------\r
986 | BBS_FLOPPY | Length | Index0 | Index1 | ... | BBS_HARDDISK | Length | Index0 | Index1 | ... | BBS_CDROM | Length | Index0 | ...\r
987 |-----------------------------------------------------------------------------------------------------------------\r
988 \r
989 Length is a 16 bit integer, it indicates how many Indexes follows, including the size of itself.\r
990 Index# is a 16 bit integer, the low byte of it stands for the index in BBS table\r
991            the high byte of it only have two value 0 and 0xFF, 0xFF means this device has been\r
992            disabled by user.\r
993 --*/\r
994 {\r
995   UINT8                     *DevOrder;\r
996   UINT8                     *NewDevOrder;\r
997   UINTN                     DevOrderSize;\r
998   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
999   EFI_STATUS                Status;\r
1000   UINT16                    HddCount;\r
1001   UINT16                    BbsCount;\r
1002   HDD_INFO                  *LocalHddInfo;\r
1003   BBS_TABLE                 *LocalBbsTable;\r
1004   UINTN                     Index;\r
1005   UINTN                     Index2;\r
1006   UINTN                     *Idx;\r
1007   UINTN                     FDCount;\r
1008   UINTN                     HDCount;\r
1009   UINTN                     CDCount;\r
1010   UINTN                     NETCount;\r
1011   UINTN                     BEVCount;\r
1012   UINTN                     TotalSize;\r
1013   UINTN                     HeaderSize;\r
1014   UINT8                     *Ptr;\r
1015   UINT8                     *NewPtr;\r
1016   UINT16                    *NewFDPtr;\r
1017   UINT16                    *NewHDPtr;\r
1018   UINT16                    *NewCDPtr;\r
1019   UINT16                    *NewNETPtr;\r
1020   UINT16                    *NewBEVPtr;\r
1021   UINT16                    *NewDevPtr;\r
1022   UINT16                    Length;\r
1023   UINT16                    tmp;\r
1024   UINTN                     FDIndex;\r
1025   UINTN                     HDIndex;\r
1026   UINTN                     CDIndex;\r
1027   UINTN                     NETIndex;\r
1028   UINTN                     BEVIndex;\r
1029 \r
1030   LocalHddInfo  = NULL;\r
1031   LocalBbsTable = NULL;\r
1032   Idx           = NULL;\r
1033   FDCount       = 0;\r
1034   HDCount       = 0;\r
1035   CDCount       = 0;\r
1036   NETCount      = 0;\r
1037   BEVCount      = 0;\r
1038   TotalSize     = 0;\r
1039   HeaderSize    = sizeof (BBS_TYPE) + sizeof (UINT16);\r
1040   FDIndex       = 0;\r
1041   HDIndex       = 0;\r
1042   CDIndex       = 0;\r
1043   NETIndex      = 0;\r
1044   BEVIndex      = 0;\r
1045   NewDevPtr     = NULL;\r
1046 \r
1047   Status        = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);\r
1048   if (EFI_ERROR (Status)) {\r
1049     return Status;\r
1050   }\r
1051 \r
1052   LegacyBios->GetBbsInfo (\r
1053                 LegacyBios,\r
1054                 &HddCount,\r
1055                 &LocalHddInfo,\r
1056                 &BbsCount,\r
1057                 &LocalBbsTable\r
1058                 );\r
1059 \r
1060   DevOrder = (UINT8 *) BdsLibGetVariableAndSize (\r
1061                         VarLegacyDevOrder,\r
1062                         &EfiLegacyDevOrderGuid,\r
1063                         &DevOrderSize\r
1064                         );\r
1065   if (NULL == DevOrder) {\r
1066     return BdsCreateDevOrder (LocalBbsTable, BbsCount);\r
1067   }\r
1068   //\r
1069   // First we figure out how many boot devices with same device type respectively\r
1070   //\r
1071   for (Index = 0; Index < BbsCount; Index++) {\r
1072     if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||\r
1073         (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)\r
1074         ) {\r
1075       continue;\r
1076     }\r
1077 \r
1078     switch (LocalBbsTable[Index].DeviceType) {\r
1079     case BBS_FLOPPY:\r
1080       FDCount++;\r
1081       break;\r
1082 \r
1083     case BBS_HARDDISK:\r
1084       HDCount++;\r
1085       break;\r
1086 \r
1087     case BBS_CDROM:\r
1088       CDCount++;\r
1089       break;\r
1090 \r
1091     case BBS_EMBED_NETWORK:\r
1092       NETCount++;\r
1093       break;\r
1094 \r
1095     case BBS_BEV_DEVICE:\r
1096       BEVCount++;\r
1097       break;\r
1098 \r
1099     default:\r
1100       break;\r
1101     }\r
1102   }\r
1103 \r
1104   TotalSize += (HeaderSize + FDCount * sizeof (UINT16));\r
1105   TotalSize += (HeaderSize + HDCount * sizeof (UINT16));\r
1106   TotalSize += (HeaderSize + CDCount * sizeof (UINT16));\r
1107   TotalSize += (HeaderSize + NETCount * sizeof (UINT16));\r
1108   TotalSize += (HeaderSize + BEVCount * sizeof (UINT16));\r
1109 \r
1110   NewDevOrder = EfiAllocateZeroPool (TotalSize);\r
1111   if (NULL == NewDevOrder) {\r
1112     return EFI_OUT_OF_RESOURCES;\r
1113   }\r
1114 \r
1115   NewFDPtr  = (UINT16 *) (NewDevOrder + HeaderSize);\r
1116   NewHDPtr  = (UINT16 *) ((UINT8 *) NewFDPtr + FDCount * sizeof (UINT16) + HeaderSize);\r
1117   NewCDPtr  = (UINT16 *) ((UINT8 *) NewHDPtr + HDCount * sizeof (UINT16) + HeaderSize);\r
1118   NewNETPtr = (UINT16 *) ((UINT8 *) NewCDPtr + CDCount * sizeof (UINT16) + HeaderSize);\r
1119   NewBEVPtr = (UINT16 *) ((UINT8 *) NewNETPtr + NETCount * sizeof (UINT16) + HeaderSize);\r
1120 \r
1121   //\r
1122   // copy FD\r
1123   //\r
1124   Ptr                     = DevOrder;\r
1125   NewPtr                  = NewDevOrder;\r
1126   *((BBS_TYPE *) NewPtr)  = *((BBS_TYPE *) Ptr);\r
1127   Ptr += sizeof (BBS_TYPE);\r
1128   NewPtr += sizeof (BBS_TYPE);\r
1129   Length                = *((UINT16 *) Ptr);\r
1130   *((UINT16 *) NewPtr)  = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));\r
1131   Ptr += sizeof (UINT16);\r
1132 \r
1133   for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {\r
1134     if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||\r
1135         LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
1136         LocalBbsTable[*Ptr].DeviceType != BBS_FLOPPY\r
1137         ) {\r
1138       Ptr += sizeof (UINT16);\r
1139       continue;\r
1140     }\r
1141 \r
1142     NewFDPtr[FDIndex] = *(UINT16 *) Ptr;\r
1143     FDIndex++;\r
1144     Ptr += sizeof (UINT16);\r
1145   }\r
1146   //\r
1147   // copy HD\r
1148   //\r
1149   NewPtr                  = (UINT8 *) NewHDPtr - HeaderSize;\r
1150   *((BBS_TYPE *) NewPtr)  = *((BBS_TYPE *) Ptr);\r
1151   Ptr += sizeof (BBS_TYPE);\r
1152   NewPtr += sizeof (BBS_TYPE);\r
1153   Length                = *((UINT16 *) Ptr);\r
1154   *((UINT16 *) NewPtr)  = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));\r
1155   Ptr += sizeof (UINT16);\r
1156 \r
1157   for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {\r
1158     if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||\r
1159         LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
1160         LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||\r
1161         LocalBbsTable[*Ptr].DeviceType != BBS_HARDDISK\r
1162         ) {\r
1163       Ptr += sizeof (UINT16);\r
1164       continue;\r
1165     }\r
1166 \r
1167     NewHDPtr[HDIndex] = *(UINT16 *) Ptr;\r
1168     HDIndex++;\r
1169     Ptr += sizeof (UINT16);\r
1170   }\r
1171   //\r
1172   // copy CD\r
1173   //\r
1174   NewPtr                  = (UINT8 *) NewCDPtr - HeaderSize;\r
1175   *((BBS_TYPE *) NewPtr)  = *((BBS_TYPE *) Ptr);\r
1176   Ptr += sizeof (BBS_TYPE);\r
1177   NewPtr += sizeof (BBS_TYPE);\r
1178   Length                = *((UINT16 *) Ptr);\r
1179   *((UINT16 *) NewPtr)  = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));\r
1180   Ptr += sizeof (UINT16);\r
1181 \r
1182   for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {\r
1183     if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||\r
1184         LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
1185         LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||\r
1186         LocalBbsTable[*Ptr].DeviceType != BBS_CDROM\r
1187         ) {\r
1188       Ptr += sizeof (UINT16);\r
1189       continue;\r
1190     }\r
1191 \r
1192     NewCDPtr[CDIndex] = *(UINT16 *) Ptr;\r
1193     CDIndex++;\r
1194     Ptr += sizeof (UINT16);\r
1195   }\r
1196   //\r
1197   // copy NET\r
1198   //\r
1199   NewPtr                  = (UINT8 *) NewNETPtr - HeaderSize;\r
1200   *((BBS_TYPE *) NewPtr)  = *((BBS_TYPE *) Ptr);\r
1201   Ptr += sizeof (BBS_TYPE);\r
1202   NewPtr += sizeof (BBS_TYPE);\r
1203   Length                = *((UINT16 *) Ptr);\r
1204   *((UINT16 *) NewPtr)  = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));\r
1205   Ptr += sizeof (UINT16);\r
1206 \r
1207   for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {\r
1208     if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||\r
1209         LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
1210         LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||\r
1211         LocalBbsTable[*Ptr].DeviceType != BBS_EMBED_NETWORK\r
1212         ) {\r
1213       Ptr += sizeof (UINT16);\r
1214       continue;\r
1215     }\r
1216 \r
1217     NewNETPtr[NETIndex] = *(UINT16 *) Ptr;\r
1218     NETIndex++;\r
1219     Ptr += sizeof (UINT16);\r
1220   }\r
1221   //\r
1222   // copy BEV\r
1223   //\r
1224   NewPtr                  = (UINT8 *) NewBEVPtr - HeaderSize;\r
1225   *((BBS_TYPE *) NewPtr)  = *((BBS_TYPE *) Ptr);\r
1226   Ptr += sizeof (BBS_TYPE);\r
1227   NewPtr += sizeof (BBS_TYPE);\r
1228   Length                = *((UINT16 *) Ptr);\r
1229   *((UINT16 *) NewPtr)  = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));\r
1230   Ptr += sizeof (UINT16);\r
1231 \r
1232   for (Index = 0; Index < Length / sizeof (UINT16) - 1; Index++) {\r
1233     if (LocalBbsTable[*Ptr].BootPriority == BBS_IGNORE_ENTRY ||\r
1234         LocalBbsTable[*Ptr].BootPriority == BBS_DO_NOT_BOOT_FROM ||\r
1235         LocalBbsTable[*Ptr].BootPriority == BBS_LOWEST_PRIORITY ||\r
1236         LocalBbsTable[*Ptr].DeviceType != BBS_BEV_DEVICE\r
1237         ) {\r
1238       Ptr += sizeof (UINT16);\r
1239       continue;\r
1240     }\r
1241 \r
1242     NewBEVPtr[BEVIndex] = *(UINT16 *) Ptr;\r
1243     BEVIndex++;\r
1244     Ptr += sizeof (UINT16);\r
1245   }\r
1246 \r
1247   for (Index = 0; Index < BbsCount; Index++) {\r
1248     if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||\r
1249         (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)\r
1250         ) {\r
1251       continue;\r
1252     }\r
1253 \r
1254     switch (LocalBbsTable[Index].DeviceType) {\r
1255     case BBS_FLOPPY:\r
1256       Idx       = &FDIndex;\r
1257       NewDevPtr = NewFDPtr;\r
1258       break;\r
1259 \r
1260     case BBS_HARDDISK:\r
1261       Idx       = &HDIndex;\r
1262       NewDevPtr = NewHDPtr;\r
1263       break;\r
1264 \r
1265     case BBS_CDROM:\r
1266       Idx       = &CDIndex;\r
1267       NewDevPtr = NewCDPtr;\r
1268       break;\r
1269 \r
1270     case BBS_EMBED_NETWORK:\r
1271       Idx       = &NETIndex;\r
1272       NewDevPtr = NewNETPtr;\r
1273       break;\r
1274 \r
1275     case BBS_BEV_DEVICE:\r
1276       Idx       = &BEVIndex;\r
1277       NewDevPtr = NewBEVPtr;\r
1278       break;\r
1279 \r
1280     default:\r
1281       Idx = NULL;\r
1282       break;\r
1283     }\r
1284     //\r
1285     // at this point we have copied those valid indexes to new buffer\r
1286     // and we should check if there is any new appeared boot device\r
1287     //\r
1288     if (Idx) {\r
1289       for (Index2 = 0; Index2 < *Idx; Index2++) {\r
1290         if ((NewDevPtr[Index2] & 0xFF) == (UINT16) Index) {\r
1291           break;\r
1292         }\r
1293       }\r
1294 \r
1295       if (Index2 == *Idx) {\r
1296         //\r
1297         // Index2 == *Idx means we didn't find Index\r
1298         // so Index is a new appeared device's index in BBS table\r
1299         // save it.\r
1300         //\r
1301         NewDevPtr[*Idx] = (UINT16) (Index & 0xFF);\r
1302         (*Idx)++;\r
1303       }\r
1304     }\r
1305   }\r
1306 \r
1307   if (FDCount) {\r
1308     //\r
1309     // Just to make sure that disabled indexes are all at the end of the array\r
1310     //\r
1311     for (Index = 0; Index < FDIndex - 1; Index++) {\r
1312       if (0xFF00 != (NewFDPtr[Index] & 0xFF00)) {\r
1313         continue;\r
1314       }\r
1315 \r
1316       for (Index2 = Index + 1; Index2 < FDIndex; Index2++) {\r
1317         if (0 == (NewFDPtr[Index2] & 0xFF00)) {\r
1318           tmp               = NewFDPtr[Index];\r
1319           NewFDPtr[Index]   = NewFDPtr[Index2];\r
1320           NewFDPtr[Index2]  = tmp;\r
1321           break;\r
1322         }\r
1323       }\r
1324     }\r
1325   }\r
1326 \r
1327   if (HDCount) {\r
1328     //\r
1329     // Just to make sure that disabled indexes are all at the end of the array\r
1330     //\r
1331     for (Index = 0; Index < HDIndex - 1; Index++) {\r
1332       if (0xFF00 != (NewHDPtr[Index] & 0xFF00)) {\r
1333         continue;\r
1334       }\r
1335 \r
1336       for (Index2 = Index + 1; Index2 < HDIndex; Index2++) {\r
1337         if (0 == (NewHDPtr[Index2] & 0xFF00)) {\r
1338           tmp               = NewHDPtr[Index];\r
1339           NewHDPtr[Index]   = NewHDPtr[Index2];\r
1340           NewHDPtr[Index2]  = tmp;\r
1341           break;\r
1342         }\r
1343       }\r
1344     }\r
1345   }\r
1346 \r
1347   if (CDCount) {\r
1348     //\r
1349     // Just to make sure that disabled indexes are all at the end of the array\r
1350     //\r
1351     for (Index = 0; Index < CDIndex - 1; Index++) {\r
1352       if (0xFF00 != (NewCDPtr[Index] & 0xFF00)) {\r
1353         continue;\r
1354       }\r
1355 \r
1356       for (Index2 = Index + 1; Index2 < CDIndex; Index2++) {\r
1357         if (0 == (NewCDPtr[Index2] & 0xFF00)) {\r
1358           tmp               = NewCDPtr[Index];\r
1359           NewCDPtr[Index]   = NewCDPtr[Index2];\r
1360           NewCDPtr[Index2]  = tmp;\r
1361           break;\r
1362         }\r
1363       }\r
1364     }\r
1365   }\r
1366 \r
1367   if (NETCount) {\r
1368     //\r
1369     // Just to make sure that disabled indexes are all at the end of the array\r
1370     //\r
1371     for (Index = 0; Index < NETIndex - 1; Index++) {\r
1372       if (0xFF00 != (NewNETPtr[Index] & 0xFF00)) {\r
1373         continue;\r
1374       }\r
1375 \r
1376       for (Index2 = Index + 1; Index2 < NETIndex; Index2++) {\r
1377         if (0 == (NewNETPtr[Index2] & 0xFF00)) {\r
1378           tmp               = NewNETPtr[Index];\r
1379           NewNETPtr[Index]  = NewNETPtr[Index2];\r
1380           NewNETPtr[Index2] = tmp;\r
1381           break;\r
1382         }\r
1383       }\r
1384     }\r
1385   }\r
1386 \r
1387   if (BEVCount) {\r
1388     //\r
1389     // Just to make sure that disabled indexes are all at the end of the array\r
1390     //\r
1391     for (Index = 0; Index < BEVIndex - 1; Index++) {\r
1392       if (0xFF00 != (NewBEVPtr[Index] & 0xFF00)) {\r
1393         continue;\r
1394       }\r
1395 \r
1396       for (Index2 = Index + 1; Index2 < BEVIndex; Index2++) {\r
1397         if (0 == (NewBEVPtr[Index2] & 0xFF00)) {\r
1398           tmp               = NewBEVPtr[Index];\r
1399           NewBEVPtr[Index]  = NewBEVPtr[Index2];\r
1400           NewBEVPtr[Index2] = tmp;\r
1401           break;\r
1402         }\r
1403       }\r
1404     }\r
1405   }\r
1406 \r
1407   SafeFreePool (DevOrder);\r
1408 \r
1409   Status = gRT->SetVariable (\r
1410                   VarLegacyDevOrder,\r
1411                   &EfiLegacyDevOrderGuid,\r
1412                   VAR_FLAG,\r
1413                   TotalSize,\r
1414                   NewDevOrder\r
1415                   );\r
1416   SafeFreePool (NewDevOrder);\r
1417 \r
1418   return Status;\r
1419 }\r
1420 \r
1421 EFI_STATUS\r
1422 BdsSetBootPriority4SameTypeDev (\r
1423   IN UINT16                                              DeviceType,\r
1424   IN OUT BBS_TABLE                                       *LocalBbsTable,\r
1425   IN OUT UINT16                                          *Priority\r
1426   )\r
1427 /*++\r
1428 DeviceType           - BBS_FLOPPY, BBS_HARDDISK, BBS_CDROM and so on\r
1429 LocalBbsTable       - BBS table instance\r
1430 Priority                 - As input arg, it is the start point of boot priority, as output arg, it is the start point of boot\r
1431                               priority can be used next time.\r
1432 --*/\r
1433 {\r
1434   UINT8   *DevOrder;\r
1435 \r
1436   UINT8   *OrigBuffer;\r
1437   UINT16  *DevIndex;\r
1438   UINTN   DevOrderSize;\r
1439   UINTN   DevCount;\r
1440   UINTN   Index;\r
1441 \r
1442   DevOrder = BdsLibGetVariableAndSize (\r
1443               VarLegacyDevOrder,\r
1444               &EfiLegacyDevOrderGuid,\r
1445               &DevOrderSize\r
1446               );\r
1447   if (NULL == DevOrder) {\r
1448     return EFI_OUT_OF_RESOURCES;\r
1449   }\r
1450 \r
1451   OrigBuffer = DevOrder;\r
1452   while (DevOrder < OrigBuffer + DevOrderSize) {\r
1453     if (DeviceType == * (BBS_TYPE *) DevOrder) {\r
1454       break;\r
1455     }\r
1456 \r
1457     DevOrder += sizeof (BBS_TYPE);\r
1458     DevOrder += *(UINT16 *) DevOrder;\r
1459   }\r
1460 \r
1461   if (DevOrder >= OrigBuffer + DevOrderSize) {\r
1462     SafeFreePool (OrigBuffer);\r
1463     return EFI_NOT_FOUND;\r
1464   }\r
1465 \r
1466   DevOrder += sizeof (BBS_TYPE);\r
1467   DevCount  = (*((UINT16 *) DevOrder) - sizeof (UINT16)) / sizeof (UINT16);\r
1468   DevIndex  = (UINT16 *) (DevOrder + sizeof (UINT16));\r
1469   //\r
1470   // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.\r
1471   //\r
1472   for (Index = 0; Index < DevCount; Index++) {\r
1473     if ((DevIndex[Index] & 0xFF00) == 0xFF00) {\r
1474       //\r
1475       // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;\r
1476       //\r
1477     } else {\r
1478       LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = *Priority;\r
1479       (*Priority)++;\r
1480     }\r
1481   }\r
1482 \r
1483   SafeFreePool (OrigBuffer);\r
1484   return EFI_SUCCESS;\r
1485 }\r
1486 \r
1487 VOID\r
1488 PrintBbsTable (\r
1489   IN BBS_TABLE                      *LocalBbsTable\r
1490   )\r
1491 {\r
1492   UINT16  Idx;\r
1493 \r
1494   DEBUG ((DEBUG_ERROR, "\n"));\r
1495   DEBUG ((DEBUG_ERROR, " NO  Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));\r
1496   DEBUG ((DEBUG_ERROR, "=============================================\n"));\r
1497   for (Idx = 0; Idx < MAX_BBS_ENTRIES; Idx++) {\r
1498     if ((LocalBbsTable[Idx].BootPriority == BBS_IGNORE_ENTRY) ||\r
1499         (LocalBbsTable[Idx].BootPriority == BBS_DO_NOT_BOOT_FROM) ||\r
1500         (LocalBbsTable[Idx].BootPriority == BBS_LOWEST_PRIORITY)\r
1501         ) {\r
1502       continue;\r
1503     }\r
1504 \r
1505     DEBUG (\r
1506       (DEBUG_ERROR,\r
1507       " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",\r
1508       (UINTN) Idx,\r
1509       (UINTN) LocalBbsTable[Idx].BootPriority,\r
1510       (UINTN) LocalBbsTable[Idx].Bus,\r
1511       (UINTN) LocalBbsTable[Idx].Device,\r
1512       (UINTN) LocalBbsTable[Idx].Function,\r
1513       (UINTN) LocalBbsTable[Idx].Class,\r
1514       (UINTN) LocalBbsTable[Idx].SubClass,\r
1515       (UINTN) LocalBbsTable[Idx].DeviceType,\r
1516       (UINTN) * (UINT16 *) &LocalBbsTable[Idx].StatusFlags,\r
1517       (UINTN) LocalBbsTable[Idx].BootHandlerSegment,\r
1518       (UINTN) LocalBbsTable[Idx].BootHandlerOffset,\r
1519       (UINTN) ((LocalBbsTable[Idx].MfgStringSegment << 4) + LocalBbsTable[Idx].MfgStringOffset),\r
1520       (UINTN) ((LocalBbsTable[Idx].DescStringSegment << 4) + LocalBbsTable[Idx].DescStringOffset))\r
1521       );\r
1522   }\r
1523 \r
1524   DEBUG ((DEBUG_ERROR, "\n"));\r
1525 }\r
1526 \r
1527 EFI_STATUS\r
1528 BdsRefreshBbsTableForBoot (\r
1529   IN BDS_COMMON_OPTION        *Entry\r
1530   )\r
1531 {\r
1532   EFI_STATUS                Status;\r
1533   UINT16                    HddCount;\r
1534   UINT16                    BbsCount;\r
1535   HDD_INFO                  *LocalHddInfo;\r
1536   BBS_TABLE                 *LocalBbsTable;\r
1537   UINT16                    DevType;\r
1538   EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;\r
1539   UINTN                     Index;\r
1540   UINT16                    Priority;\r
1541   UINT16                    *BootOrder;\r
1542   UINTN                     BootOrderSize;\r
1543   UINT8                     *BootOptionVar;\r
1544   UINTN                     BootOptionSize;\r
1545   UINT16                    BootOption[100];\r
1546   UINT8                     *Ptr;\r
1547   UINT16                    DevPathLen;\r
1548   EFI_DEVICE_PATH_PROTOCOL  *DevPath;\r
1549 \r
1550   HddCount      = 0;\r
1551   BbsCount      = 0;\r
1552   LocalHddInfo  = NULL;\r
1553   LocalBbsTable = NULL;\r
1554   DevType       = BBS_UNKNOWN;\r
1555 \r
1556   Status        = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);\r
1557   if (EFI_ERROR (Status)) {\r
1558     return Status;\r
1559   }\r
1560 \r
1561   LegacyBios->GetBbsInfo (\r
1562                 LegacyBios,\r
1563                 &HddCount,\r
1564                 &LocalHddInfo,\r
1565                 &BbsCount,\r
1566                 &LocalBbsTable\r
1567                 );\r
1568   //\r
1569   // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY\r
1570   // We will set them according to the settings setup by user\r
1571   //\r
1572   for (Index = 0; Index < BbsCount; Index++) {\r
1573     if (!((BBS_IGNORE_ENTRY == LocalBbsTable[Index].BootPriority) ||\r
1574         (BBS_DO_NOT_BOOT_FROM == LocalBbsTable[Index].BootPriority) ||\r
1575          (BBS_LOWEST_PRIORITY == LocalBbsTable[Index].BootPriority))) {\r
1576       LocalBbsTable[Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;\r
1577     }\r
1578   }\r
1579   //\r
1580   // boot priority always starts at 0\r
1581   //\r
1582   Priority = 0;\r
1583   if (Entry->LoadOptionsSize == sizeof (BBS_TABLE) + sizeof (UINT16)) {\r
1584     //\r
1585     // If Entry stands for a legacy boot option, we prioritize the devices with the same type first.\r
1586     //\r
1587     DevType = ((BBS_TABLE *) Entry->LoadOptions)->DeviceType;\r
1588     Status = BdsSetBootPriority4SameTypeDev (\r
1589               DevType,\r
1590               LocalBbsTable,\r
1591               &Priority\r
1592               );\r
1593     if (EFI_ERROR (Status)) {\r
1594       return Status;\r
1595     }\r
1596   }\r
1597   //\r
1598   // we have to set the boot priority for other BBS entries with different device types\r
1599   //\r
1600   BootOrder = (UINT16 *) BdsLibGetVariableAndSize (\r
1601                           L"BootOrder",\r
1602                           &gEfiGlobalVariableGuid,\r
1603                           &BootOrderSize\r
1604                           );\r
1605   for (Index = 0; BootOrder && Index < BootOrderSize / sizeof (UINT16); Index++) {\r
1606     UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);\r
1607     BootOptionVar = BdsLibGetVariableAndSize (\r
1608                       BootOption,\r
1609                       &gEfiGlobalVariableGuid,\r
1610                       &BootOptionSize\r
1611                       );\r
1612     if (NULL == BootOptionVar) {\r
1613       continue;\r
1614     }\r
1615 \r
1616     Ptr = BootOptionVar;\r
1617 \r
1618     Ptr += sizeof (UINT32);\r
1619     DevPathLen = *(UINT16 *) Ptr;\r
1620     Ptr += sizeof (UINT16);\r
1621     Ptr += StrSize ((UINT16 *) Ptr);\r
1622     DevPath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;\r
1623     if (BBS_DEVICE_PATH != DevPath->Type || BBS_BBS_DP != DevPath->SubType) {\r
1624       SafeFreePool (BootOptionVar);\r
1625       continue;\r
1626     }\r
1627 \r
1628     Ptr += DevPathLen;\r
1629     if (DevType == ((BBS_TABLE *) Ptr)->DeviceType) {\r
1630       //\r
1631       // We don't want to process twice for a device type\r
1632       //\r
1633       SafeFreePool (BootOptionVar);\r
1634       continue;\r
1635     }\r
1636 \r
1637     Status = BdsSetBootPriority4SameTypeDev (\r
1638               ((BBS_TABLE *) Ptr)->DeviceType,\r
1639               LocalBbsTable,\r
1640               &Priority\r
1641               );\r
1642     SafeFreePool (BootOptionVar);\r
1643     if (EFI_ERROR (Status)) {\r
1644       break;\r
1645     }\r
1646   }\r
1647 \r
1648   if (BootOrder) {\r
1649     SafeFreePool (BootOrder);\r
1650   }\r
1651   //\r
1652   // For debug\r
1653   //\r
1654   PrintBbsTable (LocalBbsTable);\r
1655 \r
1656   return Status;\r
1657 }\r