]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/PlatformBdsLib/BdsPlatform.c
df07281448b342578dcbef84aa72b5aa3399bfb2
[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 "QemuBootOrder.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 (0x40);
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 (0x40);
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 UINT16 Timeout;
1189 EFI_BOOT_MODE BootMode;
1190
1191 DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior\n"));
1192
1193 ConnectRootBridge ();
1194
1195 if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {
1196 DEBUG ((EFI_D_INFO, "PlatformBdsPolicyBehavior: not restoring NvVars "
1197 "from disk since flash variables appear to be supported.\n"));
1198 } else {
1199 //
1200 // Try to restore variables from the hard disk early so
1201 // they can be used for the other BDS connect operations.
1202 //
1203 PlatformBdsRestoreNvVarsFromHardDisk ();
1204 }
1205
1206 //
1207 // Init the time out value
1208 //
1209 Timeout = PcdGet16 (PcdPlatformBootTimeOut);
1210
1211 //
1212 // Load the driver option as the driver option list
1213 //
1214 PlatformBdsGetDriverOption (DriverOptionList);
1215
1216 //
1217 // Get current Boot Mode
1218 //
1219 Status = BdsLibGetBootMode (&BootMode);
1220 DEBUG ((EFI_D_ERROR, "Boot Mode:%x\n", BootMode));
1221
1222 //
1223 // Go the different platform policy with different boot mode
1224 // Notes: this part code can be change with the table policy
1225 //
1226 ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);
1227 //
1228 // Connect platform console
1229 //
1230 Status = PlatformBdsConnectConsole (gPlatformConsole);
1231 if (EFI_ERROR (Status)) {
1232 //
1233 // Here OEM/IBV can customize with defined action
1234 //
1235 PlatformBdsNoConsoleAction ();
1236 }
1237
1238 //
1239 // Memory test and Logo show
1240 //
1241 PlatformBdsDiagnostics (IGNORE, TRUE, BaseMemoryTest);
1242
1243 //
1244 // Perform some platform specific connect sequence
1245 //
1246 PlatformBdsConnectSequence ();
1247
1248 //
1249 // Process QEMU's -kernel command line option
1250 //
1251 TryRunningQemuKernel ();
1252
1253 DEBUG ((EFI_D_INFO, "BdsLibConnectAll\n"));
1254 BdsLibConnectAll ();
1255 BdsLibEnumerateAllBootOption (BootOptionList);
1256
1257 SetBootOrderFromQemu (BootOptionList);
1258 //
1259 // The BootOrder variable may have changed, reload the in-memory list with
1260 // it.
1261 //
1262 BdsLibBuildOptionFromVar (BootOptionList, L"BootOrder");
1263
1264 PlatformBdsEnterFrontPage (Timeout, TRUE);
1265 }
1266
1267 VOID
1268 EFIAPI
1269 PlatformBdsBootSuccess (
1270 IN BDS_COMMON_OPTION *Option
1271 )
1272 /*++
1273
1274 Routine Description:
1275
1276 Hook point after a boot attempt succeeds. We don't expect a boot option to
1277 return, so the EFI 1.0 specification defines that you will default to an
1278 interactive mode and stop processing the BootOrder list in this case. This
1279 is alos a platform implementation and can be customized by IBV/OEM.
1280
1281 Arguments:
1282
1283 Option - Pointer to Boot Option that succeeded to boot.
1284
1285 Returns:
1286
1287 None.
1288
1289 --*/
1290 {
1291 CHAR16 *TmpStr;
1292
1293 DEBUG ((EFI_D_INFO, "PlatformBdsBootSuccess\n"));
1294 //
1295 // If Boot returned with EFI_SUCCESS and there is not in the boot device
1296 // select loop then we need to pop up a UI and wait for user input.
1297 //
1298 TmpStr = Option->StatusString;
1299 if (TmpStr != NULL) {
1300 BdsLibOutputStrings (gST->ConOut, TmpStr, Option->Description, L"\n\r", NULL);
1301 FreePool (TmpStr);
1302 }
1303 }
1304
1305 VOID
1306 EFIAPI
1307 PlatformBdsBootFail (
1308 IN BDS_COMMON_OPTION *Option,
1309 IN EFI_STATUS Status,
1310 IN CHAR16 *ExitData,
1311 IN UINTN ExitDataSize
1312 )
1313 /*++
1314
1315 Routine Description:
1316
1317 Hook point after a boot attempt fails.
1318
1319 Arguments:
1320
1321 Option - Pointer to Boot Option that failed to boot.
1322
1323 Status - Status returned from failed boot.
1324
1325 ExitData - Exit data returned from failed boot.
1326
1327 ExitDataSize - Exit data size returned from failed boot.
1328
1329 Returns:
1330
1331 None.
1332
1333 --*/
1334 {
1335 CHAR16 *TmpStr;
1336
1337 DEBUG ((EFI_D_INFO, "PlatformBdsBootFail\n"));
1338
1339 //
1340 // If Boot returned with failed status then we need to pop up a UI and wait
1341 // for user input.
1342 //
1343 TmpStr = Option->StatusString;
1344 if (TmpStr != NULL) {
1345 BdsLibOutputStrings (gST->ConOut, TmpStr, Option->Description, L"\n\r", NULL);
1346 FreePool (TmpStr);
1347 }
1348 }
1349
1350 EFI_STATUS
1351 PlatformBdsNoConsoleAction (
1352 VOID
1353 )
1354 /*++
1355
1356 Routine Description:
1357
1358 This function is remained for IBV/OEM to do some platform action,
1359 if there no console device can be connected.
1360
1361 Arguments:
1362
1363 None.
1364
1365 Returns:
1366
1367 EFI_SUCCESS - Direct return success now.
1368
1369 --*/
1370 {
1371 DEBUG ((EFI_D_INFO, "PlatformBdsNoConsoleAction\n"));
1372 return EFI_SUCCESS;
1373 }
1374
1375 VOID
1376 EFIAPI
1377 PlatformBdsLockNonUpdatableFlash (
1378 VOID
1379 )
1380 {
1381 DEBUG ((EFI_D_INFO, "PlatformBdsLockNonUpdatableFlash\n"));
1382 return;
1383 }
1384
1385
1386 /**
1387 This notification function is invoked when an instance of the
1388 EFI_DEVICE_PATH_PROTOCOL is produced.
1389
1390 @param Event The event that occured
1391 @param Context For EFI compatiblity. Not used.
1392
1393 **/
1394 VOID
1395 EFIAPI
1396 NotifyDevPath (
1397 IN EFI_EVENT Event,
1398 IN VOID *Context
1399 )
1400 {
1401 EFI_HANDLE Handle;
1402 EFI_STATUS Status;
1403 UINTN BufferSize;
1404 EFI_DEVICE_PATH_PROTOCOL *DevPathNode;
1405 ATAPI_DEVICE_PATH *Atapi;
1406
1407 //
1408 // Examine all new handles
1409 //
1410 for (;;) {
1411 //
1412 // Get the next handle
1413 //
1414 BufferSize = sizeof (Handle);
1415 Status = gBS->LocateHandle (
1416 ByRegisterNotify,
1417 NULL,
1418 mEfiDevPathNotifyReg,
1419 &BufferSize,
1420 &Handle
1421 );
1422
1423 //
1424 // If not found, we're done
1425 //
1426 if (EFI_NOT_FOUND == Status) {
1427 break;
1428 }
1429
1430 if (EFI_ERROR (Status)) {
1431 continue;
1432 }
1433
1434 //
1435 // Get the DevicePath protocol on that handle
1436 //
1437 Status = gBS->HandleProtocol (Handle, &gEfiDevicePathProtocolGuid, (VOID **)&DevPathNode);
1438 ASSERT_EFI_ERROR (Status);
1439
1440 while (!IsDevicePathEnd (DevPathNode)) {
1441 //
1442 // Find the handler to dump this device path node
1443 //
1444 if (
1445 (DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) &&
1446 (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)
1447 ) {
1448 Atapi = (ATAPI_DEVICE_PATH*) DevPathNode;
1449 PciOr16 (
1450 PCI_LIB_ADDRESS (
1451 0,
1452 1,
1453 1,
1454 (Atapi->PrimarySecondary == 1) ? 0x42: 0x40
1455 ),
1456 BIT15
1457 );
1458 }
1459
1460 //
1461 // Next device path node
1462 //
1463 DevPathNode = NextDevicePathNode (DevPathNode);
1464 }
1465 }
1466
1467 return;
1468 }
1469
1470
1471 VOID
1472 InstallDevicePathCallback (
1473 VOID
1474 )
1475 {
1476 DEBUG ((EFI_D_INFO, "Registered NotifyDevPath Event\n"));
1477 mEfiDevPathEvent = EfiCreateProtocolNotifyEvent (
1478 &gEfiDevicePathProtocolGuid,
1479 TPL_CALLBACK,
1480 NotifyDevPath,
1481 NULL,
1482 &mEfiDevPathNotifyReg
1483 );
1484 }
1485
1486 /**
1487 Lock the ConsoleIn device in system table. All key
1488 presses will be ignored until the Password is typed in. The only way to
1489 disable the password is to type it in to a ConIn device.
1490
1491 @param Password Password used to lock ConIn device.
1492
1493 @retval EFI_SUCCESS lock the Console In Spliter virtual handle successfully.
1494 @retval EFI_UNSUPPORTED Password not found
1495
1496 **/
1497 EFI_STATUS
1498 EFIAPI
1499 LockKeyboards (
1500 IN CHAR16 *Password
1501 )
1502 {
1503 return EFI_UNSUPPORTED;
1504 }
1505