2 Rewrite the BootOrder NvVar based on QEMU's "bootorder" fw_cfg file.
4 Copyright (C) 2012 - 2013, Red Hat, Inc.
6 This program and the accompanying materials are licensed and made available
7 under the terms and conditions of the BSD License which accompanies this
8 distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
12 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include <Library/QemuFwCfgLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/GenericBdsLib.h>
19 #include <Library/UefiBootServicesTableLib.h>
20 #include <Library/UefiRuntimeServicesTableLib.h>
21 #include <Library/BaseLib.h>
22 #include <Library/PrintLib.h>
23 #include <Library/DevicePathLib.h>
24 #include <Guid/GlobalVariable.h>
28 OpenFirmware to UEFI device path translation output buffer size in CHAR16's.
30 #define TRANSLATION_OUTPUT_SIZE 0x100
34 Numbers of nodes in OpenFirmware device paths that are required and examined.
36 #define REQUIRED_OFW_NODES 2
37 #define EXAMINED_OFW_NODES 4
41 Simple character classification routines, corresponding to POSIX class names
50 return (('0' <= Chr
&& Chr
<= '9') ||
51 ('A' <= Chr
&& Chr
<= 'Z') ||
52 ('a' <= Chr
&& Chr
<= 'z')
63 return (Chr
== ',' || Chr
== '.' || Chr
== '_' ||
64 Chr
== '+' || Chr
== '-'
75 return (32 <= Chr
&& Chr
<= 126 &&
76 Chr
!= '/' && Chr
!= '@' && Chr
!= ':');
81 Utility types and functions.
84 CONST CHAR8
*Ptr
; // not necessarily NUL-terminated
85 UINTN Len
; // number of non-NUL characters
91 Check if Substring and String have identical contents.
93 The function relies on the restriction that a SUBSTRING cannot have embedded
96 @param[in] Substring The SUBSTRING input to the comparison.
98 @param[in] String The ASCII string input to the comparison.
101 @return Whether the inputs have identical contents.
107 IN SUBSTRING Substring
,
108 IN CONST CHAR8
*String
117 while (Pos
< Substring
.Len
&& Substring
.Ptr
[Pos
] == *Chr
) {
122 return (BOOLEAN
)(Pos
== Substring
.Len
&& *Chr
== '\0');
128 Parse a comma-separated list of hexadecimal integers into the elements of an
131 Whitespace, "0x" prefixes, leading or trailing commas, sequences of commas,
132 or an empty string are not allowed; they are rejected.
134 The function relies on ASCII encoding.
136 @param[in] UnitAddress The substring to parse.
138 @param[out] Result The array, allocated by the caller, to receive
139 the parsed values. This parameter may be NULL if
140 NumResults is zero on input.
142 @param[in out] NumResults On input, the number of elements allocated for
143 Result. On output, the number of elements it has
144 taken (or would have taken) to parse the string
148 @retval RETURN_SUCCESS UnitAddress has been fully parsed.
149 NumResults is set to the number of parsed
150 values; the corresponding elements have
151 been set in Result. The rest of Result's
152 elements are unchanged.
154 @retval RETURN_BUFFER_TOO_SMALL UnitAddress has been fully parsed.
155 NumResults is set to the number of parsed
156 values, but elements have been stored only
157 up to the input value of NumResults, which
158 is less than what has been parsed.
160 @retval RETURN_INVALID_PARAMETER Parse error. The contents of Results is
161 indeterminate. NumResults has not been
167 ParseUnitAddressHexList (
168 IN SUBSTRING UnitAddress
,
170 IN OUT UINTN
*NumResults
173 UINTN Entry
; // number of entry currently being parsed
174 UINT32 EntryVal
; // value being constructed for current entry
175 CHAR8 PrevChr
; // UnitAddress character previously checked
176 UINTN Pos
; // current position within UnitAddress
177 RETURN_STATUS Status
;
183 for (Pos
= 0; Pos
< UnitAddress
.Len
; ++Pos
) {
187 Chr
= UnitAddress
.Ptr
[Pos
];
188 Val
= ('a' <= Chr
&& Chr
<= 'f') ? (Chr
- 'a' + 10) :
189 ('A' <= Chr
&& Chr
<= 'F') ? (Chr
- 'A' + 10) :
190 ('0' <= Chr
&& Chr
<= '9') ? (Chr
- '0' ) :
194 if (EntryVal
> 0xFFFFFFF) {
195 return RETURN_INVALID_PARAMETER
;
197 EntryVal
= (EntryVal
<< 4) | Val
;
198 } else if (Chr
== ',') {
199 if (PrevChr
== ',') {
200 return RETURN_INVALID_PARAMETER
;
202 if (Entry
< *NumResults
) {
203 Result
[Entry
] = EntryVal
;
208 return RETURN_INVALID_PARAMETER
;
214 if (PrevChr
== ',') {
215 return RETURN_INVALID_PARAMETER
;
217 if (Entry
< *NumResults
) {
218 Result
[Entry
] = EntryVal
;
219 Status
= RETURN_SUCCESS
;
221 Status
= RETURN_BUFFER_TOO_SMALL
;
231 A simple array of Boot Option ID's.
242 Append BootOptionId to BootOrder, reallocating the latter if needed.
244 @param[in out] BootOrder The structure pointing to the array and holding
245 allocation and usage counters.
247 @param[in] BootOptionId The value to append to the array.
250 @retval RETURN_SUCCESS BootOptionId appended.
252 @retval RETURN_OUT_OF_RESOURCES Memory reallocation failed.
258 IN OUT BOOT_ORDER
*BootOrder
,
259 IN UINT16 BootOptionId
262 if (BootOrder
->Produced
== BootOrder
->Allocated
) {
266 ASSERT (BootOrder
->Allocated
> 0);
267 AllocatedNew
= BootOrder
->Allocated
* 2;
268 DataNew
= ReallocatePool (
269 BootOrder
->Allocated
* sizeof (*BootOrder
->Data
),
270 AllocatedNew
* sizeof (*DataNew
),
273 if (DataNew
== NULL
) {
274 return RETURN_OUT_OF_RESOURCES
;
276 BootOrder
->Allocated
= AllocatedNew
;
277 BootOrder
->Data
= DataNew
;
280 BootOrder
->Data
[BootOrder
->Produced
++] = BootOptionId
;
281 return RETURN_SUCCESS
;
286 OpenFirmware device path node
289 SUBSTRING DriverName
;
290 SUBSTRING UnitAddress
;
291 SUBSTRING DeviceArguments
;
297 Parse an OpenFirmware device path node into the caller-allocated OFW_NODE
298 structure, and advance in the input string.
300 The node format is mostly parsed after IEEE 1275-1994, 3.2.1.1 "Node names"
301 (a leading slash is expected and not returned):
303 /driver-name@unit-address[:device-arguments][<LF>]
305 A single trailing <LF> character is consumed but not returned. A trailing
306 <LF> or NUL character terminates the device path.
308 The function relies on ASCII encoding.
310 @param[in out] Ptr Address of the pointer pointing to the start of the
311 node string. After successful parsing *Ptr is set to
312 the byte immediately following the consumed
313 characters. On error it points to the byte that
314 caused the error. The input string is never modified.
316 @param[out] OfwNode The members of this structure point into the input
317 string, designating components of the node.
318 Separators are never included. If "device-arguments"
319 is missing, then DeviceArguments.Ptr is set to NULL.
320 All components that are present have nonzero length.
322 If the call doesn't succeed, the contents of this
323 structure is indeterminate.
325 @param[out] IsFinal In case of successul parsing, this parameter signals
326 whether the node just parsed is the final node in the
327 device path. The call after a final node will attempt
328 to start parsing the next path. If the call doesn't
329 succeed, then this parameter is not changed.
332 @retval RETURN_SUCCESS Parsing successful.
334 @retval RETURN_NOT_FOUND Parsing terminated. *Ptr was (and is)
335 pointing to an empty string.
337 @retval RETURN_INVALID_PARAMETER Parse error.
343 IN OUT CONST CHAR8
**Ptr
,
344 OUT OFW_NODE
*OfwNode
,
349 // A leading slash is expected. End of string is tolerated.
353 return RETURN_NOT_FOUND
;
360 return RETURN_INVALID_PARAMETER
;
366 OfwNode
->DriverName
.Ptr
= *Ptr
;
367 OfwNode
->DriverName
.Len
= 0;
368 while (OfwNode
->DriverName
.Len
< 32 &&
369 (IsAlnum (**Ptr
) || IsDriverNamePunct (**Ptr
))
372 ++OfwNode
->DriverName
.Len
;
375 if (OfwNode
->DriverName
.Len
== 0 || OfwNode
->DriverName
.Len
== 32) {
376 return RETURN_INVALID_PARAMETER
;
384 return RETURN_INVALID_PARAMETER
;
388 OfwNode
->UnitAddress
.Ptr
= *Ptr
;
389 OfwNode
->UnitAddress
.Len
= 0;
390 while (IsPrintNotDelim (**Ptr
)) {
392 ++OfwNode
->UnitAddress
.Len
;
395 if (OfwNode
->UnitAddress
.Len
== 0) {
396 return RETURN_INVALID_PARAMETER
;
401 // device-arguments, may be omitted
403 OfwNode
->DeviceArguments
.Len
= 0;
406 OfwNode
->DeviceArguments
.Ptr
= *Ptr
;
408 while (IsPrintNotDelim (**Ptr
)) {
410 ++OfwNode
->DeviceArguments
.Len
;
413 if (OfwNode
->DeviceArguments
.Len
== 0) {
414 return RETURN_INVALID_PARAMETER
;
418 OfwNode
->DeviceArguments
.Ptr
= NULL
;
437 return RETURN_INVALID_PARAMETER
;
442 "%a: DriverName=\"%.*a\" UnitAddress=\"%.*a\" DeviceArguments=\"%.*a\"\n",
444 OfwNode
->DriverName
.Len
, OfwNode
->DriverName
.Ptr
,
445 OfwNode
->UnitAddress
.Len
, OfwNode
->UnitAddress
.Ptr
,
446 OfwNode
->DeviceArguments
.Len
,
447 OfwNode
->DeviceArguments
.Ptr
== NULL
? "" : OfwNode
->DeviceArguments
.Ptr
449 return RETURN_SUCCESS
;
455 Translate an array of OpenFirmware device nodes to a UEFI device path
458 @param[in] OfwNode Array of OpenFirmware device nodes to
459 translate, constituting the beginning of an
460 OpenFirmware device path.
462 @param[in] NumNodes Number of elements in OfwNode.
464 @param[out] Translated Destination array receiving the UEFI path
465 fragment, allocated by the caller. If the
466 return value differs from RETURN_SUCCESS, its
467 contents is indeterminate.
469 @param[in out] TranslatedSize On input, the number of CHAR16's in
470 Translated. On RETURN_SUCCESS this parameter
471 is assigned the number of non-NUL CHAR16's
472 written to Translated. In case of other return
473 values, TranslatedSize is indeterminate.
476 @retval RETURN_SUCCESS Translation successful.
478 @retval RETURN_BUFFER_TOO_SMALL The translation does not fit into the number
481 @retval RETURN_UNSUPPORTED The array of OpenFirmware device nodes can't
482 be translated in the current implementation.
488 IN CONST OFW_NODE
*OfwNode
,
490 OUT CHAR16
*Translated
,
491 IN OUT UINTN
*TranslatedSize
499 // Get PCI device and optional PCI function. Assume a single PCI root.
501 if (NumNodes
< REQUIRED_OFW_NODES
||
502 !SubstringEq (OfwNode
[0].DriverName
, "pci")
504 return RETURN_UNSUPPORTED
;
507 NumEntries
= sizeof (PciDevFun
) / sizeof (PciDevFun
[0]);
508 if (ParseUnitAddressHexList (
509 OfwNode
[1].UnitAddress
,
514 return RETURN_UNSUPPORTED
;
518 SubstringEq (OfwNode
[1].DriverName
, "ide") &&
519 SubstringEq (OfwNode
[2].DriverName
, "drive") &&
520 SubstringEq (OfwNode
[3].DriverName
, "disk")
523 // OpenFirmware device path (IDE disk, IDE CD-ROM):
525 // /pci@i0cf8/ide@1,1/drive@0/disk@0
527 // | | | | master or slave
528 // | | | primary or secondary
529 // | PCI slot & function holding IDE controller
530 // PCI root at system bus port, PIO
534 // PciRoot(0x0)/Pci(0x1,0x1)/Ata(Primary,Master,0x0)
542 if (ParseUnitAddressHexList (
543 OfwNode
[2].UnitAddress
,
546 ) != RETURN_SUCCESS
||
548 ParseUnitAddressHexList (
549 OfwNode
[3].UnitAddress
,
551 &NumEntries
// reuse after previous single-element call
552 ) != RETURN_SUCCESS
||
555 return RETURN_UNSUPPORTED
;
558 Written
= UnicodeSPrintAsciiFormat (
560 *TranslatedSize
* sizeof (*Translated
), // BufferSize in bytes
561 "PciRoot(0x0)/Pci(0x%x,0x%x)/Ata(%a,%a,0x0)",
564 Secondary
? "Secondary" : "Primary",
565 Slave
? "Slave" : "Master"
567 } else if (NumNodes
>= 4 &&
568 SubstringEq (OfwNode
[1].DriverName
, "isa") &&
569 SubstringEq (OfwNode
[2].DriverName
, "fdc") &&
570 SubstringEq (OfwNode
[3].DriverName
, "floppy")
573 // OpenFirmware device path (floppy disk):
575 // /pci@i0cf8/isa@1/fdc@03f0/floppy@0
578 // | | ISA controller io-port (hex)
579 // | PCI slot holding ISA controller
580 // PCI root at system bus port, PIO
584 // PciRoot(0x0)/Pci(0x1,0x0)/Floppy(0x0)
591 if (ParseUnitAddressHexList (
592 OfwNode
[3].UnitAddress
,
595 ) != RETURN_SUCCESS
||
598 return RETURN_UNSUPPORTED
;
601 Written
= UnicodeSPrintAsciiFormat (
603 *TranslatedSize
* sizeof (*Translated
), // BufferSize in bytes
604 "PciRoot(0x0)/Pci(0x%x,0x%x)/Floppy(0x%x)",
609 } else if (NumNodes
>= 3 &&
610 SubstringEq (OfwNode
[1].DriverName
, "scsi") &&
611 SubstringEq (OfwNode
[2].DriverName
, "disk")
614 // OpenFirmware device path (virtio-blk disk):
616 // /pci@i0cf8/scsi@6[,3]/disk@0,0
619 // | | PCI function corresponding to disk (optional)
620 // | PCI slot holding disk
621 // PCI root at system bus port, PIO
623 // UEFI device path prefix:
625 // PciRoot(0x0)/Pci(0x6,0x0)/HD( -- if PCI function is 0 or absent
626 // PciRoot(0x0)/Pci(0x6,0x3)/HD( -- if PCI function is present and nonzero
628 Written
= UnicodeSPrintAsciiFormat (
630 *TranslatedSize
* sizeof (*Translated
), // BufferSize in bytes
631 "PciRoot(0x0)/Pci(0x%x,0x%x)/HD(",
635 } else if (NumNodes
>= 4 &&
636 SubstringEq (OfwNode
[1].DriverName
, "scsi") &&
637 SubstringEq (OfwNode
[2].DriverName
, "channel") &&
638 SubstringEq (OfwNode
[3].DriverName
, "disk")
641 // OpenFirmware device path (virtio-scsi disk):
643 // /pci@i0cf8/scsi@7[,3]/channel@0/disk@2,3
647 // | | channel (unused, fixed 0)
648 // | PCI slot[, function] holding SCSI controller
649 // PCI root at system bus port, PIO
651 // UEFI device path prefix:
653 // PciRoot(0x0)/Pci(0x7,0x0)/Scsi(0x2,0x3)
654 // -- if PCI function is 0 or absent
655 // PciRoot(0x0)/Pci(0x7,0x3)/Scsi(0x2,0x3)
656 // -- if PCI function is present and nonzero
661 NumEntries
= sizeof (TargetLun
) / sizeof (TargetLun
[0]);
662 if (ParseUnitAddressHexList (
663 OfwNode
[3].UnitAddress
,
668 return RETURN_UNSUPPORTED
;
671 Written
= UnicodeSPrintAsciiFormat (
673 *TranslatedSize
* sizeof (*Translated
), // BufferSize in bytes
674 "PciRoot(0x0)/Pci(0x%x,0x%x)/Scsi(0x%x,0x%x)",
680 } else if (NumNodes
>= 3 &&
681 SubstringEq (OfwNode
[1].DriverName
, "ethernet") &&
682 SubstringEq (OfwNode
[2].DriverName
, "ethernet-phy")
685 // OpenFirmware device path (Ethernet NIC):
687 // /pci@i0cf8/ethernet@3[,2]/ethernet-phy@0
690 // | PCI slot[, function] holding Ethernet card
691 // PCI root at system bus port, PIO
693 // UEFI device path prefix (dependent on presence of nonzero PCI function):
695 // PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400E15EEF,0x1)
696 // PciRoot(0x0)/Pci(0x3,0x2)/MAC(525400E15EEF,0x1)
698 // MAC address IfType (1 == Ethernet)
700 // (Some UEFI NIC drivers don't set 0x1 for IfType.)
702 Written
= UnicodeSPrintAsciiFormat (
704 *TranslatedSize
* sizeof (*Translated
), // BufferSize in bytes
705 "PciRoot(0x0)/Pci(0x%x,0x%x)/MAC",
710 return RETURN_UNSUPPORTED
;
714 // There's no way to differentiate between "completely used up without
715 // truncation" and "truncated", so treat the former as the latter, and return
716 // success only for "some room left unused".
718 if (Written
+ 1 < *TranslatedSize
) {
719 *TranslatedSize
= Written
;
720 return RETURN_SUCCESS
;
723 return RETURN_BUFFER_TOO_SMALL
;
729 Translate an OpenFirmware device path fragment to a UEFI device path
730 fragment, and advance in the input string.
732 @param[in out] Ptr Address of the pointer pointing to the start
733 of the path string. After successful
734 translation (RETURN_SUCCESS) or at least
735 successful parsing (RETURN_UNSUPPORTED,
736 RETURN_BUFFER_TOO_SMALL), *Ptr is set to the
737 byte immediately following the consumed
738 characters. In other error cases, it points to
739 the byte that caused the error.
741 @param[out] Translated Destination array receiving the UEFI path
742 fragment, allocated by the caller. If the
743 return value differs from RETURN_SUCCESS, its
744 contents is indeterminate.
746 @param[in out] TranslatedSize On input, the number of CHAR16's in
747 Translated. On RETURN_SUCCESS this parameter
748 is assigned the number of non-NUL CHAR16's
749 written to Translated. In case of other return
750 values, TranslatedSize is indeterminate.
753 @retval RETURN_SUCCESS Translation successful.
755 @retval RETURN_BUFFER_TOO_SMALL The OpenFirmware device path was parsed
756 successfully, but its translation did not
757 fit into the number of bytes provided.
758 Further calls to this function are
761 @retval RETURN_UNSUPPORTED The OpenFirmware device path was parsed
762 successfully, but it can't be translated in
763 the current implementation. Further calls
764 to this function are possible.
766 @retval RETURN_NOT_FOUND Translation terminated, *Ptr was (and is)
767 pointing to an empty string.
769 @retval RETURN_INVALID_PARAMETER Parse error. This is a permanent error.
775 IN OUT CONST CHAR8
**Ptr
,
776 OUT CHAR16
*Translated
,
777 IN OUT UINTN
*TranslatedSize
781 RETURN_STATUS Status
;
782 OFW_NODE Node
[EXAMINED_OFW_NODES
];
787 Status
= ParseOfwNode (Ptr
, &Node
[NumNodes
], &IsFinal
);
789 if (Status
== RETURN_NOT_FOUND
) {
790 DEBUG ((DEBUG_VERBOSE
, "%a: no more nodes\n", __FUNCTION__
));
791 return RETURN_NOT_FOUND
;
794 while (Status
== RETURN_SUCCESS
&& !IsFinal
) {
796 Status
= ParseOfwNode (
798 (NumNodes
< EXAMINED_OFW_NODES
) ? &Node
[NumNodes
] : &Skip
,
808 case RETURN_INVALID_PARAMETER
:
809 DEBUG ((DEBUG_VERBOSE
, "%a: parse error\n", __FUNCTION__
));
810 return RETURN_INVALID_PARAMETER
;
816 Status
= TranslateOfwNodes (
818 NumNodes
< EXAMINED_OFW_NODES
? NumNodes
: EXAMINED_OFW_NODES
,
823 DEBUG ((DEBUG_VERBOSE
, "%a: success: \"%s\"\n", __FUNCTION__
, Translated
));
826 case RETURN_BUFFER_TOO_SMALL
:
827 DEBUG ((DEBUG_VERBOSE
, "%a: buffer too small\n", __FUNCTION__
));
830 case RETURN_UNSUPPORTED
:
831 DEBUG ((DEBUG_VERBOSE
, "%a: unsupported\n", __FUNCTION__
));
843 Convert the UEFI DevicePath to full text representation with DevPathToText,
844 then match the UEFI device path fragment in Translated against it.
846 @param[in] Translated UEFI device path fragment, translated from
847 OpenFirmware format, to search for.
849 @param[in] TranslatedLength The length of Translated in CHAR16's.
851 @param[in] DevicePath Boot option device path whose textual rendering
854 @param[in] DevPathToText Binary-to-text conversion protocol for DevicePath.
857 @retval TRUE If Translated was found at the beginning of DevicePath after
858 converting the latter to text.
860 @retval FALSE If DevicePath was NULL, or it could not be converted, or there
867 IN CONST CHAR16
*Translated
,
868 IN UINTN TranslatedLength
,
869 IN CONST EFI_DEVICE_PATH_PROTOCOL
*DevicePath
875 Converted
= ConvertDevicePathToText (
877 FALSE
, // DisplayOnly
878 FALSE
// AllowShortcuts
880 if (Converted
== NULL
) {
885 // Is Translated a prefix of Converted?
887 Result
= (BOOLEAN
)(StrnCmp (Converted
, Translated
, TranslatedLength
) == 0);
890 "%a: against \"%s\": %a\n",
893 Result
? "match" : "no match"
895 FreePool (Converted
);
902 Set the boot order based on configuration retrieved from QEMU.
904 Attempt to retrieve the "bootorder" fw_cfg file from QEMU. Translate the
905 OpenFirmware device paths therein to UEFI device path fragments. Match the
906 translated fragments against BootOptionList, and rewrite the BootOrder NvVar
907 so that it corresponds to the order described in fw_cfg.
909 @param[in] BootOptionList A boot option list, created with
910 BdsLibEnumerateAllBootOption ().
913 @retval RETURN_SUCCESS BootOrder NvVar rewritten.
915 @retval RETURN_UNSUPPORTED QEMU's fw_cfg is not supported.
917 @retval RETURN_NOT_FOUND Empty or nonexistent "bootorder" fw_cfg
918 file, or no match found between the
919 "bootorder" fw_cfg file and BootOptionList.
921 @retval RETURN_INVALID_PARAMETER Parse error in the "bootorder" fw_cfg file.
923 @retval RETURN_OUT_OF_RESOURCES Memory allocation failed.
925 @return Values returned by gBS->LocateProtocol ()
926 or gRT->SetVariable ().
930 SetBootOrderFromQemu (
931 IN CONST LIST_ENTRY
*BootOptionList
934 RETURN_STATUS Status
;
935 FIRMWARE_CONFIG_ITEM FwCfgItem
;
938 CONST CHAR8
*FwCfgPtr
;
940 BOOT_ORDER BootOrder
;
942 UINTN TranslatedSize
;
943 CHAR16 Translated
[TRANSLATION_OUTPUT_SIZE
];
945 Status
= QemuFwCfgFindFile ("bootorder", &FwCfgItem
, &FwCfgSize
);
946 if (Status
!= RETURN_SUCCESS
) {
950 if (FwCfgSize
== 0) {
951 return RETURN_NOT_FOUND
;
954 FwCfg
= AllocatePool (FwCfgSize
);
956 return RETURN_OUT_OF_RESOURCES
;
959 QemuFwCfgSelectItem (FwCfgItem
);
960 QemuFwCfgReadBytes (FwCfgSize
, FwCfg
);
961 if (FwCfg
[FwCfgSize
- 1] != '\0') {
962 Status
= RETURN_INVALID_PARAMETER
;
966 DEBUG ((DEBUG_VERBOSE
, "%a: FwCfg:\n", __FUNCTION__
));
967 DEBUG ((DEBUG_VERBOSE
, "%a\n", FwCfg
));
968 DEBUG ((DEBUG_VERBOSE
, "%a: FwCfg: <end>\n", __FUNCTION__
));
971 BootOrder
.Produced
= 0;
972 BootOrder
.Allocated
= 1;
973 BootOrder
.Data
= AllocatePool (
974 BootOrder
.Allocated
* sizeof (*BootOrder
.Data
)
976 if (BootOrder
.Data
== NULL
) {
977 Status
= RETURN_OUT_OF_RESOURCES
;
982 // translate each OpenFirmware path
984 TranslatedSize
= sizeof (Translated
) / sizeof (Translated
[0]);
985 Status
= TranslateOfwPath (&FwCfgPtr
, Translated
, &TranslatedSize
);
986 while (Status
== RETURN_SUCCESS
||
987 Status
== RETURN_UNSUPPORTED
||
988 Status
== RETURN_BUFFER_TOO_SMALL
) {
989 if (Status
== RETURN_SUCCESS
) {
990 CONST LIST_ENTRY
*Link
;
993 // match translated OpenFirmware path against all enumerated boot options
995 for (Link
= BootOptionList
->ForwardLink
; Link
!= BootOptionList
;
996 Link
= Link
->ForwardLink
) {
997 CONST BDS_COMMON_OPTION
*BootOption
;
1003 BDS_LOAD_OPTION_SIGNATURE
1005 if (IS_LOAD_OPTION_TYPE (BootOption
->Attribute
, LOAD_OPTION_ACTIVE
) &&
1008 TranslatedSize
, // contains length, not size, in CHAR16's here
1009 BootOption
->DevicePath
1013 // match found, store ID and continue with next OpenFirmware path
1015 Status
= BootOrderAppend (&BootOrder
, BootOption
->BootCurrent
);
1016 if (Status
!= RETURN_SUCCESS
) {
1017 goto ErrorFreeBootOrder
;
1021 } // scanned all enumerated boot options
1022 } // translation successful
1024 TranslatedSize
= sizeof (Translated
) / sizeof (Translated
[0]);
1025 Status
= TranslateOfwPath (&FwCfgPtr
, Translated
, &TranslatedSize
);
1026 } // scanning of OpenFirmware paths done
1028 if (Status
== RETURN_NOT_FOUND
&& BootOrder
.Produced
> 0) {
1030 // No more OpenFirmware paths, some matches found: rewrite BootOrder NvVar.
1031 // See Table 10 in the UEFI Spec 2.3.1 with Errata C for the required
1034 Status
= gRT
->SetVariable (
1036 &gEfiGlobalVariableGuid
,
1037 EFI_VARIABLE_NON_VOLATILE
|
1038 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
1039 EFI_VARIABLE_RUNTIME_ACCESS
,
1040 BootOrder
.Produced
* sizeof (*BootOrder
.Data
),
1045 "%a: setting BootOrder: %a\n",
1047 Status
== EFI_SUCCESS
? "success" : "error"
1052 FreePool (BootOrder
.Data
);