uefibiosvideo.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 2,161 行 · 第 1/5 页
C
2,161 行
Returns:
NONE
---*/
{
if (BiosVideoPrivate == NULL) {
return ;
}
//
// Release all the resourses occupied by the BIOS_VIDEO_DEV
//
//
// 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);
}
//
// Free graphics output protocol occupied resource
//
if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {
if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {
gBS->FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);
}
gBS->FreePool (BiosVideoPrivate->GraphicsOutput.Mode);
}
//
// Free EDID discovered protocol occupied resource
//
if (BiosVideoPrivate->EdidDiscovered.Edid != NULL) {
gBS->FreePool (BiosVideoPrivate->EdidDiscovered.Edid);
}
//
// Free EDID active protocol occupied resource
//
if (BiosVideoPrivate->EdidActive.Edid != NULL) {
gBS->FreePool (BiosVideoPrivate->EdidActive.Edid);
}
if (BiosVideoPrivate->DevicePath!= NULL) {
gBS->FreePool (BiosVideoPrivate->DevicePath);
}
//
// Close the ExitBootServices event
//
if (BiosVideoPrivate->ExitBootServicesEvent != NULL) {
gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent);
}
gBS->FreePool (BiosVideoPrivate);
return ;
}
STATIC
UINT32
CalculateEdidKey (
VESA_BIOS_EXTENSIONS_EDID_TIMING *EdidTiming
)
/*++
Routine Description:
Generate a search key for a specified timing data.
Arguments:
EdidTiming - Pointer to EDID timing
Returns:
The 32 bit unique key for search.
--*/
{
UINT32 Key;
//
// Be sure no conflicts for all standard timing defined by VESA.
//
Key = (EdidTiming->HorizontalResolution * 2) + EdidTiming->VerticalResolution + EdidTiming->RefreshRate;
return Key;
}
STATIC
BOOLEAN
ParseEdidData (
UINT8 *EdidBuffer,
VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING *ValidEdidTiming
)
/*++
Routine Description:
Parse the Established Timing and Standard Timing in EDID data block.
Arguments:
EdidBuffer - Pointer to EDID data block
ValidEdidTiming - Valid EDID timing information
Returns:
TRUE - The EDID data is valid.
FALSE - The EDID data is invalid.
--*/
{
UINT8 CheckSum;
UINT32 Index;
UINT32 ValidNumber;
UINT32 TimingBits;
UINT8 *BufferIndex;
UINT16 HorizontalResolution;
UINT16 VerticalResolution;
UINT8 AspectRatio;
UINT8 RefreshRate;
VESA_BIOS_EXTENSIONS_EDID_TIMING TempTiming;
VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *EdidDataBlock;
EdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) EdidBuffer;
//
// Check the checksum of EDID data
//
CheckSum = 0;
for (Index = 0; Index < VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE; Index ++) {
CheckSum = CheckSum + EdidBuffer[Index];
}
if (CheckSum != 0) {
return FALSE;
}
ValidNumber = 0;
gBS->SetMem (ValidEdidTiming, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING), 0);
if ((EdidDataBlock->EstablishedTimings[0] != 0) ||
(EdidDataBlock->EstablishedTimings[1] != 0) ||
(EdidDataBlock->EstablishedTimings[2] != 0)
) {
//
// Established timing data
//
TimingBits = EdidDataBlock->EstablishedTimings[0] |
(EdidDataBlock->EstablishedTimings[1] << 8) |
((EdidDataBlock->EstablishedTimings[2] & 0x80) << 9) ;
for (Index = 0; Index < VESA_BIOS_EXTENSIONS_EDID_ESTABLISHED_TIMING_MAX_NUMBER; Index ++) {
if (TimingBits & 0x1) {
ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&mEstablishedEdidTiming[Index]);
ValidNumber ++;
}
TimingBits = TimingBits >> 1;
}
} else {
//
// If no Established timing data, read the standard timing data
//
BufferIndex = &EdidDataBlock->StandardTimingIdentification[0];
for (Index = 0; Index < 8; Index ++) {
if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){
//
// A valid Standard Timing
//
HorizontalResolution = BufferIndex[0] * 8 + 248;
AspectRatio = BufferIndex[1] >> 6;
switch (AspectRatio) {
case 0:
VerticalResolution = HorizontalResolution / 16 * 10;
break;
case 1:
VerticalResolution = HorizontalResolution / 4 * 3;
break;
case 2:
VerticalResolution = HorizontalResolution / 5 * 4;
break;
case 3:
VerticalResolution = HorizontalResolution / 16 * 9;
break;
default:
VerticalResolution = HorizontalResolution / 4 * 3;
break;
}
RefreshRate = (BufferIndex[1] & 0x1f) + 60;
TempTiming.HorizontalResolution = HorizontalResolution;
TempTiming.VerticalResolution = VerticalResolution;
TempTiming.RefreshRate = RefreshRate;
ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);
ValidNumber ++;
}
BufferIndex += 2;
}
}
ValidEdidTiming->ValidNumber = ValidNumber;
return TRUE;
}
STATIC
BOOLEAN
SearchEdidTiming (
VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING *ValidEdidTiming,
VESA_BIOS_EXTENSIONS_EDID_TIMING *EdidTiming
)
/*++
Routine Description:
Search a specified Timing in all the valid EDID timings.
Arguments:
ValidEdidTiming - All valid EDID timing information.
EdidTiming - The Timing to search for.
Returns:
TRUE - Found.
FALSE - Not found.
--*/
{
UINT32 Index;
UINT32 Key;
Key = CalculateEdidKey (EdidTiming);
for (Index = 0; Index < ValidEdidTiming->ValidNumber; Index ++) {
if (Key == ValidEdidTiming->Key[Index]) {
return TRUE;
}
}
return FALSE;
}
#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
EFIAPI
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;
BOOLEAN EdidFound;
BIOS_VIDEO_MODE_DATA *ModeBuffer;
BIOS_VIDEO_MODE_DATA *CurrentModeData;
UINTN PreferMode;
UINTN ModeNumber;
VESA_BIOS_EXTENSIONS_EDID_TIMING Timing;
VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING ValidEdidTiming;
EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *GraphicsOutputMode;
//
// 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_EDID_DATA_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 Graphics Output Protocol
//
BiosVideoPrivate->GraphicsOutput.QueryMode = BiosVideoGraphicsOutputQueryMode;
BiosVideoPrivate->GraphicsOutput.SetMode = BiosVideoGraphicsOutputSetMode;
BiosVideoPrivate->GraphicsOutput.Blt = BiosVideoGraphicsOutputVbeBlt;
BiosVideoPrivate->GraphicsOutput.Mode = NULL;
//
// 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->VbeEdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) (BiosVideoPrivate->VbeModeInformationBlock + 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);
BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 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;
}
//
// Read EDID information
//
gBS->SetMem (&Regs, sizeof (Regs), 0);
Regs.X.AX = VESA_BIOS_EXTENSIONS_EDID;
Regs.X.BX = 1;
Regs.X.CX = 0;
Regs.X.DX = 0;
Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);
Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?