]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c
OvmfPkg: consolidate POWER_MGMT_REGISTER_PIIX4() on "I440FxPiix4.h" macros
[mirror_edk2.git] / OvmfPkg / Library / PlatformBdsLib / BdsPlatform.c
1 /** @file
2 Platform BDS customizations.
3
4 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "BdsPlatform.h"
16 #include <Library/QemuBootOrderLib.h>
17
18
19 //
20 // Global data
21 //
22
23 VOID *mEfiDevPathNotifyReg;
24 EFI_EVENT mEfiDevPathEvent;
25 VOID *mEmuVariableEventReg;
26 EFI_EVENT mEmuVariableEvent;
27 BOOLEAN mDetectVgaOnly;
28 UINT16 mHostBridgeDevId;
29
30 //
31 // Table of host IRQs matching PCI IRQs A-D
32 // (for configuring PCI Interrupt Line register)
33 //
34 CONST UINT8 PciHostIrqs[] = {
35 0x0a, 0x0a, 0x0b, 0x0b
36 };
37
38 //
39 // Array Size macro
40 //
41 #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0]))
42
43 //
44 // Type definitions
45 //
46
47 typedef
48 EFI_STATUS
49 (EFIAPI *PROTOCOL_INSTANCE_CALLBACK)(
50 IN EFI_HANDLE Handle,
51 IN VOID *Instance,
52 IN VOID *Context
53 );
54
55 /**
56 @param[in] Handle - Handle of PCI device instance
57 @param[in] PciIo - PCI IO protocol instance
58 @param[in] Pci - PCI Header register block
59 **/
60 typedef
61 EFI_STATUS
62 (EFIAPI *VISIT_PCI_INSTANCE_CALLBACK)(
63 IN EFI_HANDLE Handle,
64 IN EFI_PCI_IO_PROTOCOL *PciIo,
65 IN PCI_TYPE00 *Pci
66 );
67
68
69 //
70 // Function prototypes
71 //
72
73 EFI_STATUS
74 VisitAllInstancesOfProtocol (
75 IN EFI_GUID *Id,
76 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
77 IN VOID *Context
78 );
79
80 EFI_STATUS
81 VisitAllPciInstancesOfProtocol (
82 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
83 );
84
85 VOID
86 InstallDevicePathCallback (
87 VOID
88 );
89
90 //
91 // BDS Platform Functions
92 //
93 VOID
94 EFIAPI
95 PlatformBdsInit (
96 VOID
97 )
98 /*++
99
100 Routine Description:
101
102 Platform Bds init. Incude the platform firmware vendor, revision
103 and so crc check.
104
105 Arguments:
106
107 Returns:
108
109 None.
110
111 --*/
112 {
113 DEBUG ((EFI_D_INFO, "PlatformBdsInit\n"));
114 InstallDevicePathCallback ();
115 }
116
117
118 EFI_STATUS
119 ConnectRootBridge (
120 VOID
121 )
122 /*++
123
124 Routine Description:
125
126 Connect RootBridge
127
128 Arguments:
129
130 None.
131
132 Returns:
133
134 EFI_SUCCESS - Connect RootBridge successfully.
135 EFI_STATUS - Connect RootBridge fail.
136
137 --*/
138 {
139 EFI_STATUS Status;
140 EFI_HANDLE RootHandle;
141
142 //
143 // Make all the PCI_IO protocols on PCI Seg 0 show up
144 //
145 BdsLibConnectDevicePath (gPlatformRootBridges[0]);
146
147 Status = gBS->LocateDevicePath (
148 &gEfiDevicePathProtocolGuid,
149 &gPlatformRootBridges[0],
150 &RootHandle
151 );
152 if (EFI_ERROR (Status)) {
153 return Status;
154 }
155
156 Status = gBS->ConnectController (RootHandle, NULL, NULL, FALSE);
157 if (EFI_ERROR (Status)) {
158 return Status;
159 }
160
161 return EFI_SUCCESS;
162 }
163
164
165 EFI_STATUS
166 PrepareLpcBridgeDevicePath (
167 IN EFI_HANDLE DeviceHandle
168 )
169 /*++
170
171 Routine Description:
172
173 Add IsaKeyboard to ConIn,
174 add IsaSerial to ConOut, ConIn, ErrOut.
175 LPC Bridge: 06 01 00
176
177 Arguments:
178
179 DeviceHandle - Handle of PCIIO protocol.
180
181 Returns:
182
183 EFI_SUCCESS - LPC bridge is added to ConOut, ConIn, and ErrOut.
184 EFI_STATUS - No LPC bridge is added.
185
186 --*/
187 {
188 EFI_STATUS Status;
189 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
190 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
191 CHAR16 *DevPathStr;
192
193 DevicePath = NULL;
194 Status = gBS->HandleProtocol (
195 DeviceHandle,
196 &gEfiDevicePathProtocolGuid,
197 (VOID*)&DevicePath
198 );
199 if (EFI_ERROR (Status)) {
200 return Status;
201 }
202 TempDevicePath = DevicePath;
203
204 //
205 // Register Keyboard
206 //
207 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnpPs2KeyboardDeviceNode);
208
209 BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL);
210
211 //
212 // Register COM1
213 //
214 DevicePath = TempDevicePath;
215 gPnp16550ComPortDeviceNode.UID = 0;
216
217 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
218 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
219 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
220
221 //
222 // Print Device Path
223 //
224 DevPathStr = DevicePathToStr(DevicePath);
225 if (DevPathStr != NULL) {
226 DEBUG((
227 EFI_D_INFO,
228 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
229 __LINE__,
230 gPnp16550ComPortDeviceNode.UID + 1,
231 DevPathStr
232 ));
233 FreePool(DevPathStr);
234 }
235
236 BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL);
237 BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL);
238 BdsLibUpdateConsoleVariable (VarErrorOut, DevicePath, NULL);
239
240 //
241 // Register COM2
242 //
243 DevicePath = TempDevicePath;
244 gPnp16550ComPortDeviceNode.UID = 1;
245
246 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gPnp16550ComPortDeviceNode);
247 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
248 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
249
250 //
251 // Print Device Path
252 //
253 DevPathStr = DevicePathToStr(DevicePath);
254 if (DevPathStr != NULL) {
255 DEBUG((
256 EFI_D_INFO,
257 "BdsPlatform.c+%d: COM%d DevPath: %s\n",
258 __LINE__,
259 gPnp16550ComPortDeviceNode.UID + 1,
260 DevPathStr
261 ));
262 FreePool(DevPathStr);
263 }
264
265 BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL);
266 BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL);
267 BdsLibUpdateConsoleVariable (VarErrorOut, DevicePath, NULL);
268
269 return EFI_SUCCESS;
270 }
271
272 EFI_STATUS
273 GetGopDevicePath (
274 IN EFI_DEVICE_PATH_PROTOCOL *PciDevicePath,
275 OUT EFI_DEVICE_PATH_PROTOCOL **GopDevicePath
276 )
277 {
278 UINTN Index;
279 EFI_STATUS Status;
280 EFI_HANDLE PciDeviceHandle;
281 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
282 EFI_DEVICE_PATH_PROTOCOL *TempPciDevicePath;
283 UINTN GopHandleCount;
284 EFI_HANDLE *GopHandleBuffer;
285
286 if (PciDevicePath == NULL || GopDevicePath == NULL) {
287 return EFI_INVALID_PARAMETER;
288 }
289
290 //
291 // Initialize the GopDevicePath to be PciDevicePath
292 //
293 *GopDevicePath = PciDevicePath;
294 TempPciDevicePath = PciDevicePath;
295
296 Status = gBS->LocateDevicePath (
297 &gEfiDevicePathProtocolGuid,
298 &TempPciDevicePath,
299 &PciDeviceHandle
300 );
301 if (EFI_ERROR (Status)) {
302 return Status;
303 }
304
305 //
306 // Try to connect this handle, so that GOP dirver could start on this
307 // device and create child handles with GraphicsOutput Protocol installed
308 // on them, then we get device paths of these child handles and select
309 // them as possible console device.
310 //
311 gBS->ConnectController (PciDeviceHandle, NULL, NULL, FALSE);
312
313 Status = gBS->LocateHandleBuffer (
314 ByProtocol,
315 &gEfiGraphicsOutputProtocolGuid,
316 NULL,
317 &GopHandleCount,
318 &GopHandleBuffer
319 );
320 if (!EFI_ERROR (Status)) {
321 //
322 // Add all the child handles as possible Console Device
323 //
324 for (Index = 0; Index < GopHandleCount; Index++) {
325 Status = gBS->HandleProtocol (GopHandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID*)&TempDevicePath);
326 if (EFI_ERROR (Status)) {
327 continue;
328 }
329 if (CompareMem (
330 PciDevicePath,
331 TempDevicePath,
332 GetDevicePathSize (PciDevicePath) - END_DEVICE_PATH_LENGTH
333 ) == 0) {
334 //
335 // In current implementation, we only enable one of the child handles
336 // as console device, i.e. sotre one of the child handle's device
337 // path to variable "ConOut"
338 // In futhure, we could select all child handles to be console device
339 //
340
341 *GopDevicePath = TempDevicePath;
342
343 //
344 // Delete the PCI device's path that added by GetPlugInPciVgaDevicePath()
345 // Add the integrity GOP device path.
346 //
347 BdsLibUpdateConsoleVariable (VarConsoleOutDev, NULL, PciDevicePath);
348 BdsLibUpdateConsoleVariable (VarConsoleOutDev, TempDevicePath, NULL);
349 }
350 }
351 gBS->FreePool (GopHandleBuffer);
352 }
353
354 return EFI_SUCCESS;
355 }
356
357 EFI_STATUS
358 PreparePciVgaDevicePath (
359 IN EFI_HANDLE DeviceHandle
360 )
361 /*++
362
363 Routine Description:
364
365 Add PCI VGA to ConOut.
366 PCI VGA: 03 00 00
367
368 Arguments:
369
370 DeviceHandle - Handle of PCIIO protocol.
371
372 Returns:
373
374 EFI_SUCCESS - PCI VGA is added to ConOut.
375 EFI_STATUS - No PCI VGA device is added.
376
377 --*/
378 {
379 EFI_STATUS Status;
380 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
381 EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
382
383 DevicePath = NULL;
384 GopDevicePath = NULL;
385 Status = gBS->HandleProtocol (
386 DeviceHandle,
387 &gEfiDevicePathProtocolGuid,
388 (VOID*)&DevicePath
389 );
390 if (EFI_ERROR (Status)) {
391 return Status;
392 }
393
394 GetGopDevicePath (DevicePath, &GopDevicePath);
395 DevicePath = GopDevicePath;
396
397 BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL);
398
399 return EFI_SUCCESS;
400 }
401
402 EFI_STATUS
403 PreparePciSerialDevicePath (
404 IN EFI_HANDLE DeviceHandle
405 )
406 /*++
407
408 Routine Description:
409
410 Add PCI Serial to ConOut, ConIn, ErrOut.
411 PCI Serial: 07 00 02
412
413 Arguments:
414
415 DeviceHandle - Handle of PCIIO protocol.
416
417 Returns:
418
419 EFI_SUCCESS - PCI Serial is added to ConOut, ConIn, and ErrOut.
420 EFI_STATUS - No PCI Serial device is added.
421
422 --*/
423 {
424 EFI_STATUS Status;
425 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
426
427 DevicePath = NULL;
428 Status = gBS->HandleProtocol (
429 DeviceHandle,
430 &gEfiDevicePathProtocolGuid,
431 (VOID*)&DevicePath
432 );
433 if (EFI_ERROR (Status)) {
434 return Status;
435 }
436
437 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gUartDeviceNode);
438 DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&gTerminalTypeDeviceNode);
439
440 BdsLibUpdateConsoleVariable (VarConsoleOut, DevicePath, NULL);
441 BdsLibUpdateConsoleVariable (VarConsoleInp, DevicePath, NULL);
442 BdsLibUpdateConsoleVariable (VarErrorOut, DevicePath, NULL);
443
444 return EFI_SUCCESS;
445 }
446
447 EFI_STATUS
448 VisitAllInstancesOfProtocol (
449 IN EFI_GUID *Id,
450 IN PROTOCOL_INSTANCE_CALLBACK CallBackFunction,
451 IN VOID *Context
452 )
453 {
454 EFI_STATUS Status;
455 UINTN HandleCount;
456 EFI_HANDLE *HandleBuffer;
457 UINTN Index;
458 VOID *Instance;
459
460 //
461 // Start to check all the PciIo to find all possible device
462 //
463 HandleCount = 0;
464 HandleBuffer = NULL;
465 Status = gBS->LocateHandleBuffer (
466 ByProtocol,
467 Id,
468 NULL,
469 &HandleCount,
470 &HandleBuffer
471 );
472 if (EFI_ERROR (Status)) {
473 return Status;
474 }
475
476 for (Index = 0; Index < HandleCount; Index++) {
477 Status = gBS->HandleProtocol (HandleBuffer[Index], Id, &Instance);
478 if (EFI_ERROR (Status)) {
479 continue;
480 }
481
482 Status = (*CallBackFunction) (
483 HandleBuffer[Index],
484 Instance,
485 Context
486 );
487 }
488
489 gBS->FreePool (HandleBuffer);
490
491 return EFI_SUCCESS;
492 }
493
494
495 EFI_STATUS
496 EFIAPI
497 VisitingAPciInstance (
498 IN EFI_HANDLE Handle,
499 IN VOID *Instance,
500 IN VOID *Context
501 )
502 {
503 EFI_STATUS Status;
504 EFI_PCI_IO_PROTOCOL *PciIo;
505 PCI_TYPE00 Pci;
506
507 PciIo = (EFI_PCI_IO_PROTOCOL*) Instance;
508
509 //
510 // Check for all PCI device
511 //
512 Status = PciIo->Pci.Read (
513 PciIo,
514 EfiPciIoWidthUint32,
515 0,
516 sizeof (Pci) / sizeof (UINT32),
517 &Pci
518 );
519 if (EFI_ERROR (Status)) {
520 return Status;
521 }
522
523 return (*(VISIT_PCI_INSTANCE_CALLBACK)(UINTN) Context) (
524 Handle,
525 PciIo,
526 &Pci
527 );
528
529 }
530
531
532
533 EFI_STATUS
534 VisitAllPciInstances (
535 IN VISIT_PCI_INSTANCE_CALLBACK CallBackFunction
536 )
537 {
538 return VisitAllInstancesOfProtocol (
539 &gEfiPciIoProtocolGuid,
540 VisitingAPciInstance,
541 (VOID*)(UINTN) CallBackFunction
542 );
543 }
544
545
546 /**
547 Do platform specific PCI Device check and add them to
548 ConOut, ConIn, ErrOut.
549
550 @param[in] Handle - Handle of PCI device instance
551 @param[in] PciIo - PCI IO protocol instance
552 @param[in] Pci - PCI Header register block
553
554 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
555 @retval EFI_STATUS - PCI Device check or Console variable update fail.
556
557 **/
558 EFI_STATUS
559 EFIAPI
560 DetectAndPreparePlatformPciDevicePath (
561 IN EFI_HANDLE Handle,
562 IN EFI_PCI_IO_PROTOCOL *PciIo,
563 IN PCI_TYPE00 *Pci
564 )
565 {
566 EFI_STATUS Status;
567
568 Status = PciIo->Attributes (
569 PciIo,
570 EfiPciIoAttributeOperationEnable,
571 EFI_PCI_DEVICE_ENABLE,
572 NULL
573 );
574 ASSERT_EFI_ERROR (Status);
575
576 if (!mDetectVgaOnly) {
577 //
578 // Here we decide whether it is LPC Bridge
579 //
580 if ((IS_PCI_LPC (Pci)) ||
581 ((IS_PCI_ISA_PDECODE (Pci)) &&
582 (Pci->Hdr.VendorId == 0x8086) &&
583 (Pci->Hdr.DeviceId == 0x7000)
584 )
585 ) {
586 //
587 // Add IsaKeyboard to ConIn,
588 // add IsaSerial to ConOut, ConIn, ErrOut
589 //
590 DEBUG ((EFI_D_INFO, "Found LPC Bridge device\n"));
591 PrepareLpcBridgeDevicePath (Handle);
592 return EFI_SUCCESS;
593 }
594 //
595 // Here we decide which Serial device to enable in PCI bus
596 //
597 if (IS_PCI_16550SERIAL (Pci)) {
598 //
599 // Add them to ConOut, ConIn, ErrOut.
600 //
601 DEBUG ((EFI_D_INFO, "Found PCI 16550 SERIAL device\n"));
602 PreparePciSerialDevicePath (Handle);
603 return EFI_SUCCESS;
604 }
605 }
606
607 //
608 // Here we decide which VGA device to enable in PCI bus
609 //
610 if (IS_PCI_VGA (Pci)) {
611 //
612 // Add them to ConOut.
613 //
614 DEBUG ((EFI_D_INFO, "Found PCI VGA device\n"));
615 PreparePciVgaDevicePath (Handle);
616 return EFI_SUCCESS;
617 }
618
619 return Status;
620 }
621
622
623 /**
624 Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
625
626 @param[in] DetectVgaOnly - Only detect VGA device if it's TRUE.
627
628 @retval EFI_SUCCESS - PCI Device check and Console variable update successfully.
629 @retval EFI_STATUS - PCI Device check or Console variable update fail.
630
631 **/
632 EFI_STATUS
633 DetectAndPreparePlatformPciDevicePaths (
634 BOOLEAN DetectVgaOnly
635 )
636 {
637 mDetectVgaOnly = DetectVgaOnly;
638 return VisitAllPciInstances (DetectAndPreparePlatformPciDevicePath);
639 }
640
641
642 EFI_STATUS
643 PlatformBdsConnectConsole (
644 IN BDS_CONSOLE_CONNECT_ENTRY *PlatformConsole
645 )
646 /*++
647
648 Routine Description:
649
650 Connect the predefined platform default console device. Always try to find
651 and enable the vga device if have.
652
653 Arguments:
654
655 PlatformConsole - Predfined platform default console device array.
656
657 Returns:
658
659 EFI_SUCCESS - Success connect at least one ConIn and ConOut
660 device, there must have one ConOut device is
661 active vga device.
662
663 EFI_STATUS - Return the status of
664 BdsLibConnectAllDefaultConsoles ()
665
666 --*/
667 {
668 EFI_STATUS Status;
669 UINTN Index;
670 EFI_DEVICE_PATH_PROTOCOL *VarConout;
671 EFI_DEVICE_PATH_PROTOCOL *VarConin;
672 UINTN DevicePathSize;
673
674 //
675 // Connect RootBridge
676 //
677 VarConout = BdsLibGetVariableAndSize (
678 VarConsoleOut,
679 &gEfiGlobalVariableGuid,
680 &DevicePathSize
681 );
682 VarConin = BdsLibGetVariableAndSize (
683 VarConsoleInp,
684 &gEfiGlobalVariableGuid,
685 &DevicePathSize
686 );
687
688 if (VarConout == NULL || VarConin == NULL) {
689 //
690 // Do platform specific PCI Device check and add them to ConOut, ConIn, ErrOut
691 //
692 DetectAndPreparePlatformPciDevicePaths (FALSE);
693
694 //
695 // Have chance to connect the platform default console,
696 // the platform default console is the minimue device group
697 // the platform should support
698 //
699 for (Index = 0; PlatformConsole[Index].DevicePath != NULL; ++Index) {
700 //
701 // Update the console variable with the connect type
702 //
703 if ((PlatformConsole[Index].ConnectType & CONSOLE_IN) == CONSOLE_IN) {
704 BdsLibUpdateConsoleVariable (VarConsoleInp, PlatformConsole[Index].DevicePath, NULL);
705 }
706 if ((PlatformConsole[Index].ConnectType & CONSOLE_OUT) == CONSOLE_OUT) {
707 BdsLibUpdateConsoleVariable (VarConsoleOut, PlatformConsole[Index].DevicePath, NULL);
708 }
709 if ((PlatformConsole[Index].ConnectType & STD_ERROR) == STD_ERROR) {
710 BdsLibUpdateConsoleVariable (VarErrorOut, PlatformConsole[Index].DevicePath, NULL);
711 }
712 }
713 } else {
714 //
715 // Only detect VGA device and add them to ConOut
716 //
717 DetectAndPreparePlatformPciDevicePaths (TRUE);
718 }
719
720 //
721 // Connect the all the default console with current cosole variable
722 //
723 Status = BdsLibConnectAllDefaultConsoles ();
724 if (EFI_ERROR (Status)) {
725 return Status;
726 }
727
728 return EFI_SUCCESS;
729 }
730
731
732 /**
733 Configure PCI Interrupt Line register for applicable devices
734 Ported from SeaBIOS, src/fw/pciinit.c, *_pci_slot_get_irq()
735
736 @param[in] Handle - Handle of PCI device instance
737 @param[in] PciIo - PCI IO protocol instance
738 @param[in] PciHdr - PCI Header register block
739
740 @retval EFI_SUCCESS - PCI Interrupt Line register configured successfully.
741
742 **/
743 EFI_STATUS
744 EFIAPI
745 SetPciIntLine (
746 IN EFI_HANDLE Handle,
747 IN EFI_PCI_IO_PROTOCOL *PciIo,
748 IN PCI_TYPE00 *PciHdr
749 )
750 {
751 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
752 UINTN RootSlot;
753 UINTN Idx;
754 UINT8 IrqLine;
755 EFI_STATUS Status;
756
757 Status = EFI_SUCCESS;
758
759 if (PciHdr->Device.InterruptPin != 0) {
760
761 DevPathNode = DevicePathFromHandle (Handle);
762 ASSERT (DevPathNode != NULL);
763
764 //
765 // Compute index into PciHostIrqs[] table by walking
766 // the device path and adding up all device numbers
767 //
768 Status = EFI_NOT_FOUND;
769 RootSlot = 0;
770 Idx = PciHdr->Device.InterruptPin - 1;
771 while (!IsDevicePathEnd (DevPathNode)) {
772 if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&
773 DevicePathSubType (DevPathNode) == HW_PCI_DP) {
774
775 Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;
776
777 //
778 // Unlike SeaBIOS, which starts climbing from the leaf device
779 // up toward the root, we traverse the device path starting at
780 // the root moving toward the leaf node.
781 // The slot number of the top-level parent bridge is needed for
782 // Q35 cases with more than 24 slots on the root bus.
783 //
784 if (Status != EFI_SUCCESS) {
785 Status = EFI_SUCCESS;
786 RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;
787 }
788 }
789
790 DevPathNode = NextDevicePathNode (DevPathNode);
791 }
792 if (EFI_ERROR (Status)) {
793 return Status;
794 }
795 if (RootSlot == 0) {
796 DEBUG((
797 EFI_D_ERROR,
798 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
799 __FUNCTION__
800 ));
801 ASSERT (FALSE);
802 }
803
804 //
805 // Final PciHostIrqs[] index calculation depends on the platform
806 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
807 //
808 switch (mHostBridgeDevId) {
809 case INTEL_82441_DEVICE_ID:
810 Idx -= 1;
811 break;
812 case INTEL_Q35_MCH_DEVICE_ID:
813 //
814 // SeaBIOS contains the following comment:
815 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
816 // with a different starting index - see q35-acpi-dsdt.dsl.
817 //
818 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
819 //
820 if (RootSlot > 24) {
821 //
822 // in this case, subtract back out RootSlot from Idx
823 // (SeaBIOS never adds it to begin with, but that would make our
824 // device path traversal loop above too awkward)
825 //
826 Idx -= RootSlot;
827 }
828 break;
829 default:
830 ASSERT (FALSE); // should never get here
831 }
832 Idx %= ARRAY_SIZE (PciHostIrqs);
833 IrqLine = PciHostIrqs[Idx];
834
835 //
836 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
837 //
838 Status = PciIo->Pci.Write (
839 PciIo,
840 EfiPciIoWidthUint8,
841 PCI_INT_LINE_OFFSET,
842 1,
843 &IrqLine
844 );
845 }
846
847 return Status;
848 }
849
850
851 VOID
852 PciAcpiInitialization (
853 )
854 {
855 UINTN Pmba;
856
857 //
858 // Query Host Bridge DID to determine platform type
859 //
860 mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
861 switch (mHostBridgeDevId) {
862 case INTEL_82441_DEVICE_ID:
863 Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
864 //
865 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
866 //
867 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
868 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
869 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
870 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
871 break;
872 case INTEL_Q35_MCH_DEVICE_ID:
873 Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
874 //
875 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
876 //
877 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
878 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
879 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
880 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
881 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
882 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
883 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
884 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
885 break;
886 default:
887 DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
888 __FUNCTION__, mHostBridgeDevId));
889 ASSERT (FALSE);
890 return;
891 }
892
893 //
894 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
895 //
896 VisitAllPciInstances (SetPciIntLine);
897
898 //
899 // Set ACPI SCI_EN bit in PMCNTRL
900 //
901 IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);
902 }
903
904
905 EFI_STATUS
906 EFIAPI
907 ConnectRecursivelyIfPciMassStorage (
908 IN EFI_HANDLE Handle,
909 IN EFI_PCI_IO_PROTOCOL *Instance,
910 IN PCI_TYPE00 *PciHeader
911 )
912 {
913 EFI_STATUS Status;
914 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
915 CHAR16 *DevPathStr;
916
917 if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE)) {
918 DevicePath = NULL;
919 Status = gBS->HandleProtocol (
920 Handle,
921 &gEfiDevicePathProtocolGuid,
922 (VOID*)&DevicePath
923 );
924 if (EFI_ERROR (Status)) {
925 return Status;
926 }
927
928 //
929 // Print Device Path
930 //
931 DevPathStr = DevicePathToStr (DevicePath);
932 if (DevPathStr != NULL) {
933 DEBUG((
934 EFI_D_INFO,
935 "Found Mass Storage device: %s\n",
936 DevPathStr
937 ));
938 FreePool(DevPathStr);
939 }
940
941 Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);
942 if (EFI_ERROR (Status)) {
943 return Status;
944 }
945
946 }
947
948 return EFI_SUCCESS;
949 }
950
951
952 /**
953 This notification function is invoked when the
954 EMU Variable FVB has been changed.
955
956 @param Event The event that occured
957 @param Context For EFI compatiblity. Not used.
958
959 **/
960 VOID
961 EFIAPI
962 EmuVariablesUpdatedCallback (
963 IN EFI_EVENT Event,
964 IN VOID *Context
965 )
966 {
967 DEBUG ((EFI_D_INFO, "EmuVariablesUpdatedCallback\n"));
968 UpdateNvVarsOnFileSystem ();
969 }
970
971
972 EFI_STATUS
973 EFIAPI
974 VisitingFileSystemInstance (
975 IN EFI_HANDLE Handle,
976 IN VOID *Instance,
977 IN VOID *Context
978 )
979 {
980 EFI_STATUS Status;
981 STATIC BOOLEAN ConnectedToFileSystem = FALSE;
982
983 if (ConnectedToFileSystem) {
984 return EFI_ALREADY_STARTED;
985 }
986
987 Status = ConnectNvVarsToFileSystem (Handle);
988 if (EFI_ERROR (Status)) {
989 return Status;
990 }
991
992 ConnectedToFileSystem = TRUE;
993 mEmuVariableEvent =
994 EfiCreateProtocolNotifyEvent (
995 &gEfiDevicePathProtocolGuid,
996 TPL_CALLBACK,
997 EmuVariablesUpdatedCallback,
998 NULL,
999 &mEmuVariableEventReg
1000 );
1001 PcdSet64 (PcdEmuVariableEvent, (UINT64)(UINTN) mEmuVariableEvent);
1002
1003 return EFI_SUCCESS;
1004 }
1005
1006
1007 VOID
1008 PlatformBdsRestoreNvVarsFromHardDisk (
1009 )
1010 {
1011 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage);
1012 VisitAllInstancesOfProtocol (
1013 &gEfiSimpleFileSystemProtocolGuid,
1014 VisitingFileSystemInstance,
1015 NULL
1016 );
1017
1018 }
1019
1020
1021 VOID
1022 PlatformBdsConnectSequence (
1023 VOID
1024 )
1025 /*++
1026
1027 Routine Description:
1028
1029 Connect with predeined platform connect sequence,
1030 the OEM/IBV can customize with their own connect sequence.
1031
1032 Arguments:
1033
1034 None.
1035
1036 Returns:
1037
1038 None.
1039
1040 --*/
1041 {
1042 UINTN Index;
1043
1044 DEBUG ((EFI_D_INFO, "PlatformBdsConnectSequence\n"));
1045
1046 Index = 0;
1047
1048 //
1049 // Here we can get the customized platform connect sequence
1050 // Notes: we can connect with new variable which record the
1051 // last time boots connect device path sequence
1052 //
1053 while (gPlatformConnectSequence[Index] != NULL) {
1054 //
1055 // Build the platform boot option
1056 //
1057 BdsLibConnectDevicePath (gPlatformConnectSequence[Index]);
1058 Index++;
1059 }
1060
1061 //
1062 // Just use the simple policy to connect all devices
1063 //
1064 BdsLibConnectAll ();
1065
1066 PciAcpiInitialization ();
1067
1068 //
1069 // Clear the logo after all devices are connected.
1070 //
1071 gST->ConOut->ClearScreen (gST->ConOut);
1072 }
1073
1074 VOID
1075 PlatformBdsGetDriverOption (
1076 IN OUT LIST_ENTRY *BdsDriverLists
1077 )
1078 /*++
1079
1080 Routine Description:
1081
1082 Load the predefined driver option, OEM/IBV can customize this
1083 to load their own drivers
1084
1085 Arguments:
1086
1087 BdsDriverLists - The header of the driver option link list.
1088
1089 Returns:
1090
1091 None.
1092
1093 --*/
1094 {
1095 DEBUG ((EFI_D_INFO, "PlatformBdsGetDriverOption\n"));
1096 return;
1097 }
1098
1099 VOID
1100 PlatformBdsDiagnostics (
1101 IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel,
1102 IN BOOLEAN QuietBoot,
1103 IN BASEM_MEMORY_TEST BaseMemoryTest
1104 )
1105 /*++
1106
1107 Routine Description:
1108
1109 Perform the platform diagnostic, such like test memory. OEM/IBV also
1110 can customize this fuction to support specific platform diagnostic.
1111
1112 Arguments:
1113
1114 MemoryTestLevel - The memory test intensive level
1115
1116 QuietBoot - Indicate if need to enable the quiet boot
1117
1118 BaseMemoryTest - A pointer to BaseMemoryTest()
1119
1120 Returns:
1121
1122 None.
1123
1124 --*/
1125 {
1126 EFI_STATUS Status;
1127
1128 DEBUG ((EFI_D_INFO, "PlatformBdsDiagnostics\n"));
1129
1130 //
1131 // Here we can decide if we need to show
1132 // the diagnostics screen
1133 // Notes: this quiet boot code should be remove
1134 // from the graphic lib
1135 //
1136 if (QuietBoot) {
1137 EnableQuietBoot (PcdGetPtr(PcdLogoFile));
1138 //
1139 // Perform system diagnostic
1140 //
1141 Status = BaseMemoryTest (MemoryTestLevel);
1142 if (EFI_ERROR (Status)) {
1143 DisableQuietBoot ();
1144 }
1145
1146 return ;
1147 }
1148 //
1149 // Perform system diagnostic
1150 //
1151 Status = BaseMemoryTest (MemoryTestLevel);
1152 }
1153
1154
1155 VOID
1156 EFIAPI
1157 PlatformBdsPolicyBehavior (
1158 IN OUT LIST_ENTRY *DriverOptionList,
1159 IN OUT LIST_ENTRY *BootOptionList,
1160 IN PROCESS_CAPSULES ProcessCapsules,
1161 IN BASEM_MEMORY_TEST BaseMemoryTest
1162 )
1163 /*++
1164
1165 Routine Description:
1166
1167 The function will excute with as the platform policy, current policy
1168 is driven by boot mode. IBV/OEM can customize this code for their specific
1169 policy action.
1170
1171 Arguments:
1172
1173 DriverOptionList - The header of the driver option link list
1174
1175 BootOptionList - The header of the boot option link list
1176
1177 ProcessCapsules - A pointer to ProcessCapsules()
1178
1179 BaseMemoryTest - A pointer to BaseMemoryTest()
1180
1181 Returns:
1182
1183 None.
1184
1185 --*/
1186 {
1187 EFI_STATUS Status;
1188 EFI_BOOT_MODE BootMode;
1189
1190 DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior\n"));
1191
1192 ConnectRootBridge ();
1193
1194 if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {
1195 DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars "
1196 "from disk since flash variables appear to be supported.\n"));
1197 } else {
1198 //
1199 // Try to restore variables from the hard disk early so
1200 // they can be used for the other BDS connect operations.
1201 //
1202 PlatformBdsRestoreNvVarsFromHardDisk ();
1203 }
1204
1205 //
1206 // Load the driver option as the driver option list
1207 //
1208 PlatformBdsGetDriverOption (DriverOptionList);
1209
1210 //
1211 // Get current Boot Mode
1212 //
1213 Status = BdsLibGetBootMode (&BootMode);
1214 DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", BootMode));
1215
1216 //
1217 // Go the different platform policy with different boot mode
1218 // Notes: this part code can be change with the table policy
1219 //
1220 ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);
1221 //
1222 // Connect platform console
1223 //
1224 Status = PlatformBdsConnectConsole (gPlatformConsole);
1225 if (EFI_ERROR (Status)) {
1226 //
1227 // Here OEM/IBV can customize with defined action
1228 //
1229 PlatformBdsNoConsoleAction ();
1230 }
1231
1232 //
1233 // Memory test and Logo show
1234 //
1235 PlatformBdsDiagnostics (IGNORE, TRUE, BaseMemoryTest);
1236
1237 //
1238 // Perform some platform specific connect sequence
1239 //
1240 PlatformBdsConnectSequence ();
1241
1242 //
1243 // Process QEMU's -kernel command line option
1244 //
1245 TryRunningQemuKernel ();
1246
1247 DEBUG ((EFI_D_INFO, "BdsLibConnectAll\n"));
1248 BdsLibConnectAll ();
1249 BdsLibEnumerateAllBootOption (BootOptionList);
1250
1251 SetBootOrderFromQemu (BootOptionList);
1252 //
1253 // The BootOrder variable may have changed, reload the in-memory list with
1254 // it.
1255 //
1256 BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder");
1257
1258 PlatformBdsEnterFrontPage (GetFrontPageTimeoutFromQemu(), TRUE);
1259 }
1260
1261 VOID
1262 EFIAPI
1263 PlatformBdsBootSuccess (
1264 IN BDS_COMMON_OPTION *Option
1265 )
1266 /*++
1267
1268 Routine Description:
1269
1270 Hook point after a boot attempt succeeds. We don't expect a boot option to
1271 return, so the EFI 1.0 specification defines that you will default to an
1272 interactive mode and stop processing the BootOrder list in this case. This
1273 is alos a platform implementation and can be customized by IBV/OEM.
1274
1275 Arguments:
1276
1277 Option - Pointer to Boot Option that succeeded to boot.
1278
1279 Returns:
1280
1281 None.
1282
1283 --*/
1284 {
1285 CHAR16 *TmpStr;
1286
1287 DEBUG ((EFI_D_INFO, "PlatformBdsBootSuccess\n"));
1288 //
1289 // If Boot returned with EFI_SUCCESS and there is not in the boot device
1290 // select loop then we need to pop up a UI and wait for user input.
1291 //
1292 TmpStr = Option->StatusString;
1293 if (TmpStr != NULL) {
1294 BdsLibOutputStrings (gST->ConOut, TmpStr, Option->Description, L"\n\r", NULL);
1295 FreePool (TmpStr);
1296 }
1297 }
1298
1299 VOID
1300 EFIAPI
1301 PlatformBdsBootFail (
1302 IN BDS_COMMON_OPTION *Option,
1303 IN EFI_STATUS Status,
1304 IN CHAR16 *ExitData,
1305 IN UINTN ExitDataSize
1306 )
1307 /*++
1308
1309 Routine Description:
1310
1311 Hook point after a boot attempt fails.
1312
1313 Arguments:
1314
1315 Option - Pointer to Boot Option that failed to boot.
1316
1317 Status - Status returned from failed boot.
1318
1319 ExitData - Exit data returned from failed boot.
1320
1321 ExitDataSize - Exit data size returned from failed boot.
1322
1323 Returns:
1324
1325 None.
1326
1327 --*/
1328 {
1329 CHAR16 *TmpStr;
1330
1331 DEBUG ((EFI_D_INFO, "PlatformBdsBootFail\n"));
1332
1333 //
1334 // If Boot returned with failed status then we need to pop up a UI and wait
1335 // for user input.
1336 //
1337 TmpStr = Option->StatusString;
1338 if (TmpStr != NULL) {
1339 BdsLibOutputStrings (gST->ConOut, TmpStr, Option->Description, L"\n\r", NULL);
1340 FreePool (TmpStr);
1341 }
1342 }
1343
1344 EFI_STATUS
1345 PlatformBdsNoConsoleAction (
1346 VOID
1347 )
1348 /*++
1349
1350 Routine Description:
1351
1352 This function is remained for IBV/OEM to do some platform action,
1353 if there no console device can be connected.
1354
1355 Arguments:
1356
1357 None.
1358
1359 Returns:
1360
1361 EFI_SUCCESS - Direct return success now.
1362
1363 --*/
1364 {
1365 DEBUG ((EFI_D_INFO, "PlatformBdsNoConsoleAction\n"));
1366 return EFI_SUCCESS;
1367 }
1368
1369 VOID
1370 EFIAPI
1371 PlatformBdsLockNonUpdatableFlash (
1372 VOID
1373 )
1374 {
1375 DEBUG ((EFI_D_INFO, "PlatformBdsLockNonUpdatableFlash\n"));
1376 return;
1377 }
1378
1379
1380 /**
1381 This notification function is invoked when an instance of the
1382 EFI_DEVICE_PATH_PROTOCOL is produced.
1383
1384 @param Event The event that occured
1385 @param Context For EFI compatiblity. Not used.
1386
1387 **/
1388 VOID
1389 EFIAPI
1390 NotifyDevPath (
1391 IN EFI_EVENT Event,
1392 IN VOID *Context
1393 )
1394 {
1395 EFI_HANDLE Handle;
1396 EFI_STATUS Status;
1397 UINTN BufferSize;
1398 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
1399 ATAPI_DEVICE_PATH *Atapi;
1400
1401 //
1402 // Examine all new handles
1403 //
1404 for (;;) {
1405 //
1406 // Get the next handle
1407 //
1408 BufferSize = sizeof (Handle);
1409 Status = gBS->LocateHandle (
1410 ByRegisterNotify,
1411 NULL,
1412 mEfiDevPathNotifyReg,
1413 &BufferSize,
1414 &Handle
1415 );
1416
1417 //
1418 // If not found, we're done
1419 //
1420 if (EFI_NOT_FOUND == Status) {
1421 break;
1422 }
1423
1424 if (EFI_ERROR (Status)) {
1425 continue;
1426 }
1427
1428 //
1429 // Get the DevicePath protocol on that handle
1430 //
1431 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevPathNode);
1432 ASSERT_EFI_ERROR (Status);
1433
1434 while (!IsDevicePathEnd (DevPathNode)) {
1435 //
1436 // Find the handler to dump this device path node
1437 //
1438 if (
1439 (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&
1440 (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)
1441 ) {
1442 Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;
1443 PciOr16 (
1444 PCI_LIB_ADDRESS (
1445 0,
1446 1,
1447 1,
1448 (Atapi->PrimarySecondary == 1) ? 0x42: 0x40
1449 ),
1450 BIT15
1451 );
1452 }
1453
1454 //
1455 // Next device path node
1456 //
1457 DevPathNode = NextDevicePathNode (DevPathNode);
1458 }
1459 }
1460
1461 return;
1462 }
1463
1464
1465 VOID
1466 InstallDevicePathCallback (
1467 VOID
1468 )
1469 {
1470 DEBUG ((EFI_D_INFO, "Registered NotifyDevPath Event\n"));
1471 mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (
1472 &gEfiDevicePathProtocolGuid,
1473 TPL_CALLBACK,
1474 NotifyDevPath,
1475 NULL,
1476 &mEfiDevPathNotifyReg
1477 );
1478 }
1479
1480 /**
1481 Lock the ConsoleIn device in system table. All key
1482 presses will be ignored until the Password is typed in. The only way to
1483 disable the password is to type it in to a ConIn device.
1484
1485 @param Password Password used to lock ConIn device.
1486
1487 @retval EFI_SUCCESS lock the Console In Spliter virtual handle successfully.
1488 @retval EFI_UNSUPPORTED Password not found
1489
1490 **/
1491 EFI_STATUS
1492 EFIAPI
1493 LockKeyboards (
1494 IN CHAR16 *Password
1495 )
1496 {
1497 return EFI_UNSUPPORTED;
1498 }
1499