git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@7736 6f19259b-4bc3-4df7-8a09-765794883524
2649 lines
77 KiB
C
2649 lines
77 KiB
C
/*++
|
|
|
|
Copyright (c) 2006 - 2008, Intel Corporation
|
|
All rights reserved. This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
Module Name:
|
|
|
|
BiosVideo.c
|
|
|
|
Abstract:
|
|
|
|
ConsoleOut Routines that speak VGA.
|
|
|
|
Revision History
|
|
|
|
--*/
|
|
|
|
#include "BiosVideo.h"
|
|
|
|
|
|
//
|
|
// EFI Driver Binding Protocol Instance
|
|
//
|
|
EFI_DRIVER_BINDING_PROTOCOL gBiosVideoDriverBinding = {
|
|
BiosVideoDriverBindingSupported,
|
|
BiosVideoDriverBindingStart,
|
|
BiosVideoDriverBindingStop,
|
|
0x3,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
//
|
|
// Global lookup tables for VGA graphics modes
|
|
//
|
|
UINT8 mVgaLeftMaskTable[] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
|
|
|
|
UINT8 mVgaRightMaskTable[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
|
|
|
|
UINT8 mVgaBitMaskTable[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
|
|
|
|
THUNK_CONTEXT mThunkContext;
|
|
|
|
EFI_LEGACY_8259_PROTOCOL *mLegacy8259 = NULL;
|
|
|
|
#define EFI_CPU_EFLAGS_IF 0x200
|
|
|
|
EFI_UGA_PIXEL mVgaColorToUgaColor[] = {
|
|
{
|
|
0x00,
|
|
0x00,
|
|
0x00,
|
|
0x00
|
|
},
|
|
{
|
|
0x98,
|
|
0x00,
|
|
0x00,
|
|
0x00
|
|
},
|
|
{
|
|
0x00,
|
|
0x98,
|
|
0x00,
|
|
0x00
|
|
},
|
|
{
|
|
0x98,
|
|
0x98,
|
|
0x00,
|
|
0x00
|
|
},
|
|
{
|
|
0x00,
|
|
0x00,
|
|
0x98,
|
|
0x00
|
|
},
|
|
{
|
|
0x98,
|
|
0x00,
|
|
0x98,
|
|
0x00
|
|
},
|
|
{
|
|
0x00,
|
|
0x98,
|
|
0x98,
|
|
0x00
|
|
},
|
|
{
|
|
0x98,
|
|
0x98,
|
|
0x98,
|
|
0x00
|
|
},
|
|
{
|
|
0x10,
|
|
0x10,
|
|
0x10,
|
|
0x00
|
|
},
|
|
{
|
|
0xff,
|
|
0x10,
|
|
0x10,
|
|
0x00
|
|
},
|
|
{
|
|
0x10,
|
|
0xff,
|
|
0x10,
|
|
0x00
|
|
},
|
|
{
|
|
0xff,
|
|
0xff,
|
|
0x10,
|
|
0x00
|
|
},
|
|
{
|
|
0x10,
|
|
0x10,
|
|
0xff,
|
|
0x00
|
|
},
|
|
{
|
|
0xf0,
|
|
0x10,
|
|
0xff,
|
|
0x00
|
|
},
|
|
{
|
|
0x10,
|
|
0xff,
|
|
0xff,
|
|
0x00
|
|
},
|
|
{
|
|
0xff,
|
|
0xff,
|
|
0xff,
|
|
0x00
|
|
}
|
|
};
|
|
|
|
VOID
|
|
InitializeBiosIntCaller (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
InitializeInterruptRedirection (
|
|
VOID
|
|
);
|
|
|
|
BOOLEAN
|
|
EFIAPI
|
|
LegacyBiosInt86 (
|
|
IN UINT8 BiosInt,
|
|
IN EFI_IA32_REGISTER_SET *Regs
|
|
);
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BiosVideoDriverEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Driver Entry Point.
|
|
|
|
Arguments:
|
|
|
|
ImageHandle - Handle of driver image.
|
|
SystemTable - Pointer to system table.
|
|
|
|
Returns:
|
|
|
|
EFI_STATUS
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
Status = EfiLibInstallDriverBindingComponentName2 (
|
|
ImageHandle,
|
|
SystemTable,
|
|
&gBiosVideoDriverBinding,
|
|
ImageHandle,
|
|
&gBiosVideoComponentName,
|
|
&gBiosVideoComponentName2
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
EFIAPI
|
|
BiosVideoExitBootServices (
|
|
EFI_EVENT Event,
|
|
VOID *Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback function for exit boot service event
|
|
|
|
Arguments:
|
|
|
|
Event - EFI_EVENT structure
|
|
Context - Event context
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
/*
|
|
BIOS_VIDEO_DEV *BiosVideoPrivate;
|
|
EFI_IA32_REGISTER_SET Regs;
|
|
|
|
//
|
|
// Get our context
|
|
//
|
|
BiosVideoPrivate = (BIOS_VIDEO_DEV *) Context;
|
|
|
|
//
|
|
// Set the 80x25 Text VGA Mode
|
|
//
|
|
Regs.H.AH = 0x00;
|
|
Regs.H.AL = 0x83;
|
|
BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
|
|
|
|
Regs.H.AH = 0x11;
|
|
Regs.H.AL = 0x14;
|
|
Regs.H.BL = 0;
|
|
BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
|
|
*/
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BiosVideoDriverBindingSupported (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Supported.
|
|
|
|
Arguments:
|
|
|
|
This - Pointer to driver binding protocol
|
|
Controller - Controller handle to connect
|
|
RemainingDevicePath - A pointer to the remaining portion of a device path
|
|
|
|
|
|
Returns:
|
|
|
|
EFI_STATUS - EFI_SUCCESS:This controller can be managed by this driver,
|
|
Otherwise, this controller cannot be managed by this driver
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_LEGACY_8259_PROTOCOL *Legacy8259;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
|
|
DEBUG ((EFI_D_INFO, "BiosVideoDriverBindingSupported\n"));
|
|
|
|
//
|
|
// See if the Legacy BIOS Protocol is available
|
|
//
|
|
Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &Legacy8259);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Open the IO Abstraction(s) needed to perform the supported test
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
(VOID **) &PciIo,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_INFO, "BiosVideoDriverBindingSupported: Fail to open PciIo protocol!\n"));
|
|
return Status;
|
|
}
|
|
|
|
if (!BiosVideoIsVga (PciIo)) {
|
|
DEBUG ((EFI_D_INFO, "BiosVideoDriverBindingSupported: Is not VGA!\n"));
|
|
Status = EFI_UNSUPPORTED;
|
|
}
|
|
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BiosVideoDriverBindingStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Install UGA Draw Protocol onto VGA device handles
|
|
|
|
Arguments:
|
|
|
|
This - Pointer to driver binding protocol
|
|
Controller - Controller handle to connect
|
|
RemainingDevicePath - A pointer to the remaining portion of a device path
|
|
|
|
Returns:
|
|
|
|
EFI_STATUS
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
BIOS_VIDEO_DEV *BiosVideoPrivate;
|
|
|
|
DEBUG ((EFI_D_INFO, "BiosVideoDriverBindingStart\n"));
|
|
//
|
|
// Initialize local variables
|
|
//
|
|
BiosVideoPrivate = NULL;
|
|
|
|
//
|
|
// Allocate the private device structure
|
|
//
|
|
Status = gBS->AllocatePool (
|
|
EfiBootServicesData,
|
|
sizeof (BIOS_VIDEO_DEV),
|
|
(VOID**)&BiosVideoPrivate
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
ZeroMem (BiosVideoPrivate, sizeof (BIOS_VIDEO_DEV));
|
|
|
|
//
|
|
// See if the Legacy BIOS Protocol is available
|
|
//
|
|
Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &mLegacy8259);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Prepare for status code
|
|
//
|
|
Status = gBS->HandleProtocol (
|
|
Controller,
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID**)&BiosVideoPrivate->DevicePath
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
//
|
|
// Open the IO Abstraction(s) needed
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
(VOID **) &(BiosVideoPrivate->PciIo),
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
DEBUG ((EFI_D_INFO, "InitializeBiosIntCaller\n"));
|
|
InitializeBiosIntCaller();
|
|
InitializeInterruptRedirection();
|
|
DEBUG ((EFI_D_INFO, "InitializeBiosIntCaller Finished!\n"));
|
|
|
|
if (!BiosVideoIsVga (BiosVideoPrivate->PciIo)) {
|
|
DEBUG ((EFI_D_INFO, "BiosVideoDriverBindingStart: not VGA\n"));
|
|
Status = EFI_UNSUPPORTED;
|
|
goto Done;
|
|
}
|
|
|
|
BiosVideoPrivate->VgaCompatible = TRUE;
|
|
//
|
|
// Initialize the private device structure
|
|
//
|
|
BiosVideoPrivate->Signature = BIOS_VIDEO_DEV_SIGNATURE;
|
|
BiosVideoPrivate->Handle = Controller;
|
|
|
|
/**
|
|
Status = gBS->CreateEvent (
|
|
EFI_EVENT_SIGNAL_EXIT_BOOT_SERVICES,
|
|
EFI_TPL_NOTIFY,
|
|
BiosVideoExitBootServices,
|
|
BiosVideoPrivate,
|
|
&BiosVideoPrivate->ExitBootServicesEvent
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
**/
|
|
|
|
//
|
|
// Fill in UGA Draw specific mode structures
|
|
//
|
|
BiosVideoPrivate->HardwareNeedsStarting = TRUE;
|
|
BiosVideoPrivate->CurrentMode = 0;
|
|
BiosVideoPrivate->MaxMode = 0;
|
|
BiosVideoPrivate->ModeData = NULL;
|
|
BiosVideoPrivate->LineBuffer = NULL;
|
|
BiosVideoPrivate->VgaFrameBuffer = NULL;
|
|
BiosVideoPrivate->VbeFrameBuffer = NULL;
|
|
|
|
//
|
|
// Fill in the VGA Mini Port Protocol fields
|
|
//
|
|
BiosVideoPrivate->VgaMiniPort.SetMode = BiosVideoVgaMiniPortSetMode;
|
|
BiosVideoPrivate->VgaMiniPort.VgaMemoryOffset = 0xb8000;
|
|
BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterOffset = 0x3d4;
|
|
BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterOffset = 0x3d5;
|
|
BiosVideoPrivate->VgaMiniPort.VgaMemoryBar = EFI_PCI_IO_PASS_THROUGH_BAR;
|
|
BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR;
|
|
BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR;
|
|
|
|
//
|
|
// Assume that UGA Draw will be produced until proven otherwise
|
|
//
|
|
BiosVideoPrivate->ProduceUgaDraw = TRUE;
|
|
|
|
//
|
|
// Check for VESA BIOS Extensions for modes that are compatible with UGA Draw
|
|
//
|
|
//CpuDeadLoop();
|
|
DEBUG ((EFI_D_INFO, "BiosVideoDriverBindingStart: Before check VBE!\n"));
|
|
Status = BiosVideoCheckForVbe (BiosVideoPrivate);
|
|
DEBUG ((EFI_D_INFO, "BiosVideoDriverBindingStart: check VBE status=%r!\n", Status));
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
DEBUG ((EFI_D_INFO, "BiosVideoDriverBindingStart: Fail to check VBE!\n"));
|
|
//
|
|
// The VESA BIOS Extensions are not compatible with UGA Draw, so check for support
|
|
// for the standard 640x480 16 color VGA mode
|
|
//
|
|
if (BiosVideoPrivate->VgaCompatible) {
|
|
Status = BiosVideoCheckForVga (BiosVideoPrivate);
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Neither VBE nor the standard 640x480 16 color VGA mode are supported, so do
|
|
// not produce the UGA Draw protocol. Instead, produce the VGA MiniPort Protocol.
|
|
//
|
|
BiosVideoPrivate->ProduceUgaDraw = FALSE;
|
|
|
|
//
|
|
// INT services are available, so on the 80x25 and 80x50 text mode are supported
|
|
//
|
|
BiosVideoPrivate->VgaMiniPort.MaxMode = 2;
|
|
}
|
|
}
|
|
|
|
if (BiosVideoPrivate->ProduceUgaDraw) {
|
|
DEBUG ((EFI_D_INFO, "BiosVideoDriverBindingStart: Produce Uga Draw!\n"));
|
|
//
|
|
// Install UGA Draw Protocol
|
|
//
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&Controller,
|
|
&gEfiUgaDrawProtocolGuid,
|
|
&BiosVideoPrivate->UgaDraw,
|
|
NULL
|
|
);
|
|
} else {
|
|
//
|
|
// Install VGA Mini Port Protocol
|
|
//
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&Controller,
|
|
&gEfiVgaMiniPortProtocolGuid,
|
|
&BiosVideoPrivate->VgaMiniPort,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
Done:
|
|
if (EFI_ERROR (Status)) {
|
|
if (BiosVideoPrivate != NULL) {
|
|
//
|
|
// Free mode data
|
|
//
|
|
if (BiosVideoPrivate->ModeData != NULL) {
|
|
gBS->FreePool (BiosVideoPrivate->ModeData);
|
|
}
|
|
//
|
|
// Free memory allocated below 1MB
|
|
//
|
|
if (BiosVideoPrivate->PagesBelow1MB != 0) {
|
|
gBS->FreePages (BiosVideoPrivate->PagesBelow1MB, BiosVideoPrivate->NumberOfPagesBelow1MB);
|
|
}
|
|
|
|
if (BiosVideoPrivate->PciIo != NULL) {
|
|
//
|
|
// Release PCI I/O and UGA Draw Protocols on the controller handle.
|
|
//
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
}
|
|
//
|
|
// Close the ExitBootServices event
|
|
//
|
|
if (BiosVideoPrivate->ExitBootServicesEvent != NULL) {
|
|
gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent);
|
|
}
|
|
//
|
|
// Free private data structure
|
|
//
|
|
gBS->FreePool (BiosVideoPrivate);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BiosVideoDriverBindingStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Stop.
|
|
|
|
Arguments:
|
|
|
|
This - Pointer to driver binding protocol
|
|
Controller - Controller handle to connect
|
|
NumberOfChilren - Number of children handle created by this driver
|
|
ChildHandleBuffer - Buffer containing child handle created
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - Driver disconnected successfully from controller
|
|
EFI_UNSUPPORTED - Cannot find BIOS_VIDEO_DEV structure
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_UGA_DRAW_PROTOCOL *Uga;
|
|
EFI_VGA_MINI_PORT_PROTOCOL *VgaMiniPort;
|
|
BIOS_VIDEO_DEV *BiosVideoPrivate;
|
|
EFI_IA32_REGISTER_SET Regs;
|
|
|
|
BiosVideoPrivate = NULL;
|
|
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiUgaDrawProtocolGuid,
|
|
(VOID **) &Uga,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_UGA_DRAW_THIS (Uga);
|
|
}
|
|
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiVgaMiniPortProtocolGuid,
|
|
(VOID **) &VgaMiniPort,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (VgaMiniPort);
|
|
}
|
|
|
|
if (BiosVideoPrivate == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (BiosVideoPrivate->ProduceUgaDraw) {
|
|
Status = gBS->UninstallMultipleProtocolInterfaces (
|
|
Controller,
|
|
&gEfiUgaDrawProtocolGuid,
|
|
&BiosVideoPrivate->UgaDraw,
|
|
NULL
|
|
);
|
|
} else {
|
|
Status = gBS->UninstallMultipleProtocolInterfaces (
|
|
Controller,
|
|
&gEfiVgaMiniPortProtocolGuid,
|
|
&BiosVideoPrivate->VgaMiniPort,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
gBS->SetMem (&Regs, sizeof (Regs), 0);
|
|
|
|
//
|
|
// Set the 80x25 Text VGA Mode
|
|
//
|
|
Regs.H.AH = 0x00;
|
|
Regs.H.AL = 0x03;
|
|
LegacyBiosInt86 (0x10, &Regs);
|
|
|
|
Regs.H.AH = 0x11;
|
|
Regs.H.AL = 0x14;
|
|
Regs.H.BL = 0;
|
|
LegacyBiosInt86 (0x10, &Regs);
|
|
|
|
//
|
|
// Do not disable IO/memory decode since that would prevent legacy ROM from working
|
|
//
|
|
//
|
|
// Free VGA Frame Buffer
|
|
//
|
|
if (BiosVideoPrivate->VgaFrameBuffer != NULL) {
|
|
gBS->FreePool (BiosVideoPrivate->VgaFrameBuffer);
|
|
}
|
|
//
|
|
// Free VBE Frame Buffer
|
|
//
|
|
if (BiosVideoPrivate->VbeFrameBuffer != NULL) {
|
|
gBS->FreePool (BiosVideoPrivate->VbeFrameBuffer);
|
|
}
|
|
//
|
|
// Free line buffer
|
|
//
|
|
if (BiosVideoPrivate->LineBuffer != NULL) {
|
|
gBS->FreePool (BiosVideoPrivate->LineBuffer);
|
|
}
|
|
//
|
|
// Free mode data
|
|
//
|
|
if (BiosVideoPrivate->ModeData != NULL) {
|
|
gBS->FreePool (BiosVideoPrivate->ModeData);
|
|
}
|
|
//
|
|
// Free memory allocated below 1MB
|
|
//
|
|
if (BiosVideoPrivate->PagesBelow1MB != 0) {
|
|
gBS->FreePages (BiosVideoPrivate->PagesBelow1MB, BiosVideoPrivate->NumberOfPagesBelow1MB);
|
|
}
|
|
|
|
if (BiosVideoPrivate->VbeSaveRestorePages != 0) {
|
|
gBS->FreePages (BiosVideoPrivate->VbeSaveRestoreBuffer, BiosVideoPrivate->VbeSaveRestorePages);
|
|
}
|
|
//
|
|
// Release PCI I/O and UGA Draw Protocols on the controller handle.
|
|
//
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
|
|
//
|
|
// Close the ExitBootServices event
|
|
//
|
|
gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent);
|
|
|
|
//
|
|
// Free private data structure
|
|
//
|
|
gBS->FreePool (BiosVideoPrivate);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
#define PCI_DEVICE_ENABLED (EFI_PCI_COMMAND_IO_SPACE | EFI_PCI_COMMAND_MEMORY_SPACE)
|
|
|
|
|
|
BOOLEAN
|
|
BiosVideoIsVga (
|
|
IN EFI_PCI_IO_PROTOCOL *PciIo
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOLEAN VgaCompatible;
|
|
PCI_TYPE00 Pci;
|
|
|
|
VgaCompatible = FALSE;
|
|
|
|
//
|
|
// Read the PCI Configuration Header
|
|
//
|
|
Status = PciIo->Pci.Read (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
0,
|
|
sizeof (Pci) / sizeof (UINT32),
|
|
&Pci
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return VgaCompatible;
|
|
}
|
|
|
|
//
|
|
// See if this is a VGA compatible controller or not
|
|
//
|
|
if ((Pci.Hdr.Command & PCI_DEVICE_ENABLED) == PCI_DEVICE_ENABLED) {
|
|
if (Pci.Hdr.ClassCode[2] == PCI_CLASS_OLD && Pci.Hdr.ClassCode[1] == PCI_CLASS_OLD_VGA) {
|
|
//
|
|
// Base Class 0x00 Sub-Class 0x01 - Backward compatible VGA device
|
|
//
|
|
VgaCompatible = TRUE;
|
|
}
|
|
|
|
if (Pci.Hdr.ClassCode[2] == PCI_CLASS_DISPLAY && Pci.Hdr.ClassCode[1] == PCI_CLASS_DISPLAY_VGA && Pci.Hdr.ClassCode[0] == 0x00) {
|
|
//
|
|
// Base Class 3 Sub-Class 0 Programming interface 0 - VGA compatible Display controller
|
|
//
|
|
VgaCompatible = TRUE;
|
|
}
|
|
}
|
|
|
|
return VgaCompatible;
|
|
}
|
|
|
|
|
|
EFI_STATUS
|
|
BiosVideoCheckForVbe (
|
|
IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check for VBE device
|
|
|
|
Arguments:
|
|
|
|
BiosVideoPrivate - Pointer to BIOS_VIDEO_DEV structure
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - VBE device found
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_IA32_REGISTER_SET Regs;
|
|
UINT16 *ModeNumberPtr;
|
|
BOOLEAN ModeFound;
|
|
BIOS_VIDEO_MODE_DATA *ModeBuffer;
|
|
UINTN Index;
|
|
|
|
//
|
|
// Allocate buffer under 1MB for VBE data structures
|
|
//
|
|
BiosVideoPrivate->NumberOfPagesBelow1MB = EFI_SIZE_TO_PAGES (
|
|
sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK) + sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK) +
|
|
sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK)
|
|
);
|
|
|
|
BiosVideoPrivate->PagesBelow1MB = 0x00100000 - 1;
|
|
|
|
Status = gBS->AllocatePages (
|
|
AllocateMaxAddress,
|
|
EfiBootServicesData,
|
|
BiosVideoPrivate->NumberOfPagesBelow1MB,
|
|
&BiosVideoPrivate->PagesBelow1MB
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Fill in the UGA Draw Protocol
|
|
//
|
|
BiosVideoPrivate->UgaDraw.GetMode = BiosVideoUgaDrawGetMode;
|
|
BiosVideoPrivate->UgaDraw.SetMode = BiosVideoUgaDrawSetMode;
|
|
BiosVideoPrivate->UgaDraw.Blt = BiosVideoUgaDrawVbeBlt;
|
|
|
|
//
|
|
// Fill in the VBE related data structures
|
|
//
|
|
BiosVideoPrivate->VbeInformationBlock = (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK *) (UINTN) (BiosVideoPrivate->PagesBelow1MB);
|
|
BiosVideoPrivate->VbeModeInformationBlock = (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeInformationBlock + 1);
|
|
BiosVideoPrivate->VbeCrtcInformationBlock = (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeModeInformationBlock + 1);
|
|
BiosVideoPrivate->VbeSaveRestorePages = 0;
|
|
BiosVideoPrivate->VbeSaveRestoreBuffer = 0;
|
|
|
|
//
|
|
// Test to see if the Video Adapter is compliant with VBE 3.0
|
|
//
|
|
gBS->SetMem (&Regs, sizeof (Regs), 0);
|
|
Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION;
|
|
gBS->SetMem (BiosVideoPrivate->VbeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK), 0);
|
|
BiosVideoPrivate->VbeInformationBlock->VESASignature = VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE;
|
|
Regs.X.ES = EFI_SEGMENT ((UINTN)BiosVideoPrivate->VbeInformationBlock);
|
|
Regs.X.DI = EFI_OFFSET ((UINTN)BiosVideoPrivate->VbeInformationBlock);
|
|
|
|
LegacyBiosInt86 (0x10, &Regs);
|
|
|
|
Status = EFI_DEVICE_ERROR;
|
|
|
|
//
|
|
// See if the VESA call succeeded
|
|
//
|
|
if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Check for 'VESA' signature
|
|
//
|
|
if (BiosVideoPrivate->VbeInformationBlock->VESASignature != VESA_BIOS_EXTENSIONS_VESA_SIGNATURE) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Check to see if this is VBE 2.0 or higher
|
|
//
|
|
if (BiosVideoPrivate->VbeInformationBlock->VESAVersion < VESA_BIOS_EXTENSIONS_VERSION_2_0) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Walk through the mode list to see if there is at least one mode the is compatible with the UGA_DRAW protocol
|
|
//
|
|
ModeNumberPtr = (UINT16 *)
|
|
(
|
|
(((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0xffff0000) >> 12) |
|
|
((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0x0000ffff)
|
|
);
|
|
for (; *ModeNumberPtr != VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST; ModeNumberPtr++) {
|
|
//
|
|
// Make sure this is a mode number defined by the VESA VBE specification. If it isn'tm then skip this mode number.
|
|
//
|
|
if ((*ModeNumberPtr & VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA) == 0) {
|
|
continue;
|
|
}
|
|
//
|
|
// Get the information about the mode
|
|
//
|
|
gBS->SetMem (&Regs, sizeof (Regs), 0);
|
|
Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION;
|
|
Regs.X.CX = *ModeNumberPtr;
|
|
gBS->SetMem (BiosVideoPrivate->VbeModeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK), 0);
|
|
Regs.X.ES = EFI_SEGMENT ((UINTN)BiosVideoPrivate->VbeModeInformationBlock);
|
|
Regs.X.DI = EFI_OFFSET ((UINTN)BiosVideoPrivate->VbeModeInformationBlock);
|
|
|
|
LegacyBiosInt86 (0x10, &Regs);
|
|
|
|
//
|
|
// See if the call succeeded. If it didn't, then try the next mode.
|
|
//
|
|
if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
|
|
continue;
|
|
}
|
|
//
|
|
// See if the mode supports color. If it doesn't then try the next mode.
|
|
//
|
|
if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR) == 0) {
|
|
continue;
|
|
}
|
|
//
|
|
// See if the mode supports graphics. If it doesn't then try the next mode.
|
|
//
|
|
if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS) == 0) {
|
|
continue;
|
|
}
|
|
//
|
|
// See if the mode supports a linear frame buffer. If it doesn't then try the next mode.
|
|
//
|
|
if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER) == 0) {
|
|
continue;
|
|
}
|
|
//
|
|
// See if the mode supports 32 bit color. If it doesn't then try the next mode.
|
|
// 32 bit mode can be implemented by 24 Bits Per Pixels. Also make sure the
|
|
// number of bits per pixel is a multiple of 8 or more than 32 bits per pixel
|
|
//
|
|
if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel < 24) {
|
|
continue;
|
|
}
|
|
|
|
if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel > 32) {
|
|
continue;
|
|
}
|
|
|
|
if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel % 8) != 0) {
|
|
continue;
|
|
}
|
|
//
|
|
// See if the physical base pointer for the linear mode is valid. If it isn't then try the next mode.
|
|
//
|
|
if (BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr == 0) {
|
|
continue;
|
|
}
|
|
//
|
|
// See if the resolution is 1024x768, 800x600, or 640x480
|
|
//
|
|
ModeFound = FALSE;
|
|
if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 1024 &&
|
|
BiosVideoPrivate->VbeModeInformationBlock->YResolution == 768
|
|
) {
|
|
ModeFound = TRUE;
|
|
}
|
|
|
|
if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 800 &&
|
|
BiosVideoPrivate->VbeModeInformationBlock->YResolution == 600
|
|
) {
|
|
ModeFound = TRUE;
|
|
}
|
|
|
|
if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 640 &&
|
|
BiosVideoPrivate->VbeModeInformationBlock->YResolution == 480
|
|
) {
|
|
ModeFound = TRUE;
|
|
}
|
|
|
|
if (!ModeFound) {
|
|
continue;
|
|
}
|
|
//
|
|
// Add mode to the list of available modes
|
|
//
|
|
BiosVideoPrivate->MaxMode++;
|
|
Status = gBS->AllocatePool (
|
|
EfiBootServicesData,
|
|
BiosVideoPrivate->MaxMode * sizeof (BIOS_VIDEO_MODE_DATA),
|
|
(VOID **) &ModeBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Done;
|
|
}
|
|
|
|
if (BiosVideoPrivate->MaxMode > 1) {
|
|
gBS->CopyMem (
|
|
ModeBuffer,
|
|
BiosVideoPrivate->ModeData,
|
|
(BiosVideoPrivate->MaxMode - 1) * sizeof (BIOS_VIDEO_MODE_DATA)
|
|
);
|
|
}
|
|
|
|
if (BiosVideoPrivate->ModeData != NULL) {
|
|
gBS->FreePool (BiosVideoPrivate->ModeData);
|
|
}
|
|
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].VbeModeNumber = *ModeNumberPtr;
|
|
if (BiosVideoPrivate->VbeInformationBlock->VESAVersion >= VESA_BIOS_EXTENSIONS_VERSION_3_0) {
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->LinBytesPerScanLine;
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].Red.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRedFieldPosition;
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRedMaskSize) - 1);
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->LinBlueFieldPosition;
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinBlueMaskSize) - 1);
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].Green.Position = BiosVideoPrivate->VbeModeInformationBlock->LinGreenFieldPosition;
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinGreenMaskSize) - 1);
|
|
|
|
} else {
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->BytesPerScanLine;
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].Red.Position = BiosVideoPrivate->VbeModeInformationBlock->RedFieldPosition;
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RedMaskSize) - 1);
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->BlueFieldPosition;
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->BlueMaskSize) - 1);
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].Green.Position = BiosVideoPrivate->VbeModeInformationBlock->GreenFieldPosition;
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->GreenMaskSize) - 1);
|
|
|
|
}
|
|
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].LinearFrameBuffer = (VOID *) (UINTN)BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr;
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
|
|
|
|
if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel >= 24) {
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].ColorDepth = 32;
|
|
} else {
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].ColorDepth = BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel;
|
|
}
|
|
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].BitsPerPixel = BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel;
|
|
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].RefreshRate = 60;
|
|
|
|
BiosVideoPrivate->ModeData = ModeBuffer;
|
|
}
|
|
//
|
|
// Check to see if we found any modes that are compatible with UGA DRAW
|
|
//
|
|
if (BiosVideoPrivate->MaxMode == 0) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
goto Done;
|
|
}
|
|
//
|
|
// Find the best mode to initialize
|
|
//
|
|
Status = BiosVideoUgaDrawSetMode (&BiosVideoPrivate->UgaDraw, 1024, 768, 32, 60);
|
|
//Status = BiosVideoUgaDrawSetMode (&BiosVideoPrivate->UgaDraw, 800, 600, 32, 60);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = BiosVideoUgaDrawSetMode (&BiosVideoPrivate->UgaDraw, 800, 600, 32, 60);
|
|
//Status = BiosVideoUgaDrawSetMode (&BiosVideoPrivate->UgaDraw, 1024, 768, 32, 60);
|
|
if (EFI_ERROR (Status)) {
|
|
Status = BiosVideoUgaDrawSetMode (&BiosVideoPrivate->UgaDraw, 640, 480, 32, 60);
|
|
for (Index = 0; EFI_ERROR (Status) && Index < BiosVideoPrivate->MaxMode; Index++) {
|
|
Status = BiosVideoUgaDrawSetMode (
|
|
&BiosVideoPrivate->UgaDraw,
|
|
BiosVideoPrivate->ModeData[Index].HorizontalResolution,
|
|
BiosVideoPrivate->ModeData[Index].VerticalResolution,
|
|
BiosVideoPrivate->ModeData[Index].ColorDepth,
|
|
BiosVideoPrivate->ModeData[Index].RefreshRate
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
Done:
|
|
//
|
|
// If there was an error, then free the mode structure
|
|
//
|
|
if (EFI_ERROR (Status)) {
|
|
if (BiosVideoPrivate->ModeData != NULL) {
|
|
gBS->FreePool (BiosVideoPrivate->ModeData);
|
|
BiosVideoPrivate->ModeData = NULL;
|
|
BiosVideoPrivate->MaxMode = 0;
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
BiosVideoCheckForVga (
|
|
IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check for VGA device
|
|
|
|
Arguments:
|
|
|
|
BiosVideoPrivate - Pointer to BIOS_VIDEO_DEV structure
|
|
|
|
Returns:
|
|
|
|
EFI_SUCCESS - Standard VGA device found
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
BIOS_VIDEO_MODE_DATA *ModeBuffer;
|
|
|
|
//
|
|
// Fill in the UGA Draw Protocol
|
|
//
|
|
BiosVideoPrivate->UgaDraw.GetMode = BiosVideoUgaDrawGetMode;
|
|
BiosVideoPrivate->UgaDraw.SetMode = BiosVideoUgaDrawSetMode;
|
|
BiosVideoPrivate->UgaDraw.Blt = BiosVideoUgaDrawVgaBlt;
|
|
|
|
//
|
|
// Add mode to the list of available modes
|
|
//
|
|
BiosVideoPrivate->MaxMode++;
|
|
Status = gBS->AllocatePool (
|
|
EfiBootServicesData,
|
|
BiosVideoPrivate->MaxMode * sizeof (BIOS_VIDEO_MODE_DATA),
|
|
(VOID **) &ModeBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (BiosVideoPrivate->MaxMode > 1) {
|
|
gBS->CopyMem (
|
|
ModeBuffer,
|
|
BiosVideoPrivate->ModeData,
|
|
(BiosVideoPrivate->MaxMode - 1) * sizeof (BIOS_VIDEO_MODE_DATA)
|
|
);
|
|
}
|
|
|
|
if (BiosVideoPrivate->ModeData != NULL) {
|
|
gBS->FreePool (BiosVideoPrivate->ModeData);
|
|
}
|
|
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].VbeModeNumber = 0x0012;
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].BytesPerScanLine = 640;
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].LinearFrameBuffer = (VOID *) (UINTN)(0xa0000);
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].HorizontalResolution = 640;
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].VerticalResolution = 480;
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].ColorDepth = 32;
|
|
ModeBuffer[BiosVideoPrivate->MaxMode - 1].RefreshRate = 60;
|
|
|
|
BiosVideoPrivate->ModeData = ModeBuffer;
|
|
|
|
//
|
|
// Test to see if the Video Adapter support the 640x480 16 color mode
|
|
//
|
|
Status = BiosVideoUgaDrawSetMode (&BiosVideoPrivate->UgaDraw, 640, 480, 32, 60);
|
|
|
|
//
|
|
// If there was an error, then free the mode structure
|
|
//
|
|
if (EFI_ERROR (Status)) {
|
|
BiosVideoPrivate->MaxMode = 0;
|
|
if (BiosVideoPrivate->ModeData != NULL) {
|
|
gBS->FreePool (BiosVideoPrivate->ModeData);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
//
|
|
// UGA Protocol Member Functions for VESA BIOS Extensions
|
|
//
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BiosVideoUgaDrawGetMode (
|
|
IN EFI_UGA_DRAW_PROTOCOL *This,
|
|
OUT UINT32 *HorizontalResolution,
|
|
OUT UINT32 *VerticalResolution,
|
|
OUT UINT32 *ColorDepth,
|
|
OUT UINT32 *RefreshRate
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
UGA protocol interface to get video mode
|
|
|
|
Arguments:
|
|
|
|
This - Pointer to UGA draw protocol instance
|
|
HorizontalResolution - Horizontal Resolution, in pixels
|
|
VerticalResolution - Vertical Resolution, in pixels
|
|
ColorDepth - Bit number used to represent color value of a pixel
|
|
RefreshRate - Refresh rate, in Hertz
|
|
|
|
Returns:
|
|
|
|
EFI_DEVICE_ERROR - Hardware need starting
|
|
EFI_INVALID_PARAMETER - Invalid parameter passed in
|
|
EFI_SUCCESS - Video mode query successfully
|
|
|
|
--*/
|
|
{
|
|
BIOS_VIDEO_DEV *BiosVideoPrivate;
|
|
|
|
BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_UGA_DRAW_THIS (This);
|
|
|
|
if (BiosVideoPrivate->HardwareNeedsStarting) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
|
|
if (HorizontalResolution == NULL || VerticalResolution == NULL || ColorDepth == NULL || RefreshRate == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
*HorizontalResolution = BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].HorizontalResolution;
|
|
*VerticalResolution = BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].VerticalResolution;
|
|
*ColorDepth = BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].ColorDepth;
|
|
*RefreshRate = BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].RefreshRate;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BiosVideoUgaDrawSetMode (
|
|
IN EFI_UGA_DRAW_PROTOCOL *This,
|
|
IN UINT32 HorizontalResolution,
|
|
IN UINT32 VerticalResolution,
|
|
IN UINT32 ColorDepth,
|
|
IN UINT32 RefreshRate
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
UGA draw protocol interface to set video mode
|
|
|
|
Arguments:
|
|
|
|
This - Pointer to UGA draw protocol instance
|
|
HorizontalResolution - Horizontal Resolution, in pixels
|
|
VerticalResolution - Vertical Resolution, in pixels
|
|
ColorDepth - Bit number used to represent color value of a pixel
|
|
RefreshRate - Refresh rate, in Hertz
|
|
|
|
Returns:
|
|
|
|
EFI_DEVICE_ERROR - Device error
|
|
EFI_SUCCESS - Video mode set successfully
|
|
EFI_UNSUPPORTED - Cannot support this video mode
|
|
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
BIOS_VIDEO_DEV *BiosVideoPrivate;
|
|
UINTN Index;
|
|
EFI_IA32_REGISTER_SET Regs;
|
|
|
|
BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_UGA_DRAW_THIS (This);
|
|
|
|
for (Index = 0; Index < BiosVideoPrivate->MaxMode; Index++) {
|
|
|
|
if (HorizontalResolution != BiosVideoPrivate->ModeData[Index].HorizontalResolution) {
|
|
continue;
|
|
}
|
|
|
|
if (VerticalResolution != BiosVideoPrivate->ModeData[Index].VerticalResolution) {
|
|
continue;
|
|
}
|
|
|
|
if (ColorDepth != BiosVideoPrivate->ModeData[Index].ColorDepth) {
|
|
continue;
|
|
}
|
|
|
|
if (RefreshRate != BiosVideoPrivate->ModeData[Index].RefreshRate) {
|
|
continue;
|
|
}
|
|
|
|
if (BiosVideoPrivate->LineBuffer) {
|
|
gBS->FreePool (BiosVideoPrivate->LineBuffer);
|
|
}
|
|
|
|
if (BiosVideoPrivate->VgaFrameBuffer) {
|
|
gBS->FreePool (BiosVideoPrivate->VgaFrameBuffer);
|
|
}
|
|
|
|
if (BiosVideoPrivate->VbeFrameBuffer) {
|
|
gBS->FreePool (BiosVideoPrivate->VbeFrameBuffer);
|
|
}
|
|
|
|
BiosVideoPrivate->LineBuffer = NULL;
|
|
Status = gBS->AllocatePool (
|
|
EfiBootServicesData,
|
|
BiosVideoPrivate->ModeData[Index].BytesPerScanLine,
|
|
(VOID**)&BiosVideoPrivate->LineBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Clear all registers
|
|
//
|
|
gBS->SetMem (&Regs, sizeof (Regs), 0);
|
|
|
|
if (BiosVideoPrivate->ModeData[Index].VbeModeNumber < 0x100) {
|
|
//
|
|
// Allocate a working buffer for BLT operations to the VGA frame buffer
|
|
//
|
|
BiosVideoPrivate->VgaFrameBuffer = NULL;
|
|
Status = gBS->AllocatePool (
|
|
EfiBootServicesData,
|
|
4 * 480 * 80,
|
|
(VOID**)&BiosVideoPrivate->VgaFrameBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Set VGA Mode
|
|
//
|
|
Regs.X.AX = BiosVideoPrivate->ModeData[Index].VbeModeNumber;
|
|
LegacyBiosInt86 (0x10, &Regs);
|
|
|
|
} else {
|
|
//
|
|
// Allocate a working buffer for BLT operations to the VBE frame buffer
|
|
//
|
|
BiosVideoPrivate->VbeFrameBuffer = NULL;
|
|
Status = gBS->AllocatePool (
|
|
EfiBootServicesData,
|
|
BiosVideoPrivate->ModeData[Index].BytesPerScanLine * BiosVideoPrivate->ModeData[Index].VerticalResolution,
|
|
(VOID**)&BiosVideoPrivate->VbeFrameBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Set VBE mode
|
|
//
|
|
Regs.X.AX = VESA_BIOS_EXTENSIONS_SET_MODE;
|
|
Regs.X.BX = (UINT16) (BiosVideoPrivate->ModeData[Index].VbeModeNumber | VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER);
|
|
gBS->SetMem (BiosVideoPrivate->VbeCrtcInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK), 0);
|
|
Regs.X.ES = EFI_SEGMENT ((UINTN)BiosVideoPrivate->VbeCrtcInformationBlock);
|
|
Regs.X.DI = EFI_OFFSET ((UINTN)BiosVideoPrivate->VbeCrtcInformationBlock);
|
|
LegacyBiosInt86 (0x10, &Regs);
|
|
|
|
//
|
|
// Check to see if the call succeeded
|
|
//
|
|
if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
//
|
|
// Initialize the state of the VbeFrameBuffer
|
|
//
|
|
Status = BiosVideoPrivate->PciIo->Mem.Read (
|
|
BiosVideoPrivate->PciIo,
|
|
EfiPciIoWidthUint32,
|
|
EFI_PCI_IO_PASS_THROUGH_BAR,
|
|
(UINT64) (UINTN) BiosVideoPrivate->ModeData[Index].LinearFrameBuffer,
|
|
(BiosVideoPrivate->ModeData[Index].BytesPerScanLine * BiosVideoPrivate->ModeData[Index].VerticalResolution) >> 2,
|
|
BiosVideoPrivate->VbeFrameBuffer
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
BiosVideoPrivate->CurrentMode = Index;
|
|
|
|
BiosVideoPrivate->HardwareNeedsStarting = FALSE;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
VOID
|
|
CopyVideoBuffer (
|
|
IN EFI_PCI_IO_PROTOCOL *PciIo,
|
|
IN UINT8 *VbeBuffer,
|
|
IN VOID *MemAddress,
|
|
IN UINTN DestinationX,
|
|
IN UINTN DestinationY,
|
|
IN UINTN TotalBytes,
|
|
IN UINT32 VbePixelWidth,
|
|
IN UINTN BytesPerScanLine
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update physical frame buffer, copy 4 bytes block, then copy remaining bytes.
|
|
|
|
Arguments:
|
|
|
|
PciIo - The pointer of EFI_PCI_IO_PROTOCOL
|
|
VbeBuffer - The data to transfer to screen
|
|
MemAddress - Physical frame buffer base address
|
|
DestinationX - The X coordinate of the destination for BltOperation
|
|
DestinationY - The Y coordinate of the destination for BltOperation
|
|
TotalBytes - The total bytes of copy
|
|
VbePixelWidth - Bytes per pixel
|
|
BytesPerScanLine - Bytes per scan line
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
UINTN FrameBufferAddr;
|
|
UINTN CopyBlockNum;
|
|
UINTN RemainingBytes;
|
|
UINTN UnalignedBytes;
|
|
EFI_STATUS Status;
|
|
|
|
FrameBufferAddr = (UINTN) MemAddress + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth;
|
|
|
|
//
|
|
// If TotalBytes is less than 4 bytes, only start byte copy.
|
|
//
|
|
if (TotalBytes < 4) {
|
|
Status = PciIo->Mem.Write (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
EFI_PCI_IO_PASS_THROUGH_BAR,
|
|
(UINT64) FrameBufferAddr,
|
|
TotalBytes,
|
|
VbeBuffer
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// If VbeBuffer is not 4-byte aligned, start byte copy.
|
|
//
|
|
UnalignedBytes = (4 - ((UINTN) VbeBuffer & 0x3)) & 0x3;
|
|
|
|
if (UnalignedBytes != 0) {
|
|
Status = PciIo->Mem.Write (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
EFI_PCI_IO_PASS_THROUGH_BAR,
|
|
(UINT64) FrameBufferAddr,
|
|
UnalignedBytes,
|
|
VbeBuffer
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
FrameBufferAddr += UnalignedBytes;
|
|
VbeBuffer += UnalignedBytes;
|
|
}
|
|
|
|
//
|
|
// Calculate 4-byte block count and remaining bytes.
|
|
//
|
|
CopyBlockNum = (TotalBytes - UnalignedBytes) >> 2;
|
|
RemainingBytes = (TotalBytes - UnalignedBytes) & 3;
|
|
|
|
//
|
|
// Copy 4-byte block and remaining bytes to physical frame buffer.
|
|
//
|
|
if (CopyBlockNum != 0) {
|
|
Status = PciIo->Mem.Write (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
EFI_PCI_IO_PASS_THROUGH_BAR,
|
|
(UINT64) FrameBufferAddr,
|
|
CopyBlockNum,
|
|
VbeBuffer
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|
|
|
|
if (RemainingBytes != 0) {
|
|
FrameBufferAddr += (CopyBlockNum << 2);
|
|
VbeBuffer += (CopyBlockNum << 2);
|
|
Status = PciIo->Mem.Write (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
EFI_PCI_IO_PASS_THROUGH_BAR,
|
|
(UINT64) FrameBufferAddr,
|
|
RemainingBytes,
|
|
VbeBuffer
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|
|
}
|
|
|
|
//
|
|
// BUGBUG : Add Blt for 16 bit color, 15 bit color, and 8 bit color modes
|
|
//
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BiosVideoUgaDrawVbeBlt (
|
|
IN EFI_UGA_DRAW_PROTOCOL *This,
|
|
IN EFI_UGA_PIXEL *BltBuffer, OPTIONAL
|
|
IN EFI_UGA_BLT_OPERATION BltOperation,
|
|
IN UINTN SourceX,
|
|
IN UINTN SourceY,
|
|
IN UINTN DestinationX,
|
|
IN UINTN DestinationY,
|
|
IN UINTN Width,
|
|
IN UINTN Height,
|
|
IN UINTN Delta
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
UGA draw protocol instance to block transfer for VBE device
|
|
|
|
Arguments:
|
|
|
|
This - Pointer to UGA draw protocol instance
|
|
BltBuffer - The data to transfer to screen
|
|
BltOperation - The operation to perform
|
|
SourceX - The X coordinate of the source for BltOperation
|
|
SourceY - The Y coordinate of the source for BltOperation
|
|
DestinationX - The X coordinate of the destination for BltOperation
|
|
DestinationY - The Y coordinate of the destination for BltOperation
|
|
Width - The width of a rectangle in the blt rectangle in pixels
|
|
Height - The height of a rectangle in the blt rectangle in pixels
|
|
Delta - Not used for EfiUgaVideoFill and EfiUgaVideoToVideo operation.
|
|
If a Delta of 0 is used, the entire BltBuffer will be operated on.
|
|
If a subrectangle of the BltBuffer is used, then Delta represents
|
|
the number of bytes in a row of the BltBuffer.
|
|
|
|
Returns:
|
|
|
|
EFI_INVALID_PARAMETER - Invalid parameter passed in
|
|
EFI_SUCCESS - Blt operation success
|
|
|
|
--*/
|
|
{
|
|
BIOS_VIDEO_DEV *BiosVideoPrivate;
|
|
BIOS_VIDEO_MODE_DATA *Mode;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
EFI_TPL OriginalTPL;
|
|
UINTN DstY;
|
|
UINTN SrcY;
|
|
UINTN DstX;
|
|
EFI_UGA_PIXEL *Blt;
|
|
VOID *MemAddress;
|
|
EFI_UGA_PIXEL *VbeFrameBuffer;
|
|
UINTN BytesPerScanLine;
|
|
UINTN Index;
|
|
UINT8 *VbeBuffer;
|
|
UINT8 *VbeBuffer1;
|
|
UINT8 *BltUint8;
|
|
UINT32 VbePixelWidth;
|
|
UINT32 Pixel;
|
|
UINTN TotalBytes;
|
|
|
|
BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_UGA_DRAW_THIS (This);
|
|
Mode = &BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode];
|
|
PciIo = BiosVideoPrivate->PciIo;
|
|
|
|
VbeFrameBuffer = BiosVideoPrivate->VbeFrameBuffer;
|
|
MemAddress = Mode->LinearFrameBuffer;
|
|
BytesPerScanLine = Mode->BytesPerScanLine;
|
|
VbePixelWidth = Mode->BitsPerPixel / 8;
|
|
BltUint8 = (UINT8 *) BltBuffer;
|
|
TotalBytes = Width * VbePixelWidth;
|
|
|
|
if ((BltOperation < EfiUgaVideoFill) || (BltOperation >= EfiUgaBltMax)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (Width == 0 || Height == 0) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
//
|
|
// We need to fill the Virtual Screen buffer with the blt data.
|
|
// The virtual screen is upside down, as the first row is the bootom row of
|
|
// the image.
|
|
//
|
|
if (BltOperation == EfiUgaVideoToBltBuffer) {
|
|
//
|
|
// Video to BltBuffer: Source is Video, destination is BltBuffer
|
|
//
|
|
if (SourceY + Height > Mode->VerticalResolution) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (SourceX + Width > Mode->HorizontalResolution) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
} else {
|
|
//
|
|
// BltBuffer to Video: Source is BltBuffer, destination is Video
|
|
//
|
|
if (DestinationY + Height > Mode->VerticalResolution) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (DestinationX + Width > Mode->HorizontalResolution) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
//
|
|
// If Delta is zero, then the entire BltBuffer is being used, so Delta
|
|
// is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
|
|
// the number of bytes in each row can be computed.
|
|
//
|
|
if (Delta == 0) {
|
|
Delta = Width * sizeof (EFI_UGA_PIXEL);
|
|
}
|
|
//
|
|
// We have to raise to TPL Notify, so we make an atomic write the frame buffer.
|
|
// We would not want a timer based event (Cursor, ...) to come in while we are
|
|
// doing this operation.
|
|
//
|
|
OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
|
|
|
|
switch (BltOperation) {
|
|
case EfiUgaVideoToBltBuffer:
|
|
for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {
|
|
Blt = (EFI_UGA_PIXEL *) (BltUint8 + DstY * Delta + DestinationX * sizeof (EFI_UGA_PIXEL));
|
|
//
|
|
// Shuffle the packed bytes in the hardware buffer to match EFI_UGA_PIXEL
|
|
//
|
|
VbeBuffer = ((UINT8 *) VbeFrameBuffer + (SrcY * BytesPerScanLine + SourceX * VbePixelWidth));
|
|
for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
|
|
Pixel = *(UINT32 *) (VbeBuffer);
|
|
Blt->Red = (UINT8) ((Pixel >> Mode->Red.Position) & Mode->Red.Mask);
|
|
Blt->Blue = (UINT8) ((Pixel >> Mode->Blue.Position) & Mode->Blue.Mask);
|
|
Blt->Green = (UINT8) ((Pixel >> Mode->Green.Position) & Mode->Green.Mask);
|
|
Blt->Reserved = 0;
|
|
Blt++;
|
|
VbeBuffer += VbePixelWidth;
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case EfiUgaVideoToVideo:
|
|
for (Index = 0; Index < Height; Index++) {
|
|
if (DestinationY <= SourceY) {
|
|
SrcY = SourceY + Index;
|
|
DstY = DestinationY + Index;
|
|
} else {
|
|
SrcY = SourceY + Height - Index - 1;
|
|
DstY = DestinationY + Height - Index - 1;
|
|
}
|
|
|
|
VbeBuffer = ((UINT8 *) VbeFrameBuffer + DstY * BytesPerScanLine + DestinationX * VbePixelWidth);
|
|
VbeBuffer1 = ((UINT8 *) VbeFrameBuffer + SrcY * BytesPerScanLine + SourceX * VbePixelWidth);
|
|
|
|
gBS->CopyMem (
|
|
VbeBuffer,
|
|
VbeBuffer1,
|
|
TotalBytes
|
|
);
|
|
|
|
//
|
|
// Update physical frame buffer.
|
|
//
|
|
CopyVideoBuffer (
|
|
PciIo,
|
|
VbeBuffer,
|
|
MemAddress,
|
|
DestinationX,
|
|
DstY,
|
|
TotalBytes,
|
|
VbePixelWidth,
|
|
BytesPerScanLine
|
|
);
|
|
}
|
|
break;
|
|
|
|
case EfiUgaVideoFill:
|
|
VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
|
|
Blt = (EFI_UGA_PIXEL *) BltUint8;
|
|
//
|
|
// Shuffle the RGB fields in EFI_UGA_PIXEL to match the hardware buffer
|
|
//
|
|
Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
|
|
(
|
|
(Blt->Green & Mode->Green.Mask) <<
|
|
Mode->Green.Position
|
|
) |
|
|
((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
|
|
|
|
for (Index = 0; Index < Width; Index++) {
|
|
gBS->CopyMem (
|
|
VbeBuffer,
|
|
&Pixel,
|
|
VbePixelWidth
|
|
);
|
|
VbeBuffer += VbePixelWidth;
|
|
}
|
|
|
|
VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
|
|
for (DstY = DestinationY + 1; DstY < (Height + DestinationY); DstY++) {
|
|
gBS->CopyMem (
|
|
(VOID *) ((UINTN) VbeFrameBuffer + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth),
|
|
VbeBuffer,
|
|
TotalBytes
|
|
);
|
|
}
|
|
for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
|
|
//
|
|
// Update physical frame buffer.
|
|
//
|
|
CopyVideoBuffer (
|
|
PciIo,
|
|
VbeBuffer,
|
|
MemAddress,
|
|
DestinationX,
|
|
DstY,
|
|
TotalBytes,
|
|
VbePixelWidth,
|
|
BytesPerScanLine
|
|
);
|
|
}
|
|
|
|
break;
|
|
|
|
case EfiUgaBltBufferToVideo:
|
|
for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
|
|
Blt = (EFI_UGA_PIXEL *) (BltUint8 + (SrcY * Delta) + (SourceX) * sizeof (EFI_UGA_PIXEL));
|
|
VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
|
|
for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
|
|
//
|
|
// Shuffle the RGB fields in EFI_UGA_PIXEL to match the hardware buffer
|
|
//
|
|
Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
|
|
((Blt->Green & Mode->Green.Mask) << Mode->Green.Position) |
|
|
((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
|
|
gBS->CopyMem (
|
|
VbeBuffer,
|
|
&Pixel,
|
|
VbePixelWidth
|
|
);
|
|
Blt++;
|
|
VbeBuffer += VbePixelWidth;
|
|
}
|
|
|
|
VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
|
|
|
|
//
|
|
// Update physical frame buffer.
|
|
//
|
|
CopyVideoBuffer (
|
|
PciIo,
|
|
VbeBuffer,
|
|
MemAddress,
|
|
DestinationX,
|
|
DstY,
|
|
TotalBytes,
|
|
VbePixelWidth,
|
|
BytesPerScanLine
|
|
);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
gBS->RestoreTPL (OriginalTPL);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
STATIC
|
|
VOID
|
|
WriteGraphicsController (
|
|
IN EFI_PCI_IO_PROTOCOL *PciIo,
|
|
IN UINTN Address,
|
|
IN UINTN Data
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Write graphics controller registers
|
|
|
|
Arguments:
|
|
|
|
PciIo - Pointer to PciIo protocol instance of the controller
|
|
Address - Register address
|
|
Data - Data to be written to register
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
Address = Address | (Data << 8);
|
|
PciIo->Io.Write (
|
|
PciIo,
|
|
EfiPciIoWidthUint16,
|
|
EFI_PCI_IO_PASS_THROUGH_BAR,
|
|
VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER,
|
|
1,
|
|
&Address
|
|
);
|
|
}
|
|
|
|
VOID
|
|
VgaReadBitPlanes (
|
|
EFI_PCI_IO_PROTOCOL *PciIo,
|
|
UINT8 *HardwareBuffer,
|
|
UINT8 *MemoryBuffer,
|
|
UINTN WidthInBytes,
|
|
UINTN Height
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read the four bit plane of VGA frame buffer
|
|
|
|
Arguments:
|
|
|
|
PciIo - Pointer to PciIo protocol instance of the controller
|
|
HardwareBuffer - Hardware VGA frame buffer address
|
|
MemoryBuffer - Memory buffer address
|
|
WidthInBytes - Number of bytes in a line to read
|
|
Height - Height of the area to read
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
UINTN BitPlane;
|
|
UINTN Rows;
|
|
UINTN FrameBufferOffset;
|
|
UINT8 *Source;
|
|
UINT8 *Destination;
|
|
|
|
//
|
|
// Program the Mode Register Write mode 0, Read mode 0
|
|
//
|
|
WriteGraphicsController (
|
|
PciIo,
|
|
VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
|
|
VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0
|
|
);
|
|
|
|
for (BitPlane = 0, FrameBufferOffset = 0;
|
|
BitPlane < VGA_NUMBER_OF_BIT_PLANES;
|
|
BitPlane++, FrameBufferOffset += VGA_BYTES_PER_BIT_PLANE
|
|
) {
|
|
//
|
|
// Program the Read Map Select Register to select the correct bit plane
|
|
//
|
|
WriteGraphicsController (
|
|
PciIo,
|
|
VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER,
|
|
BitPlane
|
|
);
|
|
|
|
Source = HardwareBuffer;
|
|
Destination = MemoryBuffer + FrameBufferOffset;
|
|
|
|
for (Rows = 0; Rows < Height; Rows++, Source += VGA_BYTES_PER_SCAN_LINE, Destination += VGA_BYTES_PER_SCAN_LINE) {
|
|
PciIo->Mem.Read (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
EFI_PCI_IO_PASS_THROUGH_BAR,
|
|
(UINT64) (UINTN)Source,
|
|
WidthInBytes,
|
|
(VOID *) Destination
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID
|
|
VgaConvertToUgaColor (
|
|
UINT8 *MemoryBuffer,
|
|
UINTN X,
|
|
UINTN Y,
|
|
EFI_UGA_PIXEL *BltBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Internal routine to convert VGA color to UGA color
|
|
|
|
Arguments:
|
|
|
|
MemoryBuffer - Buffer containing VGA color
|
|
X - The X coordinate of pixel on screen
|
|
Y - The Y coordinate of pixel on screen
|
|
BltBuffer - Buffer to contain converted UGA color
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
UINTN Mask;
|
|
UINTN Bit;
|
|
UINTN Color;
|
|
|
|
MemoryBuffer += ((Y << 6) + (Y << 4) + (X >> 3));
|
|
Mask = mVgaBitMaskTable[X & 0x07];
|
|
for (Bit = 0x01, Color = 0; Bit < 0x10; Bit <<= 1, MemoryBuffer += VGA_BYTES_PER_BIT_PLANE) {
|
|
if (*MemoryBuffer & Mask) {
|
|
Color |= Bit;
|
|
}
|
|
}
|
|
|
|
*BltBuffer = mVgaColorToUgaColor[Color];
|
|
}
|
|
|
|
UINT8
|
|
VgaConvertColor (
|
|
IN EFI_UGA_PIXEL *BltBuffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Internal routine to convert UGA color to VGA color
|
|
|
|
Arguments:
|
|
|
|
BltBuffer - buffer containing UGA color
|
|
|
|
Returns:
|
|
|
|
Converted VGA color
|
|
|
|
--*/
|
|
{
|
|
UINT8 Color;
|
|
|
|
Color = (UINT8) ((BltBuffer->Blue >> 7) | ((BltBuffer->Green >> 6) & 0x02) | ((BltBuffer->Red >> 5) & 0x04));
|
|
if ((BltBuffer->Red + BltBuffer->Green + BltBuffer->Blue) > 0x180) {
|
|
Color |= 0x08;
|
|
}
|
|
|
|
return Color;
|
|
}
|
|
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BiosVideoUgaDrawVgaBlt (
|
|
IN EFI_UGA_DRAW_PROTOCOL *This,
|
|
IN EFI_UGA_PIXEL *BltBuffer, OPTIONAL
|
|
IN EFI_UGA_BLT_OPERATION BltOperation,
|
|
IN UINTN SourceX,
|
|
IN UINTN SourceY,
|
|
IN UINTN DestinationX,
|
|
IN UINTN DestinationY,
|
|
IN UINTN Width,
|
|
IN UINTN Height,
|
|
IN UINTN Delta
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
UGA draw protocol instance to block transfer for VGA device
|
|
|
|
Arguments:
|
|
|
|
This - Pointer to UGA draw protocol instance
|
|
BltBuffer - The data to transfer to screen
|
|
BltOperation - The operation to perform
|
|
SourceX - The X coordinate of the source for BltOperation
|
|
SourceY - The Y coordinate of the source for BltOperation
|
|
DestinationX - The X coordinate of the destination for BltOperation
|
|
DestinationY - The Y coordinate of the destination for BltOperation
|
|
Width - The width of a rectangle in the blt rectangle in pixels
|
|
Height - The height of a rectangle in the blt rectangle in pixels
|
|
Delta - Not used for EfiUgaVideoFill and EfiUgaVideoToVideo operation.
|
|
If a Delta of 0 is used, the entire BltBuffer will be operated on.
|
|
If a subrectangle of the BltBuffer is used, then Delta represents
|
|
the number of bytes in a row of the BltBuffer.
|
|
|
|
Returns:
|
|
|
|
EFI_INVALID_PARAMETER - Invalid parameter passed in
|
|
EFI_SUCCESS - Blt operation success
|
|
|
|
--*/
|
|
{
|
|
BIOS_VIDEO_DEV *BiosVideoPrivate;
|
|
EFI_TPL OriginalTPL;
|
|
UINT8 *MemAddress;
|
|
UINTN BytesPerScanLine;
|
|
UINTN BytesPerBitPlane;
|
|
UINTN Bit;
|
|
UINTN Index;
|
|
UINTN Index1;
|
|
UINTN StartAddress;
|
|
UINTN Bytes;
|
|
UINTN Offset;
|
|
UINT8 LeftMask;
|
|
UINT8 RightMask;
|
|
UINTN Address;
|
|
UINTN AddressFix;
|
|
UINT8 *Address1;
|
|
UINT8 *SourceAddress;
|
|
UINT8 *DestinationAddress;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
UINT8 Data;
|
|
UINT8 PixelColor;
|
|
UINT8 *VgaFrameBuffer;
|
|
UINTN SourceOffset;
|
|
UINTN SourceWidth;
|
|
UINTN Rows;
|
|
UINTN Columns;
|
|
UINTN X;
|
|
UINTN Y;
|
|
|
|
BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_UGA_DRAW_THIS (This);
|
|
|
|
PciIo = BiosVideoPrivate->PciIo;
|
|
MemAddress = BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].LinearFrameBuffer;
|
|
BytesPerScanLine = BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].BytesPerScanLine >> 3;
|
|
BytesPerBitPlane = BytesPerScanLine * BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].VerticalResolution;
|
|
VgaFrameBuffer = BiosVideoPrivate->VgaFrameBuffer;
|
|
|
|
if ((BltOperation < EfiUgaVideoFill) || (BltOperation >= EfiUgaBltMax)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (Width == 0 || Height == 0) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
//
|
|
// We need to fill the Virtual Screen buffer with the blt data.
|
|
// The virtual screen is upside down, as the first row is the bootom row of
|
|
// the image.
|
|
//
|
|
if (BltOperation == EfiUgaVideoToBltBuffer) {
|
|
//
|
|
// Video to BltBuffer: Source is Video, destination is BltBuffer
|
|
//
|
|
if (SourceY + Height > BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].VerticalResolution) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (SourceX + Width > BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].HorizontalResolution) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
} else {
|
|
//
|
|
// BltBuffer to Video: Source is BltBuffer, destination is Video
|
|
//
|
|
if (DestinationY + Height > BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].VerticalResolution) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (DestinationX + Width > BiosVideoPrivate->ModeData[BiosVideoPrivate->CurrentMode].HorizontalResolution) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
//
|
|
// If Delta is zero, then the entire BltBuffer is being used, so Delta
|
|
// is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
|
|
// the number of bytes in each row can be computed.
|
|
//
|
|
if (Delta == 0) {
|
|
Delta = Width * sizeof (EFI_UGA_PIXEL);
|
|
}
|
|
//
|
|
// We have to raise to TPL Notify, so we make an atomic write the frame buffer.
|
|
// We would not want a timer based event (Cursor, ...) to come in while we are
|
|
// doing this operation.
|
|
//
|
|
OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
|
|
|
|
//
|
|
// Compute some values we need for VGA
|
|
//
|
|
switch (BltOperation) {
|
|
case EfiUgaVideoToBltBuffer:
|
|
|
|
SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
|
|
SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
|
|
|
|
//
|
|
// Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
|
|
//
|
|
VgaReadBitPlanes (
|
|
PciIo,
|
|
MemAddress + SourceOffset,
|
|
VgaFrameBuffer + SourceOffset,
|
|
SourceWidth,
|
|
Height
|
|
);
|
|
|
|
//
|
|
// Convert VGA Bit Planes to a UGA 32-bit color value
|
|
//
|
|
BltBuffer += (DestinationY * (Delta >> 2) + DestinationX);
|
|
for (Rows = 0, Y = SourceY; Rows < Height; Rows++, Y++, BltBuffer += (Delta >> 2)) {
|
|
for (Columns = 0, X = SourceX; Columns < Width; Columns++, X++, BltBuffer++) {
|
|
VgaConvertToUgaColor (VgaFrameBuffer, X, Y, BltBuffer);
|
|
}
|
|
|
|
BltBuffer -= Width;
|
|
}
|
|
|
|
break;
|
|
|
|
case EfiUgaVideoToVideo:
|
|
//
|
|
// Check for an aligned Video to Video operation
|
|
//
|
|
if ((SourceX & 0x07) == 0x00 && (DestinationX & 0x07) == 0x00 && (Width & 0x07) == 0x00) {
|
|
//
|
|
// Program the Mode Register Write mode 1, Read mode 0
|
|
//
|
|
WriteGraphicsController (
|
|
BiosVideoPrivate->PciIo,
|
|
VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
|
|
VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1
|
|
);
|
|
|
|
SourceAddress = (UINT8 *) (MemAddress + (SourceY << 6) + (SourceY << 4) + (SourceX >> 3));
|
|
DestinationAddress = (UINT8 *) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
|
|
Bytes = Width >> 3;
|
|
for (Index = 0, Offset = 0; Index < Height; Index++, Offset += BytesPerScanLine) {
|
|
PciIo->CopyMem (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
EFI_PCI_IO_PASS_THROUGH_BAR,
|
|
(UINT64) ((UINTN)DestinationAddress + Offset),
|
|
EFI_PCI_IO_PASS_THROUGH_BAR,
|
|
(UINT64) ((UINTN)SourceAddress + Offset),
|
|
Bytes
|
|
);
|
|
}
|
|
} else {
|
|
SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
|
|
SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
|
|
|
|
//
|
|
// Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
|
|
//
|
|
VgaReadBitPlanes (
|
|
PciIo,
|
|
MemAddress + SourceOffset,
|
|
VgaFrameBuffer + SourceOffset,
|
|
SourceWidth,
|
|
Height
|
|
);
|
|
}
|
|
|
|
break;
|
|
|
|
case EfiUgaVideoFill:
|
|
StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
|
|
Bytes = ((DestinationX + Width - 1) >> 3) - (DestinationX >> 3);
|
|
LeftMask = mVgaLeftMaskTable[DestinationX & 0x07];
|
|
RightMask = mVgaRightMaskTable[(DestinationX + Width - 1) & 0x07];
|
|
if (Bytes == 0) {
|
|
LeftMask &= RightMask;
|
|
RightMask = 0;
|
|
}
|
|
|
|
if (LeftMask == 0xff) {
|
|
StartAddress--;
|
|
Bytes++;
|
|
LeftMask = 0;
|
|
}
|
|
|
|
if (RightMask == 0xff) {
|
|
Bytes++;
|
|
RightMask = 0;
|
|
}
|
|
|
|
PixelColor = VgaConvertColor (BltBuffer);
|
|
|
|
//
|
|
// Program the Mode Register Write mode 2, Read mode 0
|
|
//
|
|
WriteGraphicsController (
|
|
BiosVideoPrivate->PciIo,
|
|
VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
|
|
VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
|
|
);
|
|
|
|
//
|
|
// Program the Data Rotate/Function Select Register to replace
|
|
//
|
|
WriteGraphicsController (
|
|
BiosVideoPrivate->PciIo,
|
|
VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
|
|
VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
|
|
);
|
|
|
|
if (LeftMask != 0) {
|
|
//
|
|
// Program the BitMask register with the Left column mask
|
|
//
|
|
WriteGraphicsController (
|
|
BiosVideoPrivate->PciIo,
|
|
VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
|
|
LeftMask
|
|
);
|
|
|
|
for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
|
|
//
|
|
// Read data from the bit planes into the latches
|
|
//
|
|
PciIo->Mem.Read (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
EFI_PCI_IO_PASS_THROUGH_BAR,
|
|
(UINT64) Address,
|
|
1,
|
|
&Data
|
|
);
|
|
//
|
|
// Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
|
|
//
|
|
PciIo->Mem.Write (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
EFI_PCI_IO_PASS_THROUGH_BAR,
|
|
(UINT64) Address,
|
|
1,
|
|
&PixelColor
|
|
);
|
|
}
|
|
}
|
|
|
|
if (Bytes > 1) {
|
|
//
|
|
// Program the BitMask register with the middle column mask of 0xff
|
|
//
|
|
WriteGraphicsController (
|
|
BiosVideoPrivate->PciIo,
|
|
VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
|
|
0xff
|
|
);
|
|
|
|
for (Index = 0, Address = StartAddress + 1; Index < Height; Index++, Address += BytesPerScanLine) {
|
|
PciIo->Mem.Write (
|
|
PciIo,
|
|
EfiPciIoWidthFillUint8,
|
|
EFI_PCI_IO_PASS_THROUGH_BAR,
|
|
(UINT64) Address,
|
|
Bytes - 1,
|
|
&PixelColor
|
|
);
|
|
}
|
|
}
|
|
|
|
if (RightMask != 0) {
|
|
//
|
|
// Program the BitMask register with the Right column mask
|
|
//
|
|
WriteGraphicsController (
|
|
BiosVideoPrivate->PciIo,
|
|
VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
|
|
RightMask
|
|
);
|
|
|
|
for (Index = 0, Address = StartAddress + Bytes; Index < Height; Index++, Address += BytesPerScanLine) {
|
|
//
|
|
// Read data from the bit planes into the latches
|
|
//
|
|
PciIo->Mem.Read (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
EFI_PCI_IO_PASS_THROUGH_BAR,
|
|
(UINT64) Address,
|
|
1,
|
|
&Data
|
|
);
|
|
//
|
|
// Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
|
|
//
|
|
PciIo->Mem.Write (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
EFI_PCI_IO_PASS_THROUGH_BAR,
|
|
(UINT64) Address,
|
|
1,
|
|
&PixelColor
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case EfiUgaBltBufferToVideo:
|
|
StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
|
|
LeftMask = mVgaBitMaskTable[DestinationX & 0x07];
|
|
|
|
//
|
|
// Program the Mode Register Write mode 2, Read mode 0
|
|
//
|
|
WriteGraphicsController (
|
|
BiosVideoPrivate->PciIo,
|
|
VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
|
|
VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
|
|
);
|
|
|
|
//
|
|
// Program the Data Rotate/Function Select Register to replace
|
|
//
|
|
WriteGraphicsController (
|
|
BiosVideoPrivate->PciIo,
|
|
VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
|
|
VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
|
|
);
|
|
|
|
for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
|
|
for (Index1 = 0; Index1 < Width; Index1++) {
|
|
BiosVideoPrivate->LineBuffer[Index1] = VgaConvertColor (&BltBuffer[(SourceY + Index) * (Delta >> 2) + SourceX + Index1]);
|
|
}
|
|
AddressFix = Address;
|
|
|
|
for (Bit = 0; Bit < 8; Bit++) {
|
|
//
|
|
// Program the BitMask register with the Left column mask
|
|
//
|
|
WriteGraphicsController (
|
|
BiosVideoPrivate->PciIo,
|
|
VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
|
|
LeftMask
|
|
);
|
|
|
|
for (Index1 = Bit, Address1 = (UINT8 *) AddressFix; Index1 < Width; Index1 += 8, Address1++) {
|
|
//
|
|
// Read data from the bit planes into the latches
|
|
//
|
|
PciIo->Mem.Read (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
EFI_PCI_IO_PASS_THROUGH_BAR,
|
|
(UINT64) (UINTN) Address1,
|
|
1,
|
|
&Data
|
|
);
|
|
|
|
PciIo->Mem.Write (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
EFI_PCI_IO_PASS_THROUGH_BAR,
|
|
(UINT64) (UINTN) Address1,
|
|
1,
|
|
&BiosVideoPrivate->LineBuffer[Index1]
|
|
);
|
|
}
|
|
|
|
LeftMask = (UINT8) (LeftMask >> 1);
|
|
if (LeftMask == 0) {
|
|
LeftMask = 0x80;
|
|
AddressFix++;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
gBS->RestoreTPL (OriginalTPL);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
//
|
|
// VGA Mini Port Protocol Functions
|
|
//
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BiosVideoVgaMiniPortSetMode (
|
|
IN EFI_VGA_MINI_PORT_PROTOCOL *This,
|
|
IN UINTN ModeNumber
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
VgaMiniPort protocol interface to set mode
|
|
|
|
Arguments:
|
|
|
|
This - Pointer to VgaMiniPort protocol instance
|
|
ModeNumber - The index of the mode
|
|
|
|
Returns:
|
|
|
|
EFI_UNSUPPORTED - The requested mode is not supported
|
|
EFI_SUCCESS - The requested mode is set successfully
|
|
|
|
--*/
|
|
{
|
|
BIOS_VIDEO_DEV *BiosVideoPrivate;
|
|
EFI_IA32_REGISTER_SET Regs;
|
|
|
|
//
|
|
// Make sure the ModeNumber is a valid value
|
|
//
|
|
if (ModeNumber >= This->MaxMode) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
//
|
|
// Get the device structure for this device
|
|
//
|
|
BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (This);
|
|
|
|
gBS->SetMem (&Regs, sizeof (Regs), 0);
|
|
|
|
switch (ModeNumber) {
|
|
case 0:
|
|
//
|
|
// Set the 80x25 Text VGA Mode
|
|
//
|
|
Regs.H.AH = 0x00;
|
|
Regs.H.AL = 0x83;
|
|
LegacyBiosInt86 (0x10, &Regs);
|
|
|
|
Regs.H.AH = 0x11;
|
|
Regs.H.AL = 0x14;
|
|
Regs.H.BL = 0;
|
|
LegacyBiosInt86 (0x10, &Regs);
|
|
break;
|
|
|
|
case 1:
|
|
//
|
|
// Set the 80x50 Text VGA Mode
|
|
//
|
|
Regs.H.AH = 0x00;
|
|
Regs.H.AL = 0x83;
|
|
LegacyBiosInt86 (0x10, &Regs);
|
|
Regs.H.AH = 0x11;
|
|
Regs.H.AL = 0x12;
|
|
Regs.H.BL = 0;
|
|
LegacyBiosInt86 (0x10, &Regs);
|
|
break;
|
|
|
|
default:
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
InitializeBiosIntCaller (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 RealModeBufferSize;
|
|
UINT32 ExtraStackSize;
|
|
EFI_PHYSICAL_ADDRESS LegacyRegionBase;
|
|
|
|
//
|
|
// Get LegacyRegion
|
|
//
|
|
AsmGetThunk16Properties (&RealModeBufferSize, &ExtraStackSize);
|
|
|
|
LegacyRegionBase = 0x100000;
|
|
Status = gBS->AllocatePages (
|
|
AllocateMaxAddress,
|
|
EfiACPIMemoryNVS,
|
|
EFI_SIZE_TO_PAGES(RealModeBufferSize + ExtraStackSize + 200),
|
|
&LegacyRegionBase
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
mThunkContext.RealModeBuffer = (VOID*)(UINTN)LegacyRegionBase;
|
|
mThunkContext.RealModeBufferSize = EFI_PAGES_TO_SIZE (RealModeBufferSize);
|
|
mThunkContext.ThunkAttributes = 3;
|
|
AsmPrepareThunk16(&mThunkContext);
|
|
|
|
//Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &mLegacy8259);
|
|
//ASSERT_EFI_ERROR (Status);
|
|
}
|
|
|
|
VOID
|
|
InitializeInterruptRedirection (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Initialize interrupt redirection code and entries, because
|
|
IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.
|
|
Or the interrupt will lost when we do thunk.
|
|
NOTE: We do not reset 8259 vector base, because it will cause pending
|
|
interrupt lost.
|
|
|
|
Arguments:
|
|
NONE
|
|
|
|
Returns:
|
|
NONE
|
|
--*/
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_PHYSICAL_ADDRESS LegacyRegionBase;
|
|
UINTN LegacyRegionLength;
|
|
UINT32 *IdtArray;
|
|
UINTN Index;
|
|
UINT8 ProtectedModeBaseVector;
|
|
UINT32 InterruptRedirectionCode[] = {
|
|
0x90CF08CD, // INT8; IRET; NOP
|
|
0x90CF09CD, // INT9; IRET; NOP
|
|
0x90CF0ACD, // INTA; IRET; NOP
|
|
0x90CF0BCD, // INTB; IRET; NOP
|
|
0x90CF0CCD, // INTC; IRET; NOP
|
|
0x90CF0DCD, // INTD; IRET; NOP
|
|
0x90CF0ECD, // INTE; IRET; NOP
|
|
0x90CF0FCD // INTF; IRET; NOP
|
|
};
|
|
|
|
//
|
|
// Get LegacyRegion
|
|
//
|
|
LegacyRegionLength = sizeof(InterruptRedirectionCode);
|
|
LegacyRegionBase = 0x100000;
|
|
Status = gBS->AllocatePages (
|
|
AllocateMaxAddress,
|
|
EfiACPIMemoryNVS,
|
|
EFI_SIZE_TO_PAGES(LegacyRegionLength),
|
|
&LegacyRegionBase
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
//
|
|
// Copy code to legacy region
|
|
//
|
|
CopyMem ((VOID *)(UINTN)LegacyRegionBase, InterruptRedirectionCode, sizeof (InterruptRedirectionCode));
|
|
|
|
//
|
|
// Get VectorBase, it should be 0x68
|
|
//
|
|
Status = mLegacy8259->GetVector (mLegacy8259, Efi8259Irq0, &ProtectedModeBaseVector);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
//
|
|
// Patch IVT 0x68 ~ 0x6f
|
|
//
|
|
IdtArray = (UINT32 *) 0;
|
|
for (Index = 0; Index < 8; Index++) {
|
|
IdtArray[ProtectedModeBaseVector + Index] = ((EFI_SEGMENT (LegacyRegionBase + Index * 4)) << 16) | (EFI_OFFSET (LegacyRegionBase + Index * 4));
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
BOOLEAN
|
|
EFIAPI
|
|
LegacyBiosInt86 (
|
|
IN UINT8 BiosInt,
|
|
IN EFI_IA32_REGISTER_SET *Regs
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Thunk to 16-bit real mode and execute a software interrupt with a vector
|
|
of BiosInt. Regs will contain the 16-bit register context on entry and
|
|
exit.
|
|
|
|
Arguments:
|
|
This - Protocol instance pointer.
|
|
BiosInt - Processor interrupt vector to invoke
|
|
Reg - Register contexted passed into (and returned) from thunk to
|
|
16-bit mode
|
|
|
|
Returns:
|
|
FALSE - Thunk completed, and there were no BIOS errors in the target code.
|
|
See Regs for status.
|
|
TRUE - There was a BIOS erro in the target code.
|
|
|
|
--*/
|
|
{
|
|
UINTN Status;
|
|
UINTN Eflags;
|
|
IA32_REGISTER_SET ThunkRegSet;
|
|
BOOLEAN Ret;
|
|
UINT16 *Stack16;
|
|
|
|
Regs->X.Flags.Reserved1 = 1;
|
|
Regs->X.Flags.Reserved2 = 0;
|
|
Regs->X.Flags.Reserved3 = 0;
|
|
Regs->X.Flags.Reserved4 = 0;
|
|
Regs->X.Flags.IOPL = 3;
|
|
Regs->X.Flags.NT = 0;
|
|
Regs->X.Flags.IF = 1;
|
|
Regs->X.Flags.TF = 0;
|
|
Regs->X.Flags.CF = 0;
|
|
|
|
ZeroMem (&ThunkRegSet, sizeof (ThunkRegSet));
|
|
ThunkRegSet.E.EDI = Regs->E.EDI;
|
|
ThunkRegSet.E.ESI = Regs->E.ESI;
|
|
ThunkRegSet.E.EBP = Regs->E.EBP;
|
|
ThunkRegSet.E.EBX = Regs->E.EBX;
|
|
ThunkRegSet.E.EDX = Regs->E.EDX;
|
|
ThunkRegSet.E.ECX = Regs->E.ECX;
|
|
ThunkRegSet.E.EAX = Regs->E.EAX;
|
|
ThunkRegSet.E.DS = Regs->E.DS;
|
|
ThunkRegSet.E.ES = Regs->E.ES;
|
|
|
|
CopyMem (&(ThunkRegSet.E.EFLAGS), &(Regs->E.EFlags), sizeof (UINT32));
|
|
|
|
//
|
|
// The call to Legacy16 is a critical section to EFI
|
|
//
|
|
Eflags = AsmReadEflags ();
|
|
if ((Eflags | EFI_CPU_EFLAGS_IF) != 0) {
|
|
DisableInterrupts ();
|
|
}
|
|
|
|
//
|
|
// Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
|
|
//
|
|
Status = mLegacy8259->SetMode (mLegacy8259, Efi8259LegacyMode, NULL, NULL);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
Stack16 = (UINT16 *)((UINT8 *) mThunkContext.RealModeBuffer + mThunkContext.RealModeBufferSize - sizeof (UINT16));
|
|
Stack16 -= sizeof (ThunkRegSet.E.EFLAGS) / sizeof (UINT16);
|
|
CopyMem (Stack16, &ThunkRegSet.E.EFLAGS, sizeof (ThunkRegSet.E.EFLAGS));
|
|
|
|
ThunkRegSet.E.SS = (UINT16) (((UINTN) Stack16 >> 16) << 12);
|
|
ThunkRegSet.E.ESP = (UINT16) (UINTN) Stack16;
|
|
ThunkRegSet.E.Eip = (UINT16)((UINT32 *)NULL)[BiosInt];
|
|
ThunkRegSet.E.CS = (UINT16)(((UINT32 *)NULL)[BiosInt] >> 16);
|
|
mThunkContext.RealModeState = &ThunkRegSet;
|
|
AsmThunk16 (&mThunkContext);
|
|
|
|
//
|
|
// Restore protected mode interrupt state
|
|
//
|
|
Status = mLegacy8259->SetMode (mLegacy8259, Efi8259ProtectedMode, NULL, NULL);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
//
|
|
// End critical section
|
|
//
|
|
if ((Eflags | EFI_CPU_EFLAGS_IF) != 0) {
|
|
EnableInterrupts ();
|
|
}
|
|
|
|
Regs->E.EDI = ThunkRegSet.E.EDI;
|
|
Regs->E.ESI = ThunkRegSet.E.ESI;
|
|
Regs->E.EBP = ThunkRegSet.E.EBP;
|
|
Regs->E.EBX = ThunkRegSet.E.EBX;
|
|
Regs->E.EDX = ThunkRegSet.E.EDX;
|
|
Regs->E.ECX = ThunkRegSet.E.ECX;
|
|
Regs->E.EAX = ThunkRegSet.E.EAX;
|
|
Regs->E.SS = ThunkRegSet.E.SS;
|
|
Regs->E.CS = ThunkRegSet.E.CS;
|
|
Regs->E.DS = ThunkRegSet.E.DS;
|
|
Regs->E.ES = ThunkRegSet.E.ES;
|
|
|
|
CopyMem (&(Regs->E.EFlags), &(ThunkRegSet.E.EFLAGS), sizeof (UINT32));
|
|
|
|
Ret = (BOOLEAN) (Regs->E.EFlags.CF == 1);
|
|
|
|
return Ret;
|
|
}
|
|
|
|
|