]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/BdsDxe/BdsEntry.c
Add 2 new Bds features
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / BdsDxe / BdsEntry.c
1 /** @file
2 This module produce main entry for BDS phase - BdsEntry.
3 When this module was dispatched by DxeCore, gEfiBdsArchProtocolGuid will be installed
4 which contains interface of BdsEntry.
5 After DxeCore finish DXE phase, gEfiBdsArchProtocolGuid->BdsEntry will be invoked
6 to enter BDS phase.
7
8 Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>
9 This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
13
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16
17 **/
18
19 #include "Bds.h"
20 #include "Language.h"
21 #include "FrontPage.h"
22 #include "Hotkey.h"
23 #include "HwErrRecSupport.h"
24
25 ///
26 /// BDS arch protocol instance initial value.
27 ///
28 /// Note: Current BDS not directly get the BootMode, DefaultBoot,
29 /// TimeoutDefault, MemoryTestLevel value from the BDS arch protocol.
30 /// Please refer to the library useage of BdsLibGetBootMode, BdsLibGetTimeout
31 /// and PlatformBdsDiagnostics in BdsPlatform.c
32 ///
33 EFI_HANDLE gBdsHandle = NULL;
34
35 EFI_BDS_ARCH_PROTOCOL gBds = {
36 BdsEntry
37 };
38
39 UINT16 *mBootNext = NULL;
40
41 /**
42
43 Install Boot Device Selection Protocol
44
45 @param ImageHandle The image handle.
46 @param SystemTable The system table.
47
48 @retval EFI_SUCEESS BDS has finished initializing.
49 Return the dispatcher and recall BDS.Entry
50 @retval Other Return status from AllocatePool() or gBS->InstallProtocolInterface
51
52 **/
53 EFI_STATUS
54 EFIAPI
55 BdsInitialize (
56 IN EFI_HANDLE ImageHandle,
57 IN EFI_SYSTEM_TABLE *SystemTable
58 )
59 {
60 EFI_STATUS Status;
61
62 //
63 // Install protocol interface
64 //
65 Status = gBS->InstallMultipleProtocolInterfaces (
66 &gBdsHandle,
67 &gEfiBdsArchProtocolGuid, &gBds,
68 NULL
69 );
70 ASSERT_EFI_ERROR (Status);
71
72 return Status;
73 }
74
75 /**
76
77 This function attempts to boot for the boot order specified
78 by platform policy.
79
80 **/
81 VOID
82 BdsBootDeviceSelect (
83 VOID
84 )
85 {
86 EFI_STATUS Status;
87 LIST_ENTRY *Link;
88 BDS_COMMON_OPTION *BootOption;
89 UINTN ExitDataSize;
90 CHAR16 *ExitData;
91 UINT16 Timeout;
92 LIST_ENTRY BootLists;
93 CHAR16 Buffer[20];
94 BOOLEAN BootNextExist;
95 LIST_ENTRY *LinkBootNext;
96
97 //
98 // Got the latest boot option
99 //
100 BootNextExist = FALSE;
101 LinkBootNext = NULL;
102 InitializeListHead (&BootLists);
103
104 //
105 // First check the boot next option
106 //
107 ZeroMem (Buffer, sizeof (Buffer));
108
109 if (mBootNext != NULL) {
110 //
111 // Indicate we have the boot next variable, so this time
112 // boot will always have this boot option
113 //
114 BootNextExist = TRUE;
115
116 //
117 // Clear the this variable so it's only exist in this time boot
118 //
119 gRT->SetVariable (
120 L"BootNext",
121 &gEfiGlobalVariableGuid,
122 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
123 0,
124 mBootNext
125 );
126
127 //
128 // Add the boot next boot option
129 //
130 UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *mBootNext);
131 BootOption = BdsLibVariableToOption (&BootLists, Buffer);
132
133 //
134 // If fail to get boot option from variable, just return and do nothing.
135 //
136 if (BootOption == NULL) {
137 return;
138 }
139
140 BootOption->BootCurrent = *mBootNext;
141 }
142 //
143 // Parse the boot order to get boot option
144 //
145 BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
146
147 //
148 // When we didn't have chance to build boot option variables in the first
149 // full configuration boot (e.g.: Reset in the first page or in Device Manager),
150 // we have no boot options in the following mini configuration boot.
151 // Give the last chance to enumerate the boot options.
152 //
153 if (IsListEmpty (&BootLists)) {
154 BdsLibEnumerateAllBootOption (&BootLists);
155 }
156
157 Link = BootLists.ForwardLink;
158
159 //
160 // Parameter check, make sure the loop will be valid
161 //
162 if (Link == NULL) {
163 return ;
164 }
165 //
166 // Here we make the boot in a loop, every boot success will
167 // return to the front page
168 //
169 for (;;) {
170 //
171 // Check the boot option list first
172 //
173 if (Link == &BootLists) {
174 //
175 // There are two ways to enter here:
176 // 1. There is no active boot option, give user chance to
177 // add new boot option
178 // 2. All the active boot option processed, and there is no
179 // one is success to boot, then we back here to allow user
180 // add new active boot option
181 //
182 Timeout = 0xffff;
183 PlatformBdsEnterFrontPage (Timeout, FALSE);
184 InitializeListHead (&BootLists);
185 BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
186 Link = BootLists.ForwardLink;
187 continue;
188 }
189 //
190 // Get the boot option from the link list
191 //
192 BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
193
194 //
195 // According to EFI Specification, if a load option is not marked
196 // as LOAD_OPTION_ACTIVE, the boot manager will not automatically
197 // load the option.
198 //
199 if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) {
200 //
201 // skip the header of the link list, because it has no boot option
202 //
203 Link = Link->ForwardLink;
204 continue;
205 }
206 //
207 // Make sure the boot option device path connected,
208 // but ignore the BBS device path
209 //
210 if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) {
211 //
212 // Notes: the internal shell can not been connected with device path
213 // so we do not check the status here
214 //
215 BdsLibConnectDevicePath (BootOption->DevicePath);
216 }
217
218 //
219 // Restore to original mode before launching boot option.
220 //
221 BdsSetConsoleMode (FALSE);
222
223 //
224 // All the driver options should have been processed since
225 // now boot will be performed.
226 //
227 Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
228 if (Status != EFI_SUCCESS) {
229 //
230 // Call platform action to indicate the boot fail
231 //
232 BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));
233 PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize);
234
235 //
236 // Check the next boot option
237 //
238 Link = Link->ForwardLink;
239
240 } else {
241 //
242 // Call platform action to indicate the boot success
243 //
244 BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));
245 PlatformBdsBootSuccess (BootOption);
246
247 //
248 // Boot success, then stop process the boot order, and
249 // present the boot manager menu, front page
250 //
251 Timeout = 0xffff;
252 PlatformBdsEnterFrontPage (Timeout, FALSE);
253
254 //
255 // Rescan the boot option list, avoid potential risk of the boot
256 // option change in front page
257 //
258 if (BootNextExist) {
259 LinkBootNext = BootLists.ForwardLink;
260 }
261
262 InitializeListHead (&BootLists);
263 if (LinkBootNext != NULL) {
264 //
265 // Reserve the boot next option
266 //
267 InsertTailList (&BootLists, LinkBootNext);
268 }
269
270 BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
271 Link = BootLists.ForwardLink;
272 }
273 }
274
275 }
276
277 /**
278 Validate the device path instance.
279
280 Only base on the length filed in the device path node to validate the device path.
281
282 @param DevicePath A pointer to a device path data structure.
283 @param MaxSize Max valid device path size. If big than this size,
284 return error.
285
286 @retval TRUE An valid device path.
287 @retval FALSE An invalid device path.
288
289 **/
290 BOOLEAN
291 IsValidDevicePath (
292 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
293 IN UINTN MaxSize
294 )
295 {
296 UINTN Size;
297 UINTN NodeSize;
298
299 if (DevicePath == NULL) {
300 return TRUE;
301 }
302
303 Size = 0;
304
305 while (!IsDevicePathEnd (DevicePath)) {
306 NodeSize = DevicePathNodeLength (DevicePath);
307 if (NodeSize < END_DEVICE_PATH_LENGTH) {
308 return FALSE;
309 }
310
311 Size += NodeSize;
312 if (Size > MaxSize) {
313 return FALSE;
314 }
315
316 DevicePath = NextDevicePathNode (DevicePath);
317 }
318
319 Size += DevicePathNodeLength (DevicePath);
320 if (Size > MaxSize) {
321 return FALSE;
322 }
323
324 return TRUE;
325 }
326
327 /**
328
329 Validate input console variable data.
330
331 If found the device path is not a valid device path, remove the variable.
332
333 @param VariableName Input console variable name.
334
335 **/
336 VOID
337 BdsFormalizeConsoleVariable (
338 IN CHAR16 *VariableName
339 )
340 {
341 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
342 UINTN VariableSize;
343 EFI_STATUS Status;
344
345 DevicePath = BdsLibGetVariableAndSize (
346 VariableName,
347 &gEfiGlobalVariableGuid,
348 &VariableSize
349 );
350 if (!IsValidDevicePath (DevicePath, VariableSize)) {
351 Status = gRT->SetVariable (
352 VariableName,
353 &gEfiGlobalVariableGuid,
354 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
355 0,
356 NULL
357 );
358 ASSERT_EFI_ERROR (Status);
359 }
360 }
361
362 /**
363
364 Formalize Bds global variables.
365
366 1. For ConIn/ConOut/ConErr, if found the device path is not a valid device path, remove the variable.
367 2. For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps
368 3. Delete OsIndications variable if it is not NV/BS/RT UINT64
369 Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.
370
371 **/
372 VOID
373 BdsFormalizeEfiGlobalVariable (
374 VOID
375 )
376 {
377 EFI_STATUS Status;
378 UINT64 OsIndicationSupport;
379 UINT64 OsIndication;
380 UINTN DataSize;
381 UINT32 Attributes;
382
383 //
384 // Validate Console variable.
385 //
386 BdsFormalizeConsoleVariable (L"ConIn");
387 BdsFormalizeConsoleVariable (L"ConOut");
388 BdsFormalizeConsoleVariable (L"ErrOut");
389
390 //
391 // OS indicater support variable
392 //
393 OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
394 Status = gRT->SetVariable (
395 L"OsIndicationsSupported",
396 &gEfiGlobalVariableGuid,
397 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
398 sizeof(UINT64),
399 &OsIndicationSupport
400 );
401 ASSERT_EFI_ERROR (Status);
402
403 //
404 // If OsIndications is invalid, remove it.
405 // Invalid case
406 // 1. Data size != UINT64
407 // 2. OsIndication value inconsistence
408 // 3. OsIndication attribute inconsistence
409 //
410 OsIndication = 0;
411 Attributes = 0;
412 DataSize = sizeof(UINT64);
413 Status = gRT->GetVariable (
414 L"OsIndications",
415 &gEfiGlobalVariableGuid,
416 &Attributes,
417 &DataSize,
418 &OsIndication
419 );
420
421 if (!EFI_ERROR(Status)) {
422 if (DataSize != sizeof(UINT64) ||
423 (OsIndication & ~OsIndicationSupport) != 0 ||
424 Attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE)){
425
426 DEBUG ((EFI_D_ERROR, "Unformalized OsIndications variable exists. Delete it\n"));
427 Status = gRT->SetVariable (
428 L"OsIndications",
429 &gEfiGlobalVariableGuid,
430 Attributes,
431 0,
432 &OsIndication
433 );
434 ASSERT_EFI_ERROR (Status);
435 }
436 }
437
438 }
439
440 /**
441
442 Service routine for BdsInstance->Entry(). Devices are connected, the
443 consoles are initialized, and the boot options are tried.
444
445 @param This Protocol Instance structure.
446
447 **/
448 VOID
449 EFIAPI
450 BdsEntry (
451 IN EFI_BDS_ARCH_PROTOCOL *This
452 )
453 {
454 LIST_ENTRY DriverOptionList;
455 LIST_ENTRY BootOptionList;
456 UINTN BootNextSize;
457 CHAR16 *FirmwareVendor;
458
459 //
460 // Insert the performance probe
461 //
462 PERF_END (NULL, "DXE", NULL, 0);
463 PERF_START (NULL, "BDS", NULL, 0);
464
465 //
466 // Initialize the global system boot option and driver option
467 //
468 InitializeListHead (&DriverOptionList);
469 InitializeListHead (&BootOptionList);
470
471 //
472 // Initialize hotkey service
473 //
474 InitializeHotkeyService ();
475
476 //
477 // Fill in FirmwareVendor and FirmwareRevision from PCDs
478 //
479 FirmwareVendor = (CHAR16 *)PcdGetPtr (PcdFirmwareVendor);
480 gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor);
481 ASSERT (gST->FirmwareVendor != NULL);
482 gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision);
483
484 //
485 // Fixup Tasble CRC after we updated Firmware Vendor and Revision
486 //
487 gBS->CalculateCrc32 ((VOID *)gST, sizeof(EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);
488
489 //
490 // Validate Variable.
491 //
492 BdsFormalizeEfiGlobalVariable();
493
494 //
495 // Do the platform init, can be customized by OEM/IBV
496 //
497 PERF_START (NULL, "PlatformBds", "BDS", 0);
498 PlatformBdsInit ();
499
500 InitializeHwErrRecSupport();
501
502 //
503 // bugbug: platform specific code
504 // Initialize the platform specific string and language
505 //
506 InitializeStringSupport ();
507 InitializeLanguage (TRUE);
508 InitializeFrontPage (TRUE);
509
510 //
511 // Set up the device list based on EFI 1.1 variables
512 // process Driver#### and Load the driver's in the
513 // driver option list
514 //
515 BdsLibBuildOptionFromVar (&DriverOptionList, L"DriverOrder");
516 if (!IsListEmpty (&DriverOptionList)) {
517 BdsLibLoadDrivers (&DriverOptionList);
518 }
519 //
520 // Check if we have the boot next option
521 //
522 mBootNext = BdsLibGetVariableAndSize (
523 L"BootNext",
524 &gEfiGlobalVariableGuid,
525 &BootNextSize
526 );
527
528 //
529 // Setup some platform policy here
530 //
531 PlatformBdsPolicyBehavior (&DriverOptionList, &BootOptionList, BdsProcessCapsules, BdsMemoryTest);
532 PERF_END (NULL, "PlatformBds", "BDS", 0);
533
534 //
535 // BDS select the boot device to load OS
536 //
537 BdsBootDeviceSelect ();
538
539 //
540 // Only assert here since this is the right behavior, we should never
541 // return back to DxeCore.
542 //
543 ASSERT (FALSE);
544
545 return ;
546 }