Nt32Pkg: Platform BDS should test the untested memory
[mirror_edk2.git] / Nt32Pkg / Library / PlatformBootManagerLib / PlatformBootManager.c
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 EFI_GUID mUefiShellFileGuid = { 0x7C04A583, 0x9E3E, 0x4f1c, 0xAD, 0x65, 0xE0, 0x52, 0x68, 0xD0, 0xB4, 0xD1 };
20
21 /**
22 Perform the memory test base on the memory test intensive level,
23 and update the memory resource.
24
25 @param Level The memory test intensive level.
26
27 @retval EFI_STATUS Success test all the system memory and update
28 the memory resource
29
30 **/
31 EFI_STATUS
32 PlatformBootManagerMemoryTest (
33 IN EXTENDMEM_COVERAGE_LEVEL Level
34 )
35 {
36 EFI_STATUS Status;
37 BOOLEAN RequireSoftECCInit;
38 EFI_GENERIC_MEMORY_TEST_PROTOCOL *GenMemoryTest;
39 UINT64 TestedMemorySize;
40 UINT64 TotalMemorySize;
41 UINTN TestPercent;
42 UINT64 PreviousValue;
43 BOOLEAN ErrorOut;
44 UINT32 TempData;
45
46 TestedMemorySize = 0;
47 TotalMemorySize = 0;
48 PreviousValue = 0;
49
50 RequireSoftECCInit = FALSE;
51
52 Status = gBS->LocateProtocol (
53 &gEfiGenericMemTestProtocolGuid,
54 NULL,
55 (VOID **) &GenMemoryTest
56 );
57 if (EFI_ERROR (Status)) {
58 return EFI_SUCCESS;
59 }
60
61 Status = GenMemoryTest->MemoryTestInit (
62 GenMemoryTest,
63 Level,
64 &RequireSoftECCInit
65 );
66 if (Status == EFI_NO_MEDIA) {
67 //
68 // The PEI codes also have the relevant memory test code to check the memory,
69 // it can select to test some range of the memory or all of them. If PEI code
70 // checks all the memory, this BDS memory test will has no not-test memory to
71 // do the test, and then the status of EFI_NO_MEDIA will be returned by
72 // "MemoryTestInit". So it does not need to test memory again, just return.
73 //
74 return EFI_SUCCESS;
75 }
76
77 do {
78 Status = GenMemoryTest->PerformMemoryTest (
79 GenMemoryTest,
80 &TestedMemorySize,
81 &TotalMemorySize,
82 &ErrorOut,
83 FALSE
84 );
85 if (ErrorOut && (Status == EFI_DEVICE_ERROR)) {
86 Print (L"System encounters memory errors!");
87 CpuDeadLoop ();
88 }
89
90 TempData = (UINT32) DivU64x32 (TotalMemorySize, 16);
91 TestPercent = (UINTN) DivU64x32 (
92 DivU64x32 (MultU64x32 (TestedMemorySize, 100), 16),
93 TempData
94 );
95 if (TestPercent != PreviousValue) {
96 Print (L"Perform memory test: %d/100", TestPercent);
97 PreviousValue = TestPercent;
98 }
99 } while (Status != EFI_NOT_FOUND);
100
101 Status = GenMemoryTest->Finished (GenMemoryTest);
102
103 Print (L"\r%dM bytes of system memory tested OK\n", (UINT32) DivU64x32 (TotalMemorySize, 1024 * 1024));
104 return EFI_SUCCESS;
105 }
106
107
108 /**
109 Return the index of the load option in the load option array.
110
111 The function consider two load options are equal when the
112 OptionType, Attributes, Description, FilePath and OptionalData are equal.
113
114 @param Key Pointer to the load option to be found.
115 @param Array Pointer to the array of load options to be found.
116 @param Count Number of entries in the Array.
117
118 @retval -1 Key wasn't found in the Array.
119 @retval 0 ~ Count-1 The index of the Key in the Array.
120 **/
121 INTN
122 PlatformFindLoadOption (
123 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
124 IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
125 IN UINTN Count
126 )
127 {
128 UINTN Index;
129
130 for (Index = 0; Index < Count; Index++) {
131 if ((Key->OptionType == Array[Index].OptionType) &&
132 (Key->Attributes == Array[Index].Attributes) &&
133 (StrCmp (Key->Description, Array[Index].Description) == 0) &&
134 (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&
135 (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&
136 (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {
137 return (INTN) Index;
138 }
139 }
140
141 return -1;
142 }
143
144 VOID
145 PlatformRegisterFvBootOption (
146 EFI_GUID *FileGuid,
147 CHAR16 *Description,
148 UINT32 Attributes
149 )
150 {
151 EFI_STATUS Status;
152 UINTN OptionIndex;
153 EFI_BOOT_MANAGER_LOAD_OPTION NewOption;
154 EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
155 UINTN BootOptionCount;
156 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
157 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
158 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
159
160 Status = gBS->HandleProtocol (gImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage);
161 ASSERT_EFI_ERROR (Status);
162
163 EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
164 DevicePath = AppendDevicePathNode (
165 DevicePathFromHandle (LoadedImage->DeviceHandle),
166 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
167 );
168
169 Status = EfiBootManagerInitializeLoadOption (
170 &NewOption,
171 LoadOptionNumberUnassigned,
172 LoadOptionTypeBoot,
173 Attributes,
174 Description,
175 DevicePath,
176 NULL,
177 0
178 );
179 if (!EFI_ERROR (Status)) {
180 BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
181
182 OptionIndex = PlatformFindLoadOption (&NewOption, BootOptions, BootOptionCount);
183
184 if (OptionIndex == -1) {
185 Status = EfiBootManagerAddLoadOptionVariable (&NewOption, (UINTN) -1);
186 ASSERT_EFI_ERROR (Status);
187 }
188 EfiBootManagerFreeLoadOption (&NewOption);
189 EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
190 }
191 }
192
193 /**
194 Do the platform specific action before the console is connected.
195
196 Such as:
197 Update console variable;
198 Register new Driver#### or Boot####;
199 Signal ReadyToLock event.
200 **/
201 VOID
202 EFIAPI
203 PlatformBootManagerBeforeConsole (
204 VOID
205 )
206 {
207 UINTN Index;
208 EFI_STATUS Status;
209 WIN_NT_SYSTEM_CONFIGURATION *Configuration;
210 EFI_INPUT_KEY Enter;
211 EFI_INPUT_KEY F2;
212 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
213
214 GetVariable2 (L"Setup", &gEfiWinNtSystemConfigGuid, (VOID **) &Configuration, NULL);
215 if (Configuration != NULL) {
216 //
217 // SetupVariable is corrupt
218 //
219 Configuration->ConOutRow = PcdGet32 (PcdConOutColumn);
220 Configuration->ConOutColumn = PcdGet32 (PcdConOutRow);
221
222 Status = gRT->SetVariable (
223 L"Setup",
224 &gEfiWinNtSystemConfigGuid,
225 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
226 sizeof (WIN_NT_SYSTEM_CONFIGURATION),
227 Configuration
228 );
229 if (EFI_ERROR (Status)) {
230 DEBUG ((EFI_D_ERROR, "Failed to save Setup Variable to non-volatile storage, Status = %r\n", Status));
231 }
232 FreePool (Configuration);
233 }
234
235 //
236 // Update the ocnsole variables.
237 //
238 for (Index = 0; gPlatformConsole[Index].DevicePath != NULL; Index++) {
239 if ((gPlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
240 EfiBootManagerUpdateConsoleVariable (ConIn, gPlatformConsole[Index].DevicePath, NULL);
241 }
242
243 if ((gPlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
244 EfiBootManagerUpdateConsoleVariable (ConOut, gPlatformConsole[Index].DevicePath, NULL);
245 }
246
247 if ((gPlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
248 EfiBootManagerUpdateConsoleVariable (ErrOut, gPlatformConsole[Index].DevicePath, NULL);
249 }
250 }
251
252 //
253 // Register ENTER as CONTINUE key
254 //
255 Enter.ScanCode = SCAN_NULL;
256 Enter.UnicodeChar = CHAR_CARRIAGE_RETURN;
257 EfiBootManagerRegisterContinueKeyOption (0, &Enter, NULL);
258 //
259 // Map F2 to Boot Manager Menu
260 //
261 F2.ScanCode = SCAN_F2;
262 F2.UnicodeChar = CHAR_NULL;
263 EfiBootManagerGetBootManagerMenu (&BootOption);
264 EfiBootManagerAddKeyOptionVariable (NULL, (UINT16) BootOption.OptionNumber, 0, &F2, NULL);
265 //
266 // Register UEFI Shell
267 //
268 PlatformRegisterFvBootOption (&mUefiShellFileGuid, L"UEFI Shell", LOAD_OPTION_ACTIVE);
269 }
270
271 /**
272 Do the platform specific action after the console is connected.
273
274 Such as:
275 Dynamically switch output mode;
276 Signal console ready platform customized event;
277 Run diagnostics like memory testing;
278 Connect certain devices;
279 Dispatch aditional option roms.
280 **/
281 VOID
282 EFIAPI
283 PlatformBootManagerAfterConsole (
284 VOID
285 )
286 {
287 PlatformBootManagerMemoryTest (QUICK);
288 EfiBootManagerConnectAll ();
289 EfiBootManagerRefreshAllBootOption ();
290 Print (
291 L"\n"
292 L"F2 to enter Boot Manager Menu.\n"
293 L"Enter to boot directly.\n"
294 L"\n"
295 );
296 }
297
298 /**
299 This function is called each second during the boot manager waits the timeout.
300
301 @param TimeoutRemain The remaining timeout.
302 **/
303 VOID
304 EFIAPI
305 PlatformBootManagerWaitCallback (
306 UINT16 TimeoutRemain
307 )
308 {
309 Print (L"\r%-2d seconds remained...", TimeoutRemain);
310 }