1 /** @file 2 File explorer related functions. 3 4 Copyright (c) 2004 - 2014, 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 "BootMaint.h" 16 17 /** 18 Update the File Explore page. 19 20 @param CallbackData The BMM context data. 21 @param MenuOption Pointer to menu options to display. 22 23 **/ 24 VOID 25 UpdateFileExplorePage ( 26 IN BMM_CALLBACK_DATA *CallbackData, 27 BM_MENU_OPTION *MenuOption 28 ) 29 { 30 UINTN Index; 31 BM_MENU_ENTRY *NewMenuEntry; 32 BM_FILE_CONTEXT *NewFileContext; 33 EFI_FORM_ID FormId; 34 35 NewMenuEntry = NULL; 36 NewFileContext = NULL; 37 FormId = 0; 38 39 RefreshUpdateData (); 40 mStartLabel->Number = FORM_FILE_EXPLORER_ID; 41 42 for (Index = 0; Index < MenuOption->MenuNumber; Index++) { 43 NewMenuEntry = BOpt_GetMenuEntry (MenuOption, Index); 44 NewFileContext = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext; 45 46 if (NewFileContext->IsBootLegacy) { 47 continue; 48 } 49 50 if ((NewFileContext->IsDir) || (FileExplorerStateBootFromFile == CallbackData->FeCurrentState)) { 51 // 52 // Create Text opcode for directory, also create Text opcode for file in FileExplorerStateBootFromFile. 53 // 54 HiiCreateActionOpCode ( 55 mStartOpCodeHandle, 56 (UINT16) (FILE_OPTION_OFFSET + Index), 57 NewMenuEntry->DisplayStringToken, 58 STRING_TOKEN (STR_NULL_STRING), 59 EFI_IFR_FLAG_CALLBACK, 60 0 61 ); 62 } else { 63 // 64 // Create Goto opcode for file in FileExplorerStateAddBootOption or FileExplorerStateAddDriverOptionState. 65 // 66 if (FileExplorerStateAddBootOption == CallbackData->FeCurrentState) { 67 FormId = FORM_BOOT_ADD_DESCRIPTION_ID; 68 } else if (FileExplorerStateAddDriverOptionState == CallbackData->FeCurrentState) { 69 FormId = FORM_DRIVER_ADD_FILE_DESCRIPTION_ID; 70 } 71 72 HiiCreateGotoOpCode ( 73 mStartOpCodeHandle, 74 FormId, 75 NewMenuEntry->DisplayStringToken, 76 STRING_TOKEN (STR_NULL_STRING), 77 EFI_IFR_FLAG_CALLBACK, 78 (UINT16) (FILE_OPTION_GOTO_OFFSET + Index) 79 ); 80 } 81 } 82 83 HiiUpdateForm ( 84 CallbackData->FeHiiHandle, 85 &gFileExploreFormSetGuid, 86 FORM_FILE_EXPLORER_ID, 87 mStartOpCodeHandle, // Label FORM_FILE_EXPLORER_ID 88 mEndOpCodeHandle // LABEL_END 89 ); 90 } 91 92 /** 93 Update the file explower page with the refershed file system. 94 95 96 @param CallbackData BMM context data 97 @param KeyValue Key value to identify the type of data to expect. 98 99 @retval TRUE Inform the caller to create a callback packet to exit file explorer. 100 @retval FALSE Indicate that there is no need to exit file explorer. 101 102 **/ 103 BOOLEAN 104 UpdateFileExplorer ( 105 IN BMM_CALLBACK_DATA *CallbackData, 106 IN UINT16 KeyValue 107 ) 108 { 109 UINT16 FileOptionMask; 110 BM_MENU_ENTRY *NewMenuEntry; 111 BM_FILE_CONTEXT *NewFileContext; 112 EFI_FORM_ID FormId; 113 BOOLEAN ExitFileExplorer; 114 EFI_STATUS Status; 115 116 NewMenuEntry = NULL; 117 NewFileContext = NULL; 118 ExitFileExplorer = FALSE; 119 120 FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue); 121 122 if (FileExplorerDisplayUnknown == CallbackData->FeDisplayContext) { 123 // 124 // First in, display file system. 125 // 126 BOpt_FreeMenu (&FsOptionMenu); 127 BOpt_FindFileSystem (CallbackData); 128 CreateMenuStringToken (CallbackData, CallbackData->FeHiiHandle, &FsOptionMenu); 129 130 UpdateFileExplorePage (CallbackData, &FsOptionMenu); 131 132 CallbackData->FeDisplayContext = FileExplorerDisplayFileSystem; 133 } else { 134 if (FileExplorerDisplayFileSystem == CallbackData->FeDisplayContext) { 135 NewMenuEntry = BOpt_GetMenuEntry (&FsOptionMenu, FileOptionMask); 136 } else if (FileExplorerDisplayDirectory == CallbackData->FeDisplayContext) { 137 NewMenuEntry = BOpt_GetMenuEntry (&DirectoryMenu, FileOptionMask); 138 } 139 140 NewFileContext = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext; 141 142 if (NewFileContext->IsDir ) { 143 CallbackData->FeDisplayContext = FileExplorerDisplayDirectory; 144 145 RemoveEntryList (&NewMenuEntry->Link); 146 BOpt_FreeMenu (&DirectoryMenu); 147 Status = BOpt_FindFiles (CallbackData, NewMenuEntry); 148 if (EFI_ERROR (Status)) { 149 ExitFileExplorer = TRUE; 150 goto exit; 151 } 152 CreateMenuStringToken (CallbackData, CallbackData->FeHiiHandle, &DirectoryMenu); 153 BOpt_DestroyMenuEntry (NewMenuEntry); 154 155 UpdateFileExplorePage (CallbackData, &DirectoryMenu); 156 157 } else { 158 switch (CallbackData->FeCurrentState) { 159 case FileExplorerStateBootFromFile: 160 // 161 // Restore to original mode before launching boot option. 162 // 163 BdsSetConsoleMode (FALSE); 164 165 // 166 // Here boot from file 167 // 168 BootThisFile (NewFileContext); 169 // 170 // Set proper video resolution and text mode for setup. 171 // 172 BdsSetConsoleMode (TRUE); 173 ExitFileExplorer = TRUE; 174 break; 175 176 case FileExplorerStateAddBootOption: 177 case FileExplorerStateAddDriverOptionState: 178 if (FileExplorerStateAddBootOption == CallbackData->FeCurrentState) { 179 FormId = FORM_BOOT_ADD_DESCRIPTION_ID; 180 if (!CallbackData->FeFakeNvData.BootOptionChanged) { 181 ZeroMem (CallbackData->FeFakeNvData.BootOptionalData, sizeof (CallbackData->FeFakeNvData.BootOptionalData)); 182 ZeroMem (CallbackData->FeFakeNvData.BootDescriptionData, sizeof (CallbackData->FeFakeNvData.BootDescriptionData)); 183 } 184 } else { 185 FormId = FORM_DRIVER_ADD_FILE_DESCRIPTION_ID; 186 if (!CallbackData->FeFakeNvData.DriverOptionChanged) { 187 ZeroMem (CallbackData->FeFakeNvData.DriverOptionalData, sizeof (CallbackData->FeFakeNvData.DriverOptionalData)); 188 ZeroMem (CallbackData->FeFakeNvData.DriverDescriptionData, sizeof (CallbackData->FeFakeNvData.DriverDescriptionData)); 189 } 190 } 191 192 CallbackData->MenuEntry = NewMenuEntry; 193 CallbackData->LoadContext->FilePathList = ((BM_FILE_CONTEXT *) (CallbackData->MenuEntry->VariableContext))->DevicePath; 194 195 // 196 // Create Subtitle op-code for the display string of the option. 197 // 198 RefreshUpdateData (); 199 mStartLabel->Number = FormId; 200 201 HiiCreateSubTitleOpCode ( 202 mStartOpCodeHandle, 203 NewMenuEntry->DisplayStringToken, 204 0, 205 0, 206 0 207 ); 208 209 HiiUpdateForm ( 210 CallbackData->FeHiiHandle, 211 &gFileExploreFormSetGuid, 212 FormId, 213 mStartOpCodeHandle, // Label FormId 214 mEndOpCodeHandle // LABEL_END 215 ); 216 break; 217 218 default: 219 break; 220 } 221 } 222 } 223 exit: 224 return ExitFileExplorer; 225 } 226 227 /** 228 This function applies changes in a driver's configuration. 229 Input is a Configuration, which has the routing data for this 230 driver followed by name / value configuration pairs. The driver 231 must apply those pairs to its configurable storage. If the 232 driver's configuration is stored in a linear block of data 233 and the driver's name / value pairs are in <BlockConfig> 234 format, it may use the ConfigToBlock helper function (above) to 235 simplify the job. Currently not implemented. 236 237 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. 238 @param[in] Configuration A null-terminated Unicode string in 239 <ConfigString> format. 240 @param[out] Progress A pointer to a string filled in with the 241 offset of the most recent '&' before the 242 first failing name / value pair (or the 243 beginn ing of the string if the failure 244 is in the first name / value pair) or 245 the terminating NULL if all was 246 successful. 247 248 @retval EFI_SUCCESS The results have been distributed or are 249 awaiting distribution. 250 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the 251 parts of the results that must be 252 stored awaiting possible future 253 protocols. 254 @retval EFI_INVALID_PARAMETERS Passing in a NULL for the 255 Results parameter would result 256 in this type of error. 257 @retval EFI_NOT_FOUND Target for the specified routing data 258 was not found. 259 **/ 260 EFI_STATUS 261 EFIAPI 262 FileExplorerRouteConfig ( 263 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, 264 IN CONST EFI_STRING Configuration, 265 OUT EFI_STRING *Progress 266 ) 267 { 268 EFI_STATUS Status; 269 UINTN BufferSize; 270 EFI_HII_CONFIG_ROUTING_PROTOCOL *ConfigRouting; 271 FILE_EXPLORER_NV_DATA *FeData; 272 BMM_CALLBACK_DATA *Private; 273 274 if (Progress == NULL) { 275 return EFI_INVALID_PARAMETER; 276 } 277 *Progress = Configuration; 278 279 if (Configuration == NULL) { 280 return EFI_INVALID_PARAMETER; 281 } 282 283 // 284 // Check routing data in <ConfigHdr>. 285 // Note: there is no name for Name/Value storage, only GUID will be checked 286 // 287 if (!HiiIsConfigHdrMatch (Configuration, &gFileExploreFormSetGuid, mFileExplorerStorageName)) { 288 return EFI_NOT_FOUND; 289 } 290 291 Status = gBS->LocateProtocol ( 292 &gEfiHiiConfigRoutingProtocolGuid, 293 NULL, 294 (VOID**) &ConfigRouting 295 ); 296 if (EFI_ERROR (Status)) { 297 return Status; 298 } 299 300 Private = FE_CALLBACK_DATA_FROM_THIS (This); 301 // 302 // Get Buffer Storage data from EFI variable 303 // 304 BufferSize = sizeof (FILE_EXPLORER_NV_DATA ); 305 FeData = &Private->FeFakeNvData; 306 307 // 308 // Convert <ConfigResp> to buffer data by helper function ConfigToBlock() 309 // 310 Status = ConfigRouting->ConfigToBlock ( 311 ConfigRouting, 312 Configuration, 313 (UINT8 *) FeData, 314 &BufferSize, 315 Progress 316 ); 317 ASSERT_EFI_ERROR (Status); 318 319 if (FeData->BootDescriptionData[0] != 0x00 || FeData->BootOptionalData[0] != 0x00) { 320 Status = Var_UpdateBootOption (Private, FeData); 321 if (EFI_ERROR (Status)) { 322 return Status; 323 } 324 325 BOpt_GetBootOptions (Private); 326 CreateMenuStringToken (Private, Private->FeHiiHandle, &BootOptionMenu); 327 } 328 329 if (FeData->DriverDescriptionData[0] != 0x00 || FeData->DriverOptionalData[0] != 0x00) { 330 Status = Var_UpdateDriverOption ( 331 Private, 332 Private->FeHiiHandle, 333 FeData->DriverDescriptionData, 334 FeData->DriverOptionalData, 335 FeData->ForceReconnect 336 ); 337 if (EFI_ERROR (Status)) { 338 return Status; 339 } 340 341 BOpt_GetDriverOptions (Private); 342 CreateMenuStringToken (Private, Private->FeHiiHandle, &DriverOptionMenu); 343 } 344 345 return EFI_SUCCESS; 346 } 347 348 /** 349 This function processes the results of changes in configuration. 350 When user select a interactive opcode, this callback will be triggered. 351 Based on the Question(QuestionId) that triggers the callback, the corresponding 352 actions is performed. It handles: 353 354 1) the addition of boot option. 355 2) the addition of driver option. 356 3) exit from file browser 357 4) update of file content if a dir is selected. 358 5) boot the file if a file is selected in "boot from file" 359 360 361 @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. 362 @param Action Specifies the type of action taken by the browser. 363 @param QuestionId A unique value which is sent to the original exporting driver 364 so that it can identify the type of data to expect. 365 @param Type The type of value for the question. 366 @param Value A pointer to the data being sent to the original exporting driver. 367 @param ActionRequest On return, points to the action requested by the callback function. 368 369 @retval EFI_SUCCESS The callback successfully handled the action. 370 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. 371 @retval EFI_DEVICE_ERROR The variable could not be saved. 372 @retval EFI_UNSUPPORTED The specified Action is not supported by the callback. 373 @retval EFI_INVALID_PARAMETER If parameter Value or ActionRequest is NULL. 374 **/ 375 EFI_STATUS 376 EFIAPI 377 FileExplorerCallback ( 378 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, 379 IN EFI_BROWSER_ACTION Action, 380 IN EFI_QUESTION_ID QuestionId, 381 IN UINT8 Type, 382 IN EFI_IFR_TYPE_VALUE *Value, 383 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest 384 ) 385 { 386 BMM_CALLBACK_DATA *Private; 387 FILE_EXPLORER_NV_DATA *NvRamMap; 388 EFI_STATUS Status; 389 390 if (Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_CHANGED) { 391 // 392 // All other action return unsupported. 393 // 394 return EFI_UNSUPPORTED; 395 } 396 397 Status = EFI_SUCCESS; 398 Private = FE_CALLBACK_DATA_FROM_THIS (This); 399 400 // 401 // Retrieve uncommitted data from Form Browser 402 // 403 NvRamMap = &Private->FeFakeNvData; 404 HiiGetBrowserData (&gFileExploreFormSetGuid, mFileExplorerStorageName, sizeof (FILE_EXPLORER_NV_DATA), (UINT8 *) NvRamMap); 405 406 if (Action == EFI_BROWSER_ACTION_CHANGED) { 407 if ((Value == NULL) || (ActionRequest == NULL)) { 408 return EFI_INVALID_PARAMETER; 409 } 410 411 if (QuestionId == KEY_VALUE_SAVE_AND_EXIT_BOOT) { 412 NvRamMap->BootOptionChanged = FALSE; 413 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT; 414 } else if (QuestionId == KEY_VALUE_SAVE_AND_EXIT_DRIVER) { 415 NvRamMap->DriverOptionChanged = FALSE; 416 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT; 417 } else if (QuestionId == KEY_VALUE_NO_SAVE_AND_EXIT_DRIVER) { 418 // 419 // Discard changes and exit formset 420 // 421 NvRamMap->DriverOptionalData[0] = 0x0000; 422 NvRamMap->DriverDescriptionData[0] = 0x0000; 423 NvRamMap->DriverOptionChanged = FALSE; 424 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; 425 } else if (QuestionId == KEY_VALUE_NO_SAVE_AND_EXIT_BOOT) { 426 // 427 // Discard changes and exit formset 428 // 429 NvRamMap->BootOptionalData[0] = 0x0000; 430 NvRamMap->BootDescriptionData[0] = 0x0000; 431 NvRamMap->BootOptionChanged = FALSE; 432 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; 433 } else if (QuestionId == KEY_VALUE_BOOT_DESCRIPTION || QuestionId == KEY_VALUE_BOOT_OPTION) { 434 NvRamMap->BootOptionChanged = TRUE; 435 } else if (QuestionId == KEY_VALUE_DRIVER_DESCRIPTION || QuestionId == KEY_VALUE_DRIVER_OPTION) { 436 NvRamMap->DriverOptionChanged = TRUE; 437 } else if (QuestionId < FILE_OPTION_OFFSET) { 438 // 439 // Exit File Explorer formset 440 // 441 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; 442 } else if (QuestionId >= FILE_OPTION_OFFSET && QuestionId < FILE_OPTION_GOTO_OFFSET) { 443 // 444 // Update forms may return TRUE or FALSE, need to check here. 445 // 446 if (UpdateFileExplorer (Private, QuestionId)) { 447 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; 448 } 449 } 450 } else if (Action == EFI_BROWSER_ACTION_CHANGING) { 451 if (Value == NULL) { 452 return EFI_INVALID_PARAMETER; 453 } 454 455 if (QuestionId >= FILE_OPTION_GOTO_OFFSET) { 456 // 457 // function will always return FALSE, no need to check here. 458 // 459 UpdateFileExplorer (Private, QuestionId); 460 } 461 } 462 463 // 464 // Pass changed uncommitted data back to Form Browser 465 // 466 HiiSetBrowserData (&gFileExploreFormSetGuid, mFileExplorerStorageName, sizeof (FILE_EXPLORER_NV_DATA), (UINT8 *) NvRamMap, NULL); 467 468 return Status; 469 } 470