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
;
159 // See if this is a PCI Graphics Controller by looking at the Command register and
160 // Class Code Register
162 Status
= PciIo
->Pci
.Read (
166 sizeof (Pci
) / sizeof (UINT32
),
169 if (EFI_ERROR (Status
)) {
170 Status
= EFI_UNSUPPORTED
;
174 Status
= EFI_UNSUPPORTED
;
175 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
)))
196 Status
= EFI_UNSUPPORTED
;
205 &gEfiPciIoProtocolGuid
,
206 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
)) {
296 mPciAttributesSaved
= TRUE
;
300 // Get supported PCI attributes
302 Status
= PciIo
->Attributes (
304 EfiPciIoAttributeOperationSupported
,
308 if (EFI_ERROR (Status
)) {
312 Supports
&= (UINT64
)(EFI_PCI_IO_ATTRIBUTE_VGA_IO
| EFI_PCI_IO_ATTRIBUTE_VGA_IO_16
);
313 if ((Supports
== 0) || (Supports
== (EFI_PCI_IO_ATTRIBUTE_VGA_IO
| EFI_PCI_IO_ATTRIBUTE_VGA_IO_16
))) {
314 Status
= EFI_UNSUPPORTED
;
318 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
320 EFI_PERIPHERAL_LOCAL_CONSOLE
| EFI_P_PC_ENABLE
,
324 // Enable the device and make sure VGA cycles are being forwarded to this VGA device
326 Status
= PciIo
->Attributes (
328 EfiPciIoAttributeOperationEnable
,
329 EFI_PCI_DEVICE_ENABLE
| EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY
| Supports
,
332 if (EFI_ERROR (Status
)) {
333 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
334 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
335 EFI_PERIPHERAL_LOCAL_CONSOLE
| EFI_P_EC_RESOURCE_CONFLICT
,
342 // Check to see if there is a legacy option ROM image associated with this PCI device
344 Status
= LegacyBios
->CheckPciRom (
351 if (EFI_ERROR (Status
)) {
356 // Post the legacy option ROM if it is available.
358 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
363 Status
= LegacyBios
->InstallPciRom (
373 if (EFI_ERROR (Status
)) {
374 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
375 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
376 EFI_PERIPHERAL_LOCAL_CONSOLE
| EFI_P_EC_CONTROLLER_ERROR
,
382 if (RemainingDevicePath
!= NULL
) {
383 if (IsDevicePathEnd (RemainingDevicePath
) &&
384 (FeaturePcdGet (PcdBiosVideoCheckVbeEnable
) || FeaturePcdGet (PcdBiosVideoCheckVgaEnable
)))
387 // If RemainingDevicePath is the End of Device Path Node,
388 // don't create any child device and return EFI_SUCCESS
389 Status
= EFI_SUCCESS
;
395 // Create child handle and install GraphicsOutputProtocol on it
397 Status
= BiosVideoChildHandleInstall (
407 if ((EFI_ERROR (Status
)) && (Status
!= EFI_ALREADY_STARTED
)) {
408 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
410 EFI_PERIPHERAL_LOCAL_CONSOLE
| EFI_P_PC_DISABLE
,
414 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
416 EFI_PERIPHERAL_LOCAL_CONSOLE
| EFI_P_EC_NOT_DETECTED
,
419 if (!HasChildHandle (Controller
)) {
420 if (mPciAttributesSaved
) {
422 // Restore original PCI attributes
426 EfiPciIoAttributeOperationSet
,
427 mOriginalPciAttributes
,
434 // Release PCI I/O Protocols on the controller handle.
438 &gEfiPciIoProtocolGuid
,
439 This
->DriverBindingHandle
,
450 @param This Pointer to driver binding protocol
451 @param Controller Controller handle to connect
452 @param NumberOfChildren Number of children handle created by this driver
453 @param ChildHandleBuffer Buffer containing child handle created
455 @retval EFI_SUCCESS Driver disconnected successfully from controller
456 @retval EFI_UNSUPPORTED Cannot find BIOS_VIDEO_DEV structure
461 BiosVideoDriverBindingStop (
462 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
463 IN EFI_HANDLE Controller
,
464 IN UINTN NumberOfChildren
,
465 IN EFI_HANDLE
*ChildHandleBuffer
469 BOOLEAN AllChildrenStopped
;
471 EFI_PCI_IO_PROTOCOL
*PciIo
;
473 AllChildrenStopped
= TRUE
;
475 if (NumberOfChildren
== 0) {
477 // Close PCI I/O protocol on the controller handle
481 &gEfiPciIoProtocolGuid
,
482 This
->DriverBindingHandle
,
489 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
490 Status
= BiosVideoChildHandleUninstall (This
, Controller
, ChildHandleBuffer
[Index
]);
492 if (EFI_ERROR (Status
)) {
493 AllChildrenStopped
= FALSE
;
497 if (!AllChildrenStopped
) {
498 return EFI_DEVICE_ERROR
;
501 if (!HasChildHandle (Controller
)) {
502 if (mPciAttributesSaved
) {
503 Status
= gBS
->HandleProtocol (
505 &gEfiPciIoProtocolGuid
,
508 ASSERT_EFI_ERROR (Status
);
511 // Restore original PCI attributes
513 Status
= PciIo
->Attributes (
515 EfiPciIoAttributeOperationSet
,
516 mOriginalPciAttributes
,
519 ASSERT_EFI_ERROR (Status
);
527 Install child handles if the Handle supports MBR format.
529 @param This Calling context.
530 @param ParentHandle Parent Handle
531 @param ParentPciIo Parent PciIo interface
532 @param ParentLegacyBios Parent LegacyBios interface
533 @param ParentDevicePath Parent Device Path
534 @param RemainingDevicePath Remaining Device Path
536 @retval EFI_SUCCESS If a child handle was added
537 @retval other A child handle was not added
541 BiosVideoChildHandleInstall (
542 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
543 IN EFI_HANDLE ParentHandle
,
544 IN EFI_PCI_IO_PROTOCOL
*ParentPciIo
,
545 IN EFI_LEGACY_BIOS_PROTOCOL
*ParentLegacyBios
,
546 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
547 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
551 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
553 ACPI_ADR_DEVICE_PATH AcpiDeviceNode
;
554 BOOLEAN ProtocolInstalled
;
557 // Allocate the private device structure for video device
559 BiosVideoPrivate
= (BIOS_VIDEO_DEV
*)AllocateZeroPool (
560 sizeof (BIOS_VIDEO_DEV
)
562 if (NULL
== BiosVideoPrivate
) {
563 Status
= EFI_OUT_OF_RESOURCES
;
568 // See if this is a VGA compatible controller or not
570 Status
= ParentPciIo
->Pci
.Read (
574 sizeof (Pci
) / sizeof (UINT32
),
577 if (EFI_ERROR (Status
)) {
578 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
579 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
580 EFI_PERIPHERAL_LOCAL_CONSOLE
| EFI_P_EC_CONTROLLER_ERROR
,
586 BiosVideoPrivate
->VgaCompatible
= FALSE
;
587 if ((Pci
.Hdr
.ClassCode
[2] == 0x00) && (Pci
.Hdr
.ClassCode
[1] == 0x01)) {
588 BiosVideoPrivate
->VgaCompatible
= TRUE
;
591 if ((Pci
.Hdr
.ClassCode
[2] == 0x03) && (Pci
.Hdr
.ClassCode
[1] == 0x00) && (Pci
.Hdr
.ClassCode
[0] == 0x00)) {
592 BiosVideoPrivate
->VgaCompatible
= TRUE
;
595 if (PcdGetBool (PcdBiosVideoSetTextVgaModeEnable
)) {
597 // Create EXIT_BOOT_SERIVES Event
599 Status
= gBS
->CreateEventEx (
602 BiosVideoNotifyExitBootServices
,
604 &gEfiEventExitBootServicesGuid
,
605 &BiosVideoPrivate
->ExitBootServicesEvent
607 if (EFI_ERROR (Status
)) {
613 // Initialize the child private structure
615 BiosVideoPrivate
->Signature
= BIOS_VIDEO_DEV_SIGNATURE
;
618 // Fill in Graphics Output specific mode structures
620 BiosVideoPrivate
->HardwareNeedsStarting
= TRUE
;
621 BiosVideoPrivate
->ModeData
= NULL
;
622 BiosVideoPrivate
->LineBuffer
= NULL
;
623 BiosVideoPrivate
->VgaFrameBuffer
= NULL
;
624 BiosVideoPrivate
->VbeFrameBuffer
= NULL
;
627 // Fill in the Graphics Output Protocol
629 BiosVideoPrivate
->GraphicsOutput
.QueryMode
= BiosVideoGraphicsOutputQueryMode
;
630 BiosVideoPrivate
->GraphicsOutput
.SetMode
= BiosVideoGraphicsOutputSetMode
;
633 // Allocate buffer for Graphics Output Protocol mode information
635 BiosVideoPrivate
->GraphicsOutput
.Mode
= (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE
*)AllocatePool (
636 sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE
)
638 if (NULL
== BiosVideoPrivate
->GraphicsOutput
.Mode
) {
639 Status
= EFI_OUT_OF_RESOURCES
;
643 BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
= (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
*)AllocatePool (
644 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
)
646 if (NULL
== BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
) {
647 Status
= EFI_OUT_OF_RESOURCES
;
652 // Assume that Graphics Output Protocol will be produced until proven otherwise
654 BiosVideoPrivate
->ProduceGraphicsOutput
= TRUE
;
657 // Set Gop Device Path, here RemainingDevicePath will not be one End of Device Path Node.
659 if ((RemainingDevicePath
== NULL
) || (!IsDevicePathEnd (RemainingDevicePath
))) {
660 if (RemainingDevicePath
== NULL
) {
661 ZeroMem (&AcpiDeviceNode
, sizeof (ACPI_ADR_DEVICE_PATH
));
662 AcpiDeviceNode
.Header
.Type
= ACPI_DEVICE_PATH
;
663 AcpiDeviceNode
.Header
.SubType
= ACPI_ADR_DP
;
664 AcpiDeviceNode
.ADR
= ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA
, 0, 0);
665 SetDevicePathNodeLength (&AcpiDeviceNode
.Header
, sizeof (ACPI_ADR_DEVICE_PATH
));
667 BiosVideoPrivate
->GopDevicePath
= AppendDevicePathNode (
669 (EFI_DEVICE_PATH_PROTOCOL
*)&AcpiDeviceNode
672 BiosVideoPrivate
->GopDevicePath
= AppendDevicePathNode (ParentDevicePath
, RemainingDevicePath
);
676 // Creat child handle and device path protocol firstly
678 BiosVideoPrivate
->Handle
= NULL
;
679 Status
= gBS
->InstallMultipleProtocolInterfaces (
680 &BiosVideoPrivate
->Handle
,
681 &gEfiDevicePathProtocolGuid
,
682 BiosVideoPrivate
->GopDevicePath
,
685 if (EFI_ERROR (Status
)) {
691 // Fill in the VGA Mini Port Protocol fields
693 BiosVideoPrivate
->VgaMiniPort
.SetMode
= BiosVideoVgaMiniPortSetMode
;
694 BiosVideoPrivate
->VgaMiniPort
.VgaMemoryOffset
= 0xb8000;
695 BiosVideoPrivate
->VgaMiniPort
.CrtcAddressRegisterOffset
= 0x3d4;
696 BiosVideoPrivate
->VgaMiniPort
.CrtcDataRegisterOffset
= 0x3d5;
697 BiosVideoPrivate
->VgaMiniPort
.VgaMemoryBar
= EFI_PCI_IO_PASS_THROUGH_BAR
;
698 BiosVideoPrivate
->VgaMiniPort
.CrtcAddressRegisterBar
= EFI_PCI_IO_PASS_THROUGH_BAR
;
699 BiosVideoPrivate
->VgaMiniPort
.CrtcDataRegisterBar
= EFI_PCI_IO_PASS_THROUGH_BAR
;
702 // Child handle need to consume the Legacy Bios protocol
704 BiosVideoPrivate
->LegacyBios
= ParentLegacyBios
;
707 // When check for VBE, PCI I/O protocol is needed, so use parent's protocol interface temporally
709 BiosVideoPrivate
->PciIo
= ParentPciIo
;
712 // Check for VESA BIOS Extensions for modes that are compatible with Graphics Output
714 if (FeaturePcdGet (PcdBiosVideoCheckVbeEnable
)) {
715 Status
= BiosVideoCheckForVbe (BiosVideoPrivate
);
716 DEBUG ((DEBUG_INFO
, "BiosVideoCheckForVbe - %r\n", Status
));
718 Status
= EFI_UNSUPPORTED
;
721 if (EFI_ERROR (Status
)) {
723 // The VESA BIOS Extensions are not compatible with Graphics Output, so check for support
724 // for the standard 640x480 16 color VGA mode
726 DEBUG ((DEBUG_INFO
, "VgaCompatible - %x\n", BiosVideoPrivate
->VgaCompatible
));
727 if (BiosVideoPrivate
->VgaCompatible
) {
728 if (FeaturePcdGet (PcdBiosVideoCheckVgaEnable
)) {
729 Status
= BiosVideoCheckForVga (BiosVideoPrivate
);
730 DEBUG ((DEBUG_INFO
, "BiosVideoCheckForVga - %r\n", Status
));
732 Status
= EFI_UNSUPPORTED
;
736 if (EFI_ERROR (Status
)) {
738 // Free GOP mode structure if it is not freed before
739 // VgaMiniPort does not need this structure any more
741 if (BiosVideoPrivate
->GraphicsOutput
.Mode
!= NULL
) {
742 if (BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
!= NULL
) {
743 FreePool (BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
);
744 BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
= NULL
;
747 FreePool (BiosVideoPrivate
->GraphicsOutput
.Mode
);
748 BiosVideoPrivate
->GraphicsOutput
.Mode
= NULL
;
752 // Neither VBE nor the standard 640x480 16 color VGA mode are supported, so do
753 // not produce the Graphics Output protocol. Instead, produce the VGA MiniPort Protocol.
755 BiosVideoPrivate
->ProduceGraphicsOutput
= FALSE
;
758 // INT services are available, so on the 80x25 and 80x50 text mode are supported
760 BiosVideoPrivate
->VgaMiniPort
.MaxMode
= 2;
764 ProtocolInstalled
= FALSE
;
766 if (BiosVideoPrivate
->ProduceGraphicsOutput
) {
768 // Creat child handle and install Graphics Output Protocol,EDID Discovered/Active Protocol
770 Status
= gBS
->InstallMultipleProtocolInterfaces (
771 &BiosVideoPrivate
->Handle
,
772 &gEfiGraphicsOutputProtocolGuid
,
773 &BiosVideoPrivate
->GraphicsOutput
,
774 &gEfiEdidDiscoveredProtocolGuid
,
775 &BiosVideoPrivate
->EdidDiscovered
,
776 &gEfiEdidActiveProtocolGuid
,
777 &BiosVideoPrivate
->EdidActive
,
781 if (!EFI_ERROR (Status
)) {
783 // Open the Parent Handle for the child
785 Status
= gBS
->OpenProtocol (
787 &gEfiPciIoProtocolGuid
,
788 (VOID
**)&BiosVideoPrivate
->PciIo
,
789 This
->DriverBindingHandle
,
790 BiosVideoPrivate
->Handle
,
791 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
793 if (EFI_ERROR (Status
)) {
797 ProtocolInstalled
= TRUE
;
801 if (!ProtocolInstalled
) {
803 // Install VGA Mini Port Protocol
805 Status
= gBS
->InstallMultipleProtocolInterfaces (
807 &gEfiVgaMiniPortProtocolGuid
,
808 &BiosVideoPrivate
->VgaMiniPort
,
814 if (EFI_ERROR (Status
)) {
815 if ((BiosVideoPrivate
!= NULL
) && (BiosVideoPrivate
->ExitBootServicesEvent
!= NULL
)) {
816 gBS
->CloseEvent (BiosVideoPrivate
->ExitBootServicesEvent
);
820 // Free private data structure
822 BiosVideoDeviceReleaseResource (BiosVideoPrivate
);
829 Deregister an video child handle and free resources.
831 @param This Protocol instance pointer.
832 @param Controller Video controller handle
833 @param Handle Video child handle
839 BiosVideoChildHandleUninstall (
840 EFI_DRIVER_BINDING_PROTOCOL
*This
,
841 EFI_HANDLE Controller
,
846 EFI_IA32_REGISTER_SET Regs
;
847 EFI_GRAPHICS_OUTPUT_PROTOCOL
*GraphicsOutput
;
848 EFI_VGA_MINI_PORT_PROTOCOL
*VgaMiniPort
;
849 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
850 EFI_PCI_IO_PROTOCOL
*PciIo
;
852 BiosVideoPrivate
= NULL
;
853 GraphicsOutput
= NULL
;
855 Status
= EFI_UNSUPPORTED
;
857 Status
= gBS
->OpenProtocol (
859 &gEfiGraphicsOutputProtocolGuid
,
860 (VOID
**)&GraphicsOutput
,
861 This
->DriverBindingHandle
,
863 EFI_OPEN_PROTOCOL_GET_PROTOCOL
865 if (!EFI_ERROR (Status
)) {
866 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput
);
869 if (EFI_ERROR (Status
)) {
870 Status
= gBS
->OpenProtocol (
872 &gEfiVgaMiniPortProtocolGuid
,
873 (VOID
**)&VgaMiniPort
,
874 This
->DriverBindingHandle
,
876 EFI_OPEN_PROTOCOL_GET_PROTOCOL
878 if (!EFI_ERROR (Status
)) {
879 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (VgaMiniPort
);
883 if (BiosVideoPrivate
== NULL
) {
884 return EFI_UNSUPPORTED
;
888 // Set the 80x25 Text VGA Mode
892 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
897 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
900 // Close PCI I/O protocol that opened by child handle
902 Status
= gBS
->CloseProtocol (
904 &gEfiPciIoProtocolGuid
,
905 This
->DriverBindingHandle
,
910 // Uninstall protocols on child handle
912 if (BiosVideoPrivate
->ProduceGraphicsOutput
) {
913 Status
= gBS
->UninstallMultipleProtocolInterfaces (
914 BiosVideoPrivate
->Handle
,
915 &gEfiDevicePathProtocolGuid
,
916 BiosVideoPrivate
->GopDevicePath
,
917 &gEfiGraphicsOutputProtocolGuid
,
918 &BiosVideoPrivate
->GraphicsOutput
,
919 &gEfiEdidDiscoveredProtocolGuid
,
920 &BiosVideoPrivate
->EdidDiscovered
,
921 &gEfiEdidActiveProtocolGuid
,
922 &BiosVideoPrivate
->EdidActive
,
927 if (!BiosVideoPrivate
->ProduceGraphicsOutput
) {
928 Status
= gBS
->UninstallMultipleProtocolInterfaces (
930 &gEfiVgaMiniPortProtocolGuid
,
931 &BiosVideoPrivate
->VgaMiniPort
,
936 if (EFI_ERROR (Status
)) {
939 &gEfiPciIoProtocolGuid
,
941 This
->DriverBindingHandle
,
943 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
948 if (PcdGetBool (PcdBiosVideoSetTextVgaModeEnable
)) {
950 // Close EXIT_BOOT_SERIVES Event
952 gBS
->CloseEvent (BiosVideoPrivate
->ExitBootServicesEvent
);
956 // Release all allocated resources
958 BiosVideoDeviceReleaseResource (BiosVideoPrivate
);
964 Release resource for biso video instance.
966 @param BiosVideoPrivate Video child device private data structure
970 BiosVideoDeviceReleaseResource (
971 BIOS_VIDEO_DEV
*BiosVideoPrivate
974 if (BiosVideoPrivate
== NULL
) {
979 // Release all the resourses occupied by the BIOS_VIDEO_DEV
983 // Free VGA Frame Buffer
985 if (BiosVideoPrivate
->VgaFrameBuffer
!= NULL
) {
986 FreePool (BiosVideoPrivate
->VgaFrameBuffer
);
990 // Free VBE Frame Buffer
992 if (BiosVideoPrivate
->VbeFrameBuffer
!= NULL
) {
993 FreePool (BiosVideoPrivate
->VbeFrameBuffer
);
999 if (BiosVideoPrivate
->LineBuffer
!= NULL
) {
1000 FreePool (BiosVideoPrivate
->LineBuffer
);
1006 if (BiosVideoPrivate
->ModeData
!= NULL
) {
1007 FreePool (BiosVideoPrivate
->ModeData
);
1011 // Free memory allocated below 1MB
1013 if (BiosVideoPrivate
->PagesBelow1MB
!= 0) {
1014 gBS
->FreePages (BiosVideoPrivate
->PagesBelow1MB
, BiosVideoPrivate
->NumberOfPagesBelow1MB
);
1017 if (BiosVideoPrivate
->VbeSaveRestorePages
!= 0) {
1018 gBS
->FreePages (BiosVideoPrivate
->VbeSaveRestoreBuffer
, BiosVideoPrivate
->VbeSaveRestorePages
);
1022 // Free graphics output protocol occupied resource
1024 if (BiosVideoPrivate
->GraphicsOutput
.Mode
!= NULL
) {
1025 if (BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
!= NULL
) {
1026 FreePool (BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
);
1027 BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
= NULL
;
1030 FreePool (BiosVideoPrivate
->GraphicsOutput
.Mode
);
1031 BiosVideoPrivate
->GraphicsOutput
.Mode
= NULL
;
1035 // Free EDID discovered protocol occupied resource
1037 if (BiosVideoPrivate
->EdidDiscovered
.Edid
!= NULL
) {
1038 FreePool (BiosVideoPrivate
->EdidDiscovered
.Edid
);
1042 // Free EDID active protocol occupied resource
1044 if (BiosVideoPrivate
->EdidActive
.Edid
!= NULL
) {
1045 FreePool (BiosVideoPrivate
->EdidActive
.Edid
);
1048 if (BiosVideoPrivate
->GopDevicePath
!= NULL
) {
1049 FreePool (BiosVideoPrivate
->GopDevicePath
);
1052 FreePool (BiosVideoPrivate
);
1058 Generate a search key for a specified timing data.
1060 @param EdidTiming Pointer to EDID timing
1062 @return The 32 bit unique key for search.
1067 VESA_BIOS_EXTENSIONS_EDID_TIMING
*EdidTiming
1073 // Be sure no conflicts for all standard timing defined by VESA.
1075 Key
= (EdidTiming
->HorizontalResolution
* 2) + EdidTiming
->VerticalResolution
;
1080 Parse the Established Timing and Standard Timing in EDID data block.
1082 @param EdidBuffer Pointer to EDID data block
1083 @param ValidEdidTiming Valid EDID timing information
1085 @retval TRUE The EDID data is valid.
1086 @retval FALSE The EDID data is invalid.
1092 VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING
*ValidEdidTiming
1100 UINT16 HorizontalResolution
;
1101 UINT16 VerticalResolution
;
1104 VESA_BIOS_EXTENSIONS_EDID_TIMING TempTiming
;
1105 VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK
*EdidDataBlock
;
1107 EdidDataBlock
= (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK
*)EdidBuffer
;
1110 // Check the checksum of EDID data
1113 for (Index
= 0; Index
< VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE
; Index
++) {
1114 CheckSum
= (UINT8
)(CheckSum
+ EdidBuffer
[Index
]);
1117 if (CheckSum
!= 0) {
1122 gBS
->SetMem (ValidEdidTiming
, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING
), 0);
1124 if ((EdidDataBlock
->EstablishedTimings
[0] != 0) ||
1125 (EdidDataBlock
->EstablishedTimings
[1] != 0) ||
1126 (EdidDataBlock
->EstablishedTimings
[2] != 0)
1130 // Established timing data
1132 TimingBits
= EdidDataBlock
->EstablishedTimings
[0] |
1133 (EdidDataBlock
->EstablishedTimings
[1] << 8) |
1134 ((EdidDataBlock
->EstablishedTimings
[2] & 0x80) << 9);
1135 for (Index
= 0; Index
< VESA_BIOS_EXTENSIONS_EDID_ESTABLISHED_TIMING_MAX_NUMBER
; Index
++) {
1136 if ((TimingBits
& 0x1) != 0) {
1139 "Established Timing: %d x %d\n",
1140 mEstablishedEdidTiming
[Index
].HorizontalResolution
,
1141 mEstablishedEdidTiming
[Index
].VerticalResolution
1143 ValidEdidTiming
->Key
[ValidNumber
] = CalculateEdidKey (&mEstablishedEdidTiming
[Index
]);
1147 TimingBits
= TimingBits
>> 1;
1152 // Parse the standard timing data
1154 BufferIndex
= &EdidDataBlock
->StandardTimingIdentification
[0];
1155 for (Index
= 0; Index
< 8; Index
++) {
1157 // Check if this is a valid Standard Timing entry
1158 // VESA documents unused fields should be set to 01h
1160 if ((BufferIndex
[0] != 0x1) && (BufferIndex
[1] != 0x1)) {
1162 // A valid Standard Timing
1164 HorizontalResolution
= (UINT16
)(BufferIndex
[0] * 8 + 248);
1165 AspectRatio
= (UINT8
)(BufferIndex
[1] >> 6);
1166 switch (AspectRatio
) {
1168 VerticalResolution
= (UINT16
)(HorizontalResolution
/ 16 * 10);
1171 VerticalResolution
= (UINT16
)(HorizontalResolution
/ 4 * 3);
1174 VerticalResolution
= (UINT16
)(HorizontalResolution
/ 5 * 4);
1177 VerticalResolution
= (UINT16
)(HorizontalResolution
/ 16 * 9);
1180 VerticalResolution
= (UINT16
)(HorizontalResolution
/ 4 * 3);
1184 RefreshRate
= (UINT8
)((BufferIndex
[1] & 0x1f) + 60);
1185 DEBUG ((DEBUG_INFO
, "Standard Timing: %d x %d\n", HorizontalResolution
, VerticalResolution
));
1186 TempTiming
.HorizontalResolution
= HorizontalResolution
;
1187 TempTiming
.VerticalResolution
= VerticalResolution
;
1188 TempTiming
.RefreshRate
= RefreshRate
;
1189 ValidEdidTiming
->Key
[ValidNumber
] = CalculateEdidKey (&TempTiming
);
1197 // Parse the Detailed Timing data
1199 BufferIndex
= &EdidDataBlock
->DetailedTimingDescriptions
[0];
1200 for (Index
= 0; Index
< 4; Index
++, BufferIndex
+= VESA_BIOS_EXTENSIONS_DETAILED_TIMING_EACH_DESCRIPTOR_SIZE
) {
1201 if ((BufferIndex
[0] == 0x0) && (BufferIndex
[1] == 0x0)) {
1203 // Check if this is a valid Detailed Timing Descriptor
1204 // If first 2 bytes are zero, it is monitor descriptor other than detailed timing descriptor
1210 // Calculate Horizontal and Vertical resolution
1212 TempTiming
.HorizontalResolution
= ((UINT16
)(BufferIndex
[4] & 0xF0) << 4) | (BufferIndex
[2]);
1213 TempTiming
.VerticalResolution
= ((UINT16
)(BufferIndex
[7] & 0xF0) << 4) | (BufferIndex
[5]);
1216 "Detailed Timing %d: %d x %d\n",
1218 TempTiming
.HorizontalResolution
,
1219 TempTiming
.VerticalResolution
1221 ValidEdidTiming
->Key
[ValidNumber
] = CalculateEdidKey (&TempTiming
);
1225 ValidEdidTiming
->ValidNumber
= ValidNumber
;
1230 Search a specified Timing in all the valid EDID timings.
1232 @param ValidEdidTiming All valid EDID timing information.
1233 @param EdidTiming The Timing to search for.
1236 @retval FALSE Not found.
1241 VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING
*ValidEdidTiming
,
1242 VESA_BIOS_EXTENSIONS_EDID_TIMING
*EdidTiming
1248 Key
= CalculateEdidKey (EdidTiming
);
1250 for (Index
= 0; Index
< ValidEdidTiming
->ValidNumber
; Index
++) {
1251 if (Key
== ValidEdidTiming
->Key
[Index
]) {
1260 Check if all video child handles have been uninstalled.
1262 @param Controller Video controller handle
1264 @return TRUE Child handles exist.
1265 @return FALSE All video child handles have been uninstalled.
1270 IN EFI_HANDLE Controller
1274 EFI_OPEN_PROTOCOL_INFORMATION_ENTRY
*OpenInfoBuffer
;
1280 gBS
->OpenProtocolInformation (
1282 &gEfiPciIoProtocolGuid
,
1286 for (Index
= 0; Index
< EntryCount
; Index
++) {
1287 if ((OpenInfoBuffer
[Index
].Attributes
& EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
) != 0) {
1296 Check for VBE device.
1298 @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure
1300 @retval EFI_SUCCESS VBE device found
1304 BiosVideoCheckForVbe (
1305 IN OUT BIOS_VIDEO_DEV
*BiosVideoPrivate
1309 EFI_IA32_REGISTER_SET Regs
;
1310 UINT16
*ModeNumberPtr
;
1311 UINT16 VbeModeNumber
;
1314 BIOS_VIDEO_MODE_DATA
*ModeBuffer
;
1315 BIOS_VIDEO_MODE_DATA
*CurrentModeData
;
1318 VESA_BIOS_EXTENSIONS_EDID_TIMING Timing
;
1319 VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING ValidEdidTiming
;
1320 EFI_EDID_OVERRIDE_PROTOCOL
*EdidOverride
;
1321 UINT32 EdidAttributes
;
1322 BOOLEAN EdidOverrideFound
;
1323 UINTN EdidOverrideDataSize
;
1324 UINT8
*EdidOverrideDataBlock
;
1325 UINTN EdidActiveDataSize
;
1326 UINT8
*EdidActiveDataBlock
;
1327 UINT32 HighestHorizontalResolution
;
1328 UINT32 HighestVerticalResolution
;
1329 UINTN HighestResolutionMode
;
1332 EdidOverrideFound
= FALSE
;
1333 EdidOverrideDataBlock
= NULL
;
1334 EdidActiveDataSize
= 0;
1335 EdidActiveDataBlock
= NULL
;
1336 HighestHorizontalResolution
= 0;
1337 HighestVerticalResolution
= 0;
1338 HighestResolutionMode
= 0;
1341 // Allocate buffer under 1MB for VBE data structures
1343 BiosVideoPrivate
->NumberOfPagesBelow1MB
= EFI_SIZE_TO_PAGES (
1344 sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK
) +
1345 sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK
) +
1346 sizeof (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK
) +
1347 sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK
)
1350 BiosVideoPrivate
->PagesBelow1MB
= 0x00100000 - 1;
1352 Status
= gBS
->AllocatePages (
1354 EfiBootServicesData
,
1355 BiosVideoPrivate
->NumberOfPagesBelow1MB
,
1356 &BiosVideoPrivate
->PagesBelow1MB
1358 if (EFI_ERROR (Status
)) {
1362 ZeroMem (&ValidEdidTiming
, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING
));
1365 // Fill in the VBE related data structures
1367 BiosVideoPrivate
->VbeInformationBlock
= (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK
*)(UINTN
)(BiosVideoPrivate
->PagesBelow1MB
);
1368 BiosVideoPrivate
->VbeModeInformationBlock
= (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK
*)(BiosVideoPrivate
->VbeInformationBlock
+ 1);
1369 BiosVideoPrivate
->VbeEdidDataBlock
= (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK
*)(BiosVideoPrivate
->VbeModeInformationBlock
+ 1);
1370 BiosVideoPrivate
->VbeCrtcInformationBlock
= (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK
*)(BiosVideoPrivate
->VbeEdidDataBlock
+ 1);
1371 BiosVideoPrivate
->VbeSaveRestorePages
= 0;
1372 BiosVideoPrivate
->VbeSaveRestoreBuffer
= 0;
1375 // Test to see if the Video Adapter is compliant with VBE 3.0
1377 gBS
->SetMem (&Regs
, sizeof (Regs
), 0);
1378 Regs
.X
.AX
= VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION
;
1379 gBS
->SetMem (BiosVideoPrivate
->VbeInformationBlock
, sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK
), 0);
1380 BiosVideoPrivate
->VbeInformationBlock
->VESASignature
= VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE
;
1381 Regs
.X
.ES
= EFI_SEGMENT ((UINTN
)BiosVideoPrivate
->VbeInformationBlock
);
1382 Regs
.X
.DI
= EFI_OFFSET ((UINTN
)BiosVideoPrivate
->VbeInformationBlock
);
1384 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
1386 Status
= EFI_DEVICE_ERROR
;
1389 // See if the VESA call succeeded
1391 if (Regs
.X
.AX
!= VESA_BIOS_EXTENSIONS_STATUS_SUCCESS
) {
1396 // Check for 'VESA' signature
1398 if (BiosVideoPrivate
->VbeInformationBlock
->VESASignature
!= VESA_BIOS_EXTENSIONS_VESA_SIGNATURE
) {
1403 // Check to see if this is VBE 2.0 or higher
1405 if (BiosVideoPrivate
->VbeInformationBlock
->VESAVersion
< VESA_BIOS_EXTENSIONS_VERSION_2_0
) {
1410 EdidAttributes
= 0xff;
1411 EdidOverrideDataSize
= 0;
1414 // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
1416 Status
= gBS
->LocateProtocol (
1417 &gEfiEdidOverrideProtocolGuid
,
1419 (VOID
**)&EdidOverride
1421 if (!EFI_ERROR (Status
)) {
1423 // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
1425 EdidOverrideDataBlock
= AllocatePool (VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE
* 2);
1426 if (NULL
== EdidOverrideDataBlock
) {
1427 Status
= EFI_OUT_OF_RESOURCES
;
1431 Status
= EdidOverride
->GetEdid (
1433 BiosVideoPrivate
->Handle
,
1435 &EdidOverrideDataSize
,
1436 (UINT8
**)&EdidOverrideDataBlock
1438 if (!EFI_ERROR (Status
) &&
1439 (EdidAttributes
== 0) &&
1440 (EdidOverrideDataSize
!= 0))
1443 // Succeeded to get EDID Override Data
1445 EdidOverrideFound
= TRUE
;
1449 if (!EdidOverrideFound
|| (EdidAttributes
== EFI_EDID_OVERRIDE_DONT_OVERRIDE
)) {
1451 // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,
1452 // read EDID information through INT10 call
1455 gBS
->SetMem (&Regs
, sizeof (Regs
), 0);
1456 Regs
.X
.AX
= VESA_BIOS_EXTENSIONS_EDID
;
1460 Regs
.X
.ES
= EFI_SEGMENT ((UINTN
)BiosVideoPrivate
->VbeEdidDataBlock
);
1461 Regs
.X
.DI
= EFI_OFFSET ((UINTN
)BiosVideoPrivate
->VbeEdidDataBlock
);
1463 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
1465 // See if the VESA call succeeded
1467 if (Regs
.X
.AX
== VESA_BIOS_EXTENSIONS_STATUS_SUCCESS
) {
1469 // Set EDID Discovered Data
1471 BiosVideoPrivate
->EdidDiscovered
.SizeOfEdid
= VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE
;
1472 BiosVideoPrivate
->EdidDiscovered
.Edid
= (UINT8
*)AllocateCopyPool (
1473 VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE
,
1474 BiosVideoPrivate
->VbeEdidDataBlock
1477 if (NULL
== BiosVideoPrivate
->EdidDiscovered
.Edid
) {
1478 Status
= EFI_OUT_OF_RESOURCES
;
1487 EdidActiveDataSize
= VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE
;
1488 EdidActiveDataBlock
= BiosVideoPrivate
->EdidDiscovered
.Edid
;
1489 } else if (EdidOverrideFound
) {
1490 EdidActiveDataSize
= EdidOverrideDataSize
;
1491 EdidActiveDataBlock
= EdidOverrideDataBlock
;
1497 // Parse EDID data structure to retrieve modes supported by monitor
1499 if (ParseEdidData ((UINT8
*)EdidActiveDataBlock
, &ValidEdidTiming
)) {
1501 // Copy EDID Override Data to EDID Active Data
1503 BiosVideoPrivate
->EdidActive
.SizeOfEdid
= (UINT32
)EdidActiveDataSize
;
1504 BiosVideoPrivate
->EdidActive
.Edid
= (UINT8
*)AllocateCopyPool (
1508 if (NULL
== BiosVideoPrivate
->EdidActive
.Edid
) {
1509 Status
= EFI_OUT_OF_RESOURCES
;
1514 BiosVideoPrivate
->EdidActive
.SizeOfEdid
= 0;
1515 BiosVideoPrivate
->EdidActive
.Edid
= NULL
;
1520 // Walk through the mode list to see if there is at least one mode the is compatible with the EDID mode
1522 ModeNumberPtr
= (UINT16
*)
1524 (((UINTN
)BiosVideoPrivate
->VbeInformationBlock
->VideoModePtr
& 0xffff0000) >> 12) |
1525 ((UINTN
)BiosVideoPrivate
->VbeInformationBlock
->VideoModePtr
& 0x0000ffff)
1532 // ModeNumberPtr may be not 16-byte aligned, so ReadUnaligned16 is used to access the buffer pointed by ModeNumberPtr.
1534 for (VbeModeNumber
= ReadUnaligned16 (ModeNumberPtr
);
1535 VbeModeNumber
!= VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST
;
1536 VbeModeNumber
= ReadUnaligned16 (++ModeNumberPtr
))
1539 // Make sure this is a mode number defined by the VESA VBE specification. If it isn'tm then skip this mode number.
1541 if ((VbeModeNumber
& VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA
) == 0) {
1546 // Get the information about the mode
1548 gBS
->SetMem (&Regs
, sizeof (Regs
), 0);
1549 Regs
.X
.AX
= VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION
;
1550 Regs
.X
.CX
= VbeModeNumber
;
1551 gBS
->SetMem (BiosVideoPrivate
->VbeModeInformationBlock
, sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK
), 0);
1552 Regs
.X
.ES
= EFI_SEGMENT ((UINTN
)BiosVideoPrivate
->VbeModeInformationBlock
);
1553 Regs
.X
.DI
= EFI_OFFSET ((UINTN
)BiosVideoPrivate
->VbeModeInformationBlock
);
1555 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
1558 // See if the call succeeded. If it didn't, then try the next mode.
1560 if (Regs
.X
.AX
!= VESA_BIOS_EXTENSIONS_STATUS_SUCCESS
) {
1565 // See if the mode supports color. If it doesn't then try the next mode.
1567 if ((BiosVideoPrivate
->VbeModeInformationBlock
->ModeAttributes
& VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR
) == 0) {
1572 // See if the mode supports graphics. If it doesn't then try the next mode.
1574 if ((BiosVideoPrivate
->VbeModeInformationBlock
->ModeAttributes
& VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS
) == 0) {
1579 // See if the mode supports a linear frame buffer. If it doesn't then try the next mode.
1581 if ((BiosVideoPrivate
->VbeModeInformationBlock
->ModeAttributes
& VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER
) == 0) {
1586 // See if the mode supports 32 bit color. If it doesn't then try the next mode.
1587 // 32 bit mode can be implemented by 24 Bits Per Pixels. Also make sure the
1588 // number of bits per pixel is a multiple of 8 or more than 32 bits per pixel
1590 if (BiosVideoPrivate
->VbeModeInformationBlock
->BitsPerPixel
< 24) {
1594 if (BiosVideoPrivate
->VbeModeInformationBlock
->BitsPerPixel
> 32) {
1598 if ((BiosVideoPrivate
->VbeModeInformationBlock
->BitsPerPixel
% 8) != 0) {
1603 // See if the physical base pointer for the linear mode is valid. If it isn't then try the next mode.
1605 if (BiosVideoPrivate
->VbeModeInformationBlock
->PhysBasePtr
== 0) {
1611 "Video Controller Mode 0x%x: %d x %d\n",
1613 BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
,
1614 BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
1617 if (EdidFound
&& (ValidEdidTiming
.ValidNumber
> 0)) {
1619 // EDID exist, check whether this mode match with any mode in EDID
1621 Timing
.HorizontalResolution
= BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
;
1622 Timing
.VerticalResolution
= BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
;
1623 if (!SearchEdidTiming (&ValidEdidTiming
, &Timing
)) {
1625 // When EDID comes from INT10 call, EDID does not include 800x600, 640x480 and 1024x768,
1626 // but INT10 can support these modes, we add them into GOP mode.
1628 if ((BiosVideoPrivate
->EdidDiscovered
.SizeOfEdid
!= 0) &&
1629 !(((Timing
.HorizontalResolution
) == 1024) && (Timing
.VerticalResolution
== 768)) &&
1630 !(((Timing
.HorizontalResolution
) == 800) && (Timing
.VerticalResolution
== 600)) &&
1631 !(((Timing
.HorizontalResolution
) == 640) && (Timing
.VerticalResolution
== 480)))
1639 // Select a reasonable mode to be set for current display mode
1643 if ((BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
== 1024) &&
1644 (BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
== 768)
1650 if ((BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
== 800) &&
1651 (BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
== 600)
1655 PreferMode
= ModeNumber
;
1658 if ((BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
== 640) &&
1659 (BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
== 480)
1665 if ((!EdidFound
) && (!ModeFound
)) {
1667 // When no EDID exist, only select three possible resolutions, i.e. 1024x768, 800x600, 640x480
1673 // Record the highest resolution mode to set later
1675 if ((BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
> HighestHorizontalResolution
) ||
1676 ((BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
== HighestHorizontalResolution
) &&
1677 (BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
> HighestVerticalResolution
)))
1679 HighestHorizontalResolution
= BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
;
1680 HighestVerticalResolution
= BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
;
1681 HighestResolutionMode
= ModeNumber
;
1685 // Add mode to the list of available modes
1688 ModeBuffer
= (BIOS_VIDEO_MODE_DATA
*)AllocatePool (
1689 ModeNumber
* sizeof (BIOS_VIDEO_MODE_DATA
)
1691 if (NULL
== ModeBuffer
) {
1692 Status
= EFI_OUT_OF_RESOURCES
;
1696 if (ModeNumber
> 1) {
1699 BiosVideoPrivate
->ModeData
,
1700 (ModeNumber
- 1) * sizeof (BIOS_VIDEO_MODE_DATA
)
1704 if (BiosVideoPrivate
->ModeData
!= NULL
) {
1705 FreePool (BiosVideoPrivate
->ModeData
);
1708 CurrentModeData
= &ModeBuffer
[ModeNumber
- 1];
1709 CurrentModeData
->VbeModeNumber
= VbeModeNumber
;
1710 if (BiosVideoPrivate
->VbeInformationBlock
->VESAVersion
>= VESA_BIOS_EXTENSIONS_VERSION_3_0
) {
1711 CurrentModeData
->BytesPerScanLine
= BiosVideoPrivate
->VbeModeInformationBlock
->LinBytesPerScanLine
;
1712 CurrentModeData
->Red
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->LinRedFieldPosition
;
1713 CurrentModeData
->Red
.Mask
= (UINT8
)((1 << BiosVideoPrivate
->VbeModeInformationBlock
->LinRedMaskSize
) - 1);
1714 CurrentModeData
->Blue
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->LinBlueFieldPosition
;
1715 CurrentModeData
->Blue
.Mask
= (UINT8
)((1 << BiosVideoPrivate
->VbeModeInformationBlock
->LinBlueMaskSize
) - 1);
1716 CurrentModeData
->Green
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->LinGreenFieldPosition
;
1717 CurrentModeData
->Green
.Mask
= (UINT8
)((1 << BiosVideoPrivate
->VbeModeInformationBlock
->LinGreenMaskSize
) - 1);
1718 CurrentModeData
->Reserved
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->LinRsvdFieldPosition
;
1719 CurrentModeData
->Reserved
.Mask
= (UINT8
)((1 << BiosVideoPrivate
->VbeModeInformationBlock
->LinRsvdMaskSize
) - 1);
1721 CurrentModeData
->BytesPerScanLine
= BiosVideoPrivate
->VbeModeInformationBlock
->BytesPerScanLine
;
1722 CurrentModeData
->Red
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->RedFieldPosition
;
1723 CurrentModeData
->Red
.Mask
= (UINT8
)((1 << BiosVideoPrivate
->VbeModeInformationBlock
->RedMaskSize
) - 1);
1724 CurrentModeData
->Blue
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->BlueFieldPosition
;
1725 CurrentModeData
->Blue
.Mask
= (UINT8
)((1 << BiosVideoPrivate
->VbeModeInformationBlock
->BlueMaskSize
) - 1);
1726 CurrentModeData
->Green
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->GreenFieldPosition
;
1727 CurrentModeData
->Green
.Mask
= (UINT8
)((1 << BiosVideoPrivate
->VbeModeInformationBlock
->GreenMaskSize
) - 1);
1728 CurrentModeData
->Reserved
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->RsvdFieldPosition
;
1729 CurrentModeData
->Reserved
.Mask
= (UINT8
)((1 << BiosVideoPrivate
->VbeModeInformationBlock
->RsvdMaskSize
) - 1);
1732 CurrentModeData
->PixelFormat
= PixelBitMask
;
1733 if ((BiosVideoPrivate
->VbeModeInformationBlock
->BitsPerPixel
== 32) &&
1734 (CurrentModeData
->Red
.Mask
== 0xff) && (CurrentModeData
->Green
.Mask
== 0xff) && (CurrentModeData
->Blue
.Mask
== 0xff))
1736 if ((CurrentModeData
->Red
.Position
== 0) && (CurrentModeData
->Green
.Position
== 8) && (CurrentModeData
->Blue
.Position
== 16)) {
1737 CurrentModeData
->PixelFormat
= PixelRedGreenBlueReserved8BitPerColor
;
1738 } else if ((CurrentModeData
->Blue
.Position
== 0) && (CurrentModeData
->Green
.Position
== 8) && (CurrentModeData
->Red
.Position
== 16)) {
1739 CurrentModeData
->PixelFormat
= PixelBlueGreenRedReserved8BitPerColor
;
1743 CurrentModeData
->PixelBitMask
.RedMask
= ((UINT32
)CurrentModeData
->Red
.Mask
) << CurrentModeData
->Red
.Position
;
1744 CurrentModeData
->PixelBitMask
.GreenMask
= ((UINT32
)CurrentModeData
->Green
.Mask
) << CurrentModeData
->Green
.Position
;
1745 CurrentModeData
->PixelBitMask
.BlueMask
= ((UINT32
)CurrentModeData
->Blue
.Mask
) << CurrentModeData
->Blue
.Position
;
1746 CurrentModeData
->PixelBitMask
.ReservedMask
= ((UINT32
)CurrentModeData
->Reserved
.Mask
) << CurrentModeData
->Reserved
.Position
;
1748 CurrentModeData
->LinearFrameBuffer
= (VOID
*)(UINTN
)BiosVideoPrivate
->VbeModeInformationBlock
->PhysBasePtr
;
1749 CurrentModeData
->HorizontalResolution
= BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
;
1750 CurrentModeData
->VerticalResolution
= BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
;
1752 CurrentModeData
->BitsPerPixel
= BiosVideoPrivate
->VbeModeInformationBlock
->BitsPerPixel
;
1753 CurrentModeData
->FrameBufferSize
= CurrentModeData
->BytesPerScanLine
* CurrentModeData
->VerticalResolution
;
1755 // Make sure the FrameBufferSize does not exceed the max available frame buffer size reported by VEB.
1757 ASSERT (CurrentModeData
->FrameBufferSize
<= ((UINT32
)BiosVideoPrivate
->VbeInformationBlock
->TotalMemory
* 64 * 1024));
1759 BiosVideoPrivate
->ModeData
= ModeBuffer
;
1763 // Check to see if we found any modes that are compatible with GRAPHICS OUTPUT
1765 if (ModeNumber
== 0) {
1766 Status
= EFI_DEVICE_ERROR
;
1771 // Assign Gop's Blt function
1773 BiosVideoPrivate
->GraphicsOutput
.Blt
= BiosVideoGraphicsOutputVbeBlt
;
1775 BiosVideoPrivate
->GraphicsOutput
.Mode
->MaxMode
= (UINT32
)ModeNumber
;
1777 // Current mode is unknow till now, set it to an invalid mode.
1779 BiosVideoPrivate
->GraphicsOutput
.Mode
->Mode
= GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER
;
1782 // Find the best mode to initialize
1784 if ((PcdGet32 (PcdVideoHorizontalResolution
) == 0x0) || (PcdGet32 (PcdVideoVerticalResolution
) == 0x0)) {
1786 BIOS_VIDEO_MODE_DATA
*ModeData
;
1787 ModeData
= &BiosVideoPrivate
->ModeData
[HighestResolutionMode
];
1790 "BiosVideo set highest resolution %d x %d\n",
1791 ModeData
->HorizontalResolution
,
1792 ModeData
->VerticalResolution
1795 PreferMode
= HighestResolutionMode
;
1798 Status
= BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate
->GraphicsOutput
, (UINT32
)PreferMode
);
1799 if (EFI_ERROR (Status
)) {
1800 for (PreferMode
= 0; PreferMode
< ModeNumber
; PreferMode
++) {
1801 Status
= BiosVideoGraphicsOutputSetMode (
1802 &BiosVideoPrivate
->GraphicsOutput
,
1805 if (!EFI_ERROR (Status
)) {
1810 if (PreferMode
== ModeNumber
) {
1812 // None mode is set successfully.
1820 // If there was an error, then free the mode structure
1822 if (EFI_ERROR (Status
)) {
1823 if (BiosVideoPrivate
->ModeData
!= NULL
) {
1824 FreePool (BiosVideoPrivate
->ModeData
);
1825 BiosVideoPrivate
->ModeData
= NULL
;
1826 BiosVideoPrivate
->MaxMode
= 0;
1829 if (EdidOverrideDataBlock
!= NULL
) {
1830 FreePool (EdidOverrideDataBlock
);
1838 Check for VGA device.
1840 @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure
1842 @retval EFI_SUCCESS Standard VGA device found
1846 BiosVideoCheckForVga (
1847 IN OUT BIOS_VIDEO_DEV
*BiosVideoPrivate
1851 BIOS_VIDEO_MODE_DATA
*ModeBuffer
;
1853 Status
= EFI_UNSUPPORTED
;
1856 // Assign Gop's Blt function
1858 BiosVideoPrivate
->GraphicsOutput
.Blt
= BiosVideoGraphicsOutputVgaBlt
;
1861 // Add mode to the list of available modes
1862 // caller should guarantee that Mode has been allocated.
1864 ASSERT (BiosVideoPrivate
->GraphicsOutput
.Mode
!= NULL
);
1865 BiosVideoPrivate
->GraphicsOutput
.Mode
->MaxMode
= 1;
1867 ModeBuffer
= (BIOS_VIDEO_MODE_DATA
*)AllocatePool (
1868 sizeof (BIOS_VIDEO_MODE_DATA
)
1870 if (NULL
== ModeBuffer
) {
1871 Status
= EFI_OUT_OF_RESOURCES
;
1875 ModeBuffer
->VbeModeNumber
= 0x0012;
1876 ModeBuffer
->BytesPerScanLine
= 640;
1877 ModeBuffer
->LinearFrameBuffer
= (VOID
*)(UINTN
)(0xa0000);
1878 ModeBuffer
->HorizontalResolution
= 640;
1879 ModeBuffer
->VerticalResolution
= 480;
1880 ModeBuffer
->PixelFormat
= PixelBltOnly
;
1881 ModeBuffer
->BitsPerPixel
= 8;
1882 ModeBuffer
->ColorDepth
= 32;
1883 ModeBuffer
->RefreshRate
= 60;
1885 BiosVideoPrivate
->ModeData
= ModeBuffer
;
1888 // Test to see if the Video Adapter support the 640x480 16 color mode
1890 BiosVideoPrivate
->GraphicsOutput
.Mode
->Mode
= GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER
;
1891 Status
= BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate
->GraphicsOutput
, 0);
1895 // If there was an error, then free the mode structure
1897 if (EFI_ERROR (Status
)) {
1898 if (BiosVideoPrivate
->ModeData
!= NULL
) {
1899 FreePool (BiosVideoPrivate
->ModeData
);
1900 BiosVideoPrivate
->ModeData
= NULL
;
1903 if (BiosVideoPrivate
->GraphicsOutput
.Mode
!= NULL
) {
1904 if (BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
!= NULL
) {
1905 FreePool (BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
);
1906 BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
= NULL
;
1909 FreePool (BiosVideoPrivate
->GraphicsOutput
.Mode
);
1910 BiosVideoPrivate
->GraphicsOutput
.Mode
= NULL
;
1918 // Graphics Output Protocol Member Functions for VESA BIOS Extensions
1922 Graphics Output protocol interface to get video mode.
1924 @param This Protocol instance pointer.
1925 @param ModeNumber The mode number to return information on.
1926 @param SizeOfInfo A pointer to the size, in bytes, of the Info
1928 @param Info Caller allocated buffer that returns information
1931 @retval EFI_SUCCESS Mode information returned.
1932 @retval EFI_DEVICE_ERROR A hardware error occurred trying to retrieve the
1934 @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode ()
1935 @retval EFI_INVALID_PARAMETER One of the input args was NULL.
1940 BiosVideoGraphicsOutputQueryMode (
1941 IN EFI_GRAPHICS_OUTPUT_PROTOCOL
*This
,
1942 IN UINT32 ModeNumber
,
1943 OUT UINTN
*SizeOfInfo
,
1944 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
**Info
1947 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
1948 BIOS_VIDEO_MODE_DATA
*ModeData
;
1950 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This
);
1952 if (BiosVideoPrivate
->HardwareNeedsStarting
) {
1953 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1954 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
1955 EFI_PERIPHERAL_LOCAL_CONSOLE
| EFI_P_EC_OUTPUT_ERROR
,
1956 BiosVideoPrivate
->GopDevicePath
1958 return EFI_NOT_STARTED
;
1961 if ((This
== NULL
) || (Info
== NULL
) || (SizeOfInfo
== NULL
) || (ModeNumber
>= This
->Mode
->MaxMode
)) {
1962 return EFI_INVALID_PARAMETER
;
1965 *Info
= (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
*)AllocatePool (
1966 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
)
1968 if (NULL
== *Info
) {
1969 return EFI_OUT_OF_RESOURCES
;
1972 *SizeOfInfo
= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
);
1974 ModeData
= &BiosVideoPrivate
->ModeData
[ModeNumber
];
1975 (*Info
)->Version
= 0;
1976 (*Info
)->HorizontalResolution
= ModeData
->HorizontalResolution
;
1977 (*Info
)->VerticalResolution
= ModeData
->VerticalResolution
;
1978 (*Info
)->PixelFormat
= ModeData
->PixelFormat
;
1979 CopyMem (&((*Info
)->PixelInformation
), &(ModeData
->PixelBitMask
), sizeof (ModeData
->PixelBitMask
));
1981 (*Info
)->PixelsPerScanLine
= (ModeData
->BytesPerScanLine
* 8) / ModeData
->BitsPerPixel
;
1987 Worker function to set video mode.
1989 @param BiosVideoPrivate Instance of BIOS_VIDEO_DEV.
1990 @param ModeData The mode data to be set.
1991 @param DevicePath Pointer to Device Path Protocol.
1993 @retval EFI_SUCCESS Graphics mode was changed.
1994 @retval EFI_DEVICE_ERROR The device had an error and could not complete the
1996 @retval EFI_UNSUPPORTED ModeNumber is not supported by this device.
2000 BiosVideoSetModeWorker (
2001 IN BIOS_VIDEO_DEV
*BiosVideoPrivate
,
2002 IN BIOS_VIDEO_MODE_DATA
*ModeData
,
2003 IN EFI_DEVICE_PATH_PROTOCOL
*DevicePath
2007 EFI_IA32_REGISTER_SET Regs
;
2009 if (BiosVideoPrivate
->LineBuffer
!= NULL
) {
2010 FreePool (BiosVideoPrivate
->LineBuffer
);
2013 if (BiosVideoPrivate
->VgaFrameBuffer
!= NULL
) {
2014 FreePool (BiosVideoPrivate
->VgaFrameBuffer
);
2017 if (BiosVideoPrivate
->VbeFrameBuffer
!= NULL
) {
2018 FreePool (BiosVideoPrivate
->VbeFrameBuffer
);
2021 BiosVideoPrivate
->LineBuffer
= (UINT8
*)AllocatePool (
2022 ModeData
->BytesPerScanLine
2024 if (NULL
== BiosVideoPrivate
->LineBuffer
) {
2025 return EFI_OUT_OF_RESOURCES
;
2029 // Clear all registers
2031 ZeroMem (&Regs
, sizeof (Regs
));
2033 if (ModeData
->VbeModeNumber
< 0x100) {
2035 // Allocate a working buffer for BLT operations to the VGA frame buffer
2037 BiosVideoPrivate
->VgaFrameBuffer
= (UINT8
*)AllocatePool (4 * 480 * 80);
2038 if (NULL
== BiosVideoPrivate
->VgaFrameBuffer
) {
2039 return EFI_OUT_OF_RESOURCES
;
2045 Regs
.X
.AX
= ModeData
->VbeModeNumber
;
2046 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
2049 // Allocate a working buffer for BLT operations to the VBE frame buffer
2051 BiosVideoPrivate
->VbeFrameBuffer
=
2052 (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*)AllocatePool (
2053 ModeData
->BytesPerScanLine
* ModeData
->VerticalResolution
2055 if (NULL
== BiosVideoPrivate
->VbeFrameBuffer
) {
2056 return EFI_OUT_OF_RESOURCES
;
2062 Regs
.X
.AX
= VESA_BIOS_EXTENSIONS_SET_MODE
;
2063 Regs
.X
.BX
= (UINT16
)(ModeData
->VbeModeNumber
| VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER
);
2064 ZeroMem (BiosVideoPrivate
->VbeCrtcInformationBlock
, sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK
));
2065 Regs
.X
.ES
= EFI_SEGMENT ((UINTN
)BiosVideoPrivate
->VbeCrtcInformationBlock
);
2066 Regs
.X
.DI
= EFI_OFFSET ((UINTN
)BiosVideoPrivate
->VbeCrtcInformationBlock
);
2067 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
2070 // Check to see if the call succeeded
2072 if (Regs
.X
.AX
!= VESA_BIOS_EXTENSIONS_STATUS_SUCCESS
) {
2073 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
2074 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
2075 EFI_PERIPHERAL_LOCAL_CONSOLE
| EFI_P_EC_OUTPUT_ERROR
,
2078 return EFI_DEVICE_ERROR
;
2082 // Initialize the state of the VbeFrameBuffer
2084 Status
= BiosVideoPrivate
->PciIo
->Mem
.Read (
2085 BiosVideoPrivate
->PciIo
,
2086 EfiPciIoWidthUint32
,
2087 EFI_PCI_IO_PASS_THROUGH_BAR
,
2088 (UINT64
)(UINTN
)ModeData
->LinearFrameBuffer
,
2089 (ModeData
->BytesPerScanLine
* ModeData
->VerticalResolution
) >> 2,
2090 BiosVideoPrivate
->VbeFrameBuffer
2092 if (EFI_ERROR (Status
)) {
2101 Graphics Output protocol interface to set video mode.
2103 @param This Protocol instance pointer.
2104 @param ModeNumber The mode number to be set.
2106 @retval EFI_SUCCESS Graphics mode was changed.
2107 @retval EFI_DEVICE_ERROR The device had an error and could not complete the
2109 @retval EFI_UNSUPPORTED ModeNumber is not supported by this device.
2114 BiosVideoGraphicsOutputSetMode (
2115 IN EFI_GRAPHICS_OUTPUT_PROTOCOL
*This
,
2116 IN UINT32 ModeNumber
2120 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
2121 BIOS_VIDEO_MODE_DATA
*ModeData
;
2122 EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background
;
2125 return EFI_INVALID_PARAMETER
;
2128 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This
);
2130 ModeData
= &BiosVideoPrivate
->ModeData
[ModeNumber
];
2132 if (ModeNumber
>= This
->Mode
->MaxMode
) {
2133 return EFI_UNSUPPORTED
;
2136 if (ModeNumber
== This
->Mode
->Mode
) {
2138 // Clear screen to black
2140 ZeroMem (&Background
, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
));
2141 BiosVideoGraphicsOutputVbeBlt (
2149 ModeData
->HorizontalResolution
,
2150 ModeData
->VerticalResolution
,
2156 Status
= BiosVideoSetModeWorker (BiosVideoPrivate
, ModeData
, BiosVideoPrivate
->GopDevicePath
);
2157 if (EFI_ERROR (Status
)) {
2161 This
->Mode
->Mode
= ModeNumber
;
2162 This
->Mode
->Info
->Version
= 0;
2163 This
->Mode
->Info
->HorizontalResolution
= ModeData
->HorizontalResolution
;
2164 This
->Mode
->Info
->VerticalResolution
= ModeData
->VerticalResolution
;
2165 This
->Mode
->Info
->PixelFormat
= ModeData
->PixelFormat
;
2166 CopyMem (&(This
->Mode
->Info
->PixelInformation
), &(ModeData
->PixelBitMask
), sizeof (ModeData
->PixelBitMask
));
2167 This
->Mode
->Info
->PixelsPerScanLine
= (ModeData
->BytesPerScanLine
* 8) / ModeData
->BitsPerPixel
;
2168 This
->Mode
->SizeOfInfo
= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
);
2169 This
->Mode
->FrameBufferSize
= ModeData
->FrameBufferSize
;
2170 This
->Mode
->FrameBufferBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)ModeData
->LinearFrameBuffer
;
2172 BiosVideoPrivate
->HardwareNeedsStarting
= FALSE
;
2178 Update physical frame buffer, copy 4 bytes block, then copy remaining bytes.
2180 @param PciIo The pointer of EFI_PCI_IO_PROTOCOL
2181 @param VbeBuffer The data to transfer to screen
2182 @param MemAddress Physical frame buffer base address
2183 @param DestinationX The X coordinate of the destination for BltOperation
2184 @param DestinationY The Y coordinate of the destination for BltOperation
2185 @param TotalBytes The total bytes of copy
2186 @param VbePixelWidth Bytes per pixel
2187 @param BytesPerScanLine Bytes per scan line
2192 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2193 IN UINT8
*VbeBuffer
,
2194 IN VOID
*MemAddress
,
2195 IN UINTN DestinationX
,
2196 IN UINTN DestinationY
,
2197 IN UINTN TotalBytes
,
2198 IN UINT32 VbePixelWidth
,
2199 IN UINTN BytesPerScanLine
2202 UINTN FrameBufferAddr
;
2204 UINTN RemainingBytes
;
2205 UINTN UnalignedBytes
;
2208 FrameBufferAddr
= (UINTN
)MemAddress
+ (DestinationY
* BytesPerScanLine
) + DestinationX
* VbePixelWidth
;
2211 // If TotalBytes is less than 4 bytes, only start byte copy.
2213 if (TotalBytes
< 4) {
2214 Status
= PciIo
->Mem
.Write (
2217 EFI_PCI_IO_PASS_THROUGH_BAR
,
2218 (UINT64
)FrameBufferAddr
,
2222 ASSERT_EFI_ERROR (Status
);
2227 // If VbeBuffer is not 4-byte aligned, start byte copy.
2229 UnalignedBytes
= (4 - ((UINTN
)VbeBuffer
& 0x3)) & 0x3;
2231 if (UnalignedBytes
!= 0) {
2232 Status
= PciIo
->Mem
.Write (
2235 EFI_PCI_IO_PASS_THROUGH_BAR
,
2236 (UINT64
)FrameBufferAddr
,
2240 ASSERT_EFI_ERROR (Status
);
2241 FrameBufferAddr
+= UnalignedBytes
;
2242 VbeBuffer
+= UnalignedBytes
;
2246 // Calculate 4-byte block count and remaining bytes.
2248 CopyBlockNum
= (TotalBytes
- UnalignedBytes
) >> 2;
2249 RemainingBytes
= (TotalBytes
- UnalignedBytes
) & 3;
2252 // Copy 4-byte block and remaining bytes to physical frame buffer.
2254 if (CopyBlockNum
!= 0) {
2255 Status
= PciIo
->Mem
.Write (
2257 EfiPciIoWidthUint32
,
2258 EFI_PCI_IO_PASS_THROUGH_BAR
,
2259 (UINT64
)FrameBufferAddr
,
2263 ASSERT_EFI_ERROR (Status
);
2266 if (RemainingBytes
!= 0) {
2267 FrameBufferAddr
+= (CopyBlockNum
<< 2);
2268 VbeBuffer
+= (CopyBlockNum
<< 2);
2269 Status
= PciIo
->Mem
.Write (
2272 EFI_PCI_IO_PASS_THROUGH_BAR
,
2273 (UINT64
)FrameBufferAddr
,
2277 ASSERT_EFI_ERROR (Status
);
2282 Worker function to block transfer for VBE device.
2284 @param BiosVideoPrivate Instance of BIOS_VIDEO_DEV
2285 @param BltBuffer The data to transfer to screen
2286 @param BltOperation The operation to perform
2287 @param SourceX The X coordinate of the source for BltOperation
2288 @param SourceY The Y coordinate of the source for BltOperation
2289 @param DestinationX The X coordinate of the destination for
2291 @param DestinationY The Y coordinate of the destination for
2293 @param Width The width of a rectangle in the blt rectangle in
2295 @param Height The height of a rectangle in the blt rectangle in
2297 @param Delta Not used for EfiBltVideoFill and
2298 EfiBltVideoToVideo operation. If a Delta of 0 is
2299 used, the entire BltBuffer will be operated on. If
2300 a subrectangle of the BltBuffer is used, then
2301 Delta represents the number of bytes in a row of
2303 @param Mode Mode data.
2305 @retval EFI_INVALID_PARAMETER Invalid parameter passed in
2306 @retval EFI_SUCCESS Blt operation success
2310 BiosVideoVbeBltWorker (
2311 IN BIOS_VIDEO_DEV
*BiosVideoPrivate
,
2312 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*BltBuffer OPTIONAL
,
2313 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation
,
2316 IN UINTN DestinationX
,
2317 IN UINTN DestinationY
,
2321 IN BIOS_VIDEO_MODE_DATA
*Mode
2324 EFI_PCI_IO_PROTOCOL
*PciIo
;
2325 EFI_TPL OriginalTPL
;
2329 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*Blt
;
2331 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*VbeFrameBuffer
;
2332 UINTN BytesPerScanLine
;
2337 UINT32 VbePixelWidth
;
2341 PciIo
= BiosVideoPrivate
->PciIo
;
2343 VbeFrameBuffer
= BiosVideoPrivate
->VbeFrameBuffer
;
2344 MemAddress
= Mode
->LinearFrameBuffer
;
2345 BytesPerScanLine
= Mode
->BytesPerScanLine
;
2346 VbePixelWidth
= Mode
->BitsPerPixel
/ 8;
2347 BltUint8
= (UINT8
*)BltBuffer
;
2348 TotalBytes
= Width
* VbePixelWidth
;
2350 if (((UINTN
)BltOperation
) >= EfiGraphicsOutputBltOperationMax
) {
2351 return EFI_INVALID_PARAMETER
;
2354 if ((Width
== 0) || (Height
== 0)) {
2355 return EFI_INVALID_PARAMETER
;
2359 // We need to fill the Virtual Screen buffer with the blt data.
2360 // The virtual screen is upside down, as the first row is the bootom row of
2363 if (BltOperation
== EfiBltVideoToBltBuffer
) {
2365 // Video to BltBuffer: Source is Video, destination is BltBuffer
2367 if (SourceY
+ Height
> Mode
->VerticalResolution
) {
2368 return EFI_INVALID_PARAMETER
;
2371 if (SourceX
+ Width
> Mode
->HorizontalResolution
) {
2372 return EFI_INVALID_PARAMETER
;
2376 // BltBuffer to Video: Source is BltBuffer, destination is Video
2378 if (DestinationY
+ Height
> Mode
->VerticalResolution
) {
2379 return EFI_INVALID_PARAMETER
;
2382 if (DestinationX
+ Width
> Mode
->HorizontalResolution
) {
2383 return EFI_INVALID_PARAMETER
;
2388 // If Delta is zero, then the entire BltBuffer is being used, so Delta
2389 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
2390 // the number of bytes in each row can be computed.
2393 Delta
= Width
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
);
2397 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
2398 // We would not want a timer based event (Cursor, ...) to come in while we are
2399 // doing this operation.
2401 OriginalTPL
= gBS
->RaiseTPL (TPL_NOTIFY
);
2403 switch (BltOperation
) {
2404 case EfiBltVideoToBltBuffer
:
2405 for (SrcY
= SourceY
, DstY
= DestinationY
; DstY
< (Height
+ DestinationY
); SrcY
++, DstY
++) {
2406 Blt
= (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*)(BltUint8
+ DstY
* Delta
+ DestinationX
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
));
2408 // Shuffle the packed bytes in the hardware buffer to match EFI_GRAPHICS_OUTPUT_BLT_PIXEL
2410 VbeBuffer
= ((UINT8
*)VbeFrameBuffer
+ (SrcY
* BytesPerScanLine
+ SourceX
* VbePixelWidth
));
2411 for (DstX
= DestinationX
; DstX
< (Width
+ DestinationX
); DstX
++) {
2412 Pixel
= VbeBuffer
[0] | VbeBuffer
[1] << 8 | VbeBuffer
[2] << 16 | VbeBuffer
[3] << 24;
2413 Blt
->Red
= (UINT8
)((Pixel
>> Mode
->Red
.Position
) & Mode
->Red
.Mask
);
2414 Blt
->Blue
= (UINT8
)((Pixel
>> Mode
->Blue
.Position
) & Mode
->Blue
.Mask
);
2415 Blt
->Green
= (UINT8
)((Pixel
>> Mode
->Green
.Position
) & Mode
->Green
.Mask
);
2418 VbeBuffer
+= VbePixelWidth
;
2424 case EfiBltVideoToVideo
:
2425 for (Index
= 0; Index
< Height
; Index
++) {
2426 if (DestinationY
<= SourceY
) {
2427 SrcY
= SourceY
+ Index
;
2428 DstY
= DestinationY
+ Index
;
2430 SrcY
= SourceY
+ Height
- Index
- 1;
2431 DstY
= DestinationY
+ Height
- Index
- 1;
2434 VbeBuffer
= ((UINT8
*)VbeFrameBuffer
+ DstY
* BytesPerScanLine
+ DestinationX
* VbePixelWidth
);
2435 VbeBuffer1
= ((UINT8
*)VbeFrameBuffer
+ SrcY
* BytesPerScanLine
+ SourceX
* VbePixelWidth
);
2444 // Update physical frame buffer.
2460 case EfiBltVideoFill
:
2461 VbeBuffer
= (UINT8
*)((UINTN
)VbeFrameBuffer
+ (DestinationY
* BytesPerScanLine
) + DestinationX
* VbePixelWidth
);
2462 Blt
= (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*)BltUint8
;
2464 // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
2466 Pixel
= ((Blt
->Red
& Mode
->Red
.Mask
) << Mode
->Red
.Position
) |
2468 (Blt
->Green
& Mode
->Green
.Mask
) <<
2469 Mode
->Green
.Position
2471 ((Blt
->Blue
& Mode
->Blue
.Mask
) << Mode
->Blue
.Position
);
2473 for (Index
= 0; Index
< Width
; Index
++) {
2479 VbeBuffer
+= VbePixelWidth
;
2482 VbeBuffer
= (UINT8
*)((UINTN
)VbeFrameBuffer
+ (DestinationY
* BytesPerScanLine
) + DestinationX
* VbePixelWidth
);
2483 for (DstY
= DestinationY
+ 1; DstY
< (Height
+ DestinationY
); DstY
++) {
2485 (VOID
*)((UINTN
)VbeFrameBuffer
+ (DstY
* BytesPerScanLine
) + DestinationX
* VbePixelWidth
),
2491 for (DstY
= DestinationY
; DstY
< (Height
+ DestinationY
); DstY
++) {
2493 // Update physical frame buffer.
2509 case EfiBltBufferToVideo
:
2510 for (SrcY
= SourceY
, DstY
= DestinationY
; SrcY
< (Height
+ SourceY
); SrcY
++, DstY
++) {
2511 Blt
= (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*)(BltUint8
+ (SrcY
* Delta
) + (SourceX
) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
));
2512 VbeBuffer
= ((UINT8
*)VbeFrameBuffer
+ (DstY
* BytesPerScanLine
+ DestinationX
* VbePixelWidth
));
2513 for (DstX
= DestinationX
; DstX
< (Width
+ DestinationX
); DstX
++) {
2515 // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
2517 Pixel
= ((Blt
->Red
& Mode
->Red
.Mask
) << Mode
->Red
.Position
) |
2518 ((Blt
->Green
& Mode
->Green
.Mask
) << Mode
->Green
.Position
) |
2519 ((Blt
->Blue
& Mode
->Blue
.Mask
) << Mode
->Blue
.Position
);
2526 VbeBuffer
+= VbePixelWidth
;
2529 VbeBuffer
= ((UINT8
*)VbeFrameBuffer
+ (DstY
* BytesPerScanLine
+ DestinationX
* VbePixelWidth
));
2532 // Update physical frame buffer.
2551 gBS
->RestoreTPL (OriginalTPL
);
2557 Graphics Output protocol instance to block transfer for VBE device.
2559 @param This Pointer to Graphics Output protocol instance
2560 @param BltBuffer The data to transfer to screen
2561 @param BltOperation The operation to perform
2562 @param SourceX The X coordinate of the source for BltOperation
2563 @param SourceY The Y coordinate of the source for BltOperation
2564 @param DestinationX The X coordinate of the destination for
2566 @param DestinationY The Y coordinate of the destination for
2568 @param Width The width of a rectangle in the blt rectangle in
2570 @param Height The height of a rectangle in the blt rectangle in
2572 @param Delta Not used for EfiBltVideoFill and
2573 EfiBltVideoToVideo operation. If a Delta of 0 is
2574 used, the entire BltBuffer will be operated on. If
2575 a subrectangle of the BltBuffer is used, then
2576 Delta represents the number of bytes in a row of
2579 @retval EFI_INVALID_PARAMETER Invalid parameter passed in
2580 @retval EFI_SUCCESS Blt operation success
2585 BiosVideoGraphicsOutputVbeBlt (
2586 IN EFI_GRAPHICS_OUTPUT_PROTOCOL
*This
,
2587 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*BltBuffer OPTIONAL
,
2588 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation
,
2591 IN UINTN DestinationX
,
2592 IN UINTN DestinationY
,
2598 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
2599 BIOS_VIDEO_MODE_DATA
*Mode
;
2602 return EFI_INVALID_PARAMETER
;
2605 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This
);
2606 Mode
= &BiosVideoPrivate
->ModeData
[This
->Mode
->Mode
];
2608 return BiosVideoVbeBltWorker (
2624 Write graphics controller registers.
2626 @param PciIo Pointer to PciIo protocol instance of the
2628 @param Address Register address
2629 @param Data Data to be written to register
2635 WriteGraphicsController (
2636 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2641 Address
= Address
| (Data
<< 8);
2644 EfiPciIoWidthUint16
,
2645 EFI_PCI_IO_PASS_THROUGH_BAR
,
2646 VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER
,
2653 Read the four bit plane of VGA frame buffer.
2655 @param PciIo Pointer to PciIo protocol instance of the
2657 @param HardwareBuffer Hardware VGA frame buffer address
2658 @param MemoryBuffer Memory buffer address
2659 @param WidthInBytes Number of bytes in a line to read
2660 @param Height Height of the area to read
2667 EFI_PCI_IO_PROTOCOL
*PciIo
,
2668 UINT8
*HardwareBuffer
,
2669 UINT8
*MemoryBuffer
,
2676 UINTN FrameBufferOffset
;
2681 // Program the Mode Register Write mode 0, Read mode 0
2683 WriteGraphicsController (
2685 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER
,
2686 VGA_GRAPHICS_CONTROLLER_READ_MODE_0
| VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0
2689 for (BitPlane
= 0, FrameBufferOffset
= 0;
2690 BitPlane
< VGA_NUMBER_OF_BIT_PLANES
;
2691 BitPlane
++, FrameBufferOffset
+= VGA_BYTES_PER_BIT_PLANE
2695 // Program the Read Map Select Register to select the correct bit plane
2697 WriteGraphicsController (
2699 VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER
,
2703 Source
= HardwareBuffer
;
2704 Destination
= MemoryBuffer
+ FrameBufferOffset
;
2706 for (Rows
= 0; Rows
< Height
; Rows
++, Source
+= VGA_BYTES_PER_SCAN_LINE
, Destination
+= VGA_BYTES_PER_SCAN_LINE
) {
2710 EFI_PCI_IO_PASS_THROUGH_BAR
,
2711 (UINT64
)(UINTN
)Source
,
2720 Internal routine to convert VGA color to Grahpics Output color.
2722 @param MemoryBuffer Buffer containing VGA color
2723 @param CoordinateX The X coordinate of pixel on screen
2724 @param CoordinateY The Y coordinate of pixel on screen
2725 @param BltBuffer Buffer to contain converted Grahpics Output color
2731 VgaConvertToGraphicsOutputColor (
2732 UINT8
*MemoryBuffer
,
2735 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*BltBuffer
2742 MemoryBuffer
+= ((CoordinateY
<< 6) + (CoordinateY
<< 4) + (CoordinateX
>> 3));
2743 Mask
= mVgaBitMaskTable
[CoordinateX
& 0x07];
2744 for (Bit
= 0x01, Color
= 0; Bit
< 0x10; Bit
<<= 1, MemoryBuffer
+= VGA_BYTES_PER_BIT_PLANE
) {
2745 if ((*MemoryBuffer
& Mask
) != 0) {
2750 *BltBuffer
= mVgaColorToGraphicsOutputColor
[Color
];
2754 Internal routine to convert Grahpics Output color to VGA color.
2756 @param BltBuffer buffer containing Grahpics Output color
2758 @return Converted VGA color
2763 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*BltBuffer
2768 Color
= (UINT8
)((BltBuffer
->Blue
>> 7) | ((BltBuffer
->Green
>> 6) & 0x02) | ((BltBuffer
->Red
>> 5) & 0x04));
2769 if ((BltBuffer
->Red
+ BltBuffer
->Green
+ BltBuffer
->Blue
) > 0x180) {
2777 Grahpics Output protocol instance to block transfer for VGA device.
2779 @param This Pointer to Grahpics Output protocol instance
2780 @param BltBuffer The data to transfer to screen
2781 @param BltOperation The operation to perform
2782 @param SourceX The X coordinate of the source for BltOperation
2783 @param SourceY The Y coordinate of the source for BltOperation
2784 @param DestinationX The X coordinate of the destination for
2786 @param DestinationY The Y coordinate of the destination for
2788 @param Width The width of a rectangle in the blt rectangle in
2790 @param Height The height of a rectangle in the blt rectangle in
2792 @param Delta Not used for EfiBltVideoFill and
2793 EfiBltVideoToVideo operation. If a Delta of 0 is
2794 used, the entire BltBuffer will be operated on. If
2795 a subrectangle of the BltBuffer is used, then
2796 Delta represents the number of bytes in a row of
2799 @retval EFI_INVALID_PARAMETER Invalid parameter passed in
2800 @retval EFI_SUCCESS Blt operation success
2805 BiosVideoGraphicsOutputVgaBlt (
2806 IN EFI_GRAPHICS_OUTPUT_PROTOCOL
*This
,
2807 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*BltBuffer OPTIONAL
,
2808 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation
,
2811 IN UINTN DestinationX
,
2812 IN UINTN DestinationY
,
2818 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
2819 EFI_TPL OriginalTPL
;
2821 UINTN BytesPerScanLine
;
2833 UINT8
*SourceAddress
;
2834 UINT8
*DestinationAddress
;
2835 EFI_PCI_IO_PROTOCOL
*PciIo
;
2838 UINT8
*VgaFrameBuffer
;
2847 if ((This
== NULL
) || (((UINTN
)BltOperation
) >= EfiGraphicsOutputBltOperationMax
)) {
2848 return EFI_INVALID_PARAMETER
;
2851 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This
);
2853 CurrentMode
= This
->Mode
->Mode
;
2854 PciIo
= BiosVideoPrivate
->PciIo
;
2855 MemAddress
= BiosVideoPrivate
->ModeData
[CurrentMode
].LinearFrameBuffer
;
2856 BytesPerScanLine
= BiosVideoPrivate
->ModeData
[CurrentMode
].BytesPerScanLine
>> 3;
2857 VgaFrameBuffer
= BiosVideoPrivate
->VgaFrameBuffer
;
2859 if ((Width
== 0) || (Height
== 0)) {
2860 return EFI_INVALID_PARAMETER
;
2864 // We need to fill the Virtual Screen buffer with the blt data.
2865 // The virtual screen is upside down, as the first row is the bootom row of
2868 if (BltOperation
== EfiBltVideoToBltBuffer
) {
2870 // Video to BltBuffer: Source is Video, destination is BltBuffer
2872 if (SourceY
+ Height
> BiosVideoPrivate
->ModeData
[CurrentMode
].VerticalResolution
) {
2873 return EFI_INVALID_PARAMETER
;
2876 if (SourceX
+ Width
> BiosVideoPrivate
->ModeData
[CurrentMode
].HorizontalResolution
) {
2877 return EFI_INVALID_PARAMETER
;
2881 // BltBuffer to Video: Source is BltBuffer, destination is Video
2883 if (DestinationY
+ Height
> BiosVideoPrivate
->ModeData
[CurrentMode
].VerticalResolution
) {
2884 return EFI_INVALID_PARAMETER
;
2887 if (DestinationX
+ Width
> BiosVideoPrivate
->ModeData
[CurrentMode
].HorizontalResolution
) {
2888 return EFI_INVALID_PARAMETER
;
2893 // If Delta is zero, then the entire BltBuffer is being used, so Delta
2894 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
2895 // the number of bytes in each row can be computed.
2898 Delta
= Width
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
);
2902 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
2903 // We would not want a timer based event (Cursor, ...) to come in while we are
2904 // doing this operation.
2906 OriginalTPL
= gBS
->RaiseTPL (TPL_NOTIFY
);
2909 // Compute some values we need for VGA
2911 switch (BltOperation
) {
2912 case EfiBltVideoToBltBuffer
:
2914 SourceOffset
= (SourceY
<< 6) + (SourceY
<< 4) + (SourceX
>> 3);
2915 SourceWidth
= ((SourceX
+ Width
- 1) >> 3) - (SourceX
>> 3) + 1;
2918 // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2922 MemAddress
+ SourceOffset
,
2923 VgaFrameBuffer
+ SourceOffset
,
2929 // Convert VGA Bit Planes to a Graphics Output 32-bit color value
2931 BltBuffer
+= (DestinationY
* (Delta
>> 2) + DestinationX
);
2932 for (Rows
= 0, CoordinateY
= SourceY
; Rows
< Height
; Rows
++, CoordinateY
++, BltBuffer
+= (Delta
>> 2)) {
2933 for (Columns
= 0, CoordinateX
= SourceX
; Columns
< Width
; Columns
++, CoordinateX
++, BltBuffer
++) {
2934 VgaConvertToGraphicsOutputColor (VgaFrameBuffer
, CoordinateX
, CoordinateY
, BltBuffer
);
2942 case EfiBltVideoToVideo
:
2944 // Check for an aligned Video to Video operation
2946 if (((SourceX
& 0x07) == 0x00) && ((DestinationX
& 0x07) == 0x00) && ((Width
& 0x07) == 0x00)) {
2948 // Program the Mode Register Write mode 1, Read mode 0
2950 WriteGraphicsController (
2952 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER
,
2953 VGA_GRAPHICS_CONTROLLER_READ_MODE_0
| VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1
2956 SourceAddress
= (UINT8
*)(MemAddress
+ (SourceY
<< 6) + (SourceY
<< 4) + (SourceX
>> 3));
2957 DestinationAddress
= (UINT8
*)(MemAddress
+ (DestinationY
<< 6) + (DestinationY
<< 4) + (DestinationX
>> 3));
2959 for (Index
= 0, Offset
= 0; Index
< Height
; Index
++, Offset
+= BytesPerScanLine
) {
2963 EFI_PCI_IO_PASS_THROUGH_BAR
,
2964 (UINT64
)(UINTN
)(DestinationAddress
+ Offset
),
2965 EFI_PCI_IO_PASS_THROUGH_BAR
,
2966 (UINT64
)(UINTN
)(SourceAddress
+ Offset
),
2971 SourceOffset
= (SourceY
<< 6) + (SourceY
<< 4) + (SourceX
>> 3);
2972 SourceWidth
= ((SourceX
+ Width
- 1) >> 3) - (SourceX
>> 3) + 1;
2975 // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2979 MemAddress
+ SourceOffset
,
2980 VgaFrameBuffer
+ SourceOffset
,
2988 case EfiBltVideoFill
:
2989 StartAddress
= (UINTN
)(MemAddress
+ (DestinationY
<< 6) + (DestinationY
<< 4) + (DestinationX
>> 3));
2990 Bytes
= ((DestinationX
+ Width
- 1) >> 3) - (DestinationX
>> 3);
2991 LeftMask
= mVgaLeftMaskTable
[DestinationX
& 0x07];
2992 RightMask
= mVgaRightMaskTable
[(DestinationX
+ Width
- 1) & 0x07];
2994 LeftMask
= (UINT8
)(LeftMask
& RightMask
);
2998 if (LeftMask
== 0xff) {
3004 if (RightMask
== 0xff) {
3009 PixelColor
= VgaConvertColor (BltBuffer
);
3012 // Program the Mode Register Write mode 2, Read mode 0
3014 WriteGraphicsController (
3016 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER
,
3017 VGA_GRAPHICS_CONTROLLER_READ_MODE_0
| VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
3021 // Program the Data Rotate/Function Select Register to replace
3023 WriteGraphicsController (
3025 VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER
,
3026 VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
3029 if (LeftMask
!= 0) {
3031 // Program the BitMask register with the Left column mask
3033 WriteGraphicsController (
3035 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER
,
3039 for (Index
= 0, Address
= StartAddress
; Index
< Height
; Index
++, Address
+= BytesPerScanLine
) {
3041 // Read data from the bit planes into the latches
3046 EFI_PCI_IO_PASS_THROUGH_BAR
,
3047 (UINT64
)(UINTN
)Address
,
3052 // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
3057 EFI_PCI_IO_PASS_THROUGH_BAR
,
3058 (UINT64
)(UINTN
)Address
,
3067 // Program the BitMask register with the middle column mask of 0xff
3069 WriteGraphicsController (
3071 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER
,
3075 for (Index
= 0, Address
= StartAddress
+ 1; Index
< Height
; Index
++, Address
+= BytesPerScanLine
) {
3078 EfiPciIoWidthFillUint8
,
3079 EFI_PCI_IO_PASS_THROUGH_BAR
,
3080 (UINT64
)(UINTN
)Address
,
3087 if (RightMask
!= 0) {
3089 // Program the BitMask register with the Right column mask
3091 WriteGraphicsController (
3093 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER
,
3097 for (Index
= 0, Address
= StartAddress
+ Bytes
; Index
< Height
; Index
++, Address
+= BytesPerScanLine
) {
3099 // Read data from the bit planes into the latches
3104 EFI_PCI_IO_PASS_THROUGH_BAR
,
3105 (UINT64
)(UINTN
)Address
,
3110 // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
3115 EFI_PCI_IO_PASS_THROUGH_BAR
,
3116 (UINT64
)(UINTN
)Address
,
3125 case EfiBltBufferToVideo
:
3126 StartAddress
= (UINTN
)(MemAddress
+ (DestinationY
<< 6) + (DestinationY
<< 4) + (DestinationX
>> 3));
3127 LeftMask
= mVgaBitMaskTable
[DestinationX
& 0x07];
3130 // Program the Mode Register Write mode 2, Read mode 0
3132 WriteGraphicsController (
3134 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER
,
3135 VGA_GRAPHICS_CONTROLLER_READ_MODE_0
| VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
3139 // Program the Data Rotate/Function Select Register to replace
3141 WriteGraphicsController (
3143 VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER
,
3144 VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
3147 for (Index
= 0, Address
= StartAddress
; Index
< Height
; Index
++, Address
+= BytesPerScanLine
) {
3148 for (Index1
= 0; Index1
< Width
; Index1
++) {
3149 BiosVideoPrivate
->LineBuffer
[Index1
] = VgaConvertColor (&BltBuffer
[(SourceY
+ Index
) * (Delta
>> 2) + SourceX
+ Index1
]);
3152 AddressFix
= Address
;
3154 for (Bit
= 0; Bit
< 8; Bit
++) {
3156 // Program the BitMask register with the Left column mask
3158 WriteGraphicsController (
3160 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER
,
3164 for (Index1
= Bit
, Address1
= (UINT8
*)AddressFix
; Index1
< Width
; Index1
+= 8, Address1
++) {
3166 // Read data from the bit planes into the latches
3171 EFI_PCI_IO_PASS_THROUGH_BAR
,
3172 (UINT64
)(UINTN
)Address1
,
3180 EFI_PCI_IO_PASS_THROUGH_BAR
,
3181 (UINT64
)(UINTN
)Address1
,
3183 &BiosVideoPrivate
->LineBuffer
[Index1
]
3187 LeftMask
= (UINT8
)(LeftMask
>> 1);
3188 if (LeftMask
== 0) {
3200 gBS
->RestoreTPL (OriginalTPL
);
3206 // VGA Mini Port Protocol Functions
3210 VgaMiniPort protocol interface to set mode.
3212 @param This Pointer to VgaMiniPort protocol instance
3213 @param ModeNumber The index of the mode
3215 @retval EFI_UNSUPPORTED The requested mode is not supported
3216 @retval EFI_SUCCESS The requested mode is set successfully
3221 BiosVideoVgaMiniPortSetMode (
3222 IN EFI_VGA_MINI_PORT_PROTOCOL
*This
,
3226 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
3227 EFI_IA32_REGISTER_SET Regs
;
3230 return EFI_INVALID_PARAMETER
;
3234 // Make sure the ModeNumber is a valid value
3236 if (ModeNumber
>= This
->MaxMode
) {
3237 return EFI_UNSUPPORTED
;
3241 // Get the device structure for this device
3243 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (This
);
3245 switch (ModeNumber
) {
3248 // Set the 80x25 Text VGA Mode
3252 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
3257 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
3262 // Set the 80x50 Text VGA Mode
3266 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
3270 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
3274 return EFI_UNSUPPORTED
;
3281 Event handler for Exit Boot Service.
3283 @param Event The event that be signalled when exiting boot service.
3284 @param Context Pointer to instance of BIOS_VIDEO_DEV.
3289 BiosVideoNotifyExitBootServices (
3294 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
3295 EFI_IA32_REGISTER_SET Regs
;
3297 BiosVideoPrivate
= (BIOS_VIDEO_DEV
*)Context
;
3300 // Set the 80x25 Text VGA Mode
3304 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
3308 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
3313 BiosVideoPrivate
->LegacyBios
->Int86 (BiosVideoPrivate
->LegacyBios
, 0x10, &Regs
);
3317 The user Entry Point for module UefiBiosVideo. The user code starts with this function.
3319 @param[in] ImageHandle The firmware allocated handle for the EFI image.
3320 @param[in] SystemTable A pointer to the EFI System Table.
3322 @retval EFI_SUCCESS The entry point is executed successfully.
3323 @retval other Some error occurs when executing this entry point.
3328 BiosVideoEntryPoint (
3329 IN EFI_HANDLE ImageHandle
,
3330 IN EFI_SYSTEM_TABLE
*SystemTable
3336 // Install driver model protocol(s).
3338 Status
= EfiLibInstallDriverBindingComponentName2 (
3341 &gBiosVideoDriverBinding
,
3343 &gBiosVideoComponentName
,
3344 &gBiosVideoComponentName2
3346 ASSERT_EFI_ERROR (Status
);
3349 // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver
3351 return gBS
->InstallMultipleProtocolInterfaces (
3353 &gEfiLegacyBiosGuid
,