Home | History | Annotate | Download | only in BootMaint
      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