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
UpdateFileExplorePage(IN BMM_CALLBACK_DATA * CallbackData,BM_MENU_OPTION * MenuOption)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
UpdateFileExplorer(IN BMM_CALLBACK_DATA * CallbackData,IN UINT16 KeyValue)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
FileExplorerRouteConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Configuration,OUT EFI_STRING * Progress)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 paramter Value or ActionRequest is NULL.
374 **/
375 EFI_STATUS
376 EFIAPI
FileExplorerCallback(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN EFI_BROWSER_ACTION Action,IN EFI_QUESTION_ID QuestionId,IN UINT8 Type,IN EFI_IFR_TYPE_VALUE * Value,OUT EFI_BROWSER_ACTION_REQUEST * ActionRequest)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