]> git.proxmox.com Git - mirror_edk2.git/blob - EmulatorPkg/Library/PlatformBmLib/PlatformBm.c
EmulatorPkg: Make the shell be the first boot option
[mirror_edk2.git] / EmulatorPkg / Library / PlatformBmLib / PlatformBm.c
1 /*++ @file
2
3 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
4 Portions copyright (c) 2011, Apple Inc. All rights reserved.
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "PlatformBm.h"
10
11 EFI_GUID mBootMenuFile = {
12 0xEEC25BDC, 0x67F2, 0x4D95, { 0xB1, 0xD5, 0xF8, 0x1B, 0x20, 0x39, 0xD1, 0x1D }
13 };
14
15 /**
16 Initialize the "Setup" variable.
17 **/
18 VOID
19 SetupVariableInit (
20 VOID
21 )
22 {
23 EFI_STATUS Status;
24 UINTN Size;
25 EMU_SYSTEM_CONFIGURATION SystemConfigData;
26
27 Size = sizeof (SystemConfigData);
28 Status = gRT->GetVariable (
29 L"Setup",
30 &gEmuSystemConfigGuid,
31 NULL,
32 &Size,
33 (VOID *) &SystemConfigData
34 );
35
36 if (EFI_ERROR (Status)) {
37 //
38 // SetupVariable is corrupt
39 //
40 SystemConfigData.ConOutRow = PcdGet32 (PcdConOutColumn);
41 SystemConfigData.ConOutColumn = PcdGet32 (PcdConOutRow);
42
43 Status = gRT->SetVariable (
44 L"Setup",
45 &gEmuSystemConfigGuid,
46 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
47 sizeof (SystemConfigData),
48 (VOID *) &SystemConfigData
49 );
50 if (EFI_ERROR (Status)) {
51 DEBUG ((DEBUG_ERROR, "Failed to save Setup Variable to non-volatile storage, Status = %r\n", Status));
52 }
53 }
54 }
55
56 EFI_DEVICE_PATH *
57 FvFilePath (
58 EFI_GUID *FileGuid
59 )
60 {
61
62 EFI_STATUS Status;
63 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
64 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
65
66 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
67
68 Status = gBS->HandleProtocol (
69 gImageHandle,
70 &gEfiLoadedImageProtocolGuid,
71 (VOID **) &LoadedImage
72 );
73 ASSERT_EFI_ERROR (Status);
74 return AppendDevicePathNode (
75 DevicePathFromHandle (LoadedImage->DeviceHandle),
76 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
77 );
78 }
79
80 /**
81 Create one boot option for BootManagerMenuApp.
82
83 @param FileGuid Input file guid for the BootManagerMenuApp.
84 @param Description Description of the BootManagerMenuApp boot option.
85 @param Position Position of the new load option to put in the ****Order variable.
86 @param IsBootCategory Whether this is a boot category.
87
88
89 @retval OptionNumber Return the option number info.
90
91 **/
92 UINTN
93 RegisterBootManagerMenuAppBootOption (
94 EFI_GUID *FileGuid,
95 CHAR16 *Description,
96 UINTN Position,
97 BOOLEAN IsBootCategory
98 )
99 {
100 EFI_STATUS Status;
101 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
102 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
103 UINTN OptionNumber;
104
105 DevicePath = FvFilePath (FileGuid);
106 Status = EfiBootManagerInitializeLoadOption (
107 &NewOption,
108 LoadOptionNumberUnassigned,
109 LoadOptionTypeBoot,
110 IsBootCategory ? LOAD_OPTION_ACTIVE : LOAD_OPTION_CATEGORY_APP,
111 Description,
112 DevicePath,
113 NULL,
114 0
115 );
116 ASSERT_EFI_ERROR (Status);
117 FreePool (DevicePath);
118
119 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, Position);
120 ASSERT_EFI_ERROR (Status);
121
122 OptionNumber = NewOption.OptionNumber;
123
124 EfiBootManagerFreeLoadOption (&NewOption);
125
126 return OptionNumber;
127 }
128
129 /**
130 Check if it's a Device Path pointing to BootManagerMenuApp.
131
132 @param DevicePath Input device path.
133
134 @retval TRUE The device path is BootManagerMenuApp File Device Path.
135 @retval FALSE The device path is NOT BootManagerMenuApp File Device Path.
136 **/
137 BOOLEAN
138 IsBootManagerMenuAppFilePath (
139 EFI_DEVICE_PATH_PROTOCOL *DevicePath
140 )
141 {
142 EFI_HANDLE FvHandle;
143 VOID *NameGuid;
144 EFI_STATUS Status;
145
146 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePath, &FvHandle);
147 if (!EFI_ERROR (Status)) {
148 NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) DevicePath);
149 if (NameGuid != NULL) {
150 return CompareGuid (NameGuid, &mBootMenuFile);
151 }
152 }
153
154 return FALSE;
155 }
156
157 /**
158 Return the boot option number to the BootManagerMenuApp.
159
160 If not found it in the current boot option, create a new one.
161
162 @retval OptionNumber Return the boot option number to the BootManagerMenuApp.
163
164 **/
165 UINTN
166 GetBootManagerMenuAppOption (
167 VOID
168 )
169 {
170 UINTN BootOptionCount;
171 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
172 UINTN Index;
173 UINTN OptionNumber;
174
175 OptionNumber = 0;
176
177 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
178
179 for (Index = 0; Index < BootOptionCount; Index++) {
180 if (IsBootManagerMenuAppFilePath (BootOptions[Index].FilePath)) {
181 OptionNumber = BootOptions[Index].OptionNumber;
182 break;
183 }
184 }
185
186 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
187
188 if (Index >= BootOptionCount) {
189 //
190 // If not found the BootManagerMenuApp, create it.
191 //
192 OptionNumber = (UINT16) RegisterBootManagerMenuAppBootOption (&mBootMenuFile, L"UEFI BootManagerMenuApp", (UINTN) -1, FALSE);
193 }
194
195 return OptionNumber;
196 }
197
198 /**
199 Platform Bds init. Include the platform firmware vendor, revision
200 and so crc check.
201 **/
202 VOID
203 EFIAPI
204 PlatformBootManagerBeforeConsole (
205 VOID
206 )
207 {
208 UINTN Index;
209
210 SetupVariableInit ();
211
212 EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);
213
214 Index = 0;
215 while (gPlatformConsole[Index].DevicePath != NULL) {
216 //
217 // Update the console variable with the connect type
218 //
219 if ((gPlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
220 EfiBootManagerUpdateConsoleVariable (ConIn, gPlatformConsole[Index].DevicePath, NULL);
221 }
222
223 if ((gPlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
224 EfiBootManagerUpdateConsoleVariable (ConOut, gPlatformConsole[Index].DevicePath, NULL);
225 }
226
227 if ((gPlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
228 EfiBootManagerUpdateConsoleVariable (ErrOut, gPlatformConsole[Index].DevicePath, NULL);
229 }
230
231 Index++;
232 }
233 }
234
235 /**
236 Connect with predefined platform connect sequence,
237 the OEM/IBV can customize with their own connect sequence.
238 **/
239 VOID
240 PlatformBdsConnectSequence (
241 VOID
242 )
243 {
244 //
245 // Just use the simple policy to connect all devices
246 //
247 EfiBootManagerConnectAll ();
248 }
249
250 /**
251 Perform the platform diagnostic, such like test memory. OEM/IBV also
252 can customize this fuction to support specific platform diagnostic.
253
254 @param MemoryTestLevel The memory test intensive level
255 @param QuietBoot Indicate if need to enable the quiet boot
256 **/
257 VOID
258 PlatformBdsDiagnostics (
259 IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel,
260 IN BOOLEAN QuietBoot
261 )
262 {
263 EFI_STATUS Status;
264
265 //
266 // Here we can decide if we need to show
267 // the diagnostics screen
268 //
269 if (QuietBoot) {
270 BootLogoEnableLogo ();
271
272 //
273 // Perform system diagnostic
274 //
275 Status = PlatformBootManagerMemoryTest (MemoryTestLevel);
276 if (EFI_ERROR (Status)) {
277 BootLogoDisableLogo ();
278 }
279
280 return;
281 }
282
283 //
284 // Perform system diagnostic
285 //
286 PlatformBootManagerMemoryTest (MemoryTestLevel);
287 }
288
289 /**
290 Register the static boot options.
291 **/
292 VOID
293 PlatformBdsRegisterStaticBootOptions (
294 VOID
295 )
296 {
297 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Black;
298 EFI_GRAPHICS_OUTPUT_BLT_PIXEL White;
299 EFI_INPUT_KEY Enter;
300 EFI_INPUT_KEY F2;
301 EFI_INPUT_KEY F7;
302 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
303 UINTN OptionNumber;
304
305 Black.Blue = Black.Green = Black.Red = Black.Reserved = 0;
306 White.Blue = White.Green = White.Red = White.Reserved = 0xFF;
307
308 //
309 // Register ENTER as CONTINUE key
310 //
311 Enter.ScanCode = SCAN_NULL;
312 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
313 EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
314 //
315 // Map F2 to Boot Manager Menu
316 //
317 F2.ScanCode = SCAN_F2;
318 F2.UnicodeChar = CHAR_NULL;
319 EfiBootManagerGetBootManagerMenu (&BootOption);
320 EfiBootManagerAddKeyOptionVariable (NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL);
321
322 //
323 // 3. Boot Device List menu
324 //
325 F7.ScanCode = SCAN_F7;
326 F7.UnicodeChar = CHAR_NULL;
327 OptionNumber = GetBootManagerMenuAppOption ();
328 EfiBootManagerAddKeyOptionVariable (NULL, (UINT16)OptionNumber, 0, &F7, NULL);
329
330 PrintXY (10, 10, &White, &Black, L"F2 to enter Setup. ");
331 PrintXY (10, 30, &White, &Black, L"F7 to enter Boot Manager Menu.");
332 PrintXY (10, 50, &White, &Black, L"Enter to boot directly.");
333 }
334
335 /**
336 Returns the priority number.
337
338 @param BootOption
339 **/
340 UINTN
341 BootOptionPriority (
342 CONST EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
343 )
344 {
345 //
346 // Make sure Shell is first
347 //
348 if (StrCmp (BootOption->Description, L"UEFI Shell") == 0) {
349 return 0;
350 }
351 return 100;
352 }
353
354 INTN
355 EFIAPI
356 CompareBootOption (
357 CONST EFI_BOOT_MANAGER_LOAD_OPTION *Left,
358 CONST EFI_BOOT_MANAGER_LOAD_OPTION *Right
359 )
360 {
361 return BootOptionPriority (Left) - BootOptionPriority (Right);
362 }
363
364 /**
365 Do the platform specific action after the console is connected.
366
367 Such as:
368 Dynamically switch output mode;
369 Signal console ready platform customized event;
370 Run diagnostics like memory testing;
371 Connect certain devices;
372 Dispatch aditional option roms.
373 **/
374 VOID
375 EFIAPI
376 PlatformBootManagerAfterConsole (
377 VOID
378 )
379 {
380
381 //
382 // Go the different platform policy with different boot mode
383 // Notes: this part code can be change with the table policy
384 //
385 switch (GetBootModeHob ()) {
386
387 case BOOT_ASSUMING_NO_CONFIGURATION_CHANGES:
388 case BOOT_WITH_MINIMAL_CONFIGURATION:
389 PlatformBdsDiagnostics (IGNORE, TRUE);
390
391 //
392 // Perform some platform specific connect sequence
393 //
394 PlatformBdsConnectSequence ();
395 break;
396
397 case BOOT_IN_RECOVERY_MODE:
398 PlatformBdsDiagnostics (EXTENSIVE, FALSE);
399 break;
400
401 case BOOT_WITH_FULL_CONFIGURATION:
402 case BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS:
403 case BOOT_WITH_DEFAULT_SETTINGS:
404 default:
405 PlatformBdsDiagnostics (IGNORE, TRUE);
406 PlatformBdsRegisterStaticBootOptions ();
407 PlatformBdsConnectSequence ();
408 EfiBootManagerRefreshAllBootOption ();
409 EfiBootManagerSortLoadOptionVariable (LoadOptionTypeBoot, (SORT_COMPARE)CompareBootOption);
410 break;
411 }
412 }
413
414 /**
415 This function is called each second during the boot manager waits the timeout.
416
417 @param TimeoutRemain The remaining timeout.
418 **/
419 VOID
420 EFIAPI
421 PlatformBootManagerWaitCallback (
422 UINT16 TimeoutRemain
423 )
424 {
425 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION Black;
426 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION White;
427 UINT16 Timeout;
428
429 Timeout = PcdGet16 (PcdPlatformBootTimeOut);
430
431 Black.Raw = 0x00000000;
432 White.Raw = 0x00FFFFFF;
433
434 BootLogoUpdateProgress (
435 White.Pixel,
436 Black.Pixel,
437 L"Start boot option",
438 White.Pixel,
439 (Timeout - TimeoutRemain) * 100 / Timeout,
440 0
441 );
442 }
443
444 /**
445 The function is called when no boot option could be launched,
446 including platform recovery options and options pointing to applications
447 built into firmware volumes.
448
449 If this function returns, BDS attempts to enter an infinite loop.
450 **/
451 VOID
452 EFIAPI
453 PlatformBootManagerUnableToBoot (
454 VOID
455 )
456 {
457 return;
458 }
459