]> git.proxmox.com Git - mirror_edk2.git/blob - EdkNt32Pkg/Library/EdkGenericBdsLib/BdsMisc.c
Make NT32 SecMain not depend on ReportStatusCodeLib
[mirror_edk2.git] / EdkNt32Pkg / Library / EdkGenericBdsLib / BdsMisc.c
1 /*++
2
3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 BdsMisc.c
15
16 Abstract:
17
18 Misc BDS library function
19
20 --*/
21
22 extern UINT16 gPlatformBootTimeOutDefault;
23
24 UINT16
25 BdsLibGetTimeout (
26 VOID
27 )
28 /*++
29
30 Routine Description:
31
32 Return the default value for system Timeout variable.
33
34 Arguments:
35
36 None
37
38 Returns:
39
40 Timeout value.
41
42 --*/
43 {
44 UINT16 Timeout;
45 UINTN Size;
46 EFI_STATUS Status;
47
48 //
49 // Return Timeout variable or 0xffff if no valid
50 // Timeout variable exists.
51 //
52 Size = sizeof (UINT16);
53 Status = gRT->GetVariable (L"Timeout", &gEfiGlobalVariableGuid, NULL, &Size, &Timeout);
54 if (!EFI_ERROR (Status)) {
55 return Timeout;
56 }
57 //
58 // To make the current EFI Automatic-Test activity possible, just add
59 // following code to make AutoBoot enabled when this variable is not
60 // present.
61 // This code should be removed later.
62 //
63 Timeout = gPlatformBootTimeOutDefault;
64
65 //
66 // Notes: Platform should set default variable if non exists on all error cases!!!
67 //
68 Status = gRT->SetVariable (
69 L"Timeout",
70 &gEfiGlobalVariableGuid,
71 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
72 sizeof (UINT16),
73 &Timeout
74 );
75 return Timeout;
76 }
77
78 VOID
79 BdsLibLoadDrivers (
80 IN LIST_ENTRY *BdsDriverLists
81 )
82 /*++
83
84 Routine Description:
85
86 The function will go through the driver optoin link list, load and start
87 every driver the driver optoin device path point to.
88
89 Arguments:
90
91 BdsDriverLists - The header of the current driver option link list
92
93 Returns:
94
95 None
96
97 --*/
98 {
99 EFI_STATUS Status;
100 LIST_ENTRY *Link;
101 BDS_COMMON_OPTION *Option;
102 EFI_HANDLE ImageHandle;
103 EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
104 UINTN ExitDataSize;
105 CHAR16 *ExitData;
106 BOOLEAN ReconnectAll;
107
108 ReconnectAll = FALSE;
109
110 //
111 // Process the driver option
112 //
113 for (Link = BdsDriverLists->ForwardLink; Link != BdsDriverLists; Link = Link->ForwardLink) {
114 Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
115 //
116 // If a load option is not marked as LOAD_OPTION_ACTIVE,
117 // the boot manager will not automatically load the option.
118 //
119 if (!IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_ACTIVE)) {
120 continue;
121 }
122 //
123 // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,
124 // then all of the EFI drivers in the system will be disconnected and
125 // reconnected after the last driver load option is processed.
126 //
127 if (IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_FORCE_RECONNECT)) {
128 ReconnectAll = TRUE;
129 }
130 //
131 // Make sure the driver path is connected.
132 //
133 BdsLibConnectDevicePath (Option->DevicePath);
134
135 //
136 // Load and start the image that Driver#### describes
137 //
138 Status = gBS->LoadImage (
139 FALSE,
140 mBdsImageHandle,
141 Option->DevicePath,
142 NULL,
143 0,
144 &ImageHandle
145 );
146
147 if (!EFI_ERROR (Status)) {
148 gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, &ImageInfo);
149
150 //
151 // Verify whether this image is a driver, if not,
152 // exit it and continue to parse next load option
153 //
154 if (ImageInfo->ImageCodeType != EfiBootServicesCode && ImageInfo->ImageCodeType != EfiRuntimeServicesCode) {
155 gBS->Exit (ImageHandle, EFI_INVALID_PARAMETER, 0, NULL);
156 continue;
157 }
158
159 if (Option->LoadOptionsSize != 0) {
160 ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;
161 ImageInfo->LoadOptions = Option->LoadOptions;
162 }
163 //
164 // Before calling the image, enable the Watchdog Timer for
165 // the 5 Minute period
166 //
167 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
168
169 Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData);
170 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Driver Return Status = %r\n", Status));
171
172 //
173 // Clear the Watchdog Timer after the image returns
174 //
175 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
176 }
177 }
178 //
179 // Process the LOAD_OPTION_FORCE_RECONNECT driver option
180 //
181 if (ReconnectAll) {
182 BdsLibDisconnectAllEfi ();
183 BdsLibConnectAll ();
184 }
185
186 }
187
188 EFI_STATUS
189 BdsLibRegisterNewOption (
190 IN LIST_ENTRY *BdsOptionList,
191 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
192 IN CHAR16 *String,
193 IN CHAR16 *VariableName
194 )
195 /*++
196
197 Routine Description:
198
199 This function will register the new boot#### or driver#### option base on
200 the VariableName. The new registered boot#### or driver#### will be linked
201 to BdsOptionList and also update to the VariableName. After the boot#### or
202 driver#### updated, the BootOrder or DriverOrder will also be updated.
203
204 Arguments:
205
206 BdsOptionList - The header of the boot#### or driver#### link list
207
208 DevicePath - The device path which the boot####
209 or driver#### option present
210
211 String - The description of the boot#### or driver####
212
213 VariableName - Indicate if the boot#### or driver#### option
214
215 Returns:
216
217 EFI_SUCCESS - The boot#### or driver#### have been success registered
218
219 EFI_STATUS - Return the status of gRT->SetVariable ().
220
221 --*/
222 {
223 EFI_STATUS Status;
224 UINTN Index;
225 UINT16 MaxOptionNumber;
226 UINT16 RegisterOptionNumber;
227 UINT16 *TempOptionPtr;
228 UINTN TempOptionSize;
229 UINT16 *OptionOrderPtr;
230 VOID *OptionPtr;
231 UINTN OptionSize;
232 UINT8 *TempPtr;
233 EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
234 CHAR16 *Description;
235 CHAR16 OptionName[10];
236 BOOLEAN UpdateBootDevicePath;
237
238 OptionPtr = NULL;
239 OptionSize = 0;
240 TempPtr = NULL;
241 OptionDevicePath = NULL;
242 Description = NULL;
243 MaxOptionNumber = 0;
244 OptionOrderPtr = NULL;
245 UpdateBootDevicePath = FALSE;
246 ZeroMem (OptionName, sizeof (OptionName));
247
248 TempOptionSize = 0;
249 TempOptionPtr = BdsLibGetVariableAndSize (
250 VariableName,
251 &gEfiGlobalVariableGuid,
252 &TempOptionSize
253 );
254 //
255 // Compare with current option variable
256 //
257 for (Index = 0; Index < TempOptionSize / sizeof (UINT16); Index++) {
258 //
259 // Got the max option#### number
260 //
261 if (MaxOptionNumber < TempOptionPtr[Index]) {
262 MaxOptionNumber = TempOptionPtr[Index];
263 }
264
265 if (*VariableName == 'B') {
266 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", TempOptionPtr[Index]);
267 } else {
268 UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", TempOptionPtr[Index]);
269 }
270
271 OptionPtr = BdsLibGetVariableAndSize (
272 OptionName,
273 &gEfiGlobalVariableGuid,
274 &OptionSize
275 );
276 TempPtr = OptionPtr;
277 TempPtr += sizeof (UINT32) + sizeof (UINT16);
278 Description = (CHAR16 *) TempPtr;
279 TempPtr += StrSize ((CHAR16 *) TempPtr);
280 OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
281
282 //
283 // Notes: the description may will change base on the GetStringToken
284 //
285 if (CompareMem (Description, String, StrSize (Description)) == 0) {
286 if (CompareMem (OptionDevicePath, DevicePath, GetDevicePathSize (OptionDevicePath)) == 0) {
287 //
288 // Got the option, so just return
289 //
290 gBS->FreePool (OptionPtr);
291 gBS->FreePool (TempOptionPtr);
292 return EFI_SUCCESS;
293 } else {
294 //
295 // Boot device path changed, need update.
296 //
297 UpdateBootDevicePath = TRUE;
298 break;
299 }
300 }
301
302 gBS->FreePool (OptionPtr);
303 }
304
305 OptionSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (String) + GetDevicePathSize (DevicePath);
306 OptionPtr = AllocateZeroPool (OptionSize);
307 TempPtr = OptionPtr;
308 *(UINT32 *) TempPtr = LOAD_OPTION_ACTIVE;
309 TempPtr += sizeof (UINT32);
310 *(UINT16 *) TempPtr = (UINT16) GetDevicePathSize (DevicePath);
311 TempPtr += sizeof (UINT16);
312 CopyMem (TempPtr, String, StrSize (String));
313 TempPtr += StrSize (String);
314 CopyMem (TempPtr, DevicePath, GetDevicePathSize (DevicePath));
315
316 if (UpdateBootDevicePath) {
317 //
318 // The number in option#### to be updated
319 //
320 RegisterOptionNumber = TempOptionPtr[Index];
321 } else {
322 //
323 // The new option#### number
324 //
325 RegisterOptionNumber = MaxOptionNumber + 1;
326 }
327
328 if (*VariableName == 'B') {
329 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", RegisterOptionNumber);
330 } else {
331 UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", RegisterOptionNumber);
332 }
333
334 Status = gRT->SetVariable (
335 OptionName,
336 &gEfiGlobalVariableGuid,
337 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
338 OptionSize,
339 OptionPtr
340 );
341 if (EFI_ERROR (Status) || UpdateBootDevicePath) {
342 gBS->FreePool (OptionPtr);
343 gBS->FreePool (TempOptionPtr);
344 return Status;
345 }
346
347 gBS->FreePool (OptionPtr);
348
349 //
350 // Update the option order variable
351 //
352 OptionOrderPtr = AllocateZeroPool ((Index + 1) * sizeof (UINT16));
353 CopyMem (OptionOrderPtr, TempOptionPtr, Index * sizeof (UINT16));
354 OptionOrderPtr[Index] = RegisterOptionNumber;
355 Status = gRT->SetVariable (
356 VariableName,
357 &gEfiGlobalVariableGuid,
358 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
359 (Index + 1) * sizeof (UINT16),
360 OptionOrderPtr
361 );
362 if (EFI_ERROR (Status)) {
363 gBS->FreePool (TempOptionPtr);
364 gBS->FreePool (OptionOrderPtr);
365 return Status;
366 }
367
368 gBS->FreePool (TempOptionPtr);
369 gBS->FreePool (OptionOrderPtr);
370
371 return EFI_SUCCESS;
372 }
373
374 BDS_COMMON_OPTION *
375 BdsLibVariableToOption (
376 IN OUT LIST_ENTRY *BdsCommonOptionList,
377 IN CHAR16 *VariableName
378 )
379 /*++
380
381 Routine Description:
382
383 Build the boot#### or driver#### option from the VariableName, the
384 build boot#### or driver#### will also be linked to BdsCommonOptionList
385
386 Arguments:
387
388 BdsCommonOptionList - The header of the boot#### or driver#### option link list
389
390 VariableName - EFI Variable name indicate if it is boot#### or driver####
391
392 Returns:
393
394 BDS_COMMON_OPTION - Get the option just been created
395
396 NULL - Failed to get the new option
397
398 --*/
399 {
400 UINT32 Attribute;
401 UINT16 FilePathSize;
402 UINT8 *Variable;
403 UINT8 *TempPtr;
404 UINTN VariableSize;
405 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
406 BDS_COMMON_OPTION *Option;
407 VOID *LoadOptions;
408 UINT32 LoadOptionsSize;
409 CHAR16 *Description;
410
411 //
412 // Read the variable. We will never free this data.
413 //
414 Variable = BdsLibGetVariableAndSize (
415 VariableName,
416 &gEfiGlobalVariableGuid,
417 &VariableSize
418 );
419 if (Variable == NULL) {
420 return NULL;
421 }
422 //
423 // Notes: careful defined the variable of Boot#### or
424 // Driver####, consider use some macro to abstract the code
425 //
426 //
427 // Get the option attribute
428 //
429 TempPtr = Variable;
430 Attribute = *(UINT32 *) Variable;
431 TempPtr += sizeof (UINT32);
432
433 //
434 // Get the option's device path size
435 //
436 FilePathSize = *(UINT16 *) TempPtr;
437 TempPtr += sizeof (UINT16);
438
439 //
440 // Get the option's description string
441 //
442 Description = (CHAR16 *) TempPtr;
443
444 //
445 // Get the option's description string size
446 //
447 TempPtr += StrSize ((CHAR16 *) TempPtr);
448
449 //
450 // Get the option's device path
451 //
452 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
453 TempPtr += FilePathSize;
454
455 LoadOptions = TempPtr;
456 LoadOptionsSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable));
457
458 //
459 // The Console variables may have multiple device paths, so make
460 // an Entry for each one.
461 //
462 Option = AllocateZeroPool (sizeof (BDS_COMMON_OPTION));
463 if (Option == NULL) {
464 return NULL;
465 }
466
467 Option->Signature = BDS_LOAD_OPTION_SIGNATURE;
468 Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));
469 CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
470 Option->Attribute = Attribute;
471 Option->Description = AllocateZeroPool (StrSize (Description));
472 CopyMem (Option->Description, Description, StrSize (Description));
473 Option->LoadOptions = AllocateZeroPool (LoadOptionsSize);
474 CopyMem (Option->LoadOptions, LoadOptions, LoadOptionsSize);
475 Option->LoadOptionsSize = LoadOptionsSize;
476
477 //
478 // Insert active entry to BdsDeviceList
479 //
480 if ((Option->Attribute & LOAD_OPTION_ACTIVE) == LOAD_OPTION_ACTIVE) {
481 InsertTailList (BdsCommonOptionList, &Option->Link);
482 gBS->FreePool (Variable);
483 return Option;
484 }
485
486 gBS->FreePool (Variable);
487 gBS->FreePool (Option);
488 return NULL;
489
490 }
491
492 EFI_STATUS
493 BdsLibBuildOptionFromVar (
494 IN LIST_ENTRY *BdsCommonOptionList,
495 IN CHAR16 *VariableName
496 )
497 /*++
498
499 Routine Description:
500
501 Process BootOrder, or DriverOrder variables, by calling
502 BdsLibVariableToOption () for each UINT16 in the variables.
503
504 Arguments:
505
506 BdsCommonOptionList - The header of the option list base on variable
507 VariableName
508
509 VariableName - EFI Variable name indicate the BootOrder or DriverOrder
510
511 Returns:
512
513 EFI_SUCCESS - Success create the boot option or driver option list
514
515 EFI_OUT_OF_RESOURCES - Failed to get the boot option or driver option list
516
517 --*/
518 {
519 UINT16 *OptionOrder;
520 UINTN OptionOrderSize;
521 UINTN Index;
522 BDS_COMMON_OPTION *Option;
523 CHAR16 OptionName[20];
524
525 //
526 // Zero Buffer in order to get all BOOT#### variables
527 //
528 ZeroMem (OptionName, sizeof (OptionName));
529
530 //
531 // Read the BootOrder, or DriverOrder variable.
532 //
533 OptionOrder = BdsLibGetVariableAndSize (
534 VariableName,
535 &gEfiGlobalVariableGuid,
536 &OptionOrderSize
537 );
538 if (OptionOrder == NULL) {
539 return EFI_OUT_OF_RESOURCES;
540 }
541
542 for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
543 if (*VariableName == 'B') {
544 UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionOrder[Index]);
545 } else {
546 UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", OptionOrder[Index]);
547 }
548 Option = BdsLibVariableToOption (BdsCommonOptionList, OptionName);
549 Option->BootCurrent = OptionOrder[Index];
550
551 }
552
553 gBS->FreePool (OptionOrder);
554
555 return EFI_SUCCESS;
556 }
557
558 EFI_STATUS
559 BdsLibGetBootMode (
560 OUT EFI_BOOT_MODE *BootMode
561 )
562 /*++
563
564 Routine Description:
565
566 Get boot mode by looking up configuration table and parsing HOB list
567
568 Arguments:
569
570 BootMode - Boot mode from PEI handoff HOB.
571
572 Returns:
573
574 EFI_SUCCESS - Successfully get boot mode
575
576 EFI_NOT_FOUND - Can not find the current system boot mode
577
578 --*/
579 {
580 EFI_HOB_HANDOFF_INFO_TABLE *HobList;
581
582 HobList = GetHobList ();
583 ASSERT (HobList->Header.HobType == EFI_HOB_TYPE_HANDOFF);
584 *BootMode = HobList->BootMode;
585
586 return EFI_SUCCESS;
587 }
588
589 VOID *
590 BdsLibGetVariableAndSize (
591 IN CHAR16 *Name,
592 IN EFI_GUID *VendorGuid,
593 OUT UINTN *VariableSize
594 )
595 /*++
596
597 Routine Description:
598
599 Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
600 buffer, and the size of the buffer. If failure return NULL.
601
602 Arguments:
603
604 Name - String part of EFI variable name
605
606 VendorGuid - GUID part of EFI variable name
607
608 VariableSize - Returns the size of the EFI variable that was read
609
610 Returns:
611
612 Dynamically allocated memory that contains a copy of the EFI variable.
613 Caller is responsible freeing the buffer.
614
615 NULL - Variable was not read
616
617 --*/
618 {
619 EFI_STATUS Status;
620 UINTN BufferSize;
621 VOID *Buffer;
622
623 Buffer = NULL;
624
625 //
626 // Pass in a zero size buffer to find the required buffer size.
627 //
628 BufferSize = 0;
629 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
630 if (Status == EFI_BUFFER_TOO_SMALL) {
631 //
632 // Allocate the buffer to return
633 //
634 Buffer = AllocateZeroPool (BufferSize);
635 if (Buffer == NULL) {
636 return NULL;
637 }
638 //
639 // Read variable into the allocated buffer.
640 //
641 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
642 if (EFI_ERROR (Status)) {
643 BufferSize = 0;
644 }
645 }
646
647 *VariableSize = BufferSize;
648 return Buffer;
649 }
650
651 BOOLEAN
652 BdsLibMatchDevicePaths (
653 IN EFI_DEVICE_PATH_PROTOCOL *Multi,
654 IN EFI_DEVICE_PATH_PROTOCOL *Single
655 )
656 /*++
657
658 Routine Description:
659
660 Function compares a device path data structure to that of all the nodes of a
661 second device path instance.
662
663 Arguments:
664
665 Multi - A pointer to a multi-instance device path data structure.
666
667 Single - A pointer to a single-instance device path data structure.
668
669 Returns:
670
671 TRUE - If the Single is contained within Multi
672
673 FALSE - The Single is not match within Multi
674
675
676 --*/
677 {
678 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
679 EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
680 UINTN Size;
681
682 if (!Multi || !Single) {
683 return FALSE;
684 }
685
686 DevicePath = Multi;
687 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
688 Size -= sizeof (EFI_DEVICE_PATH_PROTOCOL);
689
690 //
691 // Search for the match of 'Single' in 'Multi'
692 //
693 while (DevicePathInst != NULL) {
694 //
695 // If the single device path is found in multiple device paths,
696 // return success
697 //
698 if (Size == 0) {
699 return FALSE;
700 }
701
702 if (CompareMem (Single, DevicePathInst, Size) == 0) {
703 return TRUE;
704 }
705
706 gBS->FreePool (DevicePathInst);
707 DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
708 Size -= sizeof (EFI_DEVICE_PATH_PROTOCOL);
709 }
710
711 return FALSE;
712 }
713
714 EFI_STATUS
715 BdsLibOutputStrings (
716 IN EFI_SIMPLE_TEXT_OUT_PROTOCOL *ConOut,
717 ...
718 )
719 /*++
720
721 Routine Description:
722
723 This function prints a series of strings.
724
725 Arguments:
726
727 ConOut - Pointer to EFI_SIMPLE_TEXT_OUT_PROTOCOL
728
729 ... - A variable argument list containing series of strings,
730 the last string must be NULL.
731
732 Returns:
733
734 EFI_SUCCESS - Success print out the string using ConOut.
735
736 EFI_STATUS - Return the status of the ConOut->OutputString ().
737
738 --*/
739 {
740 VA_LIST args;
741 EFI_STATUS Status;
742 CHAR16 *String;
743
744 Status = EFI_SUCCESS;
745 VA_START (args, ConOut);
746
747 while (!EFI_ERROR (Status)) {
748 //
749 // If String is NULL, then it's the end of the list
750 //
751 String = VA_ARG (args, CHAR16 *);
752 if (!String) {
753 break;
754 }
755
756 Status = ConOut->OutputString (ConOut, String);
757
758 if (EFI_ERROR (Status)) {
759 break;
760 }
761 }
762
763 return Status;
764 }