1 /** @file 2 The platform boot manager reference implementation 3 4 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 **/ 14 15 #include "BootManager.h" 16 17 UINT16 mKeyInput; 18 LIST_ENTRY mBootOptionsList; 19 BDS_COMMON_OPTION *gOption; 20 CHAR16 *mDeviceTypeStr[] = { 21 L"Legacy BEV", 22 L"Legacy Floppy", 23 L"Legacy Hard Drive", 24 L"Legacy CD ROM", 25 L"Legacy PCMCIA", 26 L"Legacy USB", 27 L"Legacy Embedded Network", 28 L"Legacy Unknown Device" 29 }; 30 31 32 HII_VENDOR_DEVICE_PATH mBootManagerHiiVendorDevicePath = { 33 { 34 { 35 HARDWARE_DEVICE_PATH, 36 HW_VENDOR_DP, 37 { 38 (UINT8) (sizeof (VENDOR_DEVICE_PATH)), 39 (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) 40 } 41 }, 42 BOOT_MANAGER_FORMSET_GUID 43 }, 44 { 45 END_DEVICE_PATH_TYPE, 46 END_ENTIRE_DEVICE_PATH_SUBTYPE, 47 { 48 (UINT8) (END_DEVICE_PATH_LENGTH), 49 (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) 50 } 51 } 52 }; 53 54 BOOT_MANAGER_CALLBACK_DATA gBootManagerPrivate = { 55 BOOT_MANAGER_CALLBACK_DATA_SIGNATURE, 56 NULL, 57 NULL, 58 { 59 FakeExtractConfig, 60 FakeRouteConfig, 61 BootManagerCallback 62 } 63 }; 64 65 /** 66 This call back function is registered with Boot Manager formset. 67 When user selects a boot option, this call back function will 68 be triggered. The boot option is saved for later processing. 69 70 71 @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. 72 @param Action Specifies the type of action taken by the browser. 73 @param QuestionId A unique value which is sent to the original exporting driver 74 so that it can identify the type of data to expect. 75 @param Type The type of value for the question. 76 @param Value A pointer to the data being sent to the original exporting driver. 77 @param ActionRequest On return, points to the action requested by the callback function. 78 79 @retval EFI_SUCCESS The callback successfully handled the action. 80 @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters. 81 82 **/ 83 EFI_STATUS 84 EFIAPI 85 BootManagerCallback ( 86 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, 87 IN EFI_BROWSER_ACTION Action, 88 IN EFI_QUESTION_ID QuestionId, 89 IN UINT8 Type, 90 IN EFI_IFR_TYPE_VALUE *Value, 91 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest 92 ) 93 { 94 BDS_COMMON_OPTION *Option; 95 LIST_ENTRY *Link; 96 UINT16 KeyCount; 97 98 if (Action == EFI_BROWSER_ACTION_CHANGED) { 99 if ((Value == NULL) || (ActionRequest == NULL)) { 100 return EFI_INVALID_PARAMETER; 101 } 102 103 // 104 // Initialize the key count 105 // 106 KeyCount = 0; 107 108 for (Link = GetFirstNode (&mBootOptionsList); !IsNull (&mBootOptionsList, Link); Link = GetNextNode (&mBootOptionsList, Link)) { 109 Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE); 110 111 KeyCount++; 112 113 gOption = Option; 114 115 // 116 // Is this device the one chosen? 117 // 118 if (KeyCount == QuestionId) { 119 // 120 // Assigning the returned Key to a global allows the original routine to know what was chosen 121 // 122 mKeyInput = QuestionId; 123 124 // 125 // Request to exit SendForm(), so that we could boot the selected option 126 // 127 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; 128 break; 129 } 130 } 131 132 return EFI_SUCCESS; 133 } 134 135 // 136 // All other action return unsupported. 137 // 138 return EFI_UNSUPPORTED; 139 } 140 141 /** 142 143 Registers HII packages for the Boot Manger to HII Database. 144 It also registers the browser call back function. 145 146 @retval EFI_SUCCESS HII packages for the Boot Manager were registered successfully. 147 @retval EFI_OUT_OF_RESOURCES HII packages for the Boot Manager failed to be registered. 148 149 **/ 150 EFI_STATUS 151 InitializeBootManager ( 152 VOID 153 ) 154 { 155 EFI_STATUS Status; 156 157 // 158 // Install Device Path Protocol and Config Access protocol to driver handle 159 // 160 Status = gBS->InstallMultipleProtocolInterfaces ( 161 &gBootManagerPrivate.DriverHandle, 162 &gEfiDevicePathProtocolGuid, 163 &mBootManagerHiiVendorDevicePath, 164 &gEfiHiiConfigAccessProtocolGuid, 165 &gBootManagerPrivate.ConfigAccess, 166 NULL 167 ); 168 ASSERT_EFI_ERROR (Status); 169 170 // 171 // Publish our HII data 172 // 173 gBootManagerPrivate.HiiHandle = HiiAddPackages ( 174 &gBootManagerFormSetGuid, 175 gBootManagerPrivate.DriverHandle, 176 BootManagerVfrBin, 177 BdsDxeStrings, 178 NULL 179 ); 180 if (gBootManagerPrivate.HiiHandle == NULL) { 181 Status = EFI_OUT_OF_RESOURCES; 182 } else { 183 Status = EFI_SUCCESS; 184 } 185 return Status; 186 } 187 188 /** 189 This function invokes Boot Manager. If all devices have not a chance to be connected, 190 the connect all will be triggered. It then enumerate all boot options. If 191 a boot option from the Boot Manager page is selected, Boot Manager will boot 192 from this boot option. 193 194 **/ 195 VOID 196 CallBootManager ( 197 VOID 198 ) 199 { 200 EFI_STATUS Status; 201 BDS_COMMON_OPTION *Option; 202 LIST_ENTRY *Link; 203 CHAR16 *ExitData; 204 UINTN ExitDataSize; 205 EFI_STRING_ID Token; 206 EFI_INPUT_KEY Key; 207 CHAR16 *HelpString; 208 UINTN HelpSize; 209 EFI_STRING_ID HelpToken; 210 UINT16 *TempStr; 211 EFI_HII_HANDLE HiiHandle; 212 EFI_BROWSER_ACTION_REQUEST ActionRequest; 213 VOID *StartOpCodeHandle; 214 VOID *EndOpCodeHandle; 215 EFI_IFR_GUID_LABEL *StartLabel; 216 EFI_IFR_GUID_LABEL *EndLabel; 217 UINT16 DeviceType; 218 BOOLEAN IsLegacyOption; 219 BOOLEAN NeedEndOp; 220 221 DeviceType = (UINT16) -1; 222 gOption = NULL; 223 InitializeListHead (&mBootOptionsList); 224 225 // 226 // Connect all prior to entering the platform setup menu. 227 // 228 if (!gConnectAllHappened) { 229 BdsLibConnectAllDriversToAllControllers (); 230 gConnectAllHappened = TRUE; 231 } 232 233 BdsLibEnumerateAllBootOption (&mBootOptionsList); 234 235 // 236 // Group the legacy boot options for the same device type 237 // 238 GroupMultipleLegacyBootOption4SameType (); 239 240 InitializeListHead (&mBootOptionsList); 241 BdsLibBuildOptionFromVar (&mBootOptionsList, L"BootOrder"); 242 243 HiiHandle = gBootManagerPrivate.HiiHandle; 244 245 // 246 // Allocate space for creation of UpdateData Buffer 247 // 248 StartOpCodeHandle = HiiAllocateOpCodeHandle (); 249 ASSERT (StartOpCodeHandle != NULL); 250 251 EndOpCodeHandle = HiiAllocateOpCodeHandle (); 252 ASSERT (EndOpCodeHandle != NULL); 253 254 // 255 // Create Hii Extend Label OpCode as the start opcode 256 // 257 StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL)); 258 StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; 259 StartLabel->Number = LABEL_BOOT_OPTION; 260 261 // 262 // Create Hii Extend Label OpCode as the end opcode 263 // 264 EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL)); 265 EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; 266 EndLabel->Number = LABEL_BOOT_OPTION_END; 267 268 mKeyInput = 0; 269 NeedEndOp = FALSE; 270 for (Link = GetFirstNode (&mBootOptionsList); !IsNull (&mBootOptionsList, Link); Link = GetNextNode (&mBootOptionsList, Link)) { 271 Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE); 272 273 // 274 // At this stage we are creating a menu entry, thus the Keys are reproduceable 275 // 276 mKeyInput++; 277 278 // 279 // Don't display the hidden/inactive boot option 280 // 281 if (((Option->Attribute & LOAD_OPTION_HIDDEN) != 0) || ((Option->Attribute & LOAD_OPTION_ACTIVE) == 0)) { 282 continue; 283 } 284 285 // 286 // Group the legacy boot option in the sub title created dynamically 287 // 288 IsLegacyOption = (BOOLEAN) ( 289 (DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) && 290 (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP) 291 ); 292 293 if (!IsLegacyOption && NeedEndOp) { 294 NeedEndOp = FALSE; 295 HiiCreateEndOpCode (StartOpCodeHandle); 296 } 297 298 if (IsLegacyOption && DeviceType != ((BBS_BBS_DEVICE_PATH *) Option->DevicePath)->DeviceType) { 299 if (NeedEndOp) { 300 HiiCreateEndOpCode (StartOpCodeHandle); 301 } 302 303 DeviceType = ((BBS_BBS_DEVICE_PATH *) Option->DevicePath)->DeviceType; 304 Token = HiiSetString ( 305 HiiHandle, 306 0, 307 mDeviceTypeStr[ 308 MIN (DeviceType & 0xF, ARRAY_SIZE (mDeviceTypeStr) - 1) 309 ], 310 NULL 311 ); 312 HiiCreateSubTitleOpCode (StartOpCodeHandle, Token, 0, 0, 1); 313 NeedEndOp = TRUE; 314 } 315 316 ASSERT (Option->Description != NULL); 317 318 Token = HiiSetString (HiiHandle, 0, Option->Description, NULL); 319 320 TempStr = DevicePathToStr (Option->DevicePath); 321 HelpSize = StrSize (TempStr) + StrSize (L"Device Path : "); 322 HelpString = AllocateZeroPool (HelpSize); 323 ASSERT (HelpString != NULL); 324 StrCatS (HelpString, HelpSize / sizeof (CHAR16), L"Device Path : "); 325 StrCatS (HelpString, HelpSize / sizeof (CHAR16), TempStr); 326 327 HelpToken = HiiSetString (HiiHandle, 0, HelpString, NULL); 328 329 HiiCreateActionOpCode ( 330 StartOpCodeHandle, 331 mKeyInput, 332 Token, 333 HelpToken, 334 EFI_IFR_FLAG_CALLBACK, 335 0 336 ); 337 } 338 339 if (NeedEndOp) { 340 HiiCreateEndOpCode (StartOpCodeHandle); 341 } 342 343 HiiUpdateForm ( 344 HiiHandle, 345 &gBootManagerFormSetGuid, 346 BOOT_MANAGER_FORM_ID, 347 StartOpCodeHandle, 348 EndOpCodeHandle 349 ); 350 351 HiiFreeOpCodeHandle (StartOpCodeHandle); 352 HiiFreeOpCodeHandle (EndOpCodeHandle); 353 354 ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; 355 Status = gFormBrowser2->SendForm ( 356 gFormBrowser2, 357 &HiiHandle, 358 1, 359 &gBootManagerFormSetGuid, 360 0, 361 NULL, 362 &ActionRequest 363 ); 364 if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) { 365 EnableResetRequired (); 366 } 367 368 if (gOption == NULL) { 369 return ; 370 } 371 372 // 373 // Will leave browser, check any reset required change is applied? if yes, reset system 374 // 375 SetupResetReminder (); 376 377 // 378 // Restore to original mode before launching boot option. 379 // 380 BdsSetConsoleMode (FALSE); 381 382 // 383 // parse the selected option 384 // 385 Status = BdsLibBootViaBootOption (gOption, gOption->DevicePath, &ExitDataSize, &ExitData); 386 387 if (!EFI_ERROR (Status)) { 388 gOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED)); 389 PlatformBdsBootSuccess (gOption); 390 } else { 391 gOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED)); 392 PlatformBdsBootFail (gOption, Status, ExitData, ExitDataSize); 393 gST->ConOut->OutputString ( 394 gST->ConOut, 395 GetStringById (STRING_TOKEN (STR_ANY_KEY_CONTINUE)) 396 ); 397 gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); 398 } 399 } 400