3 BiosVideo driver produce EFI_GRAPHIC_OUTPUT_PROTOCOL via LegacyBios Video rom.
5 Copyright (c) 2006 - 2008, Intel Corporation
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "BiosVideo.h"
19 // EFI Driver Binding Protocol Instance
21 EFI_DRIVER_BINDING_PROTOCOL gBiosVideoDriverBinding
= {
22 BiosVideoDriverBindingSupported
,
23 BiosVideoDriverBindingStart
,
24 BiosVideoDriverBindingStop
,
31 // Global lookup tables for VGA graphics modes
33 UINT8 mVgaLeftMaskTable
[] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
35 UINT8 mVgaRightMaskTable
[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
37 UINT8 mVgaBitMaskTable
[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
39 EFI_LEGACY_8259_PROTOCOL
*mLegacy8259
= NULL
;
40 THUNK_CONTEXT mThunkContext
;
42 EFI_GRAPHICS_OUTPUT_BLT_PIXEL mVgaColorToGraphicsOutputColor
[] = {
44 // {B, G, R, reserved}
46 {0x00, 0x00, 0x00, 0x00}, // BLACK
47 {0x98, 0x00, 0x00, 0x00}, // LIGHTBLUE
48 {0x00, 0x98, 0x00, 0x00}, // LIGHGREEN
49 {0x98, 0x98, 0x00, 0x00}, // LIGHCYAN
50 {0x00, 0x00, 0x98, 0x00}, // LIGHRED
51 {0x98, 0x00, 0x98, 0x00}, // MAGENTA
52 {0x00, 0x98, 0x98, 0x00}, // BROWN
53 {0x98, 0x98, 0x98, 0x00}, // LIGHTGRAY
54 {0x10, 0x10, 0x10, 0x00},
55 {0xff, 0x10, 0x10, 0x00}, // BLUE
56 {0x10, 0xff, 0x10, 0x00}, // LIME
57 {0xff, 0xff, 0x10, 0x00}, // CYAN
58 {0x10, 0x10, 0xff, 0x00}, // RED
59 {0xf0, 0x10, 0xff, 0x00}, // FUCHSIA
60 {0x10, 0xff, 0xff, 0x00}, // YELLOW
61 {0xff, 0xff, 0xff, 0x00} // WHITE
65 // Standard timing defined by VESA EDID
67 VESA_BIOS_EXTENSIONS_EDID_TIMING mEstablishedEdidTiming
[] = {
69 // Established Timing I
80 // Established Timing II
91 // Established Timing III
97 Install child hanlde for a detect BiosVideo device and install related protocol
98 into this handle, such as EFI_GRAPHIC_OUTPUT_PROTOCOL.
100 @param This Instance pointer of EFI_DRIVER_BINDING_PROTOCOL
101 @param ParentHandle Parent's controller handle
102 @param ParentPciIo Parent's EFI_PCI_IO_PROTOCOL instance pointer
103 @param ParentLegacy8259 Parent's EFI_LEGACY_8259_PROTOCOL instance pointer
104 @param ParentDevicePath Parent's BIOS Video controller device path
105 @param RemainingDevicePath Remaining device path node instance for children.
107 @return whether success to create children handle for a VGA device and install
108 related protocol into new children handle.
112 BiosVideoChildHandleInstall (
113 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
114 IN EFI_HANDLE ParentHandle
,
115 IN EFI_PCI_IO_PROTOCOL
*ParentPciIo
,
116 IN EFI_LEGACY_8259_PROTOCOL
*ParentLegacy8259
,
117 IN THUNK_CONTEXT
*ThunkContext
,
118 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
119 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
124 Deregister an video child handle and free resources
126 @param This Protocol instance pointer.
127 @param Controller Video controller handle
128 @param Handle Video child handle
135 BiosVideoChildHandleUninstall (
136 EFI_DRIVER_BINDING_PROTOCOL
*This
,
137 EFI_HANDLE Controller
,
143 Collect the resource from destroyed bios video device.
145 @param BiosVideoPrivate Video child device private data structure
149 BiosVideoDeviceReleaseResource (
150 BIOS_VIDEO_DEV
*BiosVideoPrivate
157 @param ImageHandle Handle of driver image.
158 @param SystemTable Pointer to system table.
164 BiosVideoDriverEntryPoint (
165 IN EFI_HANDLE ImageHandle
,
166 IN EFI_SYSTEM_TABLE
*SystemTable
171 Status
= EfiLibInstallDriverBindingComponentName2 (
174 &gBiosVideoDriverBinding
,
176 &gBiosVideoComponentName
,
177 &gBiosVideoComponentName2
184 Test to see if Bios Video could be supported on the Controller.
186 @param This Pointer to driver binding protocol
187 @param Controller Controller handle to connect
188 @param RemainingDevicePath A pointer to the remaining portion of a device path
190 @retval EFI_SUCCESS This driver supports this device.
191 @retval other This driver does not support this device.
196 BiosVideoDriverBindingSupported (
197 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
198 IN EFI_HANDLE Controller
,
199 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
203 EFI_LEGACY_8259_PROTOCOL
*LegacyBios
;
204 EFI_PCI_IO_PROTOCOL
*PciIo
;
207 // See if the Legacy 8259 Protocol is available
209 Status
= gBS
->LocateProtocol (&gEfiLegacy8259ProtocolGuid
, NULL
, (VOID
**) &LegacyBios
);
210 if (EFI_ERROR (Status
)) {
215 // Open the IO Abstraction(s) needed to perform the supported test
217 Status
= gBS
->OpenProtocol (
219 &gEfiPciIoProtocolGuid
,
221 This
->DriverBindingHandle
,
223 EFI_OPEN_PROTOCOL_BY_DRIVER
225 if (EFI_ERROR (Status
)) {
229 if (!BiosVideoIsVga (PciIo
)) {
230 Status
= EFI_UNSUPPORTED
;
235 &gEfiPciIoProtocolGuid
,
236 This
->DriverBindingHandle
,
244 Install Graphics Output Protocol onto VGA device handles
246 @param This Pointer to driver binding protocol
247 @param Controller Controller handle to connect
248 @param RemainingDevicePath A pointer to the remaining portion of a device path
255 BiosVideoDriverBindingStart (
256 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
257 IN EFI_HANDLE Controller
,
258 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
262 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
263 EFI_PCI_IO_PROTOCOL
*PciIo
;
267 // Prepare for status code
269 Status
= gBS
->HandleProtocol (
271 &gEfiDevicePathProtocolGuid
,
272 (VOID
**) &ParentDevicePath
274 if (EFI_ERROR (Status
)) {
279 // Open the IO Abstraction(s) needed
281 Status
= gBS
->OpenProtocol (
283 &gEfiPciIoProtocolGuid
,
285 This
->DriverBindingHandle
,
287 EFI_OPEN_PROTOCOL_BY_DRIVER
289 if (EFI_ERROR (Status
)) {
294 // Establish legacy environment for thunk call for all children handle.
296 if (mLegacy8259
== NULL
) {
297 Status
= gBS
->LocateProtocol (&gEfiLegacy8259ProtocolGuid
, NULL
, (VOID
**) &mLegacy8259
);
298 if (EFI_ERROR (Status
)) {
302 InitializeBiosIntCaller(&mThunkContext
);
303 InitializeInterruptRedirection(mLegacy8259
);
307 // Create child handle and install GraphicsOutputProtocol on it
309 Status
= BiosVideoChildHandleInstall (
320 if (EFI_ERROR (Status
)) {
323 // Release PCI I/O Protocols on the controller handle.
327 &gEfiPciIoProtocolGuid
,
328 This
->DriverBindingHandle
,
338 Stop this driver on Controller
340 @param This Protocol instance pointer.
341 @param Controller Handle of device to stop driver on
342 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
343 children is zero stop the entire bus driver.
344 @param ChildHandleBuffer List of Child Handles to Stop.
346 @retval EFI_SUCCESS This driver is removed Controller.
347 @retval other This driver was not removed from this device.
352 BiosVideoDriverBindingStop (
353 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
354 IN EFI_HANDLE Controller
,
355 IN UINTN NumberOfChildren
,
356 IN EFI_HANDLE
*ChildHandleBuffer
360 BOOLEAN AllChildrenStopped
;
363 if (NumberOfChildren
== 0) {
365 // Close PCI I/O protocol on the controller handle
369 &gEfiPciIoProtocolGuid
,
370 This
->DriverBindingHandle
,
377 AllChildrenStopped
= TRUE
;
378 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
379 Status
= BiosVideoChildHandleUninstall (This
, Controller
, ChildHandleBuffer
[Index
]);
381 if (EFI_ERROR (Status
)) {
382 AllChildrenStopped
= FALSE
;
386 if (!AllChildrenStopped
) {
387 return EFI_DEVICE_ERROR
;
394 Install child hanlde for a detect BiosVideo device and install related protocol
395 into this handle, such as EFI_GRAPHIC_OUTPUT_PROTOCOL.
397 @param This Instance pointer of EFI_DRIVER_BINDING_PROTOCOL
398 @param ParentHandle Parent's controller handle
399 @param ParentPciIo Parent's EFI_PCI_IO_PROTOCOL instance pointer
400 @param ParentLegacy8259 Parent's EFI_LEGACY_8259_PROTOCOL instance pointer
401 @param ParentDevicePath Parent's BIOS Video controller device path
402 @param RemainingDevicePath Remaining device path node instance for children.
404 @return whether success to create children handle for a VGA device and install
405 related protocol into new children handle.
409 BiosVideoChildHandleInstall (
410 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
411 IN EFI_HANDLE ParentHandle
,
412 IN EFI_PCI_IO_PROTOCOL
*ParentPciIo
,
413 IN EFI_LEGACY_8259_PROTOCOL
*ParentLegacy8259
,
414 IN THUNK_CONTEXT
*ParentThunkContext
,
415 IN EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
,
416 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
420 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
421 ACPI_ADR_DEVICE_PATH AcpiDeviceNode
;
424 // Allocate the private device structure for video device
426 Status
= gBS
->AllocatePool (
428 sizeof (BIOS_VIDEO_DEV
),
429 (VOID
**) &BiosVideoPrivate
431 if (EFI_ERROR (Status
)) {
435 ZeroMem (BiosVideoPrivate
, sizeof (BIOS_VIDEO_DEV
));
437 if (!BiosVideoIsVga (ParentPciIo
)) {
438 Status
= EFI_UNSUPPORTED
;
442 BiosVideoPrivate
->VgaCompatible
= TRUE
;
445 // Initialize the child private structure
447 BiosVideoPrivate
->Signature
= BIOS_VIDEO_DEV_SIGNATURE
;
448 BiosVideoPrivate
->Handle
= NULL
;
451 // Fill in Graphics Output specific mode structures
453 BiosVideoPrivate
->HardwareNeedsStarting
= TRUE
;
454 BiosVideoPrivate
->ModeData
= NULL
;
455 BiosVideoPrivate
->LineBuffer
= NULL
;
456 BiosVideoPrivate
->VgaFrameBuffer
= NULL
;
457 BiosVideoPrivate
->VbeFrameBuffer
= NULL
;
460 // Fill in the VGA Mini Port Protocol fields
462 BiosVideoPrivate
->VgaMiniPort
.SetMode
= BiosVideoVgaMiniPortSetMode
;
463 BiosVideoPrivate
->VgaMiniPort
.VgaMemoryOffset
= 0xb8000;
464 BiosVideoPrivate
->VgaMiniPort
.CrtcAddressRegisterOffset
= 0x3d4;
465 BiosVideoPrivate
->VgaMiniPort
.CrtcDataRegisterOffset
= 0x3d5;
466 BiosVideoPrivate
->VgaMiniPort
.VgaMemoryBar
= EFI_PCI_IO_PASS_THROUGH_BAR
;
467 BiosVideoPrivate
->VgaMiniPort
.CrtcAddressRegisterBar
= EFI_PCI_IO_PASS_THROUGH_BAR
;
468 BiosVideoPrivate
->VgaMiniPort
.CrtcDataRegisterBar
= EFI_PCI_IO_PASS_THROUGH_BAR
;
471 // Assume that Graphics Output Protocol will be produced until proven otherwise
473 BiosVideoPrivate
->ProduceGraphicsOutput
= TRUE
;
476 // Child handle need to consume the Legacy Bios protocol
478 BiosVideoPrivate
->Legacy8259
= ParentLegacy8259
;
479 BiosVideoPrivate
->ThunkContext
= ParentThunkContext
;
482 // When check for VBE, PCI I/O protocol is needed, so use parent's protocol interface temporally
484 BiosVideoPrivate
->PciIo
= ParentPciIo
;
487 // Check for VESA BIOS Extensions for modes that are compatible with Graphics Output
489 Status
= BiosVideoCheckForVbe (BiosVideoPrivate
);
490 if (EFI_ERROR (Status
)) {
492 // The VESA BIOS Extensions are not compatible with Graphics Output, so check for support
493 // for the standard 640x480 16 color VGA mode
495 if (BiosVideoPrivate
->VgaCompatible
) {
496 Status
= BiosVideoCheckForVga (BiosVideoPrivate
);
499 if (EFI_ERROR (Status
)) {
501 // Neither VBE nor the standard 640x480 16 color VGA mode are supported, so do
502 // not produce the Graphics Output protocol. Instead, produce the VGA MiniPort Protocol.
504 BiosVideoPrivate
->ProduceGraphicsOutput
= FALSE
;
507 // INT services are available, so on the 80x25 and 80x50 text mode are supported
509 BiosVideoPrivate
->VgaMiniPort
.MaxMode
= 2;
513 if (BiosVideoPrivate
->ProduceGraphicsOutput
) {
514 if (RemainingDevicePath
== NULL
) {
515 ZeroMem (&AcpiDeviceNode
, sizeof (ACPI_ADR_DEVICE_PATH
));
516 AcpiDeviceNode
.Header
.Type
= ACPI_DEVICE_PATH
;
517 AcpiDeviceNode
.Header
.SubType
= ACPI_ADR_DP
;
518 AcpiDeviceNode
.ADR
= ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA
, 0, 0);
519 SetDevicePathNodeLength (&AcpiDeviceNode
.Header
, sizeof (ACPI_ADR_DEVICE_PATH
));
521 BiosVideoPrivate
->DevicePath
= AppendDevicePathNode (
523 (EFI_DEVICE_PATH_PROTOCOL
*) &AcpiDeviceNode
526 BiosVideoPrivate
->DevicePath
= AppendDevicePathNode (ParentDevicePath
, RemainingDevicePath
);
530 // Creat child handle and install Graphics Output Protocol,EDID Discovered/Active Protocol
532 Status
= gBS
->InstallMultipleProtocolInterfaces (
533 &BiosVideoPrivate
->Handle
,
534 &gEfiDevicePathProtocolGuid
,
535 BiosVideoPrivate
->DevicePath
,
536 &gEfiGraphicsOutputProtocolGuid
,
537 &BiosVideoPrivate
->GraphicsOutput
,
538 &gEfiEdidDiscoveredProtocolGuid
,
539 &BiosVideoPrivate
->EdidDiscovered
,
540 &gEfiEdidActiveProtocolGuid
,
541 &BiosVideoPrivate
->EdidActive
,
545 if (!EFI_ERROR (Status
)) {
547 // Open the Parent Handle for the child
549 Status
= gBS
->OpenProtocol (
551 &gEfiPciIoProtocolGuid
,
552 (VOID
**) &BiosVideoPrivate
->PciIo
,
553 This
->DriverBindingHandle
,
554 BiosVideoPrivate
->Handle
,
555 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
557 if (EFI_ERROR (Status
)) {
563 // Install VGA Mini Port Protocol
565 Status
= gBS
->InstallMultipleProtocolInterfaces (
566 &BiosVideoPrivate
->Handle
,
567 &gEfiVgaMiniPortProtocolGuid
,
568 &BiosVideoPrivate
->VgaMiniPort
,
574 if (EFI_ERROR (Status
)) {
576 // Free private data structure
578 BiosVideoDeviceReleaseResource (BiosVideoPrivate
);
585 Deregister an video child handle and free resources
587 @param This Protocol instance pointer.
588 @param Controller Video controller handle
589 @param Handle Video child handle
595 BiosVideoChildHandleUninstall (
596 EFI_DRIVER_BINDING_PROTOCOL
*This
,
597 EFI_HANDLE Controller
,
602 IA32_REGISTER_SET Regs
;
603 EFI_GRAPHICS_OUTPUT_PROTOCOL
*GraphicsOutput
;
604 EFI_VGA_MINI_PORT_PROTOCOL
*VgaMiniPort
;
605 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
606 EFI_PCI_IO_PROTOCOL
*PciIo
;
608 BiosVideoPrivate
= NULL
;
610 Status
= gBS
->OpenProtocol (
612 &gEfiGraphicsOutputProtocolGuid
,
613 (VOID
**) &GraphicsOutput
,
614 This
->DriverBindingHandle
,
616 EFI_OPEN_PROTOCOL_GET_PROTOCOL
618 if (!EFI_ERROR (Status
)) {
619 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput
);
622 Status
= gBS
->OpenProtocol (
624 &gEfiVgaMiniPortProtocolGuid
,
625 (VOID
**) &VgaMiniPort
,
626 This
->DriverBindingHandle
,
628 EFI_OPEN_PROTOCOL_GET_PROTOCOL
630 if (!EFI_ERROR (Status
)) {
631 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (VgaMiniPort
);
634 if (BiosVideoPrivate
== NULL
) {
635 return EFI_UNSUPPORTED
;
639 // Close PCI I/O protocol that opened by child handle
641 Status
= gBS
->CloseProtocol (
643 &gEfiPciIoProtocolGuid
,
644 This
->DriverBindingHandle
,
649 // Uninstall protocols on child handle
651 if (BiosVideoPrivate
->ProduceGraphicsOutput
) {
652 Status
= gBS
->UninstallMultipleProtocolInterfaces (
653 BiosVideoPrivate
->Handle
,
654 &gEfiDevicePathProtocolGuid
,
655 BiosVideoPrivate
->DevicePath
,
656 &gEfiGraphicsOutputProtocolGuid
,
657 &BiosVideoPrivate
->GraphicsOutput
,
658 &gEfiEdidDiscoveredProtocolGuid
,
659 &BiosVideoPrivate
->EdidDiscovered
,
660 &gEfiEdidActiveProtocolGuid
,
661 &BiosVideoPrivate
->EdidActive
,
665 Status
= gBS
->UninstallMultipleProtocolInterfaces (
666 BiosVideoPrivate
->Handle
,
667 &gEfiVgaMiniPortProtocolGuid
,
668 &BiosVideoPrivate
->VgaMiniPort
,
672 if (EFI_ERROR (Status
)) {
675 &gEfiPciIoProtocolGuid
,
677 This
->DriverBindingHandle
,
679 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
684 gBS
->SetMem (&Regs
, sizeof (Regs
), 0);
687 // Set the 80x25 Text VGA Mode
691 LegacyBiosInt86 (BiosVideoPrivate
, 0x10, &Regs
);
696 LegacyBiosInt86 (BiosVideoPrivate
, 0x10, &Regs
);
699 // Do not disable IO/memory decode since that would prevent legacy ROM from working
703 // Release all allocated resources
705 BiosVideoDeviceReleaseResource (BiosVideoPrivate
);
711 Collect the resource from destroyed bios video device.
713 @param BiosVideoPrivate Video child device private data structure
717 BiosVideoDeviceReleaseResource (
718 BIOS_VIDEO_DEV
*BiosVideoPrivate
721 if (BiosVideoPrivate
== NULL
) {
726 // Release all the resourses occupied by the BIOS_VIDEO_DEV
730 // Free VGA Frame Buffer
732 if (BiosVideoPrivate
->VgaFrameBuffer
!= NULL
) {
733 gBS
->FreePool (BiosVideoPrivate
->VgaFrameBuffer
);
736 // Free VBE Frame Buffer
738 if (BiosVideoPrivate
->VbeFrameBuffer
!= NULL
) {
739 gBS
->FreePool (BiosVideoPrivate
->VbeFrameBuffer
);
744 if (BiosVideoPrivate
->LineBuffer
!= NULL
) {
745 gBS
->FreePool (BiosVideoPrivate
->LineBuffer
);
750 if (BiosVideoPrivate
->ModeData
!= NULL
) {
751 gBS
->FreePool (BiosVideoPrivate
->ModeData
);
754 // Free memory allocated below 1MB
756 if (BiosVideoPrivate
->PagesBelow1MB
!= 0) {
757 gBS
->FreePages (BiosVideoPrivate
->PagesBelow1MB
, BiosVideoPrivate
->NumberOfPagesBelow1MB
);
760 if (BiosVideoPrivate
->VbeSaveRestorePages
!= 0) {
761 gBS
->FreePages (BiosVideoPrivate
->VbeSaveRestoreBuffer
, BiosVideoPrivate
->VbeSaveRestorePages
);
764 // Free graphics output protocol occupied resource
766 if (BiosVideoPrivate
->GraphicsOutput
.Mode
!= NULL
) {
767 if (BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
!= NULL
) {
768 gBS
->FreePool (BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
);
770 gBS
->FreePool (BiosVideoPrivate
->GraphicsOutput
.Mode
);
773 // Free EDID discovered protocol occupied resource
775 if (BiosVideoPrivate
->EdidDiscovered
.Edid
!= NULL
) {
776 gBS
->FreePool (BiosVideoPrivate
->EdidDiscovered
.Edid
);
779 // Free EDID active protocol occupied resource
781 if (BiosVideoPrivate
->EdidActive
.Edid
!= NULL
) {
782 gBS
->FreePool (BiosVideoPrivate
->EdidActive
.Edid
);
785 if (BiosVideoPrivate
->DevicePath
!= NULL
) {
786 gBS
->FreePool (BiosVideoPrivate
->DevicePath
);
789 gBS
->FreePool (BiosVideoPrivate
);
796 Generate a search key for a specified timing data.
799 @param EdidTiming - Pointer to EDID timing
801 @return The 32 bit unique key for search.
807 VESA_BIOS_EXTENSIONS_EDID_TIMING
*EdidTiming
813 // Be sure no conflicts for all standard timing defined by VESA.
815 Key
= (EdidTiming
->HorizontalResolution
* 2) + EdidTiming
->VerticalResolution
;
821 Parse the Established Timing and Standard Timing in EDID data block.
824 @param EdidBuffer - Pointer to EDID data block
825 @param ValidEdidTiming - Valid EDID timing information
827 @return TRUE - The EDID data is valid.
828 FALSE - The EDID data is invalid.
835 VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING
*ValidEdidTiming
843 UINT16 HorizontalResolution
;
844 UINT16 VerticalResolution
;
847 VESA_BIOS_EXTENSIONS_EDID_TIMING TempTiming
;
848 VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK
*EdidDataBlock
;
850 EdidDataBlock
= (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK
*) EdidBuffer
;
853 // Check the checksum of EDID data
856 for (Index
= 0; Index
< VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE
; Index
++) {
857 CheckSum
= (UINT8
)(CheckSum
+ EdidBuffer
[Index
]);
864 gBS
->SetMem (ValidEdidTiming
, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING
), 0);
866 if ((EdidDataBlock
->EstablishedTimings
[0] != 0) ||
867 (EdidDataBlock
->EstablishedTimings
[1] != 0) ||
868 (EdidDataBlock
->EstablishedTimings
[2] != 0)
871 // Established timing data
873 TimingBits
= EdidDataBlock
->EstablishedTimings
[0] |
874 (EdidDataBlock
->EstablishedTimings
[1] << 8) |
875 ((EdidDataBlock
->EstablishedTimings
[2] & 0x80) << 9) ;
876 for (Index
= 0; Index
< VESA_BIOS_EXTENSIONS_EDID_ESTABLISHED_TIMING_MAX_NUMBER
; Index
++) {
877 if (TimingBits
& 0x1) {
878 ValidEdidTiming
->Key
[ValidNumber
] = CalculateEdidKey (&mEstablishedEdidTiming
[Index
]);
881 TimingBits
= TimingBits
>> 1;
885 // If no Established timing data, read the standard timing data
887 BufferIndex
= &EdidDataBlock
->StandardTimingIdentification
[0];
888 for (Index
= 0; Index
< 8; Index
++) {
889 if ((BufferIndex
[0] != 0x1) && (BufferIndex
[1] != 0x1)){
891 // A valid Standard Timing
893 HorizontalResolution
= (UINT8
) (BufferIndex
[0] * 8 + 248);
894 AspectRatio
= (UINT8
) (BufferIndex
[1] >> 6);
895 switch (AspectRatio
) {
897 VerticalResolution
= (UINT8
) (HorizontalResolution
/ 16 * 10);
900 VerticalResolution
= (UINT8
) (HorizontalResolution
/ 4 * 3);
903 VerticalResolution
= (UINT8
) (HorizontalResolution
/ 5 * 4);
906 VerticalResolution
= (UINT8
) (HorizontalResolution
/ 16 * 9);
909 VerticalResolution
= (UINT8
) (HorizontalResolution
/ 4 * 3);
912 RefreshRate
= (UINT8
) ((BufferIndex
[1] & 0x1f) + 60);
913 TempTiming
.HorizontalResolution
= HorizontalResolution
;
914 TempTiming
.VerticalResolution
= VerticalResolution
;
915 TempTiming
.RefreshRate
= RefreshRate
;
916 ValidEdidTiming
->Key
[ValidNumber
] = CalculateEdidKey (&TempTiming
);
923 ValidEdidTiming
->ValidNumber
= ValidNumber
;
929 Search a specified Timing in all the valid EDID timings.
932 @param ValidEdidTiming - All valid EDID timing information.
933 @param EdidTiming - The Timing to search for.
935 @return TRUE - Found.
942 VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING
*ValidEdidTiming
,
943 VESA_BIOS_EXTENSIONS_EDID_TIMING
*EdidTiming
949 Key
= CalculateEdidKey (EdidTiming
);
951 for (Index
= 0; Index
< ValidEdidTiming
->ValidNumber
; Index
++) {
952 if (Key
== ValidEdidTiming
->Key
[Index
]) {
960 #define PCI_DEVICE_ENABLED (EFI_PCI_COMMAND_IO_SPACE | EFI_PCI_COMMAND_MEMORY_SPACE)
964 Judge whether this device is VGA device.
966 @param PciIo Parent PciIo protocol instance pointer
968 @retval TRUE Is vga device
969 @retval FALSE Is no vga device
973 IN EFI_PCI_IO_PROTOCOL
*PciIo
977 BOOLEAN VgaCompatible
;
980 VgaCompatible
= FALSE
;
983 // Read the PCI Configuration Header
985 Status
= PciIo
->Pci
.Read (
989 sizeof (Pci
) / sizeof (UINT32
),
992 if (EFI_ERROR (Status
)) {
993 return VgaCompatible
;
997 // See if this is a VGA compatible controller or not
999 if ((Pci
.Hdr
.Command
& PCI_DEVICE_ENABLED
) == PCI_DEVICE_ENABLED
) {
1000 if (Pci
.Hdr
.ClassCode
[2] == PCI_CLASS_OLD
&& Pci
.Hdr
.ClassCode
[1] == PCI_CLASS_OLD_VGA
) {
1002 // Base Class 0x00 Sub-Class 0x01 - Backward compatible VGA device
1004 VgaCompatible
= TRUE
;
1007 if (Pci
.Hdr
.ClassCode
[2] == PCI_CLASS_DISPLAY
&& Pci
.Hdr
.ClassCode
[1] == PCI_CLASS_DISPLAY_VGA
&& Pci
.Hdr
.ClassCode
[0] == 0x00) {
1009 // Base Class 3 Sub-Class 0 Programming interface 0 - VGA compatible Display controller
1011 VgaCompatible
= TRUE
;
1015 return VgaCompatible
;
1020 Check for VBE device
1022 @param BiosVideoPrivate - Pointer to BIOS_VIDEO_DEV structure
1024 @retval EFI_SUCCESS VBE device found
1029 BiosVideoCheckForVbe (
1030 IN OUT BIOS_VIDEO_DEV
*BiosVideoPrivate
1034 IA32_REGISTER_SET Regs
;
1035 UINT16
*ModeNumberPtr
;
1038 BIOS_VIDEO_MODE_DATA
*ModeBuffer
;
1039 BIOS_VIDEO_MODE_DATA
*CurrentModeData
;
1042 VESA_BIOS_EXTENSIONS_EDID_TIMING Timing
;
1043 VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING ValidEdidTiming
;
1044 EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE
*GraphicsOutputMode
;
1047 // Allocate buffer under 1MB for VBE data structures
1049 BiosVideoPrivate
->NumberOfPagesBelow1MB
= EFI_SIZE_TO_PAGES (
1050 sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK
) +
1051 sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK
) +
1052 sizeof (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK
) +
1053 sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK
)
1056 BiosVideoPrivate
->PagesBelow1MB
= 0x00100000 - 1;
1058 Status
= gBS
->AllocatePages (
1060 EfiBootServicesData
,
1061 BiosVideoPrivate
->NumberOfPagesBelow1MB
,
1062 &BiosVideoPrivate
->PagesBelow1MB
1064 if (EFI_ERROR (Status
)) {
1068 ZeroMem (&ValidEdidTiming
, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING
));
1071 // Fill in the Graphics Output Protocol
1073 BiosVideoPrivate
->GraphicsOutput
.QueryMode
= BiosVideoGraphicsOutputQueryMode
;
1074 BiosVideoPrivate
->GraphicsOutput
.SetMode
= BiosVideoGraphicsOutputSetMode
;
1075 BiosVideoPrivate
->GraphicsOutput
.Blt
= BiosVideoGraphicsOutputVbeBlt
;
1076 BiosVideoPrivate
->GraphicsOutput
.Mode
= NULL
;
1079 // Fill in the VBE related data structures
1081 BiosVideoPrivate
->VbeInformationBlock
= (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK
*) (UINTN
) (BiosVideoPrivate
->PagesBelow1MB
);
1082 BiosVideoPrivate
->VbeModeInformationBlock
= (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK
*) (BiosVideoPrivate
->VbeInformationBlock
+ 1);
1083 BiosVideoPrivate
->VbeEdidDataBlock
= (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK
*) (BiosVideoPrivate
->VbeModeInformationBlock
+ 1);
1084 BiosVideoPrivate
->VbeCrtcInformationBlock
= (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK
*) (BiosVideoPrivate
->VbeEdidDataBlock
+ 1);
1085 BiosVideoPrivate
->VbeSaveRestorePages
= 0;
1086 BiosVideoPrivate
->VbeSaveRestoreBuffer
= 0;
1089 // Test to see if the Video Adapter is compliant with VBE 3.0
1091 gBS
->SetMem (&Regs
, sizeof (Regs
), 0);
1092 Regs
.X
.AX
= VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION
;
1093 gBS
->SetMem (BiosVideoPrivate
->VbeInformationBlock
, sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK
), 0);
1094 BiosVideoPrivate
->VbeInformationBlock
->VESASignature
= VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE
;
1095 Regs
.E
.ES
= EFI_SEGMENT ((UINTN
) BiosVideoPrivate
->VbeInformationBlock
);
1096 Regs
.X
.DI
= EFI_OFFSET ((UINTN
) BiosVideoPrivate
->VbeInformationBlock
);
1098 LegacyBiosInt86 (BiosVideoPrivate
, 0x10, &Regs
);
1100 Status
= EFI_DEVICE_ERROR
;
1103 // See if the VESA call succeeded
1105 if (Regs
.X
.AX
!= VESA_BIOS_EXTENSIONS_STATUS_SUCCESS
) {
1109 // Check for 'VESA' signature
1111 if (BiosVideoPrivate
->VbeInformationBlock
->VESASignature
!= VESA_BIOS_EXTENSIONS_VESA_SIGNATURE
) {
1115 // Check to see if this is VBE 2.0 or higher
1117 if (BiosVideoPrivate
->VbeInformationBlock
->VESAVersion
< VESA_BIOS_EXTENSIONS_VERSION_2_0
) {
1122 // Read EDID information
1124 gBS
->SetMem (&Regs
, sizeof (Regs
), 0);
1125 Regs
.X
.AX
= VESA_BIOS_EXTENSIONS_EDID
;
1129 Regs
.E
.ES
= EFI_SEGMENT ((UINTN
) BiosVideoPrivate
->VbeEdidDataBlock
);
1130 Regs
.X
.DI
= EFI_OFFSET ((UINTN
) BiosVideoPrivate
->VbeEdidDataBlock
);
1132 LegacyBiosInt86 (BiosVideoPrivate
, 0x10, &Regs
);
1135 // See if the VESA call succeeded
1138 if (Regs
.X
.AX
== VESA_BIOS_EXTENSIONS_STATUS_SUCCESS
) {
1140 // Parse EDID data structure to retrieve modes supported by monitor
1142 if (ParseEdidData ((UINT8
*) BiosVideoPrivate
->VbeEdidDataBlock
, &ValidEdidTiming
) == TRUE
) {
1145 BiosVideoPrivate
->EdidDiscovered
.SizeOfEdid
= VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE
;
1146 Status
= gBS
->AllocatePool (
1147 EfiBootServicesData
,
1148 VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE
,
1149 (VOID
**) &BiosVideoPrivate
->EdidDiscovered
.Edid
1151 if (EFI_ERROR (Status
)) {
1155 BiosVideoPrivate
->EdidDiscovered
.Edid
,
1156 BiosVideoPrivate
->VbeEdidDataBlock
,
1157 VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE
1160 BiosVideoPrivate
->EdidActive
.SizeOfEdid
= VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE
;
1161 Status
= gBS
->AllocatePool (
1162 EfiBootServicesData
,
1163 VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE
,
1164 (VOID
**)&BiosVideoPrivate
->EdidActive
.Edid
1166 if (EFI_ERROR (Status
)) {
1170 BiosVideoPrivate
->EdidActive
.Edid
,
1171 BiosVideoPrivate
->VbeEdidDataBlock
,
1172 VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE
1175 BiosVideoPrivate
->EdidDiscovered
.SizeOfEdid
= 0;
1176 BiosVideoPrivate
->EdidDiscovered
.Edid
= NULL
;
1178 BiosVideoPrivate
->EdidActive
.SizeOfEdid
= 0;
1179 BiosVideoPrivate
->EdidActive
.Edid
= NULL
;
1184 // Walk through the mode list to see if there is at least one mode the is compatible with the EDID mode
1186 ModeNumberPtr
= (UINT16
*)
1188 (((UINTN
) BiosVideoPrivate
->VbeInformationBlock
->VideoModePtr
& 0xffff0000) >> 12) |
1189 ((UINTN
) BiosVideoPrivate
->VbeInformationBlock
->VideoModePtr
& 0x0000ffff)
1195 for (; *ModeNumberPtr
!= VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST
; ModeNumberPtr
++) {
1197 // Make sure this is a mode number defined by the VESA VBE specification. If it isn'tm then skip this mode number.
1199 if ((*ModeNumberPtr
& VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA
) == 0) {
1203 // Get the information about the mode
1205 gBS
->SetMem (&Regs
, sizeof (Regs
), 0);
1206 Regs
.X
.AX
= VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION
;
1207 Regs
.X
.CX
= *ModeNumberPtr
;
1208 gBS
->SetMem (BiosVideoPrivate
->VbeModeInformationBlock
, sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK
), 0);
1209 Regs
.E
.ES
= EFI_SEGMENT ((UINTN
) BiosVideoPrivate
->VbeModeInformationBlock
);
1210 Regs
.X
.DI
= EFI_OFFSET ((UINTN
) BiosVideoPrivate
->VbeModeInformationBlock
);
1212 LegacyBiosInt86 (BiosVideoPrivate
, 0x10, &Regs
);
1215 // See if the call succeeded. If it didn't, then try the next mode.
1217 if (Regs
.X
.AX
!= VESA_BIOS_EXTENSIONS_STATUS_SUCCESS
) {
1221 // See if the mode supports color. If it doesn't then try the next mode.
1223 if ((BiosVideoPrivate
->VbeModeInformationBlock
->ModeAttributes
& VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR
) == 0) {
1227 // See if the mode supports graphics. If it doesn't then try the next mode.
1229 if ((BiosVideoPrivate
->VbeModeInformationBlock
->ModeAttributes
& VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS
) == 0) {
1233 // See if the mode supports a linear frame buffer. If it doesn't then try the next mode.
1235 if ((BiosVideoPrivate
->VbeModeInformationBlock
->ModeAttributes
& VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER
) == 0) {
1239 // See if the mode supports 32 bit color. If it doesn't then try the next mode.
1240 // 32 bit mode can be implemented by 24 Bits Per Pixels. Also make sure the
1241 // number of bits per pixel is a multiple of 8 or more than 32 bits per pixel
1243 if (BiosVideoPrivate
->VbeModeInformationBlock
->BitsPerPixel
< 24) {
1247 if (BiosVideoPrivate
->VbeModeInformationBlock
->BitsPerPixel
> 32) {
1251 if ((BiosVideoPrivate
->VbeModeInformationBlock
->BitsPerPixel
% 8) != 0) {
1255 // See if the physical base pointer for the linear mode is valid. If it isn't then try the next mode.
1257 if (BiosVideoPrivate
->VbeModeInformationBlock
->PhysBasePtr
== 0) {
1261 if (EdidFound
&& (ValidEdidTiming
.ValidNumber
> 0)) {
1263 // EDID exist, check whether this mode match with any mode in EDID
1265 Timing
.HorizontalResolution
= BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
;
1266 Timing
.VerticalResolution
= BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
;
1267 if (SearchEdidTiming (&ValidEdidTiming
, &Timing
) == FALSE
) {
1273 // Select a reasonable mode to be set for current display mode
1277 if (BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
== 1024 &&
1278 BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
== 768
1282 if (BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
== 800 &&
1283 BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
== 600
1286 PreferMode
= ModeNumber
;
1288 if (BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
== 640 &&
1289 BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
== 480
1293 if ((!EdidFound
) && (!ModeFound
)) {
1295 // When no EDID exist, only select three possible resolutions, i.e. 1024x768, 800x600, 640x480
1301 // Add mode to the list of available modes
1304 Status
= gBS
->AllocatePool (
1305 EfiBootServicesData
,
1306 ModeNumber
* sizeof (BIOS_VIDEO_MODE_DATA
),
1307 (VOID
**) &ModeBuffer
1309 if (EFI_ERROR (Status
)) {
1313 if (ModeNumber
> 1) {
1316 BiosVideoPrivate
->ModeData
,
1317 (ModeNumber
- 1) * sizeof (BIOS_VIDEO_MODE_DATA
)
1321 if (BiosVideoPrivate
->ModeData
!= NULL
) {
1322 gBS
->FreePool (BiosVideoPrivate
->ModeData
);
1325 CurrentModeData
= &ModeBuffer
[ModeNumber
- 1];
1326 CurrentModeData
->VbeModeNumber
= *ModeNumberPtr
;
1327 if (BiosVideoPrivate
->VbeInformationBlock
->VESAVersion
>= VESA_BIOS_EXTENSIONS_VERSION_3_0
) {
1328 CurrentModeData
->BytesPerScanLine
= BiosVideoPrivate
->VbeModeInformationBlock
->LinBytesPerScanLine
;
1329 CurrentModeData
->Red
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->LinRedFieldPosition
;
1330 CurrentModeData
->Red
.Mask
= (UINT8
) ((1 << BiosVideoPrivate
->VbeModeInformationBlock
->LinRedMaskSize
) - 1);
1331 CurrentModeData
->Blue
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->LinBlueFieldPosition
;
1332 CurrentModeData
->Blue
.Mask
= (UINT8
) ((1 << BiosVideoPrivate
->VbeModeInformationBlock
->LinBlueMaskSize
) - 1);
1333 CurrentModeData
->Green
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->LinGreenFieldPosition
;
1334 CurrentModeData
->Green
.Mask
= (UINT8
) ((1 << BiosVideoPrivate
->VbeModeInformationBlock
->LinGreenMaskSize
) - 1);
1335 CurrentModeData
->Reserved
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->LinRsvdFieldPosition
;
1336 CurrentModeData
->Reserved
.Mask
= (UINT8
) ((1 << BiosVideoPrivate
->VbeModeInformationBlock
->LinRsvdMaskSize
) - 1);
1338 CurrentModeData
->BytesPerScanLine
= BiosVideoPrivate
->VbeModeInformationBlock
->BytesPerScanLine
;
1339 CurrentModeData
->Red
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->RedFieldPosition
;
1340 CurrentModeData
->Red
.Mask
= (UINT8
) ((1 << BiosVideoPrivate
->VbeModeInformationBlock
->RedMaskSize
) - 1);
1341 CurrentModeData
->Blue
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->BlueFieldPosition
;
1342 CurrentModeData
->Blue
.Mask
= (UINT8
) ((1 << BiosVideoPrivate
->VbeModeInformationBlock
->BlueMaskSize
) - 1);
1343 CurrentModeData
->Green
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->GreenFieldPosition
;
1344 CurrentModeData
->Green
.Mask
= (UINT8
) ((1 << BiosVideoPrivate
->VbeModeInformationBlock
->GreenMaskSize
) - 1);
1345 CurrentModeData
->Reserved
.Position
= BiosVideoPrivate
->VbeModeInformationBlock
->RsvdFieldPosition
;
1346 CurrentModeData
->Reserved
.Mask
= (UINT8
) ((1 << BiosVideoPrivate
->VbeModeInformationBlock
->RsvdMaskSize
) - 1);
1348 CurrentModeData
->PixelFormat
= PixelBitMask
;
1349 if ((BiosVideoPrivate
->VbeModeInformationBlock
->BitsPerPixel
== 32) &&
1350 (CurrentModeData
->Red
.Mask
== 0xff) && (CurrentModeData
->Green
.Mask
== 0xff) && (CurrentModeData
->Blue
.Mask
== 0xff)) {
1351 if ((CurrentModeData
->Red
.Position
== 0) && (CurrentModeData
->Green
.Position
== 8) && (CurrentModeData
->Blue
.Position
== 16)) {
1352 CurrentModeData
->PixelFormat
= PixelRedGreenBlueReserved8BitPerColor
;
1353 } else if ((CurrentModeData
->Blue
.Position
== 0) && (CurrentModeData
->Green
.Position
== 8) && (CurrentModeData
->Red
.Position
== 16)) {
1354 CurrentModeData
->PixelFormat
= PixelBlueGreenRedReserved8BitPerColor
;
1357 CurrentModeData
->PixelBitMask
.RedMask
= ((UINT32
) CurrentModeData
->Red
.Mask
) << CurrentModeData
->Red
.Position
;
1358 CurrentModeData
->PixelBitMask
.GreenMask
= ((UINT32
) CurrentModeData
->Green
.Mask
) << CurrentModeData
->Green
.Position
;
1359 CurrentModeData
->PixelBitMask
.BlueMask
= ((UINT32
) CurrentModeData
->Blue
.Mask
) << CurrentModeData
->Blue
.Position
;
1360 CurrentModeData
->PixelBitMask
.ReservedMask
= ((UINT32
) CurrentModeData
->Reserved
.Mask
) << CurrentModeData
->Reserved
.Position
;
1362 CurrentModeData
->LinearFrameBuffer
= (VOID
*) (UINTN
)BiosVideoPrivate
->VbeModeInformationBlock
->PhysBasePtr
;
1363 CurrentModeData
->FrameBufferSize
= BiosVideoPrivate
->VbeInformationBlock
->TotalMemory
* 64 * 1024;
1364 CurrentModeData
->HorizontalResolution
= BiosVideoPrivate
->VbeModeInformationBlock
->XResolution
;
1365 CurrentModeData
->VerticalResolution
= BiosVideoPrivate
->VbeModeInformationBlock
->YResolution
;
1367 CurrentModeData
->BitsPerPixel
= BiosVideoPrivate
->VbeModeInformationBlock
->BitsPerPixel
;
1369 BiosVideoPrivate
->ModeData
= ModeBuffer
;
1372 // Check to see if we found any modes that are compatible with GRAPHICS OUTPUT
1374 if (ModeNumber
== 0) {
1375 Status
= EFI_DEVICE_ERROR
;
1380 // Allocate buffer for Graphics Output Protocol mode information
1382 Status
= gBS
->AllocatePool (
1383 EfiBootServicesData
,
1384 sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE
),
1385 (VOID
**) &BiosVideoPrivate
->GraphicsOutput
.Mode
1387 if (EFI_ERROR (Status
)) {
1390 GraphicsOutputMode
= BiosVideoPrivate
->GraphicsOutput
.Mode
;
1391 Status
= gBS
->AllocatePool (
1392 EfiBootServicesData
,
1393 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
),
1394 (VOID
**) &GraphicsOutputMode
->Info
1396 if (EFI_ERROR (Status
)) {
1400 GraphicsOutputMode
->MaxMode
= (UINT32
) ModeNumber
;
1402 // Current mode is unknow till now, set it to an invalid mode.
1404 GraphicsOutputMode
->Mode
= GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER
;
1407 // Find the best mode to initialize
1409 Status
= BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate
->GraphicsOutput
, (UINT32
) PreferMode
);
1410 if (EFI_ERROR (Status
)) {
1411 for (PreferMode
= 0; PreferMode
< ModeNumber
; PreferMode
++) {
1412 Status
= BiosVideoGraphicsOutputSetMode (
1413 &BiosVideoPrivate
->GraphicsOutput
,
1416 if (!EFI_ERROR (Status
)) {
1420 if (PreferMode
== ModeNumber
) {
1422 // None mode is set successfully.
1430 // If there was an error, then free the mode structure
1432 if (EFI_ERROR (Status
)) {
1433 if (BiosVideoPrivate
->ModeData
!= NULL
) {
1434 gBS
->FreePool (BiosVideoPrivate
->ModeData
);
1436 if (BiosVideoPrivate
->GraphicsOutput
.Mode
!= NULL
) {
1437 if (BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
!= NULL
) {
1438 gBS
->FreePool (BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
);
1440 gBS
->FreePool (BiosVideoPrivate
->GraphicsOutput
.Mode
);
1448 Check for VGA device
1450 @param BiosVideoPrivate - Pointer to BIOS_VIDEO_DEV structure
1452 @retval EFI_SUCCESS Standard VGA device found
1456 BiosVideoCheckForVga (
1457 IN OUT BIOS_VIDEO_DEV
*BiosVideoPrivate
1461 BIOS_VIDEO_MODE_DATA
*ModeBuffer
;
1464 // Fill in the Graphics Output Protocol
1466 BiosVideoPrivate
->GraphicsOutput
.QueryMode
= BiosVideoGraphicsOutputQueryMode
;
1467 BiosVideoPrivate
->GraphicsOutput
.SetMode
= BiosVideoGraphicsOutputSetMode
;
1468 BiosVideoPrivate
->GraphicsOutput
.Blt
= BiosVideoGraphicsOutputVgaBlt
;
1471 // Allocate buffer for Graphics Output Protocol mode information
1473 Status
= gBS
->AllocatePool (
1474 EfiBootServicesData
,
1475 sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE
),
1476 (VOID
**) &BiosVideoPrivate
->GraphicsOutput
.Mode
1478 if (EFI_ERROR (Status
)) {
1481 Status
= gBS
->AllocatePool (
1482 EfiBootServicesData
,
1483 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
),
1484 (VOID
**) &BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
1486 if (EFI_ERROR (Status
)) {
1491 // Add mode to the list of available modes
1493 BiosVideoPrivate
->GraphicsOutput
.Mode
->MaxMode
= 1;
1495 Status
= gBS
->AllocatePool (
1496 EfiBootServicesData
,
1497 sizeof (BIOS_VIDEO_MODE_DATA
),
1498 (VOID
**) &ModeBuffer
1500 if (EFI_ERROR (Status
)) {
1504 ModeBuffer
->VbeModeNumber
= 0x0012;
1505 ModeBuffer
->BytesPerScanLine
= 640;
1506 ModeBuffer
->LinearFrameBuffer
= (VOID
*) (UINTN
) (0xa0000);
1507 ModeBuffer
->FrameBufferSize
= 0;
1508 ModeBuffer
->HorizontalResolution
= 640;
1509 ModeBuffer
->VerticalResolution
= 480;
1510 ModeBuffer
->BitsPerPixel
= 8;
1511 ModeBuffer
->PixelFormat
= PixelBltOnly
;
1513 BiosVideoPrivate
->ModeData
= ModeBuffer
;
1516 // Test to see if the Video Adapter support the 640x480 16 color mode
1518 BiosVideoPrivate
->GraphicsOutput
.Mode
->Mode
= GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER
;
1519 Status
= BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate
->GraphicsOutput
, 0);
1523 // If there was an error, then free the mode structure
1525 if (EFI_ERROR (Status
)) {
1526 if (BiosVideoPrivate
->ModeData
!= NULL
) {
1527 gBS
->FreePool (BiosVideoPrivate
->ModeData
);
1529 if (BiosVideoPrivate
->GraphicsOutput
.Mode
!= NULL
) {
1530 if (BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
!= NULL
) {
1531 gBS
->FreePool (BiosVideoPrivate
->GraphicsOutput
.Mode
->Info
);
1533 gBS
->FreePool (BiosVideoPrivate
->GraphicsOutput
.Mode
);
1539 // Graphics Output Protocol Member Functions for VESA BIOS Extensions
1543 Graphics Output protocol interface to get video mode
1546 @param This - Protocol instance pointer.
1547 @param ModeNumber - The mode number to return information on.
1548 @param SizeOfInfo - A pointer to the size, in bytes, of the Info buffer.
1549 @param Info - Caller allocated buffer that returns information about ModeNumber.
1551 @return EFI_SUCCESS - Mode information returned.
1552 EFI_DEVICE_ERROR - A hardware error occurred trying to retrieve the video mode.
1553 EFI_NOT_STARTED - Video display is not initialized. Call SetMode ()
1554 EFI_INVALID_PARAMETER - One of the input args was NULL.
1559 BiosVideoGraphicsOutputQueryMode (
1560 IN EFI_GRAPHICS_OUTPUT_PROTOCOL
*This
,
1561 IN UINT32 ModeNumber
,
1562 OUT UINTN
*SizeOfInfo
,
1563 OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
**Info
1566 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
1568 BIOS_VIDEO_MODE_DATA
*ModeData
;
1570 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This
);
1572 if (BiosVideoPrivate
->HardwareNeedsStarting
) {
1573 return EFI_NOT_STARTED
;
1576 if (This
== NULL
|| Info
== NULL
|| SizeOfInfo
== NULL
|| ModeNumber
>= This
->Mode
->MaxMode
) {
1577 return EFI_INVALID_PARAMETER
;
1580 Status
= gBS
->AllocatePool (
1581 EfiBootServicesData
,
1582 sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
),
1585 if (EFI_ERROR (Status
)) {
1589 *SizeOfInfo
= sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
);
1591 ModeData
= &BiosVideoPrivate
->ModeData
[ModeNumber
];
1592 (*Info
)->Version
= 0;
1593 (*Info
)->HorizontalResolution
= ModeData
->HorizontalResolution
;
1594 (*Info
)->VerticalResolution
= ModeData
->VerticalResolution
;
1595 (*Info
)->PixelFormat
= ModeData
->PixelFormat
;
1596 (*Info
)->PixelInformation
= ModeData
->PixelBitMask
;
1598 (*Info
)->PixelsPerScanLine
= (ModeData
->BytesPerScanLine
* 8) / ModeData
->BitsPerPixel
;
1605 Graphics Output protocol interface to set video mode
1608 @param This - Protocol instance pointer.
1609 @param ModeNumber - The mode number to be set.
1611 @return EFI_SUCCESS - Graphics mode was changed.
1612 EFI_DEVICE_ERROR - The device had an error and could not complete the request.
1613 EFI_UNSUPPORTED - ModeNumber is not supported by this device.
1618 BiosVideoGraphicsOutputSetMode (
1619 IN EFI_GRAPHICS_OUTPUT_PROTOCOL
* This
,
1620 IN UINT32 ModeNumber
1624 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
1625 IA32_REGISTER_SET Regs
;
1626 BIOS_VIDEO_MODE_DATA
*ModeData
;
1628 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This
);
1631 return EFI_INVALID_PARAMETER
;
1634 if (ModeNumber
>= This
->Mode
->MaxMode
) {
1635 return EFI_UNSUPPORTED
;
1638 if (ModeNumber
== This
->Mode
->Mode
) {
1642 ModeData
= &BiosVideoPrivate
->ModeData
[ModeNumber
];
1644 if (BiosVideoPrivate
->LineBuffer
) {
1645 gBS
->FreePool (BiosVideoPrivate
->LineBuffer
);
1648 if (BiosVideoPrivate
->VgaFrameBuffer
) {
1649 gBS
->FreePool (BiosVideoPrivate
->VgaFrameBuffer
);
1652 if (BiosVideoPrivate
->VbeFrameBuffer
) {
1653 gBS
->FreePool (BiosVideoPrivate
->VbeFrameBuffer
);
1656 BiosVideoPrivate
->LineBuffer
= NULL
;
1657 Status
= gBS
->AllocatePool (
1658 EfiBootServicesData
,
1659 ModeData
->BytesPerScanLine
,
1660 (VOID
**) &BiosVideoPrivate
->LineBuffer
1662 if (EFI_ERROR (Status
)) {
1666 // Clear all registers
1668 gBS
->SetMem (&Regs
, sizeof (Regs
), 0);
1670 if (ModeData
->VbeModeNumber
< 0x100) {
1672 // Allocate a working buffer for BLT operations to the VGA frame buffer
1674 BiosVideoPrivate
->VgaFrameBuffer
= NULL
;
1675 Status
= gBS
->AllocatePool (
1676 EfiBootServicesData
,
1678 (VOID
**) &BiosVideoPrivate
->VgaFrameBuffer
1680 if (EFI_ERROR (Status
)) {
1686 Regs
.X
.AX
= ModeData
->VbeModeNumber
;
1687 LegacyBiosInt86 (BiosVideoPrivate
, 0x10, &Regs
);
1691 // Allocate a working buffer for BLT operations to the VBE frame buffer
1693 BiosVideoPrivate
->VbeFrameBuffer
= NULL
;
1694 Status
= gBS
->AllocatePool (
1695 EfiBootServicesData
,
1696 ModeData
->BytesPerScanLine
* ModeData
->VerticalResolution
,
1697 (VOID
**) &BiosVideoPrivate
->VbeFrameBuffer
1699 if (EFI_ERROR (Status
)) {
1705 Regs
.X
.AX
= VESA_BIOS_EXTENSIONS_SET_MODE
;
1706 Regs
.X
.BX
= (UINT16
) (ModeData
->VbeModeNumber
| VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER
);
1707 gBS
->SetMem (BiosVideoPrivate
->VbeCrtcInformationBlock
, sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK
), 0);
1708 Regs
.E
.ES
= EFI_SEGMENT ((UINTN
) BiosVideoPrivate
->VbeCrtcInformationBlock
);
1709 Regs
.X
.DI
= EFI_OFFSET ((UINTN
) BiosVideoPrivate
->VbeCrtcInformationBlock
);
1711 LegacyBiosInt86 (BiosVideoPrivate
, 0x10, &Regs
);
1714 // Check to see if the call succeeded
1716 if (Regs
.X
.AX
!= VESA_BIOS_EXTENSIONS_STATUS_SUCCESS
) {
1717 return EFI_DEVICE_ERROR
;
1720 // Initialize the state of the VbeFrameBuffer
1722 Status
= BiosVideoPrivate
->PciIo
->Mem
.Read (
1723 BiosVideoPrivate
->PciIo
,
1724 EfiPciIoWidthUint32
,
1725 EFI_PCI_IO_PASS_THROUGH_BAR
,
1726 (UINT64
) (UINTN
) ModeData
->LinearFrameBuffer
,
1727 (ModeData
->BytesPerScanLine
* ModeData
->VerticalResolution
) >> 2,
1728 BiosVideoPrivate
->VbeFrameBuffer
1730 if (EFI_ERROR (Status
)) {
1735 This
->Mode
->Mode
= ModeNumber
;
1736 This
->Mode
->Info
->Version
= 0;
1737 This
->Mode
->Info
->HorizontalResolution
= ModeData
->HorizontalResolution
;
1738 This
->Mode
->Info
->VerticalResolution
= ModeData
->VerticalResolution
;
1739 This
->Mode
->Info
->PixelFormat
= ModeData
->PixelFormat
;
1740 This
->Mode
->Info
->PixelInformation
= ModeData
->PixelBitMask
;
1741 This
->Mode
->Info
->PixelsPerScanLine
= (ModeData
->BytesPerScanLine
* 8) / ModeData
->BitsPerPixel
;
1742 This
->Mode
->SizeOfInfo
= sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
);
1745 // Frame BufferSize remain unchanged
1747 This
->Mode
->FrameBufferBase
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)ModeData
->LinearFrameBuffer
;
1748 This
->Mode
->FrameBufferSize
= ModeData
->FrameBufferSize
;
1750 BiosVideoPrivate
->HardwareNeedsStarting
= FALSE
;
1757 Update physical frame buffer, copy 4 bytes block, then copy remaining bytes.
1760 @param PciIo - The pointer of EFI_PCI_IO_PROTOCOL
1761 @param VbeBuffer - The data to transfer to screen
1762 @param MemAddress - Physical frame buffer base address
1763 @param DestinationX - The X coordinate of the destination for BltOperation
1764 @param DestinationY - The Y coordinate of the destination for BltOperation
1765 @param TotalBytes - The total bytes of copy
1766 @param VbePixelWidth - Bytes per pixel
1767 @param BytesPerScanLine - Bytes per scan line
1774 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
1775 IN UINT8
*VbeBuffer
,
1776 IN VOID
*MemAddress
,
1777 IN UINTN DestinationX
,
1778 IN UINTN DestinationY
,
1779 IN UINTN TotalBytes
,
1780 IN UINT32 VbePixelWidth
,
1781 IN UINTN BytesPerScanLine
1784 UINTN FrameBufferAddr
;
1786 UINTN RemainingBytes
;
1787 UINTN UnalignedBytes
;
1790 FrameBufferAddr
= (UINTN
) MemAddress
+ (DestinationY
* BytesPerScanLine
) + DestinationX
* VbePixelWidth
;
1793 // If TotalBytes is less than 4 bytes, only start byte copy.
1795 if (TotalBytes
< 4) {
1796 Status
= PciIo
->Mem
.Write (
1799 EFI_PCI_IO_PASS_THROUGH_BAR
,
1800 (UINT64
) FrameBufferAddr
,
1804 ASSERT_EFI_ERROR (Status
);
1809 // If VbeBuffer is not 4-byte aligned, start byte copy.
1811 UnalignedBytes
= (4 - ((UINTN
) VbeBuffer
& 0x3)) & 0x3;
1813 if (UnalignedBytes
!= 0) {
1814 Status
= PciIo
->Mem
.Write (
1817 EFI_PCI_IO_PASS_THROUGH_BAR
,
1818 (UINT64
) FrameBufferAddr
,
1822 ASSERT_EFI_ERROR (Status
);
1823 FrameBufferAddr
+= UnalignedBytes
;
1824 VbeBuffer
+= UnalignedBytes
;
1828 // Calculate 4-byte block count and remaining bytes.
1830 CopyBlockNum
= (TotalBytes
- UnalignedBytes
) >> 2;
1831 RemainingBytes
= (TotalBytes
- UnalignedBytes
) & 3;
1834 // Copy 4-byte block and remaining bytes to physical frame buffer.
1836 if (CopyBlockNum
!= 0) {
1837 Status
= PciIo
->Mem
.Write (
1839 EfiPciIoWidthUint32
,
1840 EFI_PCI_IO_PASS_THROUGH_BAR
,
1841 (UINT64
) FrameBufferAddr
,
1845 ASSERT_EFI_ERROR (Status
);
1848 if (RemainingBytes
!= 0) {
1849 FrameBufferAddr
+= (CopyBlockNum
<< 2);
1850 VbeBuffer
+= (CopyBlockNum
<< 2);
1851 Status
= PciIo
->Mem
.Write (
1854 EFI_PCI_IO_PASS_THROUGH_BAR
,
1855 (UINT64
) FrameBufferAddr
,
1859 ASSERT_EFI_ERROR (Status
);
1864 // BUGBUG : Add Blt for 16 bit color, 15 bit color, and 8 bit color modes
1868 Graphics Output protocol instance to block transfer for VBE device
1871 @param This - Pointer to Graphics Output protocol instance
1872 @param BltBuffer - The data to transfer to screen
1873 @param BltOperation - The operation to perform
1874 @param SourceX - The X coordinate of the source for BltOperation
1875 @param SourceY - The Y coordinate of the source for BltOperation
1876 @param DestinationX - The X coordinate of the destination for BltOperation
1877 @param DestinationY - The Y coordinate of the destination for BltOperation
1878 @param Width - The width of a rectangle in the blt rectangle in pixels
1879 @param Height - The height of a rectangle in the blt rectangle in pixels
1880 @param Delta - Not used for EfiBltVideoFill and EfiBltVideoToVideo operation.
1881 If a Delta of 0 is used, the entire BltBuffer will be operated on.
1882 If a subrectangle of the BltBuffer is used, then Delta represents
1883 the number of bytes in a row of the BltBuffer.
1885 @return EFI_INVALID_PARAMETER - Invalid parameter passed in
1886 EFI_SUCCESS - Blt operation success
1891 BiosVideoGraphicsOutputVbeBlt (
1892 IN EFI_GRAPHICS_OUTPUT_PROTOCOL
*This
,
1893 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*BltBuffer
, OPTIONAL
1894 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation
,
1897 IN UINTN DestinationX
,
1898 IN UINTN DestinationY
,
1904 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
1905 BIOS_VIDEO_MODE_DATA
*Mode
;
1906 EFI_PCI_IO_PROTOCOL
*PciIo
;
1907 EFI_TPL OriginalTPL
;
1911 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*Blt
;
1913 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*VbeFrameBuffer
;
1914 UINTN BytesPerScanLine
;
1919 UINT32 VbePixelWidth
;
1923 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This
);
1924 Mode
= &BiosVideoPrivate
->ModeData
[This
->Mode
->Mode
];
1925 PciIo
= BiosVideoPrivate
->PciIo
;
1927 VbeFrameBuffer
= BiosVideoPrivate
->VbeFrameBuffer
;
1928 MemAddress
= Mode
->LinearFrameBuffer
;
1929 BytesPerScanLine
= Mode
->BytesPerScanLine
;
1930 VbePixelWidth
= Mode
->BitsPerPixel
/ 8;
1931 BltUint8
= (UINT8
*) BltBuffer
;
1932 TotalBytes
= Width
* VbePixelWidth
;
1934 if (This
== NULL
|| ((UINTN
) BltOperation
) >= EfiGraphicsOutputBltOperationMax
) {
1935 return EFI_INVALID_PARAMETER
;
1938 if (Width
== 0 || Height
== 0) {
1939 return EFI_INVALID_PARAMETER
;
1942 // We need to fill the Virtual Screen buffer with the blt data.
1943 // The virtual screen is upside down, as the first row is the bootom row of
1946 if (BltOperation
== EfiBltVideoToBltBuffer
) {
1948 // Video to BltBuffer: Source is Video, destination is BltBuffer
1950 if (SourceY
+ Height
> Mode
->VerticalResolution
) {
1951 return EFI_INVALID_PARAMETER
;
1954 if (SourceX
+ Width
> Mode
->HorizontalResolution
) {
1955 return EFI_INVALID_PARAMETER
;
1959 // BltBuffer to Video: Source is BltBuffer, destination is Video
1961 if (DestinationY
+ Height
> Mode
->VerticalResolution
) {
1962 return EFI_INVALID_PARAMETER
;
1965 if (DestinationX
+ Width
> Mode
->HorizontalResolution
) {
1966 return EFI_INVALID_PARAMETER
;
1970 // If Delta is zero, then the entire BltBuffer is being used, so Delta
1971 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
1972 // the number of bytes in each row can be computed.
1975 Delta
= Width
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
);
1978 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
1979 // We would not want a timer based event (Cursor, ...) to come in while we are
1980 // doing this operation.
1982 OriginalTPL
= gBS
->RaiseTPL (TPL_NOTIFY
);
1984 switch (BltOperation
) {
1985 case EfiBltVideoToBltBuffer
:
1986 for (SrcY
= SourceY
, DstY
= DestinationY
; DstY
< (Height
+ DestinationY
); SrcY
++, DstY
++) {
1987 Blt
= (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*) (BltUint8
+ DstY
* Delta
+ DestinationX
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
));
1989 // Shuffle the packed bytes in the hardware buffer to match EFI_GRAPHICS_OUTPUT_BLT_PIXEL
1991 VbeBuffer
= ((UINT8
*) VbeFrameBuffer
+ (SrcY
* BytesPerScanLine
+ SourceX
* VbePixelWidth
));
1992 for (DstX
= DestinationX
; DstX
< (Width
+ DestinationX
); DstX
++) {
1993 Pixel
= *(UINT32
*) (VbeBuffer
);
1994 Blt
->Red
= (UINT8
) ((Pixel
>> Mode
->Red
.Position
) & Mode
->Red
.Mask
);
1995 Blt
->Blue
= (UINT8
) ((Pixel
>> Mode
->Blue
.Position
) & Mode
->Blue
.Mask
);
1996 Blt
->Green
= (UINT8
) ((Pixel
>> Mode
->Green
.Position
) & Mode
->Green
.Mask
);
1999 VbeBuffer
+= VbePixelWidth
;
2005 case EfiBltVideoToVideo
:
2006 for (Index
= 0; Index
< Height
; Index
++) {
2007 if (DestinationY
<= SourceY
) {
2008 SrcY
= SourceY
+ Index
;
2009 DstY
= DestinationY
+ Index
;
2011 SrcY
= SourceY
+ Height
- Index
- 1;
2012 DstY
= DestinationY
+ Height
- Index
- 1;
2015 VbeBuffer
= ((UINT8
*) VbeFrameBuffer
+ DstY
* BytesPerScanLine
+ DestinationX
* VbePixelWidth
);
2016 VbeBuffer1
= ((UINT8
*) VbeFrameBuffer
+ SrcY
* BytesPerScanLine
+ SourceX
* VbePixelWidth
);
2025 // Update physical frame buffer.
2040 case EfiBltVideoFill
:
2041 VbeBuffer
= (UINT8
*) ((UINTN
) VbeFrameBuffer
+ (DestinationY
* BytesPerScanLine
) + DestinationX
* VbePixelWidth
);
2042 Blt
= (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*) BltUint8
;
2044 // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
2046 Pixel
= ((Blt
->Red
& Mode
->Red
.Mask
) << Mode
->Red
.Position
) |
2048 (Blt
->Green
& Mode
->Green
.Mask
) <<
2049 Mode
->Green
.Position
2051 ((Blt
->Blue
& Mode
->Blue
.Mask
) << Mode
->Blue
.Position
);
2053 for (Index
= 0; Index
< Width
; Index
++) {
2059 VbeBuffer
+= VbePixelWidth
;
2062 VbeBuffer
= (UINT8
*) ((UINTN
) VbeFrameBuffer
+ (DestinationY
* BytesPerScanLine
) + DestinationX
* VbePixelWidth
);
2063 for (DstY
= DestinationY
+ 1; DstY
< (Height
+ DestinationY
); DstY
++) {
2065 (VOID
*) ((UINTN
) VbeFrameBuffer
+ (DstY
* BytesPerScanLine
) + DestinationX
* VbePixelWidth
),
2070 for (DstY
= DestinationY
; DstY
< (Height
+ DestinationY
); DstY
++) {
2072 // Update physical frame buffer.
2087 case EfiBltBufferToVideo
:
2088 for (SrcY
= SourceY
, DstY
= DestinationY
; SrcY
< (Height
+ SourceY
); SrcY
++, DstY
++) {
2089 Blt
= (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*) (BltUint8
+ (SrcY
* Delta
) + (SourceX
) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
));
2090 VbeBuffer
= ((UINT8
*) VbeFrameBuffer
+ (DstY
* BytesPerScanLine
+ DestinationX
* VbePixelWidth
));
2091 for (DstX
= DestinationX
; DstX
< (Width
+ DestinationX
); DstX
++) {
2093 // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
2095 Pixel
= ((Blt
->Red
& Mode
->Red
.Mask
) << Mode
->Red
.Position
) |
2096 ((Blt
->Green
& Mode
->Green
.Mask
) << Mode
->Green
.Position
) |
2097 ((Blt
->Blue
& Mode
->Blue
.Mask
) << Mode
->Blue
.Position
);
2104 VbeBuffer
+= VbePixelWidth
;
2107 VbeBuffer
= ((UINT8
*) VbeFrameBuffer
+ (DstY
* BytesPerScanLine
+ DestinationX
* VbePixelWidth
));
2110 // Update physical frame buffer.
2128 gBS
->RestoreTPL (OriginalTPL
);
2135 Write graphics controller registers
2138 @param PciIo - Pointer to PciIo protocol instance of the controller
2139 @param Address - Register address
2140 @param Data - Data to be written to register
2147 WriteGraphicsController (
2148 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2153 Address
= Address
| (Data
<< 8);
2156 EfiPciIoWidthUint16
,
2157 EFI_PCI_IO_PASS_THROUGH_BAR
,
2158 VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER
,
2166 Read the four bit plane of VGA frame buffer
2169 @param PciIo - Pointer to PciIo protocol instance of the controller
2170 @param HardwareBuffer - Hardware VGA frame buffer address
2171 @param MemoryBuffer - Memory buffer address
2172 @param WidthInBytes - Number of bytes in a line to read
2173 @param Height - Height of the area to read
2180 EFI_PCI_IO_PROTOCOL
*PciIo
,
2181 UINT8
*HardwareBuffer
,
2182 UINT8
*MemoryBuffer
,
2189 UINTN FrameBufferOffset
;
2194 // Program the Mode Register Write mode 0, Read mode 0
2196 WriteGraphicsController (
2198 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER
,
2199 VGA_GRAPHICS_CONTROLLER_READ_MODE_0
| VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0
2202 for (BitPlane
= 0, FrameBufferOffset
= 0;
2203 BitPlane
< VGA_NUMBER_OF_BIT_PLANES
;
2204 BitPlane
++, FrameBufferOffset
+= VGA_BYTES_PER_BIT_PLANE
2207 // Program the Read Map Select Register to select the correct bit plane
2209 WriteGraphicsController (
2211 VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER
,
2215 Source
= HardwareBuffer
;
2216 Destination
= MemoryBuffer
+ FrameBufferOffset
;
2218 for (Rows
= 0; Rows
< Height
; Rows
++, Source
+= VGA_BYTES_PER_SCAN_LINE
, Destination
+= VGA_BYTES_PER_SCAN_LINE
) {
2222 (UINT8
) EFI_PCI_IO_PASS_THROUGH_BAR
,
2223 (UINT64
)(UINTN
) Source
,
2225 (VOID
*) Destination
2233 Internal routine to convert VGA color to Grahpics Output color
2236 @param MemoryBuffer - Buffer containing VGA color
2237 @param X - The X coordinate of pixel on screen
2238 @param Y - The Y coordinate of pixel on screen
2239 @param BltBuffer - Buffer to contain converted Grahpics Output color
2245 VgaConvertToGraphicsOutputColor (
2246 UINT8
*MemoryBuffer
,
2249 EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*BltBuffer
2256 MemoryBuffer
+= ((Y
<< 6) + (Y
<< 4) + (X
>> 3));
2257 Mask
= mVgaBitMaskTable
[X
& 0x07];
2258 for (Bit
= 0x01, Color
= 0; Bit
< 0x10; Bit
<<= 1, MemoryBuffer
+= VGA_BYTES_PER_BIT_PLANE
) {
2259 if (*MemoryBuffer
& Mask
) {
2264 *BltBuffer
= mVgaColorToGraphicsOutputColor
[Color
];
2269 Internal routine to convert Grahpics Output color to VGA color
2272 @param BltBuffer - buffer containing Grahpics Output color
2274 @return Converted VGA color
2279 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*BltBuffer
2284 Color
= (UINT8
) ((BltBuffer
->Blue
>> 7) | ((BltBuffer
->Green
>> 6) & 0x02) | ((BltBuffer
->Red
>> 5) & 0x04));
2285 if ((BltBuffer
->Red
+ BltBuffer
->Green
+ BltBuffer
->Blue
) > 0x180) {
2293 Grahpics Output protocol instance to block transfer for VGA device
2295 @param This Pointer to Grahpics Output protocol instance
2296 @param BltBuffer The data to transfer to screen
2297 @param BltOperation The operation to perform
2298 @param SourceX The X coordinate of the source for BltOperation
2299 @param SourceY The Y coordinate of the source for BltOperation
2300 @param DestinationX The X coordinate of the destination for BltOperation
2301 @param DestinationY The Y coordinate of the destination for BltOperation
2302 @param Width The width of a rectangle in the blt rectangle in pixels
2303 @param Height The height of a rectangle in the blt rectangle in pixels
2304 @param Delta Not used for EfiBltVideoFill and EfiBltVideoToVideo operation.
2305 If a Delta of 0 is used, the entire BltBuffer will be operated on.
2306 If a subrectangle of the BltBuffer is used, then Delta represents
2307 the number of bytes in a row of the BltBuffer.
2309 @retval EFI_INVALID_PARAMETER Invalid parameter passed in
2310 @retval EFI_SUCCESS Blt operation success
2315 BiosVideoGraphicsOutputVgaBlt (
2316 IN EFI_GRAPHICS_OUTPUT_PROTOCOL
*This
,
2317 IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*BltBuffer
, OPTIONAL
2318 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation
,
2321 IN UINTN DestinationX
,
2322 IN UINTN DestinationY
,
2328 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
2329 EFI_TPL OriginalTPL
;
2331 UINTN BytesPerScanLine
;
2332 //UINTN BytesPerBitPlane;
2344 UINT8
*SourceAddress
;
2345 UINT8
*DestinationAddress
;
2346 EFI_PCI_IO_PROTOCOL
*PciIo
;
2349 UINT8
*VgaFrameBuffer
;
2358 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This
);
2360 CurrentMode
= This
->Mode
->Mode
;
2361 PciIo
= BiosVideoPrivate
->PciIo
;
2362 MemAddress
= BiosVideoPrivate
->ModeData
[CurrentMode
].LinearFrameBuffer
;
2363 BytesPerScanLine
= BiosVideoPrivate
->ModeData
[CurrentMode
].BytesPerScanLine
>> 3;
2364 //BytesPerBitPlane = BytesPerScanLine * BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution;
2365 VgaFrameBuffer
= BiosVideoPrivate
->VgaFrameBuffer
;
2367 if (This
== NULL
|| ((UINTN
) BltOperation
) >= EfiGraphicsOutputBltOperationMax
) {
2368 return EFI_INVALID_PARAMETER
;
2371 if (Width
== 0 || Height
== 0) {
2372 return EFI_INVALID_PARAMETER
;
2375 // We need to fill the Virtual Screen buffer with the blt data.
2376 // The virtual screen is upside down, as the first row is the bootom row of
2379 if (BltOperation
== EfiBltVideoToBltBuffer
) {
2381 // Video to BltBuffer: Source is Video, destination is BltBuffer
2383 if (SourceY
+ Height
> BiosVideoPrivate
->ModeData
[CurrentMode
].VerticalResolution
) {
2384 return EFI_INVALID_PARAMETER
;
2387 if (SourceX
+ Width
> BiosVideoPrivate
->ModeData
[CurrentMode
].HorizontalResolution
) {
2388 return EFI_INVALID_PARAMETER
;
2392 // BltBuffer to Video: Source is BltBuffer, destination is Video
2394 if (DestinationY
+ Height
> BiosVideoPrivate
->ModeData
[CurrentMode
].VerticalResolution
) {
2395 return EFI_INVALID_PARAMETER
;
2398 if (DestinationX
+ Width
> BiosVideoPrivate
->ModeData
[CurrentMode
].HorizontalResolution
) {
2399 return EFI_INVALID_PARAMETER
;
2403 // If Delta is zero, then the entire BltBuffer is being used, so Delta
2404 // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
2405 // the number of bytes in each row can be computed.
2408 Delta
= Width
* sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
);
2411 // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
2412 // We would not want a timer based event (Cursor, ...) to come in while we are
2413 // doing this operation.
2415 OriginalTPL
= gBS
->RaiseTPL (TPL_NOTIFY
);
2418 // Compute some values we need for VGA
2420 switch (BltOperation
) {
2421 case EfiBltVideoToBltBuffer
:
2423 SourceOffset
= (SourceY
<< 6) + (SourceY
<< 4) + (SourceX
>> 3);
2424 SourceWidth
= ((SourceX
+ Width
- 1) >> 3) - (SourceX
>> 3) + 1;
2427 // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2431 MemAddress
+ SourceOffset
,
2432 VgaFrameBuffer
+ SourceOffset
,
2438 // Convert VGA Bit Planes to a Graphics Output 32-bit color value
2440 BltBuffer
+= (DestinationY
* (Delta
>> 2) + DestinationX
);
2441 for (Rows
= 0, Y
= SourceY
; Rows
< Height
; Rows
++, Y
++, BltBuffer
+= (Delta
>> 2)) {
2442 for (Columns
= 0, X
= SourceX
; Columns
< Width
; Columns
++, X
++, BltBuffer
++) {
2443 VgaConvertToGraphicsOutputColor (VgaFrameBuffer
, X
, Y
, BltBuffer
);
2451 case EfiBltVideoToVideo
:
2453 // Check for an aligned Video to Video operation
2455 if ((SourceX
& 0x07) == 0x00 && (DestinationX
& 0x07) == 0x00 && (Width
& 0x07) == 0x00) {
2457 // Program the Mode Register Write mode 1, Read mode 0
2459 WriteGraphicsController (
2461 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER
,
2462 VGA_GRAPHICS_CONTROLLER_READ_MODE_0
| VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1
2465 SourceAddress
= (UINT8
*) (MemAddress
+ (SourceY
<< 6) + (SourceY
<< 4) + (SourceX
>> 3));
2466 DestinationAddress
= (UINT8
*) (MemAddress
+ (DestinationY
<< 6) + (DestinationY
<< 4) + (DestinationX
>> 3));
2468 for (Index
= 0, Offset
= 0; Index
< Height
; Index
++, Offset
+= BytesPerScanLine
) {
2472 EFI_PCI_IO_PASS_THROUGH_BAR
,
2473 (UINT64
) ((UINTN
)DestinationAddress
+ Offset
),
2474 EFI_PCI_IO_PASS_THROUGH_BAR
,
2475 (UINT64
) ((UINTN
)SourceAddress
+ Offset
),
2480 SourceOffset
= (SourceY
<< 6) + (SourceY
<< 4) + (SourceX
>> 3);
2481 SourceWidth
= ((SourceX
+ Width
- 1) >> 3) - (SourceX
>> 3) + 1;
2484 // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
2488 MemAddress
+ SourceOffset
,
2489 VgaFrameBuffer
+ SourceOffset
,
2497 case EfiBltVideoFill
:
2498 StartAddress
= (UINTN
) (MemAddress
+ (DestinationY
<< 6) + (DestinationY
<< 4) + (DestinationX
>> 3));
2499 Bytes
= ((DestinationX
+ Width
- 1) >> 3) - (DestinationX
>> 3);
2500 LeftMask
= mVgaLeftMaskTable
[DestinationX
& 0x07];
2501 RightMask
= mVgaRightMaskTable
[(DestinationX
+ Width
- 1) & 0x07];
2503 LeftMask
= (UINT8
) (LeftMask
& RightMask
);
2507 if (LeftMask
== 0xff) {
2513 if (RightMask
== 0xff) {
2518 PixelColor
= VgaConvertColor (BltBuffer
);
2521 // Program the Mode Register Write mode 2, Read mode 0
2523 WriteGraphicsController (
2525 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER
,
2526 VGA_GRAPHICS_CONTROLLER_READ_MODE_0
| VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
2530 // Program the Data Rotate/Function Select Register to replace
2532 WriteGraphicsController (
2534 VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER
,
2535 VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
2538 if (LeftMask
!= 0) {
2540 // Program the BitMask register with the Left column mask
2542 WriteGraphicsController (
2544 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER
,
2548 for (Index
= 0, Address
= StartAddress
; Index
< Height
; Index
++, Address
+= BytesPerScanLine
) {
2550 // Read data from the bit planes into the latches
2555 EFI_PCI_IO_PASS_THROUGH_BAR
,
2561 // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
2566 EFI_PCI_IO_PASS_THROUGH_BAR
,
2576 // Program the BitMask register with the middle column mask of 0xff
2578 WriteGraphicsController (
2580 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER
,
2584 for (Index
= 0, Address
= StartAddress
+ 1; Index
< Height
; Index
++, Address
+= BytesPerScanLine
) {
2587 EfiPciIoWidthFillUint8
,
2588 EFI_PCI_IO_PASS_THROUGH_BAR
,
2596 if (RightMask
!= 0) {
2598 // Program the BitMask register with the Right column mask
2600 WriteGraphicsController (
2602 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER
,
2606 for (Index
= 0, Address
= StartAddress
+ Bytes
; Index
< Height
; Index
++, Address
+= BytesPerScanLine
) {
2608 // Read data from the bit planes into the latches
2613 EFI_PCI_IO_PASS_THROUGH_BAR
,
2619 // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
2624 EFI_PCI_IO_PASS_THROUGH_BAR
,
2633 case EfiBltBufferToVideo
:
2634 StartAddress
= (UINTN
) (MemAddress
+ (DestinationY
<< 6) + (DestinationY
<< 4) + (DestinationX
>> 3));
2635 LeftMask
= mVgaBitMaskTable
[DestinationX
& 0x07];
2638 // Program the Mode Register Write mode 2, Read mode 0
2640 WriteGraphicsController (
2642 VGA_GRAPHICS_CONTROLLER_MODE_REGISTER
,
2643 VGA_GRAPHICS_CONTROLLER_READ_MODE_0
| VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
2647 // Program the Data Rotate/Function Select Register to replace
2649 WriteGraphicsController (
2651 VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER
,
2652 VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
2655 for (Index
= 0, Address
= StartAddress
; Index
< Height
; Index
++, Address
+= BytesPerScanLine
) {
2656 for (Index1
= 0; Index1
< Width
; Index1
++) {
2657 BiosVideoPrivate
->LineBuffer
[Index1
] = VgaConvertColor (&BltBuffer
[(SourceY
+ Index
) * (Delta
>> 2) + SourceX
+ Index1
]);
2659 AddressFix
= Address
;
2661 for (Bit
= 0; Bit
< 8; Bit
++) {
2663 // Program the BitMask register with the Left column mask
2665 WriteGraphicsController (
2667 VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER
,
2671 for (Index1
= Bit
, Address1
= (UINT8
*) AddressFix
; Index1
< Width
; Index1
+= 8, Address1
++) {
2673 // Read data from the bit planes into the latches
2678 EFI_PCI_IO_PASS_THROUGH_BAR
,
2679 (UINT64
)(UINTN
) Address1
,
2687 EFI_PCI_IO_PASS_THROUGH_BAR
,
2688 (UINT64
)(UINTN
) Address1
,
2690 &BiosVideoPrivate
->LineBuffer
[Index1
]
2694 LeftMask
= (UINT8
) (LeftMask
>> 1);
2695 if (LeftMask
== 0) {
2707 gBS
->RestoreTPL (OriginalTPL
);
2712 // VGA Mini Port Protocol Functions
2715 VgaMiniPort protocol interface to set mode
2717 @param This Pointer to VgaMiniPort protocol instance
2718 @param ModeNumber The index of the mode
2720 @retval EFI_UNSUPPORTED The requested mode is not supported
2721 @retval EFI_SUCCESS The requested mode is set successfully
2726 BiosVideoVgaMiniPortSetMode (
2727 IN EFI_VGA_MINI_PORT_PROTOCOL
*This
,
2731 BIOS_VIDEO_DEV
*BiosVideoPrivate
;
2732 IA32_REGISTER_SET Regs
;
2735 return EFI_INVALID_PARAMETER
;
2739 // Make sure the ModeNumber is a valid value
2741 if (ModeNumber
>= This
->MaxMode
) {
2742 return EFI_UNSUPPORTED
;
2745 // Get the device structure for this device
2747 BiosVideoPrivate
= BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (This
);
2749 gBS
->SetMem (&Regs
, sizeof (Regs
), 0);
2751 switch (ModeNumber
) {
2754 // Set the 80x25 Text VGA Mode
2758 LegacyBiosInt86 (BiosVideoPrivate
, 0x10, &Regs
);
2763 LegacyBiosInt86 (BiosVideoPrivate
, 0x10, &Regs
);
2769 // Set the 80x50 Text VGA Mode
2773 LegacyBiosInt86 (BiosVideoPrivate
, 0x10, &Regs
);
2778 LegacyBiosInt86 (BiosVideoPrivate
, 0x10, &Regs
);
2782 return EFI_UNSUPPORTED
;