1 /** @file
2   This file include all platform action which can be customized
3   by IBV/OEM.
4 
5 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution.  The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "PlatformBootManager.h"
17 
18 /**
19   Perform the platform diagnostic, such like test memory. OEM/IBV also
20   can customize this function to support specific platform diagnostic.
21 
22   @param MemoryTestLevel  The memory test intensive level
23   @param QuietBoot        Indicate if need to enable the quiet boot
24 
25 **/
26 VOID
PlatformBootManagerDiagnostics(IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel,IN BOOLEAN QuietBoot)27 PlatformBootManagerDiagnostics (
28   IN EXTENDMEM_COVERAGE_LEVEL    MemoryTestLevel,
29   IN BOOLEAN                     QuietBoot
30   )
31 {
32   EFI_STATUS                     Status;
33 
34   //
35   // Here we can decide if we need to show
36   // the diagnostics screen
37   // Notes: this quiet boot code should be remove
38   // from the graphic lib
39   //
40   if (QuietBoot) {
41     BootLogoEnableLogo (ImageFormatBmp, PcdGetPtr(PcdLogoFile), EdkiiPlatformLogoDisplayAttributeCenter, 0, 0);
42 
43     //
44     // Perform system diagnostic
45     //
46     Status = PlatformBootManagerMemoryTest (MemoryTestLevel);
47     if (EFI_ERROR (Status)) {
48       BootLogoDisableLogo ();
49     }
50 
51     return;
52   }
53 
54   //
55   // Perform system diagnostic
56   //
57   Status = PlatformBootManagerMemoryTest (MemoryTestLevel);
58 }
59 
60 /**
61   Return the index of the load option in the load option array.
62 
63   The function consider two load options are equal when the
64   OptionType, Attributes, Description, FilePath and OptionalData are equal.
65 
66   @param Key    Pointer to the load option to be found.
67   @param Array  Pointer to the array of load options to be found.
68   @param Count  Number of entries in the Array.
69 
70   @retval -1          Key wasn't found in the Array.
71   @retval 0 ~ Count-1 The index of the Key in the Array.
72 **/
73 INTN
PlatformFindLoadOption(IN CONST EFI_BOOT_MANAGER_LOAD_OPTION * Key,IN CONST EFI_BOOT_MANAGER_LOAD_OPTION * Array,IN UINTN Count)74 PlatformFindLoadOption (
75   IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
76   IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
77   IN UINTN                              Count
78   )
79 {
80   UINTN                             Index;
81 
82   for (Index = 0; Index < Count; Index++) {
83     if ((Key->OptionType == Array[Index].OptionType) &&
84         (Key->Attributes == Array[Index].Attributes) &&
85         (StrCmp (Key->Description, Array[Index].Description) == 0) &&
86         (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&
87         (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&
88         (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {
89       return (INTN) Index;
90     }
91   }
92 
93   return -1;
94 }
95 
96 VOID
PlatformRegisterFvBootOption(EFI_GUID * FileGuid,CHAR16 * Description,UINT32 Attributes)97 PlatformRegisterFvBootOption (
98   EFI_GUID                         *FileGuid,
99   CHAR16                           *Description,
100   UINT32                           Attributes
101   )
102 {
103   EFI_STATUS                        Status;
104   UINTN                             OptionIndex;
105   EFI_BOOT_MANAGER_LOAD_OPTION      NewOption;
106   EFI_BOOT_MANAGER_LOAD_OPTION      *BootOptions;
107   UINTN                             BootOptionCount;
108   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
109   EFI_LOADED_IMAGE_PROTOCOL         *LoadedImage;
110   EFI_DEVICE_PATH_PROTOCOL          *DevicePath;
111 
112   Status = gBS->HandleProtocol (gImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage);
113   ASSERT_EFI_ERROR (Status);
114 
115   EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
116   DevicePath = AppendDevicePathNode (
117                  DevicePathFromHandle (LoadedImage->DeviceHandle),
118                  (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
119                  );
120 
121   Status = EfiBootManagerInitializeLoadOption (
122              &NewOption,
123              LoadOptionNumberUnassigned,
124              LoadOptionTypeBoot,
125              Attributes,
126              Description,
127              DevicePath,
128              NULL,
129              0
130              );
131   if (!EFI_ERROR (Status)) {
132     BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
133 
134     OptionIndex = PlatformFindLoadOption (&NewOption, BootOptions, BootOptionCount);
135 
136     if (OptionIndex == -1) {
137       Status = EfiBootManagerAddLoadOptionVariable (&NewOption, (UINTN) -1);
138       ASSERT_EFI_ERROR (Status);
139     }
140     EfiBootManagerFreeLoadOption (&NewOption);
141     EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
142   }
143 }
144 
145 /**
146   Do the platform specific action before the console is connected.
147 
148   Such as:
149     Update console variable;
150     Register new Driver#### or Boot####;
151     Signal ReadyToLock event.
152 **/
153 VOID
154 EFIAPI
PlatformBootManagerBeforeConsole(VOID)155 PlatformBootManagerBeforeConsole (
156   VOID
157   )
158 {
159   UINTN                        Index;
160   EFI_STATUS                   Status;
161   WIN_NT_SYSTEM_CONFIGURATION  *Configuration;
162   EFI_INPUT_KEY                Enter;
163   EFI_INPUT_KEY                F2;
164   EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
165 
166   GetVariable2 (L"Setup", &gEfiWinNtSystemConfigGuid, (VOID **) &Configuration, NULL);
167   if (Configuration != NULL) {
168     //
169     // SetupVariable is corrupt
170     //
171     Configuration->ConOutRow = PcdGet32 (PcdConOutColumn);
172     Configuration->ConOutColumn = PcdGet32 (PcdConOutRow);
173 
174     Status = gRT->SetVariable (
175                     L"Setup",
176                     &gEfiWinNtSystemConfigGuid,
177                     EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
178                     sizeof (WIN_NT_SYSTEM_CONFIGURATION),
179                     Configuration
180                     );
181     if (EFI_ERROR (Status)) {
182       DEBUG ((EFI_D_ERROR, "Failed to save Setup Variable to non-volatile storage, Status = %r\n", Status));
183     }
184     FreePool (Configuration);
185   }
186 
187   //
188   // Update the ocnsole variables.
189   //
190   for (Index = 0; gPlatformConsole[Index].DevicePath != NULL; Index++) {
191     if ((gPlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
192       EfiBootManagerUpdateConsoleVariable (ConIn, gPlatformConsole[Index].DevicePath, NULL);
193     }
194 
195     if ((gPlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
196       EfiBootManagerUpdateConsoleVariable (ConOut, gPlatformConsole[Index].DevicePath, NULL);
197     }
198 
199     if ((gPlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
200       EfiBootManagerUpdateConsoleVariable (ErrOut, gPlatformConsole[Index].DevicePath, NULL);
201     }
202   }
203 
204   //
205   // Register ENTER as CONTINUE key
206   //
207   Enter.ScanCode    = SCAN_NULL;
208   Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
209   EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
210   //
211   // Map F2 to Boot Manager Menu
212   //
213   F2.ScanCode    = SCAN_F2;
214   F2.UnicodeChar = CHAR_NULL;
215   EfiBootManagerGetBootManagerMenu (&BootOption);
216   EfiBootManagerAddKeyOptionVariable (NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL);
217   //
218   // Register UEFI Shell
219   //
220   PlatformRegisterFvBootOption (PcdGetPtr (PcdShellFile), L"UEFI Shell", LOAD_OPTION_ACTIVE);
221 }
222 
223 /**
224   Do the platform specific action after the console is connected.
225 
226   Such as:
227     Dynamically switch output mode;
228     Signal console ready platform customized event;
229     Run diagnostics like memory testing;
230     Connect certain devices;
231     Dispatch aditional option roms.
232 **/
233 VOID
234 EFIAPI
PlatformBootManagerAfterConsole(VOID)235 PlatformBootManagerAfterConsole (
236   VOID
237   )
238 {
239   EFI_GRAPHICS_OUTPUT_BLT_PIXEL  Black;
240   EFI_GRAPHICS_OUTPUT_BLT_PIXEL  White;
241 
242   Black.Blue = Black.Green = Black.Red = Black.Reserved = 0;
243   White.Blue = White.Green = White.Red = White.Reserved = 0xFF;
244 
245   EfiBootManagerConnectAll ();
246   EfiBootManagerRefreshAllBootOption ();
247 
248   PlatformBootManagerDiagnostics (QUICK, TRUE);
249 
250   PrintXY (10, 10, &White, &Black, L"F2    to enter Boot Manager Menu.                                            ");
251   PrintXY (10, 30, &White, &Black, L"Enter to boot directly.");
252 }
253 
254 /**
255   This function is called each second during the boot manager waits the timeout.
256 
257   @param TimeoutRemain  The remaining timeout.
258 **/
259 VOID
260 EFIAPI
PlatformBootManagerWaitCallback(UINT16 TimeoutRemain)261 PlatformBootManagerWaitCallback (
262   UINT16          TimeoutRemain
263   )
264 {
265   EFI_GRAPHICS_OUTPUT_BLT_PIXEL Black;
266   EFI_GRAPHICS_OUTPUT_BLT_PIXEL White;
267   UINT16                        Timeout;
268 
269   Timeout = PcdGet16 (PcdPlatformBootTimeOut);
270 
271   Black.Blue = Black.Green = Black.Red = Black.Reserved = 0;
272   White.Blue = White.Green = White.Red = White.Reserved = 0xFF;
273 
274   BootLogoUpdateProgress (
275     White,
276     Black,
277     L"Start boot option",
278     White,
279     (Timeout - TimeoutRemain) * 100 / Timeout,
280     0
281     );
282 }
283