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