1 /** @file 2 This file include all platform action which can be customized 3 by IBV/OEM. 4 5 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR> 6 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> 7 This program and the accompanying materials 8 are licensed and made available under the terms and conditions of the BSD License 9 which accompanies this distribution. The full text of the license may be found at 10 http://opensource.org/licenses/bsd-license.php 11 12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 15 **/ 16 17 #include "PlatformBootManager.h" 18 19 EFI_GUID mBootMenuFile = { 20 0xEEC25BDC, 0x67F2, 0x4D95, { 0xB1, 0xD5, 0xF8, 0x1B, 0x20, 0x39, 0xD1, 0x1D } 21 }; 22 23 /** 24 Perform the platform diagnostic, such like test memory. OEM/IBV also 25 can customize this function to support specific platform diagnostic. 26 27 @param MemoryTestLevel The memory test intensive level 28 @param QuietBoot Indicate if need to enable the quiet boot 29 30 **/ 31 VOID 32 PlatformBootManagerDiagnostics ( 33 IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel, 34 IN BOOLEAN QuietBoot 35 ) 36 { 37 EFI_STATUS Status; 38 39 // 40 // Here we can decide if we need to show 41 // the diagnostics screen 42 // Notes: this quiet boot code should be remove 43 // from the graphic lib 44 // 45 if (QuietBoot) { 46 BootLogoEnableLogo (); 47 48 // 49 // Perform system diagnostic 50 // 51 Status = PlatformBootManagerMemoryTest (MemoryTestLevel); 52 if (EFI_ERROR (Status)) { 53 BootLogoDisableLogo (); 54 } 55 56 return; 57 } 58 59 // 60 // Perform system diagnostic 61 // 62 Status = PlatformBootManagerMemoryTest (MemoryTestLevel); 63 } 64 65 /** 66 Do the platform specific action before the console is connected. 67 68 Such as: 69 Update console variable; 70 Register new Driver#### or Boot####; 71 Signal ReadyToLock event. 72 **/ 73 VOID 74 EFIAPI 75 PlatformBootManagerBeforeConsole ( 76 VOID 77 ) 78 { 79 UINTN Index; 80 EFI_STATUS Status; 81 WIN_NT_SYSTEM_CONFIGURATION *Configuration; 82 83 GetVariable2 (L"Setup", &gEfiWinNtSystemConfigGuid, (VOID **) &Configuration, NULL); 84 if (Configuration != NULL) { 85 // 86 // SetupVariable is corrupt 87 // 88 Configuration->ConOutRow = PcdGet32 (PcdConOutColumn); 89 Configuration->ConOutColumn = PcdGet32 (PcdConOutRow); 90 91 Status = gRT->SetVariable ( 92 L"Setup", 93 &gEfiWinNtSystemConfigGuid, 94 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 95 sizeof (WIN_NT_SYSTEM_CONFIGURATION), 96 Configuration 97 ); 98 if (EFI_ERROR (Status)) { 99 DEBUG ((EFI_D_ERROR, "Failed to save Setup Variable to non-volatile storage, Status = %r\n", Status)); 100 } 101 FreePool (Configuration); 102 } 103 104 // 105 // Update the ocnsole variables. 106 // 107 for (Index = 0; gPlatformConsole[Index].DevicePath != NULL; Index++) { 108 if ((gPlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) { 109 EfiBootManagerUpdateConsoleVariable (ConIn, gPlatformConsole[Index].DevicePath, NULL); 110 } 111 112 if ((gPlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) { 113 EfiBootManagerUpdateConsoleVariable (ConOut, gPlatformConsole[Index].DevicePath, NULL); 114 } 115 116 if ((gPlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) { 117 EfiBootManagerUpdateConsoleVariable (ErrOut, gPlatformConsole[Index].DevicePath, NULL); 118 } 119 } 120 121 // 122 // From PI spec vol2: 123 // Prior to invoking any UEFI drivers, applications, or connecting consoles, 124 // the platform should signal the event EFI_END_OF_DXE_EVENT_GUID 125 // 126 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid); 127 128 // 129 // Dispatch deferred images after EndOfDxe event. 130 // 131 EfiBootManagerDispatchDeferredImages (); 132 } 133 134 /** 135 Returns the priority number. 136 137 @param BootOption 138 **/ 139 UINTN 140 BootOptionPriority ( 141 CONST EFI_BOOT_MANAGER_LOAD_OPTION *BootOption 142 ) 143 { 144 // 145 // Make sure Shell is first 146 // 147 if (StrCmp (BootOption->Description, L"UEFI Shell") == 0) { 148 return 0; 149 } 150 return 100; 151 } 152 153 INTN 154 EFIAPI 155 CompareBootOption ( 156 CONST EFI_BOOT_MANAGER_LOAD_OPTION *Left, 157 CONST EFI_BOOT_MANAGER_LOAD_OPTION *Right 158 ) 159 { 160 return BootOptionPriority (Left) - BootOptionPriority (Right); 161 } 162 163 /** 164 Generate device path include the input file guid info. 165 166 @param FileGuid Input file guid for the BootManagerMenuApp. 167 168 @retval DevicePath for BootManagerMenuApp. 169 **/ 170 EFI_DEVICE_PATH * 171 FvFilePath ( 172 EFI_GUID *FileGuid 173 ) 174 { 175 176 EFI_STATUS Status; 177 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; 178 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode; 179 180 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid); 181 182 Status = gBS->HandleProtocol ( 183 gImageHandle, 184 &gEfiLoadedImageProtocolGuid, 185 (VOID **) &LoadedImage 186 ); 187 ASSERT_EFI_ERROR (Status); 188 189 return AppendDevicePathNode ( 190 DevicePathFromHandle (LoadedImage->DeviceHandle), 191 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode 192 ); 193 } 194 195 /** 196 Create one boot option for BootManagerMenuApp. 197 198 @param FileGuid Input file guid for the BootManagerMenuApp. 199 @param Description Description of the BootManagerMenuApp boot option. 200 @param Position Position of the new load option to put in the ****Order variable. 201 @param IsBootCategory Whether this is a boot category. 202 203 204 @retval OptionNumber Return the option number info. 205 206 **/ 207 UINTN 208 RegisterBootManagerMenuAppBootOption ( 209 EFI_GUID *FileGuid, 210 CHAR16 *Description, 211 UINTN Position, 212 BOOLEAN IsBootCategory 213 ) 214 { 215 EFI_STATUS Status; 216 EFI_BOOT_MANAGER_LOAD_OPTION NewOption; 217 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 218 UINTN OptionNumber; 219 220 DevicePath = FvFilePath (FileGuid); 221 Status = EfiBootManagerInitializeLoadOption ( 222 &NewOption, 223 LoadOptionNumberUnassigned, 224 LoadOptionTypeBoot, 225 IsBootCategory ? LOAD_OPTION_ACTIVE : LOAD_OPTION_CATEGORY_APP, 226 Description, 227 DevicePath, 228 NULL, 229 0 230 ); 231 ASSERT_EFI_ERROR (Status); 232 FreePool (DevicePath); 233 234 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, Position); 235 ASSERT_EFI_ERROR (Status); 236 237 OptionNumber = NewOption.OptionNumber; 238 239 EfiBootManagerFreeLoadOption (&NewOption); 240 241 return OptionNumber; 242 } 243 244 /** 245 Check if it's a Device Path pointing to BootManagerMenuApp. 246 247 @param DevicePath Input device path. 248 249 @retval TRUE The device path is BootManagerMenuApp File Device Path. 250 @retval FALSE The device path is NOT BootManagerMenuApp File Device Path. 251 **/ 252 BOOLEAN 253 IsBootManagerMenuAppFilePath ( 254 EFI_DEVICE_PATH_PROTOCOL *DevicePath 255 ) 256 { 257 EFI_HANDLE FvHandle; 258 VOID *NameGuid; 259 EFI_STATUS Status; 260 261 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePath, &FvHandle); 262 if (!EFI_ERROR (Status)) { 263 NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) DevicePath); 264 if (NameGuid != NULL) { 265 return CompareGuid (NameGuid, &mBootMenuFile); 266 } 267 } 268 269 return FALSE; 270 } 271 272 /** 273 Return the boot option number to the BootManagerMenuApp. 274 275 If not found it in the current boot option, create a new one. 276 277 @retval OptionNumber Return the boot option number to the BootManagerMenuApp. 278 279 **/ 280 UINTN 281 GetBootManagerMenuAppOption ( 282 VOID 283 ) 284 { 285 UINTN BootOptionCount; 286 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions; 287 UINTN Index; 288 UINTN OptionNumber; 289 290 OptionNumber = 0; 291 292 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot); 293 294 for (Index = 0; Index < BootOptionCount; Index++) { 295 if (IsBootManagerMenuAppFilePath (BootOptions[Index].FilePath)) { 296 OptionNumber = BootOptions[Index].OptionNumber; 297 break; 298 } 299 } 300 301 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount); 302 303 if (Index >= BootOptionCount) { 304 // 305 // If not found the BootManagerMenuApp, create it. 306 // 307 OptionNumber = (UINT16) RegisterBootManagerMenuAppBootOption (&mBootMenuFile, L"UEFI BootManagerMenuApp", (UINTN) -1, FALSE); 308 } 309 310 return OptionNumber; 311 } 312 313 /** 314 Do the platform specific action after the console is connected. 315 316 Such as: 317 Dynamically switch output mode; 318 Signal console ready platform customized event; 319 Run diagnostics like memory testing; 320 Connect certain devices; 321 Dispatch aditional option roms. 322 **/ 323 VOID 324 EFIAPI 325 PlatformBootManagerAfterConsole ( 326 VOID 327 ) 328 { 329 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Black; 330 EFI_GRAPHICS_OUTPUT_BLT_PIXEL White; 331 EFI_INPUT_KEY Enter; 332 EFI_INPUT_KEY F2; 333 EFI_INPUT_KEY F7; 334 EFI_BOOT_MANAGER_LOAD_OPTION BootOption; 335 UINTN OptionNumber; 336 337 Black.Blue = Black.Green = Black.Red = Black.Reserved = 0; 338 White.Blue = White.Green = White.Red = White.Reserved = 0xFF; 339 340 EfiBootManagerConnectAll (); 341 EfiBootManagerRefreshAllBootOption (); 342 343 // 344 // Register ENTER as CONTINUE key 345 // 346 Enter.ScanCode = SCAN_NULL; 347 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN; 348 EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL); 349 // 350 // Map F2 to Boot Manager Menu 351 // 352 F2.ScanCode = SCAN_F2; 353 F2.UnicodeChar = CHAR_NULL; 354 EfiBootManagerGetBootManagerMenu (&BootOption); 355 EfiBootManagerAddKeyOptionVariable (NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL); 356 357 // 358 // 3. Boot Device List menu 359 // 360 F7.ScanCode = SCAN_F7; 361 F7.UnicodeChar = CHAR_NULL; 362 OptionNumber = GetBootManagerMenuAppOption (); 363 EfiBootManagerAddKeyOptionVariable (NULL, (UINT16)OptionNumber, 0, &F7, NULL); 364 365 // 366 // Make Shell as the first boot option 367 // 368 EfiBootManagerSortLoadOptionVariable (LoadOptionTypeBoot, (SORT_COMPARE) CompareBootOption); 369 370 PlatformBootManagerDiagnostics (QUICK, TRUE); 371 372 PrintXY (10, 10, &White, &Black, L"F2 to enter Setup. "); 373 PrintXY (10, 30, &White, &Black, L"F7 to enter Boot Manager Menu."); 374 PrintXY (10, 50, &White, &Black, L"Enter to boot directly."); 375 } 376 377 /** 378 This function is called each second during the boot manager waits the timeout. 379 380 @param TimeoutRemain The remaining timeout. 381 **/ 382 VOID 383 EFIAPI 384 PlatformBootManagerWaitCallback ( 385 UINT16 TimeoutRemain 386 ) 387 { 388 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black; 389 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White; 390 UINT16 Timeout; 391 392 Timeout = PcdGet16 (PcdPlatformBootTimeOut); 393 394 Black.Raw = 0x00000000; 395 White.Raw = 0x00FFFFFF; 396 397 BootLogoUpdateProgress ( 398 White.Pixel, 399 Black.Pixel, 400 L"Start boot option", 401 White.Pixel, 402 (Timeout - TimeoutRemain) * 100 / Timeout, 403 0 404 ); 405 } 406