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 parameter 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