UnitTestBootLibUsbClass.c 4.0 KB

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