2 ConsoleOut Routines that speak VGA.
4 Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "BiosVideo.h"
13 // EFI Driver Binding Protocol Instance
15 EFI_DRIVER_BINDING_PROTOCOL gBiosVideoDriverBinding
= {
16 BiosVideoDriverBindingSupported
,
17 BiosVideoDriverBindingStart
,
18 BiosVideoDriverBindingStop
,
25 // Global lookup tables for VGA graphics modes
27 UINT8 mVgaLeftMaskTable
[] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
29 UINT8 mVgaRightMaskTable
[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
31 UINT8 mVgaBitMaskTable
[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
34 // Save controller attributes during first start
36 UINT64 mOriginalPciAttributes
;
37 BOOLEAN mPciAttributesSaved
= FALSE
;
39 EFI_GRAPHICS_OUTPUT_BLT_PIXEL mVgaColorToGraphicsOutputColor
[] = {
40 { 0x00, 0x00, 0x00, 0x00 },
41 { 0x98, 0x00, 0x00, 0x00 },
42 { 0x00, 0x98, 0x00, 0x00 },
43 { 0x98, 0x98, 0x00, 0x00 },
44 { 0x00, 0x00, 0x98, 0x00 },
45 { 0x98, 0x00, 0x98, 0x00 },
46 { 0x00, 0x98, 0x98, 0x00 },
47 { 0x98, 0x98, 0x98, 0x00 },
48 { 0x10, 0x10, 0x10, 0x00 },
49 { 0xff, 0x10, 0x10, 0x00 },
50 { 0x10, 0xff, 0x10, 0x00 },
51 { 0xff, 0xff, 0x10, 0x00 },
52 { 0x10, 0x10, 0xff, 0x00 },
53 { 0xf0, 0x10, 0xff, 0x00 },
54 { 0x10, 0xff, 0xff, 0x00 },
55 { 0xff, 0xff, 0xff, 0x00 }
59 // Standard timing defined by VESA EDID
61 VESA_BIOS_EXTENSIONS_EDID_TIMING mEstablishedEdidTiming
[] = {
63 // Established Timing I
74 // Established Timing II
85 // Established Timing III
93 @param This Pointer to driver binding protocol
94 @param Controller Controller handle to connect
95 @param RemainingDevicePath A pointer to the remaining portion of a device
98 @retval EFI_STATUS EFI_SUCCESS:This controller can be managed by this
99 driver, Otherwise, this controller cannot be
100 managed by this driver
105 BiosVideoDriverBindingSupported (
106 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
107 IN EFI_HANDLE Controller
,
108 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
112 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
113 EFI_PCI_IO_PROTOCOL
*PciIo
;
118 // See if the Legacy BIOS Protocol is available
120 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
121 if (EFI_ERROR (Status
)) {
126 // Open the IO Abstraction(s) needed to perform the supported test
128 Status
= gBS
->OpenProtocol (
130 &gEfiPciIoProtocolGuid
,
132 This
->DriverBindingHandle
,
134 EFI_OPEN_PROTOCOL_BY_DRIVER
136 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
140 if (Status
== EFI_ALREADY_STARTED
) {
142 // If VgaMiniPort protocol is installed, EFI_ALREADY_STARTED indicates failure,
143 // because VgaMiniPort protocol is installed on controller handle directly.
145 Status
= gBS
->OpenProtocol (
147 &gEfiVgaMiniPortProtocolGuid
,
151 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
153 if (!EFI_ERROR (Status
)) {
154 return EFI_ALREADY_STARTED
;
158 // See if this is a PCI Graphics Controller by looking at the Command register and
159 // Class Code Register
161 Status
= PciIo
->Pci
.Read (
165 sizeof (Pci
) / sizeof (UINT32
),
168 if (EFI_ERROR (Status
)) {
169 Status
= EFI_UNSUPPORTED
;
173 Status
= EFI_UNSUPPORTED
;
174 if (Pci
.Hdr
.ClassCode
[2] == 0x03 || (Pci
.Hdr
.ClassCode
[2] == 0x00 && Pci
.Hdr
.ClassCode
[1] == 0x01)) {
176 Status
= EFI_SUCCESS
;
178 // If this is a graphics controller,
179 // go further check RemainingDevicePath validation
181 if (RemainingDevicePath
!= NULL
) {
182 Node
= (EFI_DEV_PATH
*) RemainingDevicePath
;
184 // Check if RemainingDevicePath is the End of Device Path Node,
185 // if yes, return EFI_SUCCESS
187 if (!IsDevicePathEnd (Node
)) {
189 // If RemainingDevicePath isn't the End of Device Path Node,
190 // check its validation
192 if (Node
->DevPath
.Type
!= ACPI_DEVICE_PATH
||
193 Node
->DevPath
.SubType
!= ACPI_ADR_DP
||
194 DevicePathNodeLength(&Node
->DevPath
) < sizeof(ACPI_ADR_DEVICE_PATH
)) {
195 Status
= EFI_UNSUPPORTED
;
204 &gEfiPciIoProtocolGuid
,
205 This
->DriverBindingHandle
,
214 Install Graphics Output Protocol onto VGA device handles.
216 @param This Pointer to driver binding protocol
217 @param Controller Controller handle to connect
218 @param RemainingDevicePath A pointer to the remaining portion of a device
226 BiosVideoDriverBindingStart (
227 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
228 IN EFI_HANDLE Controller
,
229 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
233 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
234 EFI_PCI_IO_PROTOCOL
*PciIo
;
235 EFI_LEGACY_BIOS_PROTOCOL
*LegacyBios
;
240 // Initialize local variables
243 ParentDevicePath
= NULL
;
247 // See if the Legacy BIOS Protocol is available
249 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
250 if (EFI_ERROR (Status
)) {
255 // Prepare for status code
257 Status
= gBS
->HandleProtocol (
259 &gEfiDevicePathProtocolGuid
,
260 (VOID
**) &ParentDevicePath
262 if (EFI_ERROR (Status
)) {
267 // Open the IO Abstraction(s) needed
269 Status
= gBS
->OpenProtocol (
271 &gEfiPciIoProtocolGuid
,
273 This
->DriverBindingHandle
,
275 EFI_OPEN_PROTOCOL_BY_DRIVER
277 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
282 // Save original PCI attributes
284 if (!mPciAttributesSaved
) {
285 Status
= PciIo
->Attributes (
287 EfiPciIoAttributeOperationGet
,
289 &mOriginalPciAttributes
292 if (EFI_ERROR (Status
)) {
295 mPciAttributesSaved
= TRUE
;
299 // Get supported PCI attributes
301 Status
= PciIo
->Attributes (
303 EfiPciIoAttributeOperationSupported
,
307 if (EFI_ERROR (Status
)) {
311 Supports
&= (UINT64
)(EFI_PCI_IO_ATTRIBUTE_VGA_IO
| EFI_PCI_IO_ATTRIBUTE_VGA_IO_16
);
312 if (Supports
== 0 || Supports
== (EFI_PCI_IO_ATTRIBUTE_VGA_IO
| EFI_PCI_IO_ATTRIBUTE_VGA_IO_16
)) {
313 Status
= EFI_UNSUPPORTED
;
317 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
319 EFI_PERIPHERAL_LOCAL_CONSOLE
| EFI_P_PC_ENABLE
,
323 // Enable the device and make sure VGA cycles are being forwarded to this VGA device
325 Status
= PciIo
->Attributes (
327 EfiPciIoAttributeOperationEnable
,
328 EFI_PCI_DEVICE_ENABLE
| EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY
| Supports
,
331 if (EFI_ERROR (Status
)) {
332 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
333 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
334 EFI_PERIPHERAL_LOCAL_CONSOLE
| EFI_P_EC_RESOURCE_CONFLICT
,
340 // Check to see if there is a legacy option ROM image associated with this PCI device
342 Status
= LegacyBios
->CheckPciRom (
349 if (EFI_ERROR (Status
)) {
353 // Post the legacy option ROM if it is available.
355 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
360 Status
= LegacyBios
->InstallPciRom (
370 if (EFI_ERROR (Status
)) {
371 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
372 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
373 EFI_PERIPHERAL_LOCAL_CONSOLE
| EFI_P_EC_CONTROLLER_ERROR
,
379 if (RemainingDevicePath
!= NULL
) {
380 if (IsDevicePathEnd (RemainingDevicePath
) &&
381 (FeaturePcdGet (PcdBiosVideoCheckVbeEnable
) || FeaturePcdGet (PcdBiosVideoCheckVgaEnable
))) {
383 // If RemainingDevicePath is the End of Device Path Node,
384 // don't create any child device and return EFI_SUCESS
385 Status
= EFI_SUCCESS
;
391 // Create child handle and install GraphicsOutputProtocol on it
393 Status
= BiosVideoChildHandleInstall (
403 if ((EFI_ERROR (Status
)) && (Status
!= EFI_ALREADY_STARTED
)) {
404 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
406 EFI_PERIPHERAL_LOCAL_CONSOLE
| EFI_P_PC_DISABLE
,
410 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
412 EFI_PERIPHERAL_LOCAL_CONSOLE
| EFI_P_EC_NOT_DETECTED
,
415 if (!HasChildHandle (Controller
)) {
416 if (mPciAttributesSaved
) {
418 // Restore original PCI attributes
422 EfiPciIoAttributeOperationSet
,
423 mOriginalPciAttributes
,
429 // Release PCI I/O Protocols on the controller handle.
433 &gEfiPciIoProtocolGuid
,
434 This
->DriverBindingHandle
,
446 @param This Pointer to driver binding protocol
447 @param Controller Controller handle to connect
448 @param NumberOfChildren Number of children handle created by this driver
449 @param ChildHandleBuffer Buffer containing child handle created
451 @retval EFI_SUCCESS Driver disconnected successfully from controller
452 @retval EFI_UNSUPPORTED Cannot find BIOS_VIDEO_DEV structure
457 BiosVideoDriverBindingStop (
458 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
459 IN EFI_HANDLE Controller
,
460 IN UINTN NumberOfChildren
,
461 IN EFI_HANDLE
*ChildHandleBuffer
465 BOOLEAN AllChildrenStopped
;
467 EFI_PCI_IO_PROTOCOL
*PciIo
;
469 AllChildrenStopped
= TRUE
;
471 if (NumberOfChildren
== 0) {
473 // Close PCI I/O protocol on the controller handle
477 &gEfiPciIoProtocolGuid
,
478 This
->DriverBindingHandle
,
485 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
486 Status
= BiosVideoChildHandleUninstall (This
, Controller
, ChildHandleBuffer
[Index
]);
488 if (EFI_ERROR (Status
)) {
489 AllChildrenStopped
= FALSE
;
493 if (!AllChildrenStopped
) {
494 return EFI_DEVICE_ERROR
;
497 if (!HasChildHandle (Controller
)) {
498 if (mPciAttributesSaved
) {
499 Status
= gBS
->HandleProtocol (
501 &gEfiPciIoProtocolGuid
,
504 ASSERT_EFI_ERROR (Status
);
507 // Restore original PCI attributes
509 Status
= PciIo
->Attributes (
511 EfiPciIoAttributeOperationSet
,
512 mOriginalPciAttributes
,
515 ASSERT_EFI_ERROR (Status
);
525 Install child handles if the Handle supports MBR format.
527 @param This Calling context.
528 @param ParentHandle Parent Handle
529 @param ParentPciIo Parent PciIo interface
530 @param ParentLegacyBios Parent LegacyBios interface
531 @param ParentDevicePath Parent Device Path
532 @param RemainingDevicePath Remaining Device Path
534 @retval EFI_SUCCESS If a child handle was added
535 @retval other A child handle was not added
539 BiosVideoChildHandleInstall (
540 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
541 IN EFI_HANDLE ParentHandle
,
542 IN EFI_PCI_IO_PROTOCOL
*ParentPciIo
,
543 IN EFI_LEGACY_BIOS_PROTOCOL
*ParentLegacyBios
,
544 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
545 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
549 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
551 ACPI_ADR_DEVICE_PATH AcpiDeviceNode
;
552 BOOLEAN ProtocolInstalled
;
555 // Allocate the private device structure for video device
557 BiosVideoPrivate
= (BIOS_VIDEO_DEV
*) AllocateZeroPool (
558 sizeof (BIOS_VIDEO_DEV
)
560 if (NULL
== BiosVideoPrivate
) {
561 Status
= EFI_OUT_OF_RESOURCES
;
566 // See if this is a VGA compatible controller or not
568 Status
= ParentPciIo
->Pci
.Read (
572 sizeof (Pci
) / sizeof (UINT32
),
575 if (EFI_ERROR (Status
)) {
576 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
577 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
578 EFI_PERIPHERAL_LOCAL_CONSOLE
| EFI_P_EC_CONTROLLER_ERROR
,
583 BiosVideoPrivate
->VgaCompatible
= FALSE
;
584 if (Pci
.Hdr
.ClassCode
[2] == 0x00 && Pci
.Hdr
.ClassCode
[1] == 0x01) {
585 BiosVideoPrivate
->VgaCompatible
= TRUE
;
588 if (Pci
.Hdr
.ClassCode
[2] == 0x03 && Pci
.Hdr
.ClassCode
[1] == 0x00 && Pci
.Hdr
.ClassCode
[0] == 0x00) {
589 BiosVideoPrivate
->VgaCompatible
= TRUE
;
592 if (PcdGetBool (PcdBiosVideoSetTextVgaModeEnable
)) {
594 // Create EXIT_BOOT_SERIVES Event
596 Status
= gBS
->CreateEventEx (
599 BiosVideoNotifyExitBootServices
,
601 &gEfiEventExitBootServicesGuid
,
602 &BiosVideoPrivate
->ExitBootServicesEvent
604 if (EFI_ERROR (Status
)) {
610 // Initialize the child private structure
612 BiosVideoPrivate
->Signature
= BIOS_VIDEO_DEV_SIGNATURE
;
615 // Fill in Graphics Output specific mode structures
617 BiosVideoPrivate
->HardwareNeedsStarting
= TRUE
;
618 BiosVideoPrivate
->ModeData
= NULL
;
619 BiosVideoPrivate
->LineBuffer
= NULL
;
620 BiosVideoPrivate
->VgaFrameBuffer
= NULL
;
621 BiosVideoPrivate
->VbeFrameBuffer
= NULL
;
624 // Fill in the Graphics Output Protocol
626 BiosVideoPrivate
->GraphicsOutput
.QueryMode
= BiosVideoGraphicsOutputQueryMode
;
627 BiosVideoPrivate
->GraphicsOutput
.SetMode
= BiosVideoGraphicsOutputSetMode
;
631 // Allocate buffer for Graphics Output Protocol mode information
633 BiosVideoPrivate
->GraphicsOutput
.Mode
= (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE
*) AllocatePool (
634 sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE
)
636 if (NULL
== BiosVideoPrivate
->GraphicsOutput
.Mode
) {
637 Status
= EFI_OUT_OF_RESOURCES
;
641 BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
= (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
*) AllocatePool (
642 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
)
644 if (NULL
== BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
) {
645 Status
= EFI_OUT_OF_RESOURCES
;
650 // Assume that Graphics Output Protocol will be produced until proven otherwise
652 BiosVideoPrivate
->ProduceGraphicsOutput
= TRUE
;
655 // Set Gop Device Path, here RemainingDevicePath will not be one End of Device Path Node.
657 if ((RemainingDevicePath
== NULL
) || (!IsDevicePathEnd (RemainingDevicePath
))) {
658 if (RemainingDevicePath
== NULL
) {
659 ZeroMem (&AcpiDeviceNode
, sizeof (ACPI_ADR_DEVICE_PATH
));
660 AcpiDeviceNode
.Header
.Type
= ACPI_DEVICE_PATH
;
661 AcpiDeviceNode
.Header
.SubType
= ACPI_ADR_DP
;
662 AcpiDeviceNode
.ADR
= ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA
, 0, 0);
663 SetDevicePathNodeLength (&AcpiDeviceNode
.Header
, sizeof (ACPI_ADR_DEVICE_PATH
));
665 BiosVideoPrivate
->GopDevicePath
= AppendDevicePathNode (
667 (EFI_DEVICE_PATH_PROTOCOL
*) &AcpiDeviceNode
670 BiosVideoPrivate
->GopDevicePath
= AppendDevicePathNode (ParentDevicePath
, RemainingDevicePath
);
674 // Creat child handle and device path protocol firstly
676 BiosVideoPrivate
->Handle
= NULL
;
677 Status
= gBS
->InstallMultipleProtocolInterfaces (
678 &BiosVideoPrivate
->Handle
,
679 &gEfiDevicePathProtocolGuid
,
680 BiosVideoPrivate
->GopDevicePath
,
683 if (EFI_ERROR (Status
)) {
689 // Fill in the VGA Mini Port Protocol fields
691 BiosVideoPrivate
->VgaMiniPort
.SetMode
= BiosVideoVgaMiniPortSetMode
;
692 BiosVideoPrivate
->VgaMiniPort
.VgaMemoryOffset
= 0xb8000;
693 BiosVideoPrivate
->VgaMiniPort
.CrtcAddressRegisterOffset
= 0x3d4;
694 BiosVideoPrivate
->VgaMiniPort
.CrtcDataRegisterOffset
= 0x3d5;
695 BiosVideoPrivate
->VgaMiniPort
.VgaMemoryBar
= EFI_PCI_IO_PASS_THROUGH_BAR
;
696 BiosVideoPrivate
->VgaMiniPort
.CrtcAddressRegisterBar
= EFI_PCI_IO_PASS_THROUGH_BAR
;
697 BiosVideoPrivate
->VgaMiniPort
.CrtcDataRegisterBar
= EFI_PCI_IO_PASS_THROUGH_BAR
;
700 // Child handle need to consume the Legacy Bios protocol
702 BiosVideoPrivate
->LegacyBios
= ParentLegacyBios
;
705 // When check for VBE, PCI I/O protocol is needed, so use parent's protocol interface temporally
707 BiosVideoPrivate
->PciIo
= ParentPciIo
;
710 // Check for VESA BIOS Extensions for modes that are compatible with Graphics Output
712 if (FeaturePcdGet (PcdBiosVideoCheckVbeEnable
)) {
713 Status
= BiosVideoCheckForVbe (BiosVideoPrivate
);
714 DEBUG ((EFI_D_INFO
, "BiosVideoCheckForVbe - %r\n", Status
));
716 Status
= EFI_UNSUPPORTED
;
718 if (EFI_ERROR (Status
)) {
720 // The VESA BIOS Extensions are not compatible with Graphics Output, so check for support
721 // for the standard 640x480 16 color VGA mode
723 DEBUG ((EFI_D_INFO
, "VgaCompatible - %x\n", BiosVideoPrivate
->VgaCompatible
));
724 if (BiosVideoPrivate
->VgaCompatible
) {
725 if (FeaturePcdGet (PcdBiosVideoCheckVgaEnable
)) {
726 Status
= BiosVideoCheckForVga (BiosVideoPrivate
);
727 DEBUG ((EFI_D_INFO
, "BiosVideoCheckForVga - %r\n", Status
));
729 Status
= EFI_UNSUPPORTED
;
733 if (EFI_ERROR (Status
)) {
735 // Free GOP mode structure if it is not freed before
736 // VgaMiniPort does not need this structure any more
738 if (BiosVideoPrivate
->GraphicsOutput
.Mode
!= NULL
) {
739 if (BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
!= NULL
) {
740 FreePool (BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
);
741 BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
= NULL
;
743 FreePool (BiosVideoPrivate
->GraphicsOutput
.Mode
);
744 BiosVideoPrivate
->GraphicsOutput
.Mode
= NULL
;
748 // Neither VBE nor the standard 640x480 16 color VGA mode are supported, so do
749 // not produce the Graphics Output protocol. Instead, produce the VGA MiniPort Protocol.
751 BiosVideoPrivate
->ProduceGraphicsOutput
= FALSE
;
754 // INT services are available, so on the 80x25 and 80x50 text mode are supported
756 BiosVideoPrivate
->VgaMiniPort
.MaxMode
= 2;
760 ProtocolInstalled
= FALSE
;
762 if (BiosVideoPrivate
->ProduceGraphicsOutput
) {
764 // Creat child handle and install Graphics Output Protocol,EDID Discovered/Active Protocol
766 Status
= gBS
->InstallMultipleProtocolInterfaces (
767 &BiosVideoPrivate
->Handle
,
768 &gEfiGraphicsOutputProtocolGuid
,
769 &BiosVideoPrivate
->GraphicsOutput
,
770 &gEfiEdidDiscoveredProtocolGuid
,
771 &BiosVideoPrivate
->EdidDiscovered
,
772 &gEfiEdidActiveProtocolGuid
,
773 &BiosVideoPrivate
->EdidActive
,
777 if (!EFI_ERROR (Status
)) {
779 // Open the Parent Handle for the child
781 Status
= gBS
->OpenProtocol (
783 &gEfiPciIoProtocolGuid
,
784 (VOID
**) &BiosVideoPrivate
->PciIo
,
785 This
->DriverBindingHandle
,
786 BiosVideoPrivate
->Handle
,
787 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
789 if (EFI_ERROR (Status
)) {
792 ProtocolInstalled
= TRUE
;
796 if (!ProtocolInstalled
) {
798 // Install VGA Mini Port Protocol
800 Status
= gBS
->InstallMultipleProtocolInterfaces (
802 &gEfiVgaMiniPortProtocolGuid
,
803 &BiosVideoPrivate
->VgaMiniPort
,
809 if (EFI_ERROR (Status
)) {
810 if ((BiosVideoPrivate
!= NULL
) && (BiosVideoPrivate
->ExitBootServicesEvent
!= NULL
)) {
811 gBS
->CloseEvent (BiosVideoPrivate
->ExitBootServicesEvent
);
814 // Free private data structure
816 BiosVideoDeviceReleaseResource (BiosVideoPrivate
);
824 Deregister an video child handle and free resources.
826 @param This Protocol instance pointer.
827 @param Controller Video controller handle
828 @param Handle Video child handle
834 BiosVideoChildHandleUninstall (
835 EFI_DRIVER_BINDING_PROTOCOL
*This
,
836 EFI_HANDLE Controller
,
841 EFI_IA32_REGISTER_SET Regs
;
842 EFI_GRAPHICS_OUTPUT_PROTOCOL
*GraphicsOutput
;
843 EFI_VGA_MINI_PORT_PROTOCOL
*VgaMiniPort
;
844 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
845 EFI_PCI_IO_PROTOCOL
*PciIo
;
847 BiosVideoPrivate
= NULL
;
848 GraphicsOutput
= NULL
;
850 Status
= EFI_UNSUPPORTED
;
852 Status
= gBS
->OpenProtocol (
854 &gEfiGraphicsOutputProtocolGuid
,
855 (VOID
**) &GraphicsOutput
,
856 This
->DriverBindingHandle
,
858 EFI_OPEN_PROTOCOL_GET_PROTOCOL
860 if (!EFI_ERROR (Status
)) {
861 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput
);
864 if (EFI_ERROR (Status
)) {
865 Status
= gBS
->OpenProtocol (
867 &gEfiVgaMiniPortProtocolGuid
,
868 (VOID
**) &VgaMiniPort
,
869 This
->DriverBindingHandle
,
871 EFI_OPEN_PROTOCOL_GET_PROTOCOL
873 if (!EFI_ERROR (Status
)) {
874 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (VgaMiniPort
);
878 if (BiosVideoPrivate
== NULL
) {
879 return EFI_UNSUPPORTED
;
883 // Set the 80x25 Text VGA Mode
887 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
892 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
895 // Close PCI I/O protocol that opened by child handle
897 Status
= gBS
->CloseProtocol (
899 &gEfiPciIoProtocolGuid
,
900 This
->DriverBindingHandle
,
905 // Uninstall protocols on child handle
907 if (BiosVideoPrivate
->ProduceGraphicsOutput
) {
908 Status
= gBS
->UninstallMultipleProtocolInterfaces (
909 BiosVideoPrivate
->Handle
,
910 &gEfiDevicePathProtocolGuid
,
911 BiosVideoPrivate
->GopDevicePath
,
912 &gEfiGraphicsOutputProtocolGuid
,
913 &BiosVideoPrivate
->GraphicsOutput
,
914 &gEfiEdidDiscoveredProtocolGuid
,
915 &BiosVideoPrivate
->EdidDiscovered
,
916 &gEfiEdidActiveProtocolGuid
,
917 &BiosVideoPrivate
->EdidActive
,
921 if (!BiosVideoPrivate
->ProduceGraphicsOutput
) {
922 Status
= gBS
->UninstallMultipleProtocolInterfaces (
924 &gEfiVgaMiniPortProtocolGuid
,
925 &BiosVideoPrivate
->VgaMiniPort
,
930 if (EFI_ERROR (Status
)) {
933 &gEfiPciIoProtocolGuid
,
935 This
->DriverBindingHandle
,
937 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
942 if (PcdGetBool (PcdBiosVideoSetTextVgaModeEnable
)) {
944 // Close EXIT_BOOT_SERIVES Event
946 gBS
->CloseEvent (BiosVideoPrivate
->ExitBootServicesEvent
);
950 // Release all allocated resources
952 BiosVideoDeviceReleaseResource (BiosVideoPrivate
);
959 Release resource for biso video instance.
961 @param BiosVideoPrivate Video child device private data structure
965 BiosVideoDeviceReleaseResource (
966 BIOS_VIDEO_DEV
*BiosVideoPrivate
969 if (BiosVideoPrivate
== NULL
) {
974 // Release all the resourses occupied by the BIOS_VIDEO_DEV
978 // Free VGA Frame Buffer
980 if (BiosVideoPrivate
->VgaFrameBuffer
!= NULL
) {
981 FreePool (BiosVideoPrivate
->VgaFrameBuffer
);
984 // Free VBE Frame Buffer
986 if (BiosVideoPrivate
->VbeFrameBuffer
!= NULL
) {
987 FreePool (BiosVideoPrivate
->VbeFrameBuffer
);
992 if (BiosVideoPrivate
->LineBuffer
!= NULL
) {
993 FreePool (BiosVideoPrivate
->LineBuffer
);
998 if (BiosVideoPrivate
->ModeData
!= NULL
) {
999 FreePool (BiosVideoPrivate
->ModeData
);
1002 // Free memory allocated below 1MB
1004 if (BiosVideoPrivate
->PagesBelow1MB
!= 0) {
1005 gBS
->FreePages (BiosVideoPrivate
->PagesBelow1MB
, BiosVideoPrivate
->NumberOfPagesBelow1MB
);
1008 if (BiosVideoPrivate
->VbeSaveRestorePages
!= 0) {
1009 gBS
->FreePages (BiosVideoPrivate
->VbeSaveRestoreBuffer
, BiosVideoPrivate
->VbeSaveRestorePages
);
1013 // Free graphics output protocol occupied resource
1015 if (BiosVideoPrivate
->GraphicsOutput
.Mode
!= NULL
) {
1016 if (BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
!= NULL
) {
1017 FreePool (BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
);
1018 BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
= NULL
;
1020 FreePool (BiosVideoPrivate
->GraphicsOutput
.Mode
);
1021 BiosVideoPrivate
->GraphicsOutput
.Mode
= NULL
;
1024 // Free EDID discovered protocol occupied resource
1026 if (BiosVideoPrivate
->EdidDiscovered
.Edid
!= NULL
) {
1027 FreePool (BiosVideoPrivate
->EdidDiscovered
.Edid
);
1030 // Free EDID active protocol occupied resource
1032 if (BiosVideoPrivate
->EdidActive
.Edid
!= NULL
) {
1033 FreePool (BiosVideoPrivate
->EdidActive
.Edid
);
1036 if (BiosVideoPrivate
->GopDevicePath
!= NULL
) {
1037 FreePool (BiosVideoPrivate
->GopDevicePath
);
1040 FreePool (BiosVideoPrivate
);
1047 Generate a search key for a specified timing data.
1049 @param EdidTiming Pointer to EDID timing
1051 @return The 32 bit unique key for search.
1056 VESA_BIOS_EXTENSIONS_EDID_TIMING
*EdidTiming
1062 // Be sure no conflicts for all standard timing defined by VESA.
1064 Key
= (EdidTiming
->HorizontalResolution
* 2) + EdidTiming
->VerticalResolution
;
1070 Parse the Established Timing and Standard Timing in EDID data block.
1072 @param EdidBuffer Pointer to EDID data block
1073 @param ValidEdidTiming Valid EDID timing information
1075 @retval TRUE The EDID data is valid.
1076 @retval FALSE The EDID data is invalid.
1082 VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING
*ValidEdidTiming
1090 UINT16 HorizontalResolution
;
1091 UINT16 VerticalResolution
;
1094 VESA_BIOS_EXTENSIONS_EDID_TIMING TempTiming
;
1095 VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK
*EdidDataBlock
;
1097 EdidDataBlock
= (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK
*) EdidBuffer
;
1100 // Check the checksum of EDID data
1103 for (Index
= 0; Index
< VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE
; Index
++) {
1104 CheckSum
= (UINT8
) (CheckSum
+ EdidBuffer
[Index
]);
1106 if (CheckSum
!= 0) {
1111 gBS
->SetMem (ValidEdidTiming
, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING
), 0);
1113 if ((EdidDataBlock
->EstablishedTimings
[0] != 0) ||
1114 (EdidDataBlock
->EstablishedTimings
[1] != 0) ||
1115 (EdidDataBlock
->EstablishedTimings
[2] != 0)
1118 // Established timing data
1120 TimingBits
= EdidDataBlock
->EstablishedTimings
[0] |
1121 (EdidDataBlock
->EstablishedTimings
[1] << 8) |
1122 ((EdidDataBlock
->EstablishedTimings
[2] & 0x80) << 9) ;
1123 for (Index
= 0; Index
< VESA_BIOS_EXTENSIONS_EDID_ESTABLISHED_TIMING_MAX_NUMBER
; Index
++) {
1124 if ((TimingBits
& 0x1) != 0) {
1125 DEBUG ((EFI_D_INFO
, "Established Timing: %d x %d\n",
1126 mEstablishedEdidTiming
[Index
].HorizontalResolution
, mEstablishedEdidTiming
[Index
].VerticalResolution
));
1127 ValidEdidTiming
->Key
[ValidNumber
] = CalculateEdidKey (&mEstablishedEdidTiming
[Index
]);
1130 TimingBits
= TimingBits
>> 1;
1135 // Parse the standard timing data
1137 BufferIndex
= &EdidDataBlock
->StandardTimingIdentification
[0];
1138 for (Index
= 0; Index
< 8; Index
++) {
1140 // Check if this is a valid Standard Timing entry
1141 // VESA documents unused fields should be set to 01h
1143 if ((BufferIndex
[0] != 0x1) && (BufferIndex
[1] != 0x1)){
1145 // A valid Standard Timing
1147 HorizontalResolution
= (UINT16
) (BufferIndex
[0] * 8 + 248);
1148 AspectRatio
= (UINT8
) (BufferIndex
[1] >> 6);
1149 switch (AspectRatio
) {
1151 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 16 * 10);
1154 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 4 * 3);
1157 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 5 * 4);
1160 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 16 * 9);
1163 VerticalResolution
= (UINT16
) (HorizontalResolution
/ 4 * 3);
1166 RefreshRate
= (UINT8
) ((BufferIndex
[1] & 0x1f) + 60);
1167 DEBUG ((EFI_D_INFO
, "Standard Timing: %d x %d\n", HorizontalResolution
, VerticalResolution
));
1168 TempTiming
.HorizontalResolution
= HorizontalResolution
;
1169 TempTiming
.VerticalResolution
= VerticalResolution
;
1170 TempTiming
.RefreshRate
= RefreshRate
;
1171 ValidEdidTiming
->Key
[ValidNumber
] = CalculateEdidKey (&TempTiming
);
1178 // Parse the Detailed Timing data
1180 BufferIndex
= &EdidDataBlock
->DetailedTimingDescriptions
[0];
1181 for (Index
= 0; Index
< 4; Index
++, BufferIndex
+= VESA_BIOS_EXTENSIONS_DETAILED_TIMING_EACH_DESCRIPTOR_SIZE
) {
1182 if ((BufferIndex
[0] == 0x0) && (BufferIndex
[1] == 0x0)) {
1184 // Check if this is a valid Detailed Timing Descriptor
1185 // If first 2 bytes are zero, it is monitor descriptor other than detailed timing descriptor
1190 // Calculate Horizontal and Vertical resolution
1192 TempTiming
.HorizontalResolution
= ((UINT16
)(BufferIndex
[4] & 0xF0) << 4) | (BufferIndex
[2]);
1193 TempTiming
.VerticalResolution
= ((UINT16
)(BufferIndex
[7] & 0xF0) << 4) | (BufferIndex
[5]);
1194 DEBUG ((EFI_D_INFO
, "Detailed Timing %d: %d x %d\n",
1195 Index
, TempTiming
.HorizontalResolution
, TempTiming
.VerticalResolution
));
1196 ValidEdidTiming
->Key
[ValidNumber
] = CalculateEdidKey (&TempTiming
);
1200 ValidEdidTiming
->ValidNumber
= ValidNumber
;
1206 Search a specified Timing in all the valid EDID timings.
1208 @param ValidEdidTiming All valid EDID timing information.
1209 @param EdidTiming The Timing to search for.
1212 @retval FALSE Not found.
1217 VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING
*ValidEdidTiming
,
1218 VESA_BIOS_EXTENSIONS_EDID_TIMING
*EdidTiming
1224 Key
= CalculateEdidKey (EdidTiming
);
1226 for (Index
= 0; Index
< ValidEdidTiming
->ValidNumber
; Index
++) {
1227 if (Key
== ValidEdidTiming
->Key
[Index
]) {
1236 Check if all video child handles have been uninstalled.
1238 @param Controller Video controller handle
1240 @return TRUE Child handles exist.
1241 @return FALSE All video child handles have been uninstalled.
1246 IN EFI_HANDLE Controller
1250 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfoBuffer
;
1256 gBS
->OpenProtocolInformation (
1258 &gEfiPciIoProtocolGuid
,
1262 for (Index
= 0; Index
< EntryCount
; Index
++) {
1263 if ((OpenInfoBuffer
[Index
].Attributes
& EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
) != 0) {
1272 Check for VBE device.
1274 @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure
1276 @retval EFI_SUCCESS VBE device found
1280 BiosVideoCheckForVbe (
1281 IN OUT BIOS_VIDEO_DEV
*BiosVideoPrivate
1285 EFI_IA32_REGISTER_SET Regs
;
1286 UINT16
*ModeNumberPtr
;
1287 UINT16 VbeModeNumber
;
1290 BIOS_VIDEO_MODE_DATA
*ModeBuffer
;
1291 BIOS_VIDEO_MODE_DATA
*CurrentModeData
;
1294 VESA_BIOS_EXTENSIONS_EDID_TIMING Timing
;
1295 VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING ValidEdidTiming
;
1296 EFI_EDID_OVERRIDE_PROTOCOL
*EdidOverride
;
1297 UINT32 EdidAttributes
;
1298 BOOLEAN EdidOverrideFound
;
1299 UINTN EdidOverrideDataSize
;
1300 UINT8
*EdidOverrideDataBlock
;
1301 UINTN EdidActiveDataSize
;
1302 UINT8
*EdidActiveDataBlock
;
1303 UINT32 HighestHorizontalResolution
;
1304 UINT32 HighestVerticalResolution
;
1305 UINTN HighestResolutionMode
;
1308 EdidOverrideFound
= FALSE
;
1309 EdidOverrideDataBlock
= NULL
;
1310 EdidActiveDataSize
= 0;
1311 EdidActiveDataBlock
= NULL
;
1312 HighestHorizontalResolution
= 0;
1313 HighestVerticalResolution
= 0;
1314 HighestResolutionMode
= 0;
1317 // Allocate buffer under 1MB for VBE data structures
1319 BiosVideoPrivate
->NumberOfPagesBelow1MB
= EFI_SIZE_TO_PAGES (
1320 sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK
) +
1321 sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK
) +
1322 sizeof (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK
) +
1323 sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK
)
1326 BiosVideoPrivate
->PagesBelow1MB
= 0x00100000 - 1;
1328 Status
= gBS
->AllocatePages (
1330 EfiBootServicesData
,
1331 BiosVideoPrivate
->NumberOfPagesBelow1MB
,
1332 &BiosVideoPrivate
->PagesBelow1MB
1334 if (EFI_ERROR (Status
)) {
1338 ZeroMem (&ValidEdidTiming
, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING
));
1341 // Fill in the VBE related data structures
1343 BiosVideoPrivate
->VbeInformationBlock
= (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK
*) (UINTN
) (BiosVideoPrivate
->PagesBelow1MB
);
1344 BiosVideoPrivate
->VbeModeInformationBlock
= (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK
*) (BiosVideoPrivate
->VbeInformationBlock
+ 1);
1345 BiosVideoPrivate
->VbeEdidDataBlock
= (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK
*) (BiosVideoPrivate
->VbeModeInformationBlock
+ 1);
1346 BiosVideoPrivate
->VbeCrtcInformationBlock
= (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK
*) (BiosVideoPrivate
->VbeEdidDataBlock
+ 1);
1347 BiosVideoPrivate
->VbeSaveRestorePages
= 0;
1348 BiosVideoPrivate
->VbeSaveRestoreBuffer
= 0;
1351 // Test to see if the Video Adapter is compliant with VBE 3.0
1353 gBS
->SetMem (&Regs
, sizeof (Regs
), 0);
1354 Regs
.X
.AX
= VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION
;
1355 gBS
->SetMem (BiosVideoPrivate
->VbeInformationBlock
, sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK
), 0);
1356 BiosVideoPrivate
->VbeInformationBlock
->VESASignature
= VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE
;
1357 Regs
.X
.ES
= EFI_SEGMENT ((UINTN
) BiosVideoPrivate
->VbeInformationBlock
);
1358 Regs
.X
.DI
= EFI_OFFSET ((UINTN
) BiosVideoPrivate
->VbeInformationBlock
);
1360 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
1362 Status
= EFI_DEVICE_ERROR
;
1365 // See if the VESA call succeeded
1367 if (Regs
.X
.AX
!= VESA_BIOS_EXTENSIONS_STATUS_SUCCESS
) {
1371 // Check for 'VESA' signature
1373 if (BiosVideoPrivate
->VbeInformationBlock
->VESASignature
!= VESA_BIOS_EXTENSIONS_VESA_SIGNATURE
) {
1377 // Check to see if this is VBE 2.0 or higher
1379 if (BiosVideoPrivate
->VbeInformationBlock
->VESAVersion
< VESA_BIOS_EXTENSIONS_VERSION_2_0
) {
1384 EdidAttributes
= 0xff;
1385 EdidOverrideDataSize
= 0;
1388 // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
1390 Status
= gBS
->LocateProtocol (
1391 &gEfiEdidOverrideProtocolGuid
,
1393 (VOID
**) &EdidOverride
1395 if (!EFI_ERROR (Status
)) {
1397 // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
1399 EdidOverrideDataBlock
= AllocatePool (VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE
* 2);
1400 if (NULL
== EdidOverrideDataBlock
) {
1401 Status
= EFI_OUT_OF_RESOURCES
;
1405 Status
= EdidOverride
->GetEdid (
1407 BiosVideoPrivate
->Handle
,
1409 &EdidOverrideDataSize
,
1410 (UINT8
**) &EdidOverrideDataBlock
1412 if (!EFI_ERROR (Status
) &&
1413 EdidAttributes
== 0 &&
1414 EdidOverrideDataSize
!= 0) {
1416 // Succeeded to get EDID Override Data
1418 EdidOverrideFound
= TRUE
;
1422 if (!EdidOverrideFound
|| EdidAttributes
== EFI_EDID_OVERRIDE_DONT_OVERRIDE
) {
1424 // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,
1425 // read EDID information through INT10 call
1428 gBS
->SetMem (&Regs
, sizeof (Regs
), 0);
1429 Regs
.X
.AX
= VESA_BIOS_EXTENSIONS_EDID
;
1433 Regs
.X
.ES
= EFI_SEGMENT ((UINTN
) BiosVideoPrivate
->VbeEdidDataBlock
);
1434 Regs
.X
.DI
= EFI_OFFSET ((UINTN
) BiosVideoPrivate
->VbeEdidDataBlock
);
1436 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
1438 // See if the VESA call succeeded
1440 if (Regs
.X
.AX
== VESA_BIOS_EXTENSIONS_STATUS_SUCCESS
) {
1442 // Set EDID Discovered Data
1444 BiosVideoPrivate
->EdidDiscovered
.SizeOfEdid
= VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE
;
1445 BiosVideoPrivate
->EdidDiscovered
.Edid
= (UINT8
*) AllocateCopyPool (
1446 VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE
,
1447 BiosVideoPrivate
->VbeEdidDataBlock
1450 if (NULL
== BiosVideoPrivate
->EdidDiscovered
.Edid
) {
1451 Status
= EFI_OUT_OF_RESOURCES
;
1460 EdidActiveDataSize
= VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE
;
1461 EdidActiveDataBlock
= BiosVideoPrivate
->EdidDiscovered
.Edid
;
1462 } else if (EdidOverrideFound
) {
1463 EdidActiveDataSize
= EdidOverrideDataSize
;
1464 EdidActiveDataBlock
= EdidOverrideDataBlock
;
1470 // Parse EDID data structure to retrieve modes supported by monitor
1472 if (ParseEdidData ((UINT8
*) EdidActiveDataBlock
, &ValidEdidTiming
)) {
1474 // Copy EDID Override Data to EDID Active Data
1476 BiosVideoPrivate
->EdidActive
.SizeOfEdid
= (UINT32
) EdidActiveDataSize
;
1477 BiosVideoPrivate
->EdidActive
.Edid
= (UINT8
*) AllocateCopyPool (
1481 if (NULL
== BiosVideoPrivate
->EdidActive
.Edid
) {
1482 Status
= EFI_OUT_OF_RESOURCES
;
1487 BiosVideoPrivate
->EdidActive
.SizeOfEdid
= 0;
1488 BiosVideoPrivate
->EdidActive
.Edid
= NULL
;
1493 // Walk through the mode list to see if there is at least one mode the is compatible with the EDID mode
1495 ModeNumberPtr
= (UINT16
*)
1497 (((UINTN
) BiosVideoPrivate
->VbeInformationBlock
->VideoModePtr
& 0xffff0000) >> 12) |
1498 ((UINTN
) BiosVideoPrivate
->VbeInformationBlock
->VideoModePtr
& 0x0000ffff)
1505 // ModeNumberPtr may be not 16-byte aligned, so ReadUnaligned16 is used to access the buffer pointed by ModeNumberPtr.
1507 for (VbeModeNumber
= ReadUnaligned16 (ModeNumberPtr
);
1508 VbeModeNumber
!= VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST
;
1509 VbeModeNumber
= ReadUnaligned16 (++ModeNumberPtr
)) {
1511 // Make sure this is a mode number defined by the VESA VBE specification. If it isn'tm then skip this mode number.
1513 if ((VbeModeNumber
& VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA
) == 0) {
1517 // Get the information about the mode
1519 gBS
->SetMem (&Regs
, sizeof (Regs
), 0);
1520 Regs
.X
.AX
= VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION
;
1521 Regs
.X
.CX
= VbeModeNumber
;
1522 gBS
->SetMem (BiosVideoPrivate
->VbeModeInformationBlock
, sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK
), 0);
1523 Regs
.X
.ES
= EFI_SEGMENT ((UINTN
) BiosVideoPrivate
->VbeModeInformationBlock
);
1524 Regs
.X
.DI
= EFI_OFFSET ((UINTN
) BiosVideoPrivate
->VbeModeInformationBlock
);
1526 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
1529 // See if the call succeeded. If it didn't, then try the next mode.
1531 if (Regs
.X
.AX
!= VESA_BIOS_EXTENSIONS_STATUS_SUCCESS
) {
1535 // See if the mode supports color. If it doesn't then try the next mode.
1537 if ((BiosVideoPrivate
->VbeModeInformationBlock
->ModeAttributes
& VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR
) == 0) {
1541 // See if the mode supports graphics. If it doesn't then try the next mode.
1543 if ((BiosVideoPrivate
->VbeModeInformationBlock
->ModeAttributes
& VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS
) == 0) {
1547 // See if the mode supports a linear frame buffer. If it doesn't then try the next mode.
1549 if ((BiosVideoPrivate
->VbeModeInformationBlock
->ModeAttributes
& VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER
) == 0) {
1553 // See if the mode supports 32 bit color. If it doesn't then try the next mode.
1554 // 32 bit mode can be implemented by 24 Bits Per Pixels. Also make sure the
1555 // number of bits per pixel is a multiple of 8 or more than 32 bits per pixel
1557 if (BiosVideoPrivate
->VbeModeInformationBlock
->BitsPerPixel
< 24) {
1561 if (BiosVideoPrivate
->VbeModeInformationBlock
->BitsPerPixel
> 32) {
1565 if ((BiosVideoPrivate
->VbeModeInformationBlock
->BitsPerPixel
% 8) != 0) {
1569 // See if the physical base pointer for the linear mode is valid. If it isn't then try the next mode.
1571 if (BiosVideoPrivate
->VbeModeInformationBlock
->PhysBasePtr
== 0) {
1575 DEBUG ((EFI_D_INFO
, "Video Controller Mode 0x%x: %d x %d\n",
1576 VbeModeNumber
, BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
, BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
));
1578 if (EdidFound
&& (ValidEdidTiming
.ValidNumber
> 0)) {
1580 // EDID exist, check whether this mode match with any mode in EDID
1582 Timing
.HorizontalResolution
= BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
;
1583 Timing
.VerticalResolution
= BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
;
1584 if (!SearchEdidTiming (&ValidEdidTiming
, &Timing
)) {
1586 // When EDID comes from INT10 call, EDID does not include 800x600, 640x480 and 1024x768,
1587 // but INT10 can support these modes, we add them into GOP mode.
1589 if ((BiosVideoPrivate
->EdidDiscovered
.SizeOfEdid
!= 0) &&
1590 !((Timing
.HorizontalResolution
) == 1024 && (Timing
.VerticalResolution
== 768)) &&
1591 !((Timing
.HorizontalResolution
) == 800 && (Timing
.VerticalResolution
== 600)) &&
1592 !((Timing
.HorizontalResolution
) == 640 && (Timing
.VerticalResolution
== 480))) {
1599 // Select a reasonable mode to be set for current display mode
1603 if (BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
== 1024 &&
1604 BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
== 768
1608 if (BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
== 800 &&
1609 BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
== 600
1612 PreferMode
= ModeNumber
;
1614 if (BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
== 640 &&
1615 BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
== 480
1620 if ((!EdidFound
) && (!ModeFound
)) {
1622 // When no EDID exist, only select three possible resolutions, i.e. 1024x768, 800x600, 640x480
1628 // Record the highest resolution mode to set later
1630 if ((BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
> HighestHorizontalResolution
) ||
1631 ((BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
== HighestHorizontalResolution
) &&
1632 (BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
> HighestVerticalResolution
))) {
1633 HighestHorizontalResolution
= BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
;
1634 HighestVerticalResolution
= BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
;
1635 HighestResolutionMode
= ModeNumber
;
1639 // Add mode to the list of available modes
1642 ModeBuffer
= (BIOS_VIDEO_MODE_DATA
*) AllocatePool (
1643 ModeNumber
* sizeof (BIOS_VIDEO_MODE_DATA
)
1645 if (NULL
== ModeBuffer
) {
1646 Status
= EFI_OUT_OF_RESOURCES
;
1650 if (ModeNumber
> 1) {
1653 BiosVideoPrivate
->ModeData
,
1654 (ModeNumber
- 1) * sizeof (BIOS_VIDEO_MODE_DATA
)
1658 if (BiosVideoPrivate
->ModeData
!= NULL
) {
1659 FreePool (BiosVideoPrivate
->ModeData
);
1662 CurrentModeData
= &ModeBuffer
[ModeNumber
- 1];
1663 CurrentModeData
->VbeModeNumber
= VbeModeNumber
;
1664 if (BiosVideoPrivate
->VbeInformationBlock
->VESAVersion
>= VESA_BIOS_EXTENSIONS_VERSION_3_0
) {
1665 CurrentModeData
->BytesPerScanLine
= BiosVideoPrivate
->VbeModeInformationBlock
->LinBytesPerScanLine
;
1666 CurrentModeData
->Red
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->LinRedFieldPosition
;
1667 CurrentModeData
->Red
.Mask
= (UINT8
) ((1 << BiosVideoPrivate
->VbeModeInformationBlock
->LinRedMaskSize
) - 1);
1668 CurrentModeData
->Blue
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->LinBlueFieldPosition
;
1669 CurrentModeData
->Blue
.Mask
= (UINT8
) ((1 << BiosVideoPrivate
->VbeModeInformationBlock
->LinBlueMaskSize
) - 1);
1670 CurrentModeData
->Green
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->LinGreenFieldPosition
;
1671 CurrentModeData
->Green
.Mask
= (UINT8
) ((1 << BiosVideoPrivate
->VbeModeInformationBlock
->LinGreenMaskSize
) - 1);
1672 CurrentModeData
->Reserved
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->LinRsvdFieldPosition
;
1673 CurrentModeData
->Reserved
.Mask
= (UINT8
) ((1 << BiosVideoPrivate
->VbeModeInformationBlock
->LinRsvdMaskSize
) - 1);
1675 CurrentModeData
->BytesPerScanLine
= BiosVideoPrivate
->VbeModeInformationBlock
->BytesPerScanLine
;
1676 CurrentModeData
->Red
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->RedFieldPosition
;
1677 CurrentModeData
->Red
.Mask
= (UINT8
) ((1 << BiosVideoPrivate
->VbeModeInformationBlock
->RedMaskSize
) - 1);
1678 CurrentModeData
->Blue
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->BlueFieldPosition
;
1679 CurrentModeData
->Blue
.Mask
= (UINT8
) ((1 << BiosVideoPrivate
->VbeModeInformationBlock
->BlueMaskSize
) - 1);
1680 CurrentModeData
->Green
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->GreenFieldPosition
;
1681 CurrentModeData
->Green
.Mask
= (UINT8
) ((1 << BiosVideoPrivate
->VbeModeInformationBlock
->GreenMaskSize
) - 1);
1682 CurrentModeData
->Reserved
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->RsvdFieldPosition
;
1683 CurrentModeData
->Reserved
.Mask
= (UINT8
) ((1 << BiosVideoPrivate
->VbeModeInformationBlock
->RsvdMaskSize
) - 1);
1686 CurrentModeData
->PixelFormat
= PixelBitMask
;
1687 if ((BiosVideoPrivate
->VbeModeInformationBlock
->BitsPerPixel
== 32) &&
1688 (CurrentModeData
->Red
.Mask
== 0xff) && (CurrentModeData
->Green
.Mask
== 0xff) && (CurrentModeData
->Blue
.Mask
== 0xff)) {
1689 if ((CurrentModeData
->Red
.Position
== 0) && (CurrentModeData
->Green
.Position
== 8) && (CurrentModeData
->Blue
.Position
== 16)) {
1690 CurrentModeData
->PixelFormat
= PixelRedGreenBlueReserved8BitPerColor
;
1691 } else if ((CurrentModeData
->Blue
.Position
== 0) && (CurrentModeData
->Green
.Position
== 8) && (CurrentModeData
->Red
.Position
== 16)) {
1692 CurrentModeData
->PixelFormat
= PixelBlueGreenRedReserved8BitPerColor
;
1696 CurrentModeData
->PixelBitMask
.RedMask
= ((UINT32
) CurrentModeData
->Red
.Mask
) << CurrentModeData
->Red
.Position
;
1697 CurrentModeData
->PixelBitMask
.GreenMask
= ((UINT32
) CurrentModeData
->Green
.Mask
) << CurrentModeData
->Green
.Position
;
1698 CurrentModeData
->PixelBitMask
.BlueMask
= ((UINT32
) CurrentModeData
->Blue
.Mask
) << CurrentModeData
->Blue
.Position
;
1699 CurrentModeData
->PixelBitMask
.ReservedMask
= ((UINT32
) CurrentModeData
->Reserved
.Mask
) << CurrentModeData
->Reserved
.Position
;
1701 CurrentModeData
->LinearFrameBuffer
= (VOID
*) (UINTN
)BiosVideoPrivate
->VbeModeInformationBlock
->PhysBasePtr
;
1702 CurrentModeData
->HorizontalResolution
= BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
;
1703 CurrentModeData
->VerticalResolution
= BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
;
1705 CurrentModeData
->BitsPerPixel
= BiosVideoPrivate
->VbeModeInformationBlock
->BitsPerPixel
;
1706 CurrentModeData
->FrameBufferSize
= CurrentModeData
->BytesPerScanLine
* CurrentModeData
->VerticalResolution
;
1708 // Make sure the FrameBufferSize does not exceed the max available frame buffer size reported by VEB.
1710 ASSERT (CurrentModeData
->FrameBufferSize
<= ((UINT32
)BiosVideoPrivate
->VbeInformationBlock
->TotalMemory
* 64 * 1024));
1712 BiosVideoPrivate
->ModeData
= ModeBuffer
;
1715 // Check to see if we found any modes that are compatible with GRAPHICS OUTPUT
1717 if (ModeNumber
== 0) {
1718 Status
= EFI_DEVICE_ERROR
;
1723 // Assign Gop's Blt function
1725 BiosVideoPrivate
->GraphicsOutput
.Blt
= BiosVideoGraphicsOutputVbeBlt
;
1727 BiosVideoPrivate
->GraphicsOutput
.Mode
->MaxMode
= (UINT32
) ModeNumber
;
1729 // Current mode is unknow till now, set it to an invalid mode.
1731 BiosVideoPrivate
->GraphicsOutput
.Mode
->Mode
= GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER
;
1734 // Find the best mode to initialize
1736 if ((PcdGet32 (PcdVideoHorizontalResolution
) == 0x0) || (PcdGet32 (PcdVideoVerticalResolution
) == 0x0)) {
1738 BIOS_VIDEO_MODE_DATA
*ModeData
;
1739 ModeData
= &BiosVideoPrivate
->ModeData
[HighestResolutionMode
];
1740 DEBUG ((EFI_D_INFO
, "BiosVideo set highest resolution %d x %d\n",
1741 ModeData
->HorizontalResolution
, ModeData
->VerticalResolution
));
1743 PreferMode
= HighestResolutionMode
;
1745 Status
= BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate
->GraphicsOutput
, (UINT32
) PreferMode
);
1746 if (EFI_ERROR (Status
)) {
1747 for (PreferMode
= 0; PreferMode
< ModeNumber
; PreferMode
++) {
1748 Status
= BiosVideoGraphicsOutputSetMode (
1749 &BiosVideoPrivate
->GraphicsOutput
,
1752 if (!EFI_ERROR (Status
)) {
1756 if (PreferMode
== ModeNumber
) {
1758 // None mode is set successfully.
1766 // If there was an error, then free the mode structure
1768 if (EFI_ERROR (Status
)) {
1769 if (BiosVideoPrivate
->ModeData
!= NULL
) {
1770 FreePool (BiosVideoPrivate
->ModeData
);
1771 BiosVideoPrivate
->ModeData
= NULL
;
1772 BiosVideoPrivate
->MaxMode
= 0;
1774 if (EdidOverrideDataBlock
!= NULL
) {
1775 FreePool (EdidOverrideDataBlock
);
1784 Check for VGA device.
1786 @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure
1788 @retval EFI_SUCCESS Standard VGA device found
1792 BiosVideoCheckForVga (
1793 IN OUT BIOS_VIDEO_DEV
*BiosVideoPrivate
1797 BIOS_VIDEO_MODE_DATA
*ModeBuffer
;
1799 Status
= EFI_UNSUPPORTED
;
1802 // Assign Gop's Blt function
1804 BiosVideoPrivate
->GraphicsOutput
.Blt
= BiosVideoGraphicsOutputVgaBlt
;
1807 // Add mode to the list of available modes
1808 // caller should guarantee that Mode has been allocated.
1810 ASSERT (BiosVideoPrivate
->GraphicsOutput
.Mode
!= NULL
);
1811 BiosVideoPrivate
->GraphicsOutput
.Mode
->MaxMode
= 1;
1813 ModeBuffer
= (BIOS_VIDEO_MODE_DATA
*) AllocatePool (
1814 sizeof (BIOS_VIDEO_MODE_DATA
)
1816 if (NULL
== ModeBuffer
) {
1817 Status
= EFI_OUT_OF_RESOURCES
;
1821 ModeBuffer
->VbeModeNumber
= 0x0012;
1822 ModeBuffer
->BytesPerScanLine
= 640;
1823 ModeBuffer
->LinearFrameBuffer
= (VOID
*) (UINTN
) (0xa0000);
1824 ModeBuffer
->HorizontalResolution
= 640;
1825 ModeBuffer
->VerticalResolution
= 480;
1826 ModeBuffer
->PixelFormat
= PixelBltOnly
;
1827 ModeBuffer
->BitsPerPixel
= 8;
1828 ModeBuffer
->ColorDepth
= 32;
1829 ModeBuffer
->RefreshRate
= 60;
1831 BiosVideoPrivate
->ModeData
= ModeBuffer
;
1834 // Test to see if the Video Adapter support the 640x480 16 color mode
1836 BiosVideoPrivate
->GraphicsOutput
.Mode
->Mode
= GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER
;
1837 Status
= BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate
->GraphicsOutput
, 0);
1841 // If there was an error, then free the mode structure
1843 if (EFI_ERROR (Status
)) {
1844 if (BiosVideoPrivate
->ModeData
!= NULL
) {
1845 FreePool (BiosVideoPrivate
->ModeData
);
1846 BiosVideoPrivate
->ModeData
= NULL
;
1848 if (BiosVideoPrivate
->GraphicsOutput
.Mode
!= NULL
) {
1849 if (BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
!= NULL
) {
1850 FreePool (BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
);
1851 BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
= NULL
;
1853 FreePool (BiosVideoPrivate
->GraphicsOutput
.Mode
);
1854 BiosVideoPrivate
->GraphicsOutput
.Mode
= NULL
;
1861 // Graphics Output Protocol Member Functions for VESA BIOS Extensions
1865 Graphics Output protocol interface to get video mode.
1867 @param This Protocol instance pointer.
1868 @param ModeNumber The mode number to return information on.
1869 @param SizeOfInfo A pointer to the size, in bytes, of the Info
1871 @param Info Caller allocated buffer that returns information
1874 @retval EFI_SUCCESS Mode information returned.
1875 @retval EFI_DEVICE_ERROR A hardware error occurred trying to retrieve the
1877 @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode ()
1878 @retval EFI_INVALID_PARAMETER One of the input args was NULL.
1883 BiosVideoGraphicsOutputQueryMode (
1884 IN EFI_GRAPHICS_OUTPUT_PROTOCOL
*This
,
1885 IN UINT32 ModeNumber
,
1886 OUT UINTN
*SizeOfInfo
,
1887 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
**Info
1890 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
1891 BIOS_VIDEO_MODE_DATA
*ModeData
;
1893 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This
);
1895 if (BiosVideoPrivate
->HardwareNeedsStarting
) {
1896 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1897 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1898 EFI_PERIPHERAL_LOCAL_CONSOLE
| EFI_P_EC_OUTPUT_ERROR
,
1899 BiosVideoPrivate
->GopDevicePath
1901 return EFI_NOT_STARTED
;
1904 if (This
== NULL
|| Info
== NULL
|| SizeOfInfo
== NULL
|| ModeNumber
>= This
->Mode
->MaxMode
) {
1905 return EFI_INVALID_PARAMETER
;
1908 *Info
= (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
*) AllocatePool (
1909 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
)
1911 if (NULL
== *Info
) {
1912 return EFI_OUT_OF_RESOURCES
;
1915 *SizeOfInfo
= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
);
1917 ModeData
= &BiosVideoPrivate
->ModeData
[ModeNumber
];
1918 (*Info
)->Version
= 0;
1919 (*Info
)->HorizontalResolution
= ModeData
->HorizontalResolution
;
1920 (*Info
)->VerticalResolution
= ModeData
->VerticalResolution
;
1921 (*Info
)->PixelFormat
= ModeData
->PixelFormat
;
1922 CopyMem (&((*Info
)->PixelInformation
), &(ModeData
->PixelBitMask
), sizeof(ModeData
->PixelBitMask
));
1924 (*Info
)->PixelsPerScanLine
= (ModeData
->BytesPerScanLine
* 8) / ModeData
->BitsPerPixel
;
1930 Worker function to set video mode.
1932 @param BiosVideoPrivate Instance of BIOS_VIDEO_DEV.
1933 @param ModeData The mode data to be set.
1934 @param DevicePath Pointer to Device Path Protocol.
1936 @retval EFI_SUCCESS Graphics mode was changed.
1937 @retval EFI_DEVICE_ERROR The device had an error and could not complete the
1939 @retval EFI_UNSUPPORTED ModeNumber is not supported by this device.
1943 BiosVideoSetModeWorker (
1944 IN BIOS_VIDEO_DEV
*BiosVideoPrivate
,
1945 IN BIOS_VIDEO_MODE_DATA
*ModeData
,
1946 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
1950 EFI_IA32_REGISTER_SET Regs
;
1952 if (BiosVideoPrivate
->LineBuffer
!= NULL
) {
1953 FreePool (BiosVideoPrivate
->LineBuffer
);
1956 if (BiosVideoPrivate
->VgaFrameBuffer
!= NULL
) {
1957 FreePool (BiosVideoPrivate
->VgaFrameBuffer
);
1960 if (BiosVideoPrivate
->VbeFrameBuffer
!= NULL
) {
1961 FreePool (BiosVideoPrivate
->VbeFrameBuffer
);
1964 BiosVideoPrivate
->LineBuffer
= (UINT8
*) AllocatePool (
1965 ModeData
->BytesPerScanLine
1967 if (NULL
== BiosVideoPrivate
->LineBuffer
) {
1968 return EFI_OUT_OF_RESOURCES
;
1971 // Clear all registers
1973 ZeroMem (&Regs
, sizeof (Regs
));
1975 if (ModeData
->VbeModeNumber
< 0x100) {
1977 // Allocate a working buffer for BLT operations to the VGA frame buffer
1979 BiosVideoPrivate
->VgaFrameBuffer
= (UINT8
*) AllocatePool (4 * 480 * 80);
1980 if (NULL
== BiosVideoPrivate
->VgaFrameBuffer
) {
1981 return EFI_OUT_OF_RESOURCES
;
1986 Regs
.X
.AX
= ModeData
->VbeModeNumber
;
1987 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
1991 // Allocate a working buffer for BLT operations to the VBE frame buffer
1993 BiosVideoPrivate
->VbeFrameBuffer
=
1994 (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*) AllocatePool (
1995 ModeData
->BytesPerScanLine
* ModeData
->VerticalResolution
1997 if (NULL
== BiosVideoPrivate
->VbeFrameBuffer
) {
1998 return EFI_OUT_OF_RESOURCES
;
2003 Regs
.X
.AX
= VESA_BIOS_EXTENSIONS_SET_MODE
;
2004 Regs
.X
.BX
= (UINT16
) (ModeData
->VbeModeNumber
| VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER
);
2005 ZeroMem (BiosVideoPrivate
->VbeCrtcInformationBlock
, sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK
));
2006 Regs
.X
.ES
= EFI_SEGMENT ((UINTN
) BiosVideoPrivate
->VbeCrtcInformationBlock
);
2007 Regs
.X
.DI
= EFI_OFFSET ((UINTN
) BiosVideoPrivate
->VbeCrtcInformationBlock
);
2008 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
2011 // Check to see if the call succeeded
2013 if (Regs
.X
.AX
!= VESA_BIOS_EXTENSIONS_STATUS_SUCCESS
) {
2014 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
2015 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
2016 EFI_PERIPHERAL_LOCAL_CONSOLE
| EFI_P_EC_OUTPUT_ERROR
,
2019 return EFI_DEVICE_ERROR
;
2022 // Initialize the state of the VbeFrameBuffer
2024 Status
= BiosVideoPrivate
->PciIo
->Mem
.Read (
2025 BiosVideoPrivate
->PciIo
,
2026 EfiPciIoWidthUint32
,
2027 EFI_PCI_IO_PASS_THROUGH_BAR
,
2028 (UINT64
) (UINTN
) ModeData
->LinearFrameBuffer
,
2029 (ModeData
->BytesPerScanLine
* ModeData
->VerticalResolution
) >> 2,
2030 BiosVideoPrivate
->VbeFrameBuffer
2032 if (EFI_ERROR (Status
)) {
2041 Graphics Output protocol interface to set video mode.
2043 @param This Protocol instance pointer.
2044 @param ModeNumber The mode number to be set.
2046 @retval EFI_SUCCESS Graphics mode was changed.
2047 @retval EFI_DEVICE_ERROR The device had an error and could not complete the
2049 @retval EFI_UNSUPPORTED ModeNumber is not supported by this device.
2054 BiosVideoGraphicsOutputSetMode (
2055 IN EFI_GRAPHICS_OUTPUT_PROTOCOL
* This
,
2056 IN UINT32 ModeNumber
2060 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
2061 BIOS_VIDEO_MODE_DATA
*ModeData
;
2062 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background
;
2065 return EFI_INVALID_PARAMETER
;
2068 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This
);
2070 ModeData
= &BiosVideoPrivate
->ModeData
[ModeNumber
];
2072 if (ModeNumber
>= This
->Mode
->MaxMode
) {
2073 return EFI_UNSUPPORTED
;
2076 if (ModeNumber
== This
->Mode
->Mode
) {
2078 // Clear screen to black
2080 ZeroMem (&Background
, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
));
2081 BiosVideoGraphicsOutputVbeBlt (
2089 ModeData
->HorizontalResolution
,
2090 ModeData
->VerticalResolution
,
2096 Status
= BiosVideoSetModeWorker (BiosVideoPrivate
, ModeData
, BiosVideoPrivate
->GopDevicePath
);
2097 if (EFI_ERROR (Status
)) {
2101 This
->Mode
->Mode
= ModeNumber
;
2102 This
->Mode
->Info
->Version
= 0;
2103 This
->Mode
->Info
->HorizontalResolution
= ModeData
->HorizontalResolution
;
2104 This
->Mode
->Info
->VerticalResolution
= ModeData
->VerticalResolution
;
2105 This
->Mode
->Info
->PixelFormat
= ModeData
->PixelFormat
;
2106 CopyMem (&(This
->Mode
->Info
->PixelInformation
), &(ModeData
->PixelBitMask
), sizeof (ModeData
->PixelBitMask
));
2107 This
->Mode
->Info
->PixelsPerScanLine
= (ModeData
->BytesPerScanLine
* 8) / ModeData
->BitsPerPixel
;
2108 This
->Mode
->SizeOfInfo
= sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
);
2109 This
->Mode
->FrameBufferSize
= ModeData
->FrameBufferSize
;
2110 This
->Mode
->FrameBufferBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) ModeData
->LinearFrameBuffer
;
2112 BiosVideoPrivate
->HardwareNeedsStarting
= FALSE
;
2118 Update physical frame buffer, copy 4 bytes block, then copy remaining bytes.
2120 @param PciIo The pointer of EFI_PCI_IO_PROTOCOL
2121 @param VbeBuffer The data to transfer to screen
2122 @param MemAddress Physical frame buffer base address
2123 @param DestinationX The X coordinate of the destination for BltOperation
2124 @param DestinationY The Y coordinate of the destination for BltOperation
2125 @param TotalBytes The total bytes of copy
2126 @param VbePixelWidth Bytes per pixel
2127 @param BytesPerScanLine Bytes per scan line
2132 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2133 IN UINT8
*VbeBuffer
,
2134 IN VOID
*MemAddress
,
2135 IN UINTN DestinationX
,
2136 IN UINTN DestinationY
,
2137 IN UINTN TotalBytes
,
2138 IN UINT32 VbePixelWidth
,
2139 IN UINTN BytesPerScanLine
2142 UINTN FrameBufferAddr
;
2144 UINTN RemainingBytes
;
2145 UINTN UnalignedBytes
;
2148 FrameBufferAddr
= (UINTN
) MemAddress
+ (DestinationY
* BytesPerScanLine
) + DestinationX
* VbePixelWidth
;
2151 // If TotalBytes is less than 4 bytes, only start byte copy.
2153 if (TotalBytes
< 4) {
2154 Status
= PciIo
->Mem
.Write (
2157 EFI_PCI_IO_PASS_THROUGH_BAR
,
2158 (UINT64
) FrameBufferAddr
,
2162 ASSERT_EFI_ERROR (Status
);
2167 // If VbeBuffer is not 4-byte aligned, start byte copy.
2169 UnalignedBytes
= (4 - ((UINTN
) VbeBuffer
& 0x3)) & 0x3;
2171 if (UnalignedBytes
!= 0) {
2172 Status
= PciIo
->Mem
.Write (
2175 EFI_PCI_IO_PASS_THROUGH_BAR
,
2176 (UINT64
) FrameBufferAddr
,
2180 ASSERT_EFI_ERROR (Status
);
2181 FrameBufferAddr
+= UnalignedBytes
;
2182 VbeBuffer
+= UnalignedBytes
;
2186 // Calculate 4-byte block count and remaining bytes.
2188 CopyBlockNum
= (TotalBytes
- UnalignedBytes
) >> 2;
2189 RemainingBytes
= (TotalBytes
- UnalignedBytes
) & 3;
2192 // Copy 4-byte block and remaining bytes to physical frame buffer.
2194 if (CopyBlockNum
!= 0) {
2195 Status
= PciIo
->Mem
.Write (
2197 EfiPciIoWidthUint32
,
2198 EFI_PCI_IO_PASS_THROUGH_BAR
,
2199 (UINT64
) FrameBufferAddr
,
2203 ASSERT_EFI_ERROR (Status
);
2206 if (RemainingBytes
!= 0) {
2207 FrameBufferAddr
+= (CopyBlockNum
<< 2);
2208 VbeBuffer
+= (CopyBlockNum
<< 2);
2209 Status
= PciIo
->Mem
.Write (
2212 EFI_PCI_IO_PASS_THROUGH_BAR
,
2213 (UINT64
) FrameBufferAddr
,
2217 ASSERT_EFI_ERROR (Status
);
2222 Worker function to block transfer for VBE device.
2224 @param BiosVideoPrivate Instance of BIOS_VIDEO_DEV
2225 @param BltBuffer The data to transfer to screen
2226 @param BltOperation The operation to perform
2227 @param SourceX The X coordinate of the source for BltOperation
2228 @param SourceY The Y coordinate of the source for BltOperation
2229 @param DestinationX The X coordinate of the destination for
2231 @param DestinationY The Y coordinate of the destination for
2233 @param Width The width of a rectangle in the blt rectangle in
2235 @param Height The height of a rectangle in the blt rectangle in
2237 @param Delta Not used for EfiBltVideoFill and
2238 EfiBltVideoToVideo operation. If a Delta of 0 is
2239 used, the entire BltBuffer will be operated on. If
2240 a subrectangle of the BltBuffer is used, then
2241 Delta represents the number of bytes in a row of
2243 @param Mode Mode data.
2245 @retval EFI_INVALID_PARAMETER Invalid parameter passed in
2246 @retval EFI_SUCCESS Blt operation success
2250 BiosVideoVbeBltWorker (
2251 IN BIOS_VIDEO_DEV
*BiosVideoPrivate
,
2252 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*BltBuffer
, OPTIONAL
2253 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation
,
2256 IN UINTN DestinationX
,
2257 IN UINTN DestinationY
,
2261 IN BIOS_VIDEO_MODE_DATA
*Mode
2264 EFI_PCI_IO_PROTOCOL
*PciIo
;
2265 EFI_TPL OriginalTPL
;
2269 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*Blt
;
2271 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*VbeFrameBuffer
;
2272 UINTN BytesPerScanLine
;
2277 UINT32 VbePixelWidth
;
2281 PciIo
= BiosVideoPrivate
->PciIo
;
2283 VbeFrameBuffer
= BiosVideoPrivate
->VbeFrameBuffer
;
2284 MemAddress
= Mode
->LinearFrameBuffer
;
2285 BytesPerScanLine
= Mode
->BytesPerScanLine
;
2286 VbePixelWidth
= Mode
->BitsPerPixel
/ 8;
2287 BltUint8
= (UINT8
*) BltBuffer
;
2288 TotalBytes
= Width
* VbePixelWidth
;
2290 if (((UINTN
) BltOperation
) >= EfiGraphicsOutputBltOperationMax
) {
2291 return EFI_INVALID_PARAMETER
;
2294 if (Width
== 0 || Height
== 0) {
2295 return EFI_INVALID_PARAMETER
;
2298 // We need to fill the Virtual Screen buffer with the blt data.
2299 // The virtual screen is upside down, as the first row is the bootom row of
2302 if (BltOperation
== EfiBltVideoToBltBuffer
) {
2304 // Video to BltBuffer: Source is Video, destination is BltBuffer
2306 if (SourceY
+ Height
> Mode
->VerticalResolution
) {
2307 return EFI_INVALID_PARAMETER
;
2310 if (SourceX
+ Width
> Mode
->HorizontalResolution
) {
2311 return EFI_INVALID_PARAMETER
;
2315 // BltBuffer to Video: Source is BltBuffer, destination is Video
2317 if (DestinationY
+ Height
> Mode
->VerticalResolution
) {
2318 return EFI_INVALID_PARAMETER
;
2321 if (DestinationX
+ Width
> Mode
->HorizontalResolution
) {
2322 return EFI_INVALID_PARAMETER
;
2326 // If Delta is zero, then the entire BltBuffer is being used, so Delta
2327 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
2328 // the number of bytes in each row can be computed.
2331 Delta
= Width
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
);
2334 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
2335 // We would not want a timer based event (Cursor, ...) to come in while we are
2336 // doing this operation.
2338 OriginalTPL
= gBS
->RaiseTPL (TPL_NOTIFY
);
2340 switch (BltOperation
) {
2341 case EfiBltVideoToBltBuffer
:
2342 for (SrcY
= SourceY
, DstY
= DestinationY
; DstY
< (Height
+ DestinationY
); SrcY
++, DstY
++) {
2343 Blt
= (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*) (BltUint8
+ DstY
* Delta
+ DestinationX
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
));
2345 // Shuffle the packed bytes in the hardware buffer to match EFI_GRAPHICS_OUTPUT_BLT_PIXEL
2347 VbeBuffer
= ((UINT8
*) VbeFrameBuffer
+ (SrcY
* BytesPerScanLine
+ SourceX
* VbePixelWidth
));
2348 for (DstX
= DestinationX
; DstX
< (Width
+ DestinationX
); DstX
++) {
2349 Pixel
= VbeBuffer
[0] | VbeBuffer
[1] << 8 | VbeBuffer
[2] << 16 | VbeBuffer
[3] << 24;
2350 Blt
->Red
= (UINT8
) ((Pixel
>> Mode
->Red
.Position
) & Mode
->Red
.Mask
);
2351 Blt
->Blue
= (UINT8
) ((Pixel
>> Mode
->Blue
.Position
) & Mode
->Blue
.Mask
);
2352 Blt
->Green
= (UINT8
) ((Pixel
>> Mode
->Green
.Position
) & Mode
->Green
.Mask
);
2355 VbeBuffer
+= VbePixelWidth
;
2361 case EfiBltVideoToVideo
:
2362 for (Index
= 0; Index
< Height
; Index
++) {
2363 if (DestinationY
<= SourceY
) {
2364 SrcY
= SourceY
+ Index
;
2365 DstY
= DestinationY
+ Index
;
2367 SrcY
= SourceY
+ Height
- Index
- 1;
2368 DstY
= DestinationY
+ Height
- Index
- 1;
2371 VbeBuffer
= ((UINT8
*) VbeFrameBuffer
+ DstY
* BytesPerScanLine
+ DestinationX
* VbePixelWidth
);
2372 VbeBuffer1
= ((UINT8
*) VbeFrameBuffer
+ SrcY
* BytesPerScanLine
+ SourceX
* VbePixelWidth
);
2381 // Update physical frame buffer.
2396 case EfiBltVideoFill
:
2397 VbeBuffer
= (UINT8
*) ((UINTN
) VbeFrameBuffer
+ (DestinationY
* BytesPerScanLine
) + DestinationX
* VbePixelWidth
);
2398 Blt
= (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*) BltUint8
;
2400 // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
2402 Pixel
= ((Blt
->Red
& Mode
->Red
.Mask
) << Mode
->Red
.Position
) |
2404 (Blt
->Green
& Mode
->Green
.Mask
) <<
2405 Mode
->Green
.Position
2407 ((Blt
->Blue
& Mode
->Blue
.Mask
) << Mode
->Blue
.Position
);
2409 for (Index
= 0; Index
< Width
; Index
++) {
2415 VbeBuffer
+= VbePixelWidth
;
2418 VbeBuffer
= (UINT8
*) ((UINTN
) VbeFrameBuffer
+ (DestinationY
* BytesPerScanLine
) + DestinationX
* VbePixelWidth
);
2419 for (DstY
= DestinationY
+ 1; DstY
< (Height
+ DestinationY
); DstY
++) {
2421 (VOID
*) ((UINTN
) VbeFrameBuffer
+ (DstY
* BytesPerScanLine
) + DestinationX
* VbePixelWidth
),
2427 for (DstY
= DestinationY
; DstY
< (Height
+ DestinationY
); DstY
++) {
2429 // Update physical frame buffer.
2444 case EfiBltBufferToVideo
:
2445 for (SrcY
= SourceY
, DstY
= DestinationY
; SrcY
< (Height
+ SourceY
); SrcY
++, DstY
++) {
2446 Blt
= (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*) (BltUint8
+ (SrcY
* Delta
) + (SourceX
) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
));
2447 VbeBuffer
= ((UINT8
*) VbeFrameBuffer
+ (DstY
* BytesPerScanLine
+ DestinationX
* VbePixelWidth
));
2448 for (DstX
= DestinationX
; DstX
< (Width
+ DestinationX
); DstX
++) {
2450 // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
2452 Pixel
= ((Blt
->Red
& Mode
->Red
.Mask
) << Mode
->Red
.Position
) |
2453 ((Blt
->Green
& Mode
->Green
.Mask
) << Mode
->Green
.Position
) |
2454 ((Blt
->Blue
& Mode
->Blue
.Mask
) << Mode
->Blue
.Position
);
2461 VbeBuffer
+= VbePixelWidth
;
2464 VbeBuffer
= ((UINT8
*) VbeFrameBuffer
+ (DstY
* BytesPerScanLine
+ DestinationX
* VbePixelWidth
));
2467 // Update physical frame buffer.
2485 gBS
->RestoreTPL (OriginalTPL
);
2491 Graphics Output protocol instance to block transfer for VBE device.
2493 @param This Pointer to Graphics Output protocol instance
2494 @param BltBuffer The data to transfer to screen
2495 @param BltOperation The operation to perform
2496 @param SourceX The X coordinate of the source for BltOperation
2497 @param SourceY The Y coordinate of the source for BltOperation
2498 @param DestinationX The X coordinate of the destination for
2500 @param DestinationY The Y coordinate of the destination for
2502 @param Width The width of a rectangle in the blt rectangle in
2504 @param Height The height of a rectangle in the blt rectangle in
2506 @param Delta Not used for EfiBltVideoFill and
2507 EfiBltVideoToVideo operation. If a Delta of 0 is
2508 used, the entire BltBuffer will be operated on. If
2509 a subrectangle of the BltBuffer is used, then
2510 Delta represents the number of bytes in a row of
2513 @retval EFI_INVALID_PARAMETER Invalid parameter passed in
2514 @retval EFI_SUCCESS Blt operation success
2519 BiosVideoGraphicsOutputVbeBlt (
2520 IN EFI_GRAPHICS_OUTPUT_PROTOCOL
*This
,
2521 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*BltBuffer
, OPTIONAL
2522 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation
,
2525 IN UINTN DestinationX
,
2526 IN UINTN DestinationY
,
2532 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
2533 BIOS_VIDEO_MODE_DATA
*Mode
;
2536 return EFI_INVALID_PARAMETER
;
2539 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This
);
2540 Mode
= &BiosVideoPrivate
->ModeData
[This
->Mode
->Mode
];
2542 return BiosVideoVbeBltWorker (
2558 Write graphics controller registers.
2560 @param PciIo Pointer to PciIo protocol instance of the
2562 @param Address Register address
2563 @param Data Data to be written to register
2569 WriteGraphicsController (
2570 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2575 Address
= Address
| (Data
<< 8);
2578 EfiPciIoWidthUint16
,
2579 EFI_PCI_IO_PASS_THROUGH_BAR
,
2580 VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER
,
2588 Read the four bit plane of VGA frame buffer.
2590 @param PciIo Pointer to PciIo protocol instance of the
2592 @param HardwareBuffer Hardware VGA frame buffer address
2593 @param MemoryBuffer Memory buffer address
2594 @param WidthInBytes Number of bytes in a line to read
2595 @param Height Height of the area to read
2602 EFI_PCI_IO_PROTOCOL
*PciIo
,
2603 UINT8
*HardwareBuffer
,
2604 UINT8
*MemoryBuffer
,
2611 UINTN FrameBufferOffset
;
2616 // Program the Mode Register Write mode 0, Read mode 0
2618 WriteGraphicsController (
2620 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER
,
2621 VGA_GRAPHICS_CONTROLLER_READ_MODE_0
| VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0
2624 for (BitPlane
= 0, FrameBufferOffset
= 0;
2625 BitPlane
< VGA_NUMBER_OF_BIT_PLANES
;
2626 BitPlane
++, FrameBufferOffset
+= VGA_BYTES_PER_BIT_PLANE
2629 // Program the Read Map Select Register to select the correct bit plane
2631 WriteGraphicsController (
2633 VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER
,
2637 Source
= HardwareBuffer
;
2638 Destination
= MemoryBuffer
+ FrameBufferOffset
;
2640 for (Rows
= 0; Rows
< Height
; Rows
++, Source
+= VGA_BYTES_PER_SCAN_LINE
, Destination
+= VGA_BYTES_PER_SCAN_LINE
) {
2644 EFI_PCI_IO_PASS_THROUGH_BAR
,
2645 (UINT64
) (UINTN
) Source
,
2647 (VOID
*) Destination
2655 Internal routine to convert VGA color to Grahpics Output color.
2657 @param MemoryBuffer Buffer containing VGA color
2658 @param CoordinateX The X coordinate of pixel on screen
2659 @param CoordinateY The Y coordinate of pixel on screen
2660 @param BltBuffer Buffer to contain converted Grahpics Output color
2666 VgaConvertToGraphicsOutputColor (
2667 UINT8
*MemoryBuffer
,
2670 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*BltBuffer
2677 MemoryBuffer
+= ((CoordinateY
<< 6) + (CoordinateY
<< 4) + (CoordinateX
>> 3));
2678 Mask
= mVgaBitMaskTable
[CoordinateX
& 0x07];
2679 for (Bit
= 0x01, Color
= 0; Bit
< 0x10; Bit
<<= 1, MemoryBuffer
+= VGA_BYTES_PER_BIT_PLANE
) {
2680 if ((*MemoryBuffer
& Mask
) != 0) {
2685 *BltBuffer
= mVgaColorToGraphicsOutputColor
[Color
];
2689 Internal routine to convert Grahpics Output color to VGA color.
2691 @param BltBuffer buffer containing Grahpics Output color
2693 @return Converted VGA color
2698 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*BltBuffer
2703 Color
= (UINT8
) ((BltBuffer
->Blue
>> 7) | ((BltBuffer
->Green
>> 6) & 0x02) | ((BltBuffer
->Red
>> 5) & 0x04));
2704 if ((BltBuffer
->Red
+ BltBuffer
->Green
+ BltBuffer
->Blue
) > 0x180) {
2713 Grahpics Output protocol instance to block transfer for VGA device.
2715 @param This Pointer to Grahpics Output protocol instance
2716 @param BltBuffer The data to transfer to screen
2717 @param BltOperation The operation to perform
2718 @param SourceX The X coordinate of the source for BltOperation
2719 @param SourceY The Y coordinate of the source for BltOperation
2720 @param DestinationX The X coordinate of the destination for
2722 @param DestinationY The Y coordinate of the destination for
2724 @param Width The width of a rectangle in the blt rectangle in
2726 @param Height The height of a rectangle in the blt rectangle in
2728 @param Delta Not used for EfiBltVideoFill and
2729 EfiBltVideoToVideo operation. If a Delta of 0 is
2730 used, the entire BltBuffer will be operated on. If
2731 a subrectangle of the BltBuffer is used, then
2732 Delta represents the number of bytes in a row of
2735 @retval EFI_INVALID_PARAMETER Invalid parameter passed in
2736 @retval EFI_SUCCESS Blt operation success
2741 BiosVideoGraphicsOutputVgaBlt (
2742 IN EFI_GRAPHICS_OUTPUT_PROTOCOL
*This
,
2743 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*BltBuffer
, OPTIONAL
2744 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation
,
2747 IN UINTN DestinationX
,
2748 IN UINTN DestinationY
,
2754 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
2755 EFI_TPL OriginalTPL
;
2757 UINTN BytesPerScanLine
;
2769 UINT8
*SourceAddress
;
2770 UINT8
*DestinationAddress
;
2771 EFI_PCI_IO_PROTOCOL
*PciIo
;
2774 UINT8
*VgaFrameBuffer
;
2783 if (This
== NULL
|| ((UINTN
) BltOperation
) >= EfiGraphicsOutputBltOperationMax
) {
2784 return EFI_INVALID_PARAMETER
;
2787 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This
);
2789 CurrentMode
= This
->Mode
->Mode
;
2790 PciIo
= BiosVideoPrivate
->PciIo
;
2791 MemAddress
= BiosVideoPrivate
->ModeData
[CurrentMode
].LinearFrameBuffer
;
2792 BytesPerScanLine
= BiosVideoPrivate
->ModeData
[CurrentMode
].BytesPerScanLine
>> 3;
2793 VgaFrameBuffer
= BiosVideoPrivate
->VgaFrameBuffer
;
2796 if (Width
== 0 || Height
== 0) {
2797 return EFI_INVALID_PARAMETER
;
2800 // We need to fill the Virtual Screen buffer with the blt data.
2801 // The virtual screen is upside down, as the first row is the bootom row of
2804 if (BltOperation
== EfiBltVideoToBltBuffer
) {
2806 // Video to BltBuffer: Source is Video, destination is BltBuffer
2808 if (SourceY
+ Height
> BiosVideoPrivate
->ModeData
[CurrentMode
].VerticalResolution
) {
2809 return EFI_INVALID_PARAMETER
;
2812 if (SourceX
+ Width
> BiosVideoPrivate
->ModeData
[CurrentMode
].HorizontalResolution
) {
2813 return EFI_INVALID_PARAMETER
;
2817 // BltBuffer to Video: Source is BltBuffer, destination is Video
2819 if (DestinationY
+ Height
> BiosVideoPrivate
->ModeData
[CurrentMode
].VerticalResolution
) {
2820 return EFI_INVALID_PARAMETER
;
2823 if (DestinationX
+ Width
> BiosVideoPrivate
->ModeData
[CurrentMode
].HorizontalResolution
) {
2824 return EFI_INVALID_PARAMETER
;
2828 // If Delta is zero, then the entire BltBuffer is being used, so Delta
2829 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
2830 // the number of bytes in each row can be computed.
2833 Delta
= Width
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
);
2836 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
2837 // We would not want a timer based event (Cursor, ...) to come in while we are
2838 // doing this operation.
2840 OriginalTPL
= gBS
->RaiseTPL (TPL_NOTIFY
);
2843 // Compute some values we need for VGA
2845 switch (BltOperation
) {
2846 case EfiBltVideoToBltBuffer
:
2848 SourceOffset
= (SourceY
<< 6) + (SourceY
<< 4) + (SourceX
>> 3);
2849 SourceWidth
= ((SourceX
+ Width
- 1) >> 3) - (SourceX
>> 3) + 1;
2852 // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2856 MemAddress
+ SourceOffset
,
2857 VgaFrameBuffer
+ SourceOffset
,
2863 // Convert VGA Bit Planes to a Graphics Output 32-bit color value
2865 BltBuffer
+= (DestinationY
* (Delta
>> 2) + DestinationX
);
2866 for (Rows
= 0, CoordinateY
= SourceY
; Rows
< Height
; Rows
++, CoordinateY
++, BltBuffer
+= (Delta
>> 2)) {
2867 for (Columns
= 0, CoordinateX
= SourceX
; Columns
< Width
; Columns
++, CoordinateX
++, BltBuffer
++) {
2868 VgaConvertToGraphicsOutputColor (VgaFrameBuffer
, CoordinateX
, CoordinateY
, BltBuffer
);
2876 case EfiBltVideoToVideo
:
2878 // Check for an aligned Video to Video operation
2880 if ((SourceX
& 0x07) == 0x00 && (DestinationX
& 0x07) == 0x00 && (Width
& 0x07) == 0x00) {
2882 // Program the Mode Register Write mode 1, Read mode 0
2884 WriteGraphicsController (
2886 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER
,
2887 VGA_GRAPHICS_CONTROLLER_READ_MODE_0
| VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1
2890 SourceAddress
= (UINT8
*) (MemAddress
+ (SourceY
<< 6) + (SourceY
<< 4) + (SourceX
>> 3));
2891 DestinationAddress
= (UINT8
*) (MemAddress
+ (DestinationY
<< 6) + (DestinationY
<< 4) + (DestinationX
>> 3));
2893 for (Index
= 0, Offset
= 0; Index
< Height
; Index
++, Offset
+= BytesPerScanLine
) {
2897 EFI_PCI_IO_PASS_THROUGH_BAR
,
2898 (UINT64
) (UINTN
) (DestinationAddress
+ Offset
),
2899 EFI_PCI_IO_PASS_THROUGH_BAR
,
2900 (UINT64
) (UINTN
) (SourceAddress
+ Offset
),
2905 SourceOffset
= (SourceY
<< 6) + (SourceY
<< 4) + (SourceX
>> 3);
2906 SourceWidth
= ((SourceX
+ Width
- 1) >> 3) - (SourceX
>> 3) + 1;
2909 // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2913 MemAddress
+ SourceOffset
,
2914 VgaFrameBuffer
+ SourceOffset
,
2922 case EfiBltVideoFill
:
2923 StartAddress
= (UINTN
) (MemAddress
+ (DestinationY
<< 6) + (DestinationY
<< 4) + (DestinationX
>> 3));
2924 Bytes
= ((DestinationX
+ Width
- 1) >> 3) - (DestinationX
>> 3);
2925 LeftMask
= mVgaLeftMaskTable
[DestinationX
& 0x07];
2926 RightMask
= mVgaRightMaskTable
[(DestinationX
+ Width
- 1) & 0x07];
2928 LeftMask
= (UINT8
) (LeftMask
& RightMask
);
2932 if (LeftMask
== 0xff) {
2938 if (RightMask
== 0xff) {
2943 PixelColor
= VgaConvertColor (BltBuffer
);
2946 // Program the Mode Register Write mode 2, Read mode 0
2948 WriteGraphicsController (
2950 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER
,
2951 VGA_GRAPHICS_CONTROLLER_READ_MODE_0
| VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
2955 // Program the Data Rotate/Function Select Register to replace
2957 WriteGraphicsController (
2959 VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER
,
2960 VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
2963 if (LeftMask
!= 0) {
2965 // Program the BitMask register with the Left column mask
2967 WriteGraphicsController (
2969 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER
,
2973 for (Index
= 0, Address
= StartAddress
; Index
< Height
; Index
++, Address
+= BytesPerScanLine
) {
2975 // Read data from the bit planes into the latches
2980 EFI_PCI_IO_PASS_THROUGH_BAR
,
2981 (UINT64
) (UINTN
) Address
,
2986 // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
2991 EFI_PCI_IO_PASS_THROUGH_BAR
,
2992 (UINT64
) (UINTN
) Address
,
3001 // Program the BitMask register with the middle column mask of 0xff
3003 WriteGraphicsController (
3005 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER
,
3009 for (Index
= 0, Address
= StartAddress
+ 1; Index
< Height
; Index
++, Address
+= BytesPerScanLine
) {
3012 EfiPciIoWidthFillUint8
,
3013 EFI_PCI_IO_PASS_THROUGH_BAR
,
3014 (UINT64
) (UINTN
) Address
,
3021 if (RightMask
!= 0) {
3023 // Program the BitMask register with the Right column mask
3025 WriteGraphicsController (
3027 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER
,
3031 for (Index
= 0, Address
= StartAddress
+ Bytes
; Index
< Height
; Index
++, Address
+= BytesPerScanLine
) {
3033 // Read data from the bit planes into the latches
3038 EFI_PCI_IO_PASS_THROUGH_BAR
,
3039 (UINT64
) (UINTN
) Address
,
3044 // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
3049 EFI_PCI_IO_PASS_THROUGH_BAR
,
3050 (UINT64
) (UINTN
) Address
,
3058 case EfiBltBufferToVideo
:
3059 StartAddress
= (UINTN
) (MemAddress
+ (DestinationY
<< 6) + (DestinationY
<< 4) + (DestinationX
>> 3));
3060 LeftMask
= mVgaBitMaskTable
[DestinationX
& 0x07];
3063 // Program the Mode Register Write mode 2, Read mode 0
3065 WriteGraphicsController (
3067 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER
,
3068 VGA_GRAPHICS_CONTROLLER_READ_MODE_0
| VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
3072 // Program the Data Rotate/Function Select Register to replace
3074 WriteGraphicsController (
3076 VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER
,
3077 VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
3080 for (Index
= 0, Address
= StartAddress
; Index
< Height
; Index
++, Address
+= BytesPerScanLine
) {
3081 for (Index1
= 0; Index1
< Width
; Index1
++) {
3082 BiosVideoPrivate
->LineBuffer
[Index1
] = VgaConvertColor (&BltBuffer
[(SourceY
+ Index
) * (Delta
>> 2) + SourceX
+ Index1
]);
3084 AddressFix
= Address
;
3086 for (Bit
= 0; Bit
< 8; Bit
++) {
3088 // Program the BitMask register with the Left column mask
3090 WriteGraphicsController (
3092 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER
,
3096 for (Index1
= Bit
, Address1
= (UINT8
*) AddressFix
; Index1
< Width
; Index1
+= 8, Address1
++) {
3098 // Read data from the bit planes into the latches
3103 EFI_PCI_IO_PASS_THROUGH_BAR
,
3104 (UINT64
) (UINTN
) Address1
,
3112 EFI_PCI_IO_PASS_THROUGH_BAR
,
3113 (UINT64
) (UINTN
) Address1
,
3115 &BiosVideoPrivate
->LineBuffer
[Index1
]
3119 LeftMask
= (UINT8
) (LeftMask
>> 1);
3120 if (LeftMask
== 0) {
3132 gBS
->RestoreTPL (OriginalTPL
);
3138 // VGA Mini Port Protocol Functions
3142 VgaMiniPort protocol interface to set mode.
3144 @param This Pointer to VgaMiniPort protocol instance
3145 @param ModeNumber The index of the mode
3147 @retval EFI_UNSUPPORTED The requested mode is not supported
3148 @retval EFI_SUCCESS The requested mode is set successfully
3153 BiosVideoVgaMiniPortSetMode (
3154 IN EFI_VGA_MINI_PORT_PROTOCOL
*This
,
3158 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
3159 EFI_IA32_REGISTER_SET Regs
;
3162 return EFI_INVALID_PARAMETER
;
3166 // Make sure the ModeNumber is a valid value
3168 if (ModeNumber
>= This
->MaxMode
) {
3169 return EFI_UNSUPPORTED
;
3172 // Get the device structure for this device
3174 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (This
);
3176 switch (ModeNumber
) {
3179 // Set the 80x25 Text VGA Mode
3183 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
3188 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
3193 // Set the 80x50 Text VGA Mode
3197 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
3201 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
3205 return EFI_UNSUPPORTED
;
3212 Event handler for Exit Boot Service.
3214 @param Event The event that be siganlled when exiting boot service.
3215 @param Context Pointer to instance of BIOS_VIDEO_DEV.
3220 BiosVideoNotifyExitBootServices (
3225 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
3226 EFI_IA32_REGISTER_SET Regs
;
3228 BiosVideoPrivate
= (BIOS_VIDEO_DEV
*)Context
;
3231 // Set the 80x25 Text VGA Mode
3235 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
3239 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
3244 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
3248 The user Entry Point for module UefiBiosVideo. The user code starts with this function.
3250 @param[in] ImageHandle The firmware allocated handle for the EFI image.
3251 @param[in] SystemTable A pointer to the EFI System Table.
3253 @retval EFI_SUCCESS The entry point is executed successfully.
3254 @retval other Some error occurs when executing this entry point.
3259 BiosVideoEntryPoint(
3260 IN EFI_HANDLE ImageHandle
,
3261 IN EFI_SYSTEM_TABLE
*SystemTable
3267 // Install driver model protocol(s).
3269 Status
= EfiLibInstallDriverBindingComponentName2 (
3272 &gBiosVideoDriverBinding
,
3274 &gBiosVideoComponentName
,
3275 &gBiosVideoComponentName2
3277 ASSERT_EFI_ERROR (Status
);
3280 // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver
3282 return gBS
->InstallMultipleProtocolInterfaces (
3284 &gEfiLegacyBiosGuid
,