1 /**
2 Implement UnitTestBootLib using USB Class Boot option. This should be
3 industry standard and should work on all platforms
4
5 Copyright (c) Microsoft Corporation.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 **/
8
9 #include <PiDxe.h>
10 #include <Library/DebugLib.h>
11 #include <Library/UefiRuntimeServicesTableLib.h>
12 #include <Library/UefiBootManagerLib.h>
13 #include <Library/DevicePathLib.h>
14 #include <Protocol/DevicePath.h>
15 #include <Library/MemoryAllocationLib.h>
16
17 /**
18 Set the boot manager to boot from a specific device on the next boot. This
19 should be set only for the next boot and shouldn't require any manual clean up
20
21 @retval EFI_SUCCESS Boot device for next boot was set.
22 @retval EFI_UNSUPPORTED Setting the boot device for the next boot is not
23 supportted.
24 @retval Other Boot device for next boot can not be set.
25 **/
26 EFI_STATUS
27 EFIAPI
SetBootNextDevice(VOID)28 SetBootNextDevice (
29 VOID
30 )
31 {
32 EFI_STATUS Status;
33 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
34 UINT32 Attributes;
35 UINT8 *OptionalData;
36 UINT32 OptionalDataSize;
37 UINT16 BootNextValue;
38 USB_CLASS_DEVICE_PATH UsbDp;
39 EFI_DEVICE_PATH_PROTOCOL *DpEnd;
40 EFI_DEVICE_PATH_PROTOCOL *Dp;
41 BOOLEAN NewOptionValid;
42
43 OptionalData = NULL;
44 OptionalDataSize = 0;
45 BootNextValue = 0xABCD; // this should be a safe number...
46 DpEnd = NULL;
47 Dp = NULL;
48 NewOptionValid = FALSE;
49
50 UsbDp.Header.Length[0] = (UINT8)(sizeof(USB_CLASS_DEVICE_PATH) & 0xff);
51 UsbDp.Header.Length[1] = (UINT8)(sizeof(USB_CLASS_DEVICE_PATH) >> 8);
52 UsbDp.Header.Type = MESSAGING_DEVICE_PATH;
53 UsbDp.Header.SubType = MSG_USB_CLASS_DP;
54 UsbDp.VendorId = 0xFFFF;
55 UsbDp.ProductId = 0xFFFF;
56 UsbDp.DeviceClass = 0xFF;
57 UsbDp.DeviceSubClass = 0xFF;
58 UsbDp.DeviceProtocol = 0xFF;
59
60 Attributes = LOAD_OPTION_ACTIVE;
61
62 DpEnd = AppendDevicePathNode (NULL, NULL);
63 if (DpEnd == NULL) {
64 DEBUG ((DEBUG_ERROR, "%a: Unable to create device path. DpEnd is NULL.\n", __FUNCTION__));
65 Status = EFI_OUT_OF_RESOURCES;
66 goto CLEANUP;
67 }
68
69 //@MRT --- Is this memory leak because we lose the old Dp memory
70 Dp = AppendDevicePathNode (
71 DpEnd,
72 (EFI_DEVICE_PATH_PROTOCOL *)&UsbDp
73 );
74 if (Dp == NULL) {
75 DEBUG((DEBUG_ERROR, "%a: Unable to create device path. Dp is NULL.\n", __FUNCTION__));
76 Status = EFI_OUT_OF_RESOURCES;
77 goto CLEANUP;
78 }
79
80 Status = EfiBootManagerInitializeLoadOption (
81 &NewOption,
82 (UINTN) BootNextValue,
83 LoadOptionTypeBoot,
84 Attributes,
85 L"Generic USB Class Device",
86 Dp,
87 OptionalData,
88 OptionalDataSize
89 );
90 if (EFI_ERROR (Status)) {
91 DEBUG ((DEBUG_ERROR, "%a: Error creating load option. Status = %r\n", __FUNCTION__, Status));
92 goto CLEANUP;
93 }
94
95 NewOptionValid = TRUE;
96 DEBUG ((DEBUG_VERBOSE, "%a: Generic USB Class Device boot option created.\n", __FUNCTION__));
97 Status = EfiBootManagerLoadOptionToVariable (&NewOption);
98 if (EFI_ERROR (Status)) {
99 DEBUG ((DEBUG_ERROR, "%a: Error Saving boot option NV variable. Status = %r\n", __FUNCTION__, Status));
100 goto CLEANUP;
101 }
102
103 //
104 // Set Boot Next
105 //
106 Status = gRT->SetVariable (
107 L"BootNext",
108 &gEfiGlobalVariableGuid,
109 (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE),
110 sizeof(BootNextValue),
111 &(BootNextValue)
112 );
113
114 DEBUG((DEBUG_VERBOSE, "%a - Set BootNext Status (%r)\n", __FUNCTION__, Status));
115
116 CLEANUP:
117 if (Dp != NULL) {
118 FreePool (Dp);
119 }
120 if (DpEnd != NULL) {
121 FreePool (DpEnd);
122 }
123 if (NewOptionValid) {
124 EfiBootManagerFreeLoadOption (&NewOption);
125 }
126 return Status;
127 }
128