]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c
fdae6b1cdcec9b36dcb5630dae734798cd2c1b7e
[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 EFI_DEVICE_PATH_PROTOCOL *DevPath;
753 UINTN RootSlot;
754 UINTN Idx;
755 UINT8 IrqLine;
756 EFI_STATUS Status;
757
758 Status = EFI_SUCCESS;
759
760 if (PciHdr->Device.InterruptPin != 0) {
761
762 DevPathNode = DevicePathFromHandle (Handle);
763 ASSERT (DevPathNode != NULL);
764 DevPath = DevPathNode;
765
766 //
767 // Compute index into PciHostIrqs[] table by walking
768 // the device path and adding up all device numbers
769 //
770 Status = EFI_NOT_FOUND;
771 RootSlot = 0;
772 Idx = PciHdr->Device.InterruptPin - 1;
773 while (!IsDevicePathEnd (DevPathNode)) {
774 if (DevicePathType (DevPathNode) == HARDWARE_DEVICE_PATH &&
775 DevicePathSubType (DevPathNode) == HW_PCI_DP) {
776
777 Idx += ((PCI_DEVICE_PATH *)DevPathNode)->Device;
778
779 //
780 // Unlike SeaBIOS, which starts climbing from the leaf device
781 // up toward the root, we traverse the device path starting at
782 // the root moving toward the leaf node.
783 // The slot number of the top-level parent bridge is needed for
784 // Q35 cases with more than 24 slots on the root bus.
785 //
786 if (Status != EFI_SUCCESS) {
787 Status = EFI_SUCCESS;
788 RootSlot = ((PCI_DEVICE_PATH *)DevPathNode)->Device;
789 }
790 }
791
792 DevPathNode = NextDevicePathNode (DevPathNode);
793 }
794 if (EFI_ERROR (Status)) {
795 return Status;
796 }
797 if (RootSlot == 0) {
798 DEBUG((
799 EFI_D_ERROR,
800 "%a: PCI host bridge (00:00.0) should have no interrupts!\n",
801 __FUNCTION__
802 ));
803 ASSERT (FALSE);
804 }
805
806 //
807 // Final PciHostIrqs[] index calculation depends on the platform
808 // and should match SeaBIOS src/fw/pciinit.c *_pci_slot_get_irq()
809 //
810 switch (mHostBridgeDevId) {
811 case INTEL_82441_DEVICE_ID:
812 Idx -= 1;
813 break;
814 case INTEL_Q35_MCH_DEVICE_ID:
815 //
816 // SeaBIOS contains the following comment:
817 // "Slots 0-24 rotate slot:pin mapping similar to piix above, but
818 // with a different starting index - see q35-acpi-dsdt.dsl.
819 //
820 // Slots 25-31 all use LNKA mapping (or LNKE, but A:D = E:H)"
821 //
822 if (RootSlot > 24) {
823 //
824 // in this case, subtract back out RootSlot from Idx
825 // (SeaBIOS never adds it to begin with, but that would make our
826 // device path traversal loop above too awkward)
827 //
828 Idx -= RootSlot;
829 }
830 break;
831 default:
832 ASSERT (FALSE); // should never get here
833 }
834 Idx %= ARRAY_SIZE (PciHostIrqs);
835 IrqLine = PciHostIrqs[Idx];
836
837 DEBUG_CODE_BEGIN ();
838 {
839 CHAR16 *DevPathString;
840 STATIC CHAR16 Fallback[] = L"<failed to convert>";
841 UINTN Segment, Bus, Device, Function;
842
843 DevPathString = ConvertDevicePathToText (DevPath, FALSE, FALSE);
844 if (DevPathString == NULL) {
845 DevPathString = Fallback;
846 }
847 Status = PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
848 ASSERT_EFI_ERROR (Status);
849
850 DEBUG ((EFI_D_VERBOSE, "%a: [%02x:%02x.%x] %s -> 0x%02x\n", __FUNCTION__,
851 (UINT32)Bus, (UINT32)Device, (UINT32)Function, DevPathString,
852 IrqLine));
853
854 if (DevPathString != Fallback) {
855 FreePool (DevPathString);
856 }
857 }
858 DEBUG_CODE_END ();
859
860 //
861 // Set PCI Interrupt Line register for this device to PciHostIrqs[Idx]
862 //
863 Status = PciIo->Pci.Write (
864 PciIo,
865 EfiPciIoWidthUint8,
866 PCI_INT_LINE_OFFSET,
867 1,
868 &IrqLine
869 );
870 }
871
872 return Status;
873 }
874
875
876 VOID
877 PciAcpiInitialization (
878 )
879 {
880 UINTN Pmba;
881
882 //
883 // Query Host Bridge DID to determine platform type
884 //
885 mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
886 switch (mHostBridgeDevId) {
887 case INTEL_82441_DEVICE_ID:
888 Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
889 //
890 // 00:01.0 ISA Bridge (PIIX4) LNK routing targets
891 //
892 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), 0x0b); // A
893 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), 0x0b); // B
894 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), 0x0a); // C
895 PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), 0x0a); // D
896 break;
897 case INTEL_Q35_MCH_DEVICE_ID:
898 Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
899 //
900 // 00:1f.0 LPC Bridge (Q35) LNK routing targets
901 //
902 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), 0x0a); // A
903 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), 0x0a); // B
904 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), 0x0b); // C
905 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), 0x0b); // D
906 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), 0x0a); // E
907 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), 0x0a); // F
908 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), 0x0b); // G
909 PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), 0x0b); // H
910 break;
911 default:
912 DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
913 __FUNCTION__, mHostBridgeDevId));
914 ASSERT (FALSE);
915 return;
916 }
917
918 //
919 // Initialize PCI_INTERRUPT_LINE for applicable present PCI devices
920 //
921 VisitAllPciInstances (SetPciIntLine);
922
923 //
924 // Set ACPI SCI_EN bit in PMCNTRL
925 //
926 IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);
927 }
928
929
930 EFI_STATUS
931 EFIAPI
932 ConnectRecursivelyIfPciMassStorage (
933 IN EFI_HANDLE Handle,
934 IN EFI_PCI_IO_PROTOCOL *Instance,
935 IN PCI_TYPE00 *PciHeader
936 )
937 {
938 EFI_STATUS Status;
939 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
940 CHAR16 *DevPathStr;
941
942 if (IS_CLASS1 (PciHeader, PCI_CLASS_MASS_STORAGE)) {
943 DevicePath = NULL;
944 Status = gBS->HandleProtocol (
945 Handle,
946 &gEfiDevicePathProtocolGuid,
947 (VOID*)&DevicePath
948 );
949 if (EFI_ERROR (Status)) {
950 return Status;
951 }
952
953 //
954 // Print Device Path
955 //
956 DevPathStr = DevicePathToStr (DevicePath);
957 if (DevPathStr != NULL) {
958 DEBUG((
959 EFI_D_INFO,
960 "Found Mass Storage device: %s\n",
961 DevPathStr
962 ));
963 FreePool(DevPathStr);
964 }
965
966 Status = gBS->ConnectController (Handle, NULL, NULL, TRUE);
967 if (EFI_ERROR (Status)) {
968 return Status;
969 }
970
971 }
972
973 return EFI_SUCCESS;
974 }
975
976
977 /**
978 This notification function is invoked when the
979 EMU Variable FVB has been changed.
980
981 @param Event The event that occured
982 @param Context For EFI compatiblity. Not used.
983
984 **/
985 VOID
986 EFIAPI
987 EmuVariablesUpdatedCallback (
988 IN EFI_EVENT Event,
989 IN VOID *Context
990 )
991 {
992 DEBUG ((EFI_D_INFO, "EmuVariablesUpdatedCallback\n"));
993 UpdateNvVarsOnFileSystem ();
994 }
995
996
997 EFI_STATUS
998 EFIAPI
999 VisitingFileSystemInstance (
1000 IN EFI_HANDLE Handle,
1001 IN VOID *Instance,
1002 IN VOID *Context
1003 )
1004 {
1005 EFI_STATUS Status;
1006 STATIC BOOLEAN ConnectedToFileSystem = FALSE;
1007
1008 if (ConnectedToFileSystem) {
1009 return EFI_ALREADY_STARTED;
1010 }
1011
1012 Status = ConnectNvVarsToFileSystem (Handle);
1013 if (EFI_ERROR (Status)) {
1014 return Status;
1015 }
1016
1017 ConnectedToFileSystem = TRUE;
1018 mEmuVariableEvent =
1019 EfiCreateProtocolNotifyEvent (
1020 &gEfiDevicePathProtocolGuid,
1021 TPL_CALLBACK,
1022 EmuVariablesUpdatedCallback,
1023 NULL,
1024 &mEmuVariableEventReg
1025 );
1026 PcdSet64 (PcdEmuVariableEvent, (UINT64)(UINTN) mEmuVariableEvent);
1027
1028 return EFI_SUCCESS;
1029 }
1030
1031
1032 VOID
1033 PlatformBdsRestoreNvVarsFromHardDisk (
1034 )
1035 {
1036 VisitAllPciInstances (ConnectRecursivelyIfPciMassStorage);
1037 VisitAllInstancesOfProtocol (
1038 &gEfiSimpleFileSystemProtocolGuid,
1039 VisitingFileSystemInstance,
1040 NULL
1041 );
1042
1043 }
1044
1045
1046 VOID
1047 PlatformBdsConnectSequence (
1048 VOID
1049 )
1050 /*++
1051
1052 Routine Description:
1053
1054 Connect with predeined platform connect sequence,
1055 the OEM/IBV can customize with their own connect sequence.
1056
1057 Arguments:
1058
1059 None.
1060
1061 Returns:
1062
1063 None.
1064
1065 --*/
1066 {
1067 UINTN Index;
1068
1069 DEBUG ((EFI_D_INFO, "PlatformBdsConnectSequence\n"));
1070
1071 Index = 0;
1072
1073 //
1074 // Here we can get the customized platform connect sequence
1075 // Notes: we can connect with new variable which record the
1076 // last time boots connect device path sequence
1077 //
1078 while (gPlatformConnectSequence[Index] != NULL) {
1079 //
1080 // Build the platform boot option
1081 //
1082 BdsLibConnectDevicePath (gPlatformConnectSequence[Index]);
1083 Index++;
1084 }
1085
1086 //
1087 // Just use the simple policy to connect all devices
1088 //
1089 BdsLibConnectAll ();
1090
1091 PciAcpiInitialization ();
1092
1093 //
1094 // Clear the logo after all devices are connected.
1095 //
1096 gST->ConOut->ClearScreen (gST->ConOut);
1097 }
1098
1099 VOID
1100 PlatformBdsGetDriverOption (
1101 IN OUT LIST_ENTRY *BdsDriverLists
1102 )
1103 /*++
1104
1105 Routine Description:
1106
1107 Load the predefined driver option, OEM/IBV can customize this
1108 to load their own drivers
1109
1110 Arguments:
1111
1112 BdsDriverLists - The header of the driver option link list.
1113
1114 Returns:
1115
1116 None.
1117
1118 --*/
1119 {
1120 DEBUG ((EFI_D_INFO, "PlatformBdsGetDriverOption\n"));
1121 return;
1122 }
1123
1124 VOID
1125 PlatformBdsDiagnostics (
1126 IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel,
1127 IN BOOLEAN QuietBoot,
1128 IN BASEM_MEMORY_TEST BaseMemoryTest
1129 )
1130 /*++
1131
1132 Routine Description:
1133
1134 Perform the platform diagnostic, such like test memory. OEM/IBV also
1135 can customize this fuction to support specific platform diagnostic.
1136
1137 Arguments:
1138
1139 MemoryTestLevel - The memory test intensive level
1140
1141 QuietBoot - Indicate if need to enable the quiet boot
1142
1143 BaseMemoryTest - A pointer to BaseMemoryTest()
1144
1145 Returns:
1146
1147 None.
1148
1149 --*/
1150 {
1151 EFI_STATUS Status;
1152
1153 DEBUG ((EFI_D_INFO, "PlatformBdsDiagnostics\n"));
1154
1155 //
1156 // Here we can decide if we need to show
1157 // the diagnostics screen
1158 // Notes: this quiet boot code should be remove
1159 // from the graphic lib
1160 //
1161 if (QuietBoot) {
1162 EnableQuietBoot (PcdGetPtr(PcdLogoFile));
1163 //
1164 // Perform system diagnostic
1165 //
1166 Status = BaseMemoryTest (MemoryTestLevel);
1167 if (EFI_ERROR (Status)) {
1168 DisableQuietBoot ();
1169 }
1170
1171 return ;
1172 }
1173 //
1174 // Perform system diagnostic
1175 //
1176 Status = BaseMemoryTest (MemoryTestLevel);
1177 }
1178
1179
1180 VOID
1181 EFIAPI
1182 PlatformBdsPolicyBehavior (
1183 IN OUT LIST_ENTRY *DriverOptionList,
1184 IN OUT LIST_ENTRY *BootOptionList,
1185 IN PROCESS_CAPSULES ProcessCapsules,
1186 IN BASEM_MEMORY_TEST BaseMemoryTest
1187 )
1188 /*++
1189
1190 Routine Description:
1191
1192 The function will excute with as the platform policy, current policy
1193 is driven by boot mode. IBV/OEM can customize this code for their specific
1194 policy action.
1195
1196 Arguments:
1197
1198 DriverOptionList - The header of the driver option link list
1199
1200 BootOptionList - The header of the boot option link list
1201
1202 ProcessCapsules - A pointer to ProcessCapsules()
1203
1204 BaseMemoryTest - A pointer to BaseMemoryTest()
1205
1206 Returns:
1207
1208 None.
1209
1210 --*/
1211 {
1212 EFI_STATUS Status;
1213 EFI_BOOT_MODE BootMode;
1214
1215 DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior\n"));
1216
1217 ConnectRootBridge ();
1218
1219 if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {
1220 DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars "
1221 "from disk since flash variables appear to be supported.\n"));
1222 } else {
1223 //
1224 // Try to restore variables from the hard disk early so
1225 // they can be used for the other BDS connect operations.
1226 //
1227 PlatformBdsRestoreNvVarsFromHardDisk ();
1228 }
1229
1230 //
1231 // Load the driver option as the driver option list
1232 //
1233 PlatformBdsGetDriverOption (DriverOptionList);
1234
1235 //
1236 // Get current Boot Mode
1237 //
1238 Status = BdsLibGetBootMode (&BootMode);
1239 DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", BootMode));
1240
1241 //
1242 // Go the different platform policy with different boot mode
1243 // Notes: this part code can be change with the table policy
1244 //
1245 ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);
1246 //
1247 // Connect platform console
1248 //
1249 Status = PlatformBdsConnectConsole (gPlatformConsole);
1250 if (EFI_ERROR (Status)) {
1251 //
1252 // Here OEM/IBV can customize with defined action
1253 //
1254 PlatformBdsNoConsoleAction ();
1255 }
1256
1257 //
1258 // Memory test and Logo show
1259 //
1260 PlatformBdsDiagnostics (IGNORE, TRUE, BaseMemoryTest);
1261
1262 //
1263 // Perform some platform specific connect sequence
1264 //
1265 PlatformBdsConnectSequence ();
1266
1267 //
1268 // Process QEMU's -kernel command line option
1269 //
1270 TryRunningQemuKernel ();
1271
1272 DEBUG ((EFI_D_INFO, "BdsLibConnectAll\n"));
1273 BdsLibConnectAll ();
1274 BdsLibEnumerateAllBootOption (BootOptionList);
1275
1276 SetBootOrderFromQemu (BootOptionList);
1277 //
1278 // The BootOrder variable may have changed, reload the in-memory list with
1279 // it.
1280 //
1281 BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder");
1282
1283 PlatformBdsEnterFrontPage (GetFrontPageTimeoutFromQemu(), TRUE);
1284 }
1285
1286 VOID
1287 EFIAPI
1288 PlatformBdsBootSuccess (
1289 IN BDS_COMMON_OPTION *Option
1290 )
1291 /*++
1292
1293 Routine Description:
1294
1295 Hook point after a boot attempt succeeds. We don't expect a boot option to
1296 return, so the EFI 1.0 specification defines that you will default to an
1297 interactive mode and stop processing the BootOrder list in this case. This
1298 is alos a platform implementation and can be customized by IBV/OEM.
1299
1300 Arguments:
1301
1302 Option - Pointer to Boot Option that succeeded to boot.
1303
1304 Returns:
1305
1306 None.
1307
1308 --*/
1309 {
1310 CHAR16 *TmpStr;
1311
1312 DEBUG ((EFI_D_INFO, "PlatformBdsBootSuccess\n"));
1313 //
1314 // If Boot returned with EFI_SUCCESS and there is not in the boot device
1315 // select loop then we need to pop up a UI and wait for user input.
1316 //
1317 TmpStr = Option->StatusString;
1318 if (TmpStr != NULL) {
1319 BdsLibOutputStrings (gST->ConOut, TmpStr, Option->Description, L"\n\r", NULL);
1320 FreePool (TmpStr);
1321 }
1322 }
1323
1324 VOID
1325 EFIAPI
1326 PlatformBdsBootFail (
1327 IN BDS_COMMON_OPTION *Option,
1328 IN EFI_STATUS Status,
1329 IN CHAR16 *ExitData,
1330 IN UINTN ExitDataSize
1331 )
1332 /*++
1333
1334 Routine Description:
1335
1336 Hook point after a boot attempt fails.
1337
1338 Arguments:
1339
1340 Option - Pointer to Boot Option that failed to boot.
1341
1342 Status - Status returned from failed boot.
1343
1344 ExitData - Exit data returned from failed boot.
1345
1346 ExitDataSize - Exit data size returned from failed boot.
1347
1348 Returns:
1349
1350 None.
1351
1352 --*/
1353 {
1354 CHAR16 *TmpStr;
1355
1356 DEBUG ((EFI_D_INFO, "PlatformBdsBootFail\n"));
1357
1358 //
1359 // If Boot returned with failed status then we need to pop up a UI and wait
1360 // for user input.
1361 //
1362 TmpStr = Option->StatusString;
1363 if (TmpStr != NULL) {
1364 BdsLibOutputStrings (gST->ConOut, TmpStr, Option->Description, L"\n\r", NULL);
1365 FreePool (TmpStr);
1366 }
1367 }
1368
1369 EFI_STATUS
1370 PlatformBdsNoConsoleAction (
1371 VOID
1372 )
1373 /*++
1374
1375 Routine Description:
1376
1377 This function is remained for IBV/OEM to do some platform action,
1378 if there no console device can be connected.
1379
1380 Arguments:
1381
1382 None.
1383
1384 Returns:
1385
1386 EFI_SUCCESS - Direct return success now.
1387
1388 --*/
1389 {
1390 DEBUG ((EFI_D_INFO, "PlatformBdsNoConsoleAction\n"));
1391 return EFI_SUCCESS;
1392 }
1393
1394 VOID
1395 EFIAPI
1396 PlatformBdsLockNonUpdatableFlash (
1397 VOID
1398 )
1399 {
1400 DEBUG ((EFI_D_INFO, "PlatformBdsLockNonUpdatableFlash\n"));
1401 return;
1402 }
1403
1404
1405 /**
1406 This notification function is invoked when an instance of the
1407 EFI_DEVICE_PATH_PROTOCOL is produced.
1408
1409 @param Event The event that occured
1410 @param Context For EFI compatiblity. Not used.
1411
1412 **/
1413 VOID
1414 EFIAPI
1415 NotifyDevPath (
1416 IN EFI_EVENT Event,
1417 IN VOID *Context
1418 )
1419 {
1420 EFI_HANDLE Handle;
1421 EFI_STATUS Status;
1422 UINTN BufferSize;
1423 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
1424 ATAPI_DEVICE_PATH *Atapi;
1425
1426 //
1427 // Examine all new handles
1428 //
1429 for (;;) {
1430 //
1431 // Get the next handle
1432 //
1433 BufferSize = sizeof (Handle);
1434 Status = gBS->LocateHandle (
1435 ByRegisterNotify,
1436 NULL,
1437 mEfiDevPathNotifyReg,
1438 &BufferSize,
1439 &Handle
1440 );
1441
1442 //
1443 // If not found, we're done
1444 //
1445 if (EFI_NOT_FOUND == Status) {
1446 break;
1447 }
1448
1449 if (EFI_ERROR (Status)) {
1450 continue;
1451 }
1452
1453 //
1454 // Get the DevicePath protocol on that handle
1455 //
1456 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevPathNode);
1457 ASSERT_EFI_ERROR (Status);
1458
1459 while (!IsDevicePathEnd (DevPathNode)) {
1460 //
1461 // Find the handler to dump this device path node
1462 //
1463 if (
1464 (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&
1465 (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)
1466 ) {
1467 Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;
1468 PciOr16 (
1469 PCI_LIB_ADDRESS (
1470 0,
1471 1,
1472 1,
1473 (Atapi->PrimarySecondary == 1) ? 0x42: 0x40
1474 ),
1475 BIT15
1476 );
1477 }
1478
1479 //
1480 // Next device path node
1481 //
1482 DevPathNode = NextDevicePathNode (DevPathNode);
1483 }
1484 }
1485
1486 return;
1487 }
1488
1489
1490 VOID
1491 InstallDevicePathCallback (
1492 VOID
1493 )
1494 {
1495 DEBUG ((EFI_D_INFO, "Registered NotifyDevPath Event\n"));
1496 mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (
1497 &gEfiDevicePathProtocolGuid,
1498 TPL_CALLBACK,
1499 NotifyDevPath,
1500 NULL,
1501 &mEfiDevPathNotifyReg
1502 );
1503 }
1504
1505 /**
1506 Lock the ConsoleIn device in system table. All key
1507 presses will be ignored until the Password is typed in. The only way to
1508 disable the password is to type it in to a ConIn device.
1509
1510 @param Password Password used to lock ConIn device.
1511
1512 @retval EFI_SUCCESS lock the Console In Spliter virtual handle successfully.
1513 @retval EFI_UNSUPPORTED Password not found
1514
1515 **/
1516 EFI_STATUS
1517 EFIAPI
1518 LockKeyboards (
1519 IN CHAR16 *Password
1520 )
1521 {
1522 return EFI_UNSUPPORTED;
1523 }
1524