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