]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/BdsDxe/BdsEntry.c
6eaec886f2317d484021538260a6ba5b0dfc8897
[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 - 2013, 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 An empty function to pass error checking of CreateEventEx ().
78
79 @param Event Event whose notification function is being invoked.
80 @param Context Pointer to the notification function's context,
81 which is implementation-dependent.
82
83 **/
84 VOID
85 EFIAPI
86 BdsEmptyCallbackFunction (
87 IN EFI_EVENT Event,
88 IN VOID *Context
89 )
90 {
91 }
92
93 /**
94
95 This function attempts to boot for the boot order specified
96 by platform policy.
97
98 **/
99 VOID
100 BdsBootDeviceSelect (
101 VOID
102 )
103 {
104 EFI_STATUS Status;
105 LIST_ENTRY *Link;
106 BDS_COMMON_OPTION *BootOption;
107 UINTN ExitDataSize;
108 CHAR16 *ExitData;
109 UINT16 Timeout;
110 LIST_ENTRY BootLists;
111 CHAR16 Buffer[20];
112 BOOLEAN BootNextExist;
113 LIST_ENTRY *LinkBootNext;
114 EFI_EVENT ConnectConInEvent;
115
116 //
117 // Got the latest boot option
118 //
119 BootNextExist = FALSE;
120 LinkBootNext = NULL;
121 ConnectConInEvent = NULL;
122 InitializeListHead (&BootLists);
123
124 //
125 // First check the boot next option
126 //
127 ZeroMem (Buffer, sizeof (Buffer));
128
129 //
130 // Create Event to signal ConIn connection request
131 //
132 if (PcdGetBool (PcdConInConnectOnDemand)) {
133 Status = gBS->CreateEventEx (
134 EVT_NOTIFY_SIGNAL,
135 TPL_CALLBACK,
136 BdsEmptyCallbackFunction,
137 NULL,
138 &gConnectConInEventGuid,
139 &ConnectConInEvent
140 );
141 if (EFI_ERROR(Status)) {
142 ConnectConInEvent = NULL;
143 }
144 }
145
146 if (mBootNext != NULL) {
147 //
148 // Indicate we have the boot next variable, so this time
149 // boot will always have this boot option
150 //
151 BootNextExist = TRUE;
152
153 //
154 // Clear the this variable so it's only exist in this time boot
155 //
156 gRT->SetVariable (
157 L"BootNext",
158 &gEfiGlobalVariableGuid,
159 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
160 0,
161 mBootNext
162 );
163
164 //
165 // Add the boot next boot option
166 //
167 UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *mBootNext);
168 BootOption = BdsLibVariableToOption (&BootLists, Buffer);
169
170 //
171 // If fail to get boot option from variable, just return and do nothing.
172 //
173 if (BootOption == NULL) {
174 return;
175 }
176
177 BootOption->BootCurrent = *mBootNext;
178 }
179 //
180 // Parse the boot order to get boot option
181 //
182 BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
183
184 //
185 // When we didn't have chance to build boot option variables in the first
186 // full configuration boot (e.g.: Reset in the first page or in Device Manager),
187 // we have no boot options in the following mini configuration boot.
188 // Give the last chance to enumerate the boot options.
189 //
190 if (IsListEmpty (&BootLists)) {
191 BdsLibEnumerateAllBootOption (&BootLists);
192 }
193
194 Link = BootLists.ForwardLink;
195
196 //
197 // Parameter check, make sure the loop will be valid
198 //
199 if (Link == NULL) {
200 return ;
201 }
202 //
203 // Here we make the boot in a loop, every boot success will
204 // return to the front page
205 //
206 for (;;) {
207 //
208 // Check the boot option list first
209 //
210 if (Link == &BootLists) {
211 //
212 // When LazyConIn enabled, signal connect ConIn event before enter UI
213 //
214 if (PcdGetBool (PcdConInConnectOnDemand) && ConnectConInEvent != NULL) {
215 gBS->SignalEvent (ConnectConInEvent);
216 }
217
218 //
219 // There are two ways to enter here:
220 // 1. There is no active boot option, give user chance to
221 // add new boot option
222 // 2. All the active boot option processed, and there is no
223 // one is success to boot, then we back here to allow user
224 // add new active boot option
225 //
226 Timeout = 0xffff;
227 PlatformBdsEnterFrontPage (Timeout, FALSE);
228 InitializeListHead (&BootLists);
229 BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
230 Link = BootLists.ForwardLink;
231 continue;
232 }
233 //
234 // Get the boot option from the link list
235 //
236 BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
237
238 //
239 // According to EFI Specification, if a load option is not marked
240 // as LOAD_OPTION_ACTIVE, the boot manager will not automatically
241 // load the option.
242 //
243 if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) {
244 //
245 // skip the header of the link list, because it has no boot option
246 //
247 Link = Link->ForwardLink;
248 continue;
249 }
250 //
251 // Make sure the boot option device path connected,
252 // but ignore the BBS device path
253 //
254 if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) {
255 //
256 // Notes: the internal shell can not been connected with device path
257 // so we do not check the status here
258 //
259 BdsLibConnectDevicePath (BootOption->DevicePath);
260 }
261
262 //
263 // Restore to original mode before launching boot option.
264 //
265 BdsSetConsoleMode (FALSE);
266
267 //
268 // All the driver options should have been processed since
269 // now boot will be performed.
270 //
271 Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
272 if (Status != EFI_SUCCESS) {
273 //
274 // Call platform action to indicate the boot fail
275 //
276 BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));
277 PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize);
278
279 //
280 // Check the next boot option
281 //
282 Link = Link->ForwardLink;
283
284 } else {
285 //
286 // Call platform action to indicate the boot success
287 //
288 BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));
289 PlatformBdsBootSuccess (BootOption);
290
291 //
292 // Boot success, then stop process the boot order, and
293 // present the boot manager menu, front page
294 //
295
296 //
297 // When LazyConIn enabled, signal connect ConIn Event before enter UI
298 //
299 if (PcdGetBool (PcdConInConnectOnDemand) && ConnectConInEvent != NULL) {
300 gBS->SignalEvent (ConnectConInEvent);
301 }
302
303 Timeout = 0xffff;
304 PlatformBdsEnterFrontPage (Timeout, FALSE);
305
306 //
307 // Rescan the boot option list, avoid potential risk of the boot
308 // option change in front page
309 //
310 if (BootNextExist) {
311 LinkBootNext = BootLists.ForwardLink;
312 }
313
314 InitializeListHead (&BootLists);
315 if (LinkBootNext != NULL) {
316 //
317 // Reserve the boot next option
318 //
319 InsertTailList (&BootLists, LinkBootNext);
320 }
321
322 BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
323 Link = BootLists.ForwardLink;
324 }
325 }
326
327 }
328
329 /**
330
331 Validate input console variable data.
332
333 If found the device path is not a valid device path, remove the variable.
334
335 @param VariableName Input console variable name.
336
337 **/
338 VOID
339 BdsFormalizeConsoleVariable (
340 IN CHAR16 *VariableName
341 )
342 {
343 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
344 UINTN VariableSize;
345 EFI_STATUS Status;
346
347 DevicePath = BdsLibGetVariableAndSize (
348 VariableName,
349 &gEfiGlobalVariableGuid,
350 &VariableSize
351 );
352 if ((DevicePath != NULL) && !IsDevicePathValid (DevicePath, VariableSize)) {
353 Status = gRT->SetVariable (
354 VariableName,
355 &gEfiGlobalVariableGuid,
356 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
357 0,
358 NULL
359 );
360 ASSERT_EFI_ERROR (Status);
361 }
362 }
363
364 /**
365
366 Formalize Bds global variables.
367
368 1. For ConIn/ConOut/ConErr, if found the device path is not a valid device path, remove the variable.
369 2. For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps
370 3. Delete OsIndications variable if it is not NV/BS/RT UINT64
371 Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.
372
373 **/
374 VOID
375 BdsFormalizeEfiGlobalVariable (
376 VOID
377 )
378 {
379 EFI_STATUS Status;
380 UINT64 OsIndicationSupport;
381 UINT64 OsIndication;
382 UINTN DataSize;
383 UINT32 Attributes;
384
385 //
386 // Validate Console variable.
387 //
388 BdsFormalizeConsoleVariable (L"ConIn");
389 BdsFormalizeConsoleVariable (L"ConOut");
390 BdsFormalizeConsoleVariable (L"ErrOut");
391
392 //
393 // OS indicater support variable
394 //
395 OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
396 Status = gRT->SetVariable (
397 L"OsIndicationsSupported",
398 &gEfiGlobalVariableGuid,
399 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
400 sizeof(UINT64),
401 &OsIndicationSupport
402 );
403 ASSERT_EFI_ERROR (Status);
404
405 //
406 // If OsIndications is invalid, remove it.
407 // Invalid case
408 // 1. Data size != UINT64
409 // 2. OsIndication value inconsistence
410 // 3. OsIndication attribute inconsistence
411 //
412 OsIndication = 0;
413 Attributes = 0;
414 DataSize = sizeof(UINT64);
415 Status = gRT->GetVariable (
416 L"OsIndications",
417 &gEfiGlobalVariableGuid,
418 &Attributes,
419 &DataSize,
420 &OsIndication
421 );
422
423 if (!EFI_ERROR(Status)) {
424 if (DataSize != sizeof(UINT64) ||
425 (OsIndication & ~OsIndicationSupport) != 0 ||
426 Attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE)){
427
428 DEBUG ((EFI_D_ERROR, "Unformalized OsIndications variable exists. Delete it\n"));
429 Status = gRT->SetVariable (
430 L"OsIndications",
431 &gEfiGlobalVariableGuid,
432 Attributes,
433 0,
434 &OsIndication
435 );
436 ASSERT_EFI_ERROR (Status);
437 }
438 }
439
440 }
441
442 /**
443
444 Service routine for BdsInstance->Entry(). Devices are connected, the
445 consoles are initialized, and the boot options are tried.
446
447 @param This Protocol Instance structure.
448
449 **/
450 VOID
451 EFIAPI
452 BdsEntry (
453 IN EFI_BDS_ARCH_PROTOCOL *This
454 )
455 {
456 LIST_ENTRY DriverOptionList;
457 LIST_ENTRY BootOptionList;
458 UINTN BootNextSize;
459 CHAR16 *FirmwareVendor;
460 EFI_STATUS Status;
461 UINT16 BootTimeOut;
462
463 //
464 // Insert the performance probe
465 //
466 PERF_END (NULL, "DXE", NULL, 0);
467 PERF_START (NULL, "BDS", NULL, 0);
468
469 //
470 // Initialize the global system boot option and driver option
471 //
472 InitializeListHead (&DriverOptionList);
473 InitializeListHead (&BootOptionList);
474
475 //
476 // Initialize hotkey service
477 //
478 InitializeHotkeyService ();
479
480 //
481 // Fill in FirmwareVendor and FirmwareRevision from PCDs
482 //
483 FirmwareVendor = (CHAR16 *)PcdGetPtr (PcdFirmwareVendor);
484 gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor);
485 ASSERT (gST->FirmwareVendor != NULL);
486 gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision);
487
488 //
489 // Fixup Tasble CRC after we updated Firmware Vendor and Revision
490 //
491 gST->Hdr.CRC32 = 0;
492 gBS->CalculateCrc32 ((VOID *)gST, sizeof(EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);
493
494 //
495 // Validate Variable.
496 //
497 BdsFormalizeEfiGlobalVariable();
498
499 //
500 // Report Status Code to indicate connecting drivers will happen
501 //
502 REPORT_STATUS_CODE (
503 EFI_PROGRESS_CODE,
504 (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS)
505 );
506
507 //
508 // Do the platform init, can be customized by OEM/IBV
509 //
510 PERF_START (NULL, "PlatformBds", "BDS", 0);
511 PlatformBdsInit ();
512
513 InitializeHwErrRecSupport();
514
515 //
516 // Initialize L"Timeout" EFI global variable.
517 //
518 BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);
519 if (BootTimeOut != 0xFFFF) {
520 //
521 // If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification
522 // define same behavior between no value or 0xFFFF value for L"Timeout".
523 //
524 Status = gRT->SetVariable (
525 L"Timeout",
526 &gEfiGlobalVariableGuid,
527 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
528 sizeof (UINT16),
529 &BootTimeOut
530 );
531 ASSERT_EFI_ERROR(Status);
532 }
533
534 //
535 // bugbug: platform specific code
536 // Initialize the platform specific string and language
537 //
538 InitializeStringSupport ();
539 InitializeLanguage (TRUE);
540 InitializeFrontPage (TRUE);
541
542 //
543 // Set up the device list based on EFI 1.1 variables
544 // process Driver#### and Load the driver's in the
545 // driver option list
546 //
547 BdsLibBuildOptionFromVar (&DriverOptionList, L"DriverOrder");
548 if (!IsListEmpty (&DriverOptionList)) {
549 BdsLibLoadDrivers (&DriverOptionList);
550 }
551 //
552 // Check if we have the boot next option
553 //
554 mBootNext = BdsLibGetVariableAndSize (
555 L"BootNext",
556 &gEfiGlobalVariableGuid,
557 &BootNextSize
558 );
559
560 //
561 // Setup some platform policy here
562 //
563 PlatformBdsPolicyBehavior (&DriverOptionList, &BootOptionList, BdsProcessCapsules, BdsMemoryTest);
564 PERF_END (NULL, "PlatformBds", "BDS", 0);
565
566 //
567 // BDS select the boot device to load OS
568 //
569 BdsBootDeviceSelect ();
570
571 //
572 // Only assert here since this is the right behavior, we should never
573 // return back to DxeCore.
574 //
575 ASSERT (FALSE);
576
577 return ;
578 }