diff options
author | jljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524> | 2011-06-27 23:32:56 +0000 |
---|---|---|
committer | jljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524> | 2011-06-27 23:32:56 +0000 |
commit | bcecde140a561c64e297225904afebebd62336ce (patch) | |
tree | 5f6333ccb04d851d151970e5dee6c9d8ac7ade71 /IntelFrameworkModulePkg/Csm/LegacyBiosDxe | |
parent | a7a0f78bd6fa1fe4684bf6de2b3e5ed5d9b5bf1c (diff) | |
download | edk2-bcecde140a561c64e297225904afebebd62336ce.zip edk2-bcecde140a561c64e297225904afebebd62336ce.tar.gz edk2-bcecde140a561c64e297225904afebebd62336ce.tar.bz2 |
IntelFrameworkModulePkg: Add Compatibility Support Module (CSM) drivers
Added these drivers:
* LegacyBiosDxe
* BlockIoDxe
* KeyboardDxe
* Snp16Dxe
* VideoDxe
Signed-off-by: jljusten
Reviewed-by: mdkinney
Reviewed-by: geekboy15a
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11905 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'IntelFrameworkModulePkg/Csm/LegacyBiosDxe')
20 files changed, 10801 insertions, 0 deletions
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.S b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.S new file mode 100644 index 0000000..a785256 --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.S @@ -0,0 +1,67 @@ +## @file
+# Interrupt Redirection Template
+#
+# Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
+#
+# 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.
+#
+##
+
+ASM_GLOBAL ASM_PFX(InterruptRedirectionTemplate)
+
+#----------------------------------------------------------------------------
+# Procedure: InterruptRedirectionTemplate: Redirects interrupts 0x68-0x6F
+#
+# Input: None
+#
+# Output: None
+#
+# Prototype: VOID
+# InterruptRedirectionTemplate (
+# VOID
+# );
+#
+# Saves: None
+#
+# Modified: None
+#
+# Description: Contains the code that is copied into low memory (below 640K).
+# This code reflects interrupts 0x68-0x6f to interrupts 0x08-0x0f.
+# This template must be copied into low memory, and the IDT entries
+# 0x68-0x6F must be point to the low memory copy of this code. Each
+# entry is 4 bytes long, so IDT entries 0x68-0x6F can be easily
+# computed.
+#
+#----------------------------------------------------------------------------
+ASM_PFX(InterruptRedirectionTemplate):
+ int $0x8
+ .byte 0xcf
+ nop
+ int $0x9
+ .byte 0xcf
+ nop
+ int $0xa
+ .byte 0xcf
+ nop
+ int $0xb
+ .byte 0xcf
+ nop
+ int $0xc
+ .byte 0xcf
+ nop
+ int $0xd
+ .byte 0xcf
+ nop
+ int $0xe
+ .byte 0xcf
+ nop
+ int $0xf
+ .byte 0xcf
+ nop
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.asm b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.asm new file mode 100644 index 0000000..410ce5b --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.asm @@ -0,0 +1,73 @@ +;; @file
+; Interrupt Redirection Template
+;
+; Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
+;
+; 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.
+;
+;;
+
+.686P
+.MODEL FLAT, C
+.CODE
+
+;----------------------------------------------------------------------------
+; Procedure: InterruptRedirectionTemplate: Redirects interrupts 0x68-0x6F
+;
+; Input: None
+;
+; Output: None
+;
+; Prototype: VOID
+; InterruptRedirectionTemplate (
+; VOID
+; );
+;
+; Saves: None
+;
+; Modified: None
+;
+; Description: Contains the code that is copied into low memory (below 640K).
+; This code reflects interrupts 0x68-0x6f to interrupts 0x08-0x0f.
+; This template must be copied into low memory, and the IDT entries
+; 0x68-0x6F must be point to the low memory copy of this code. Each
+; entry is 4 bytes long, so IDT entries 0x68-0x6F can be easily
+; computed.
+;
+;----------------------------------------------------------------------------
+
+InterruptRedirectionTemplate PROC C
+ int 08h
+ DB 0cfh ; IRET
+ nop
+ int 09h
+ DB 0cfh ; IRET
+ nop
+ int 0ah
+ DB 0cfh ; IRET
+ nop
+ int 0bh
+ DB 0cfh ; IRET
+ nop
+ int 0ch
+ DB 0cfh ; IRET
+ nop
+ int 0dh
+ DB 0cfh ; IRET
+ nop
+ int 0eh
+ DB 0cfh ; IRET
+ nop
+ int 0fh
+ DB 0cfh ; IRET
+ nop
+InterruptRedirectionTemplate ENDP
+
+END
\ No newline at end of file diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfBootSupport.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfBootSupport.c new file mode 100644 index 0000000..b6787ae --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfBootSupport.c @@ -0,0 +1,277 @@ +/** @file
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+
+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.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+/**
+ Assign drive number to legacy HDD drives prior to booting an EFI
+ aware OS so the OS can access drives without an EFI driver.
+ Note: BBS compliant drives ARE NOT available until this call by
+ either shell or EFI.
+
+ @param This Protocol instance pointer.
+ @param BbsCount Number of BBS_TABLE structures
+ @param BbsTable List BBS entries
+
+ @retval EFI_SUCCESS Drive numbers assigned
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosPrepareToBootEfi (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ OUT UINT16 *BbsCount,
+ OUT BBS_TABLE **BbsTable
+ )
+{
+ //
+ // Shadow All Opion ROM
+ //
+ LegacyBiosShadowAllLegacyOproms (This);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ To boot from an unconventional device like parties and/or execute
+ HDD diagnostics.
+
+ @param This Protocol instance pointer.
+ @param Attributes How to interpret the other input parameters
+ @param BbsEntry The 0-based index into the BbsTable for the
+ parent device.
+ @param BeerData Pointer to the 128 bytes of ram BEER data.
+ @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data.
+ The caller must provide a pointer to the specific
+ Service Area and not the start all Service Areas.
+ EFI_INVALID_PARAMETER if error. Does NOT return if no error.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosBootUnconventionalDevice (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UDC_ATTRIBUTES Attributes,
+ IN UINTN BbsEntry,
+ IN VOID *BeerData,
+ IN VOID *ServiceAreaData
+ )
+{
+ return EFI_INVALID_PARAMETER;
+}
+
+
+/**
+ Attempt to legacy boot the BootOption. If the EFI contexted has been
+ compromised this function will not return.
+
+ @param This Protocol instance pointer.
+ @param BbsDevicePath EFI Device Path from BootXXXX variable.
+ @param LoadOptionsSize Size of LoadOption in size.
+ @param LoadOptions LoadOption from BootXXXX variable
+
+ @retval EFI_SUCCESS Removable media not present
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosLegacyBoot (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN BBS_BBS_DEVICE_PATH *BbsDevicePath,
+ IN UINT32 LoadOptionsSize,
+ IN VOID *LoadOptions
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Build the E820 table.
+
+ @param Private Legacy BIOS Instance data
+ @param Size Size of E820 Table
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildE820 (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ OUT UINTN *Size
+ )
+{
+ *Size = 0;
+ return EFI_SUCCESS;
+}
+
+/**
+ Get all BBS info
+
+ @param This Protocol instance pointer.
+ @param HddCount Number of HDD_INFO structures
+ @param HddInfo Onboard IDE controller information
+ @param BbsCount Number of BBS_TABLE structures
+ @param BbsTable List BBS entries
+
+ @retval EFI_SUCCESS Tables returned
+ @retval EFI_NOT_FOUND resource not found
+ @retval EFI_DEVICE_ERROR can not get BBS table
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosGetBbsInfo (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ OUT UINT16 *HddCount,
+ OUT HDD_INFO **HddInfo,
+ OUT UINT16 *BbsCount,
+ OUT BBS_TABLE **BbsTable
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Fill in the standard BDA for Keyboard LEDs
+
+ @param This Protocol instance pointer.
+ @param Leds Current LED status
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosUpdateKeyboardLedStatus (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT8 Leds
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Relocate this image under 4G memory for IPF.
+
+ @param ImageHandle Handle of driver image.
+ @param SystemTable Pointer to system table.
+
+ @retval EFI_SUCCESS Image successfully relocated.
+ @retval EFI_ABORTED Failed to relocate image.
+
+**/
+EFI_STATUS
+RelocateImageUnder4GIfNeeded (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ UINTN NumberOfPages;
+ EFI_PHYSICAL_ADDRESS LoadedImageBase;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ EFI_PHYSICAL_ADDRESS MemoryAddress;
+ EFI_HANDLE NewImageHandle;
+
+ Status = gBS->HandleProtocol (
+ ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID *) &LoadedImage
+ );
+
+ if (!EFI_ERROR (Status)) {
+ LoadedImageBase = (EFI_PHYSICAL_ADDRESS) (UINTN) LoadedImage->ImageBase;
+ if (LoadedImageBase > 0xffffffff) {
+ NumberOfPages = (UINTN) (DivU64x32(LoadedImage->ImageSize, EFI_PAGE_SIZE) + 1);
+
+ //
+ // Allocate buffer below 4GB here
+ //
+ Status = AllocateLegacyMemory (
+ AllocateMaxAddress,
+ 0x7FFFFFFF,
+ NumberOfPages, // do we have to convert this to pages??
+ &MemoryAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ZeroMem (&ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
+ ImageContext.Handle = (VOID *)(UINTN)LoadedImageBase;
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+
+ //
+ // Get information about the image being loaded
+ //
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ImageContext.ImageAddress = (PHYSICAL_ADDRESS)MemoryAddress;
+ //
+ // Align buffer on section boundry
+ //
+ ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
+ ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);
+
+ //
+ // Load the image to our new buffer
+ //
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages (MemoryAddress, NumberOfPages);
+ return Status;
+ }
+
+ //
+ // Relocate the image in our new buffer
+ //
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages (MemoryAddress, NumberOfPages);
+ return Status;
+ }
+
+ //
+ // Create a new handle with gEfiCallerIdGuid to be used as the ImageHandle fore the reloaded image
+ //
+ NewImageHandle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &NewImageHandle,
+ &gEfiCallerIdGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+
+ //
+ // Flush the instruction cache so the image data is written before we execute it
+ //
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
+
+ Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages (MemoryAddress, NumberOfPages);
+ return Status;
+ }
+ //
+ // return error directly the BS will unload this image
+ //
+ return EFI_ABORTED;
+ }
+ }
+ return EFI_SUCCESS;
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.h b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.h new file mode 100644 index 0000000..26aa3a6 --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.h @@ -0,0 +1,102 @@ +/** @file
+
+Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
+
+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.
+
+**/
+
+#ifndef _IPF_THUNK_H_
+#define _IPF_THUNK_H_
+
+#include "LegacyBiosInterface.h"
+#include <IndustryStandard/Sal.h>
+
+/**
+ Template of real mode code.
+
+ @param CodeStart Start address of code.
+ @param CodeEnd End address of code
+ @param ReverseThunkStart Start of reverse thunk.
+ @param IntThunk Low memory thunk.
+
+**/
+VOID
+RealModeTemplate (
+ OUT UINTN *CodeStart,
+ OUT UINTN *CodeEnd,
+ OUT UINTN *ReverseThunkStart,
+ LOW_MEMORY_THUNK *IntThunk
+ );
+
+/**
+ Register physical address of Esal Data Area
+
+ @param ReverseThunkCodeAddress Reverse Thunk Address
+ @param IntThunkAddress IntThunk Address
+
+ @retval EFI_SUCCESS ESAL data area set successfully.
+
+**/
+EFI_STATUS
+EsalSetSalDataArea (
+ IN UINTN ReverseThunkCodeAddress,
+ IN UINTN IntThunkAddress
+ );
+
+/**
+ Get address of reverse thunk.
+
+ @retval EFI_SAL_SUCCESS Address of reverse thunk returned successfully.
+
+**/
+SAL_RETURN_REGS
+EsalGetReverseThunkAddress (
+ VOID
+ );
+
+typedef struct {
+ UINT32 Eax; // 0
+ UINT32 Ecx; // 4
+ UINT32 Edx; // 8
+ UINT32 Ebx; // 12
+ UINT32 Esp; // 16
+ UINT32 Ebp; // 20
+ UINT32 Esi; // 24
+ UINT32 Edi; // 28
+ UINT32 Eflag; // 32
+ UINT32 Eip; // 36
+ UINT16 Cs; // 40
+ UINT16 Ds; // 42
+ UINT16 Es; // 44
+ UINT16 Fs; // 46
+ UINT16 Gs; // 48
+ UINT16 Ss; // 50
+} IPF_DWORD_REGS;
+
+/**
+ Entrypoint of IA32 code.
+
+ @param CallTypeData Data of call type
+ @param DwordRegister Register set of IA32 general registers
+ and segment registers
+ @param StackPointer Stack pointer.
+ @param StackSize Size of stack.
+
+**/
+VOID
+EfiIaEntryPoint (
+ UINT64 CallTypeData,
+ IPF_DWORD_REGS *DwordRegister,
+ UINT64 StackPointer,
+ UINT64 StackSize
+ );
+
+#endif
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.i b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.i new file mode 100644 index 0000000..441bb25 --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.i @@ -0,0 +1,89 @@ +//// @file
+//
+// Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
+//
+// 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.
+//
+////
+
+#define NUM_REAL_GDT_ENTRIES 3
+#define LOW_STACK_SIZE (8*1024) // 8k?
+
+//
+// Low memory Thunk Structure
+//
+#define Code 0
+#define LowReverseThunkStart Code + 4096
+#define GdtDesc LowReverseThunkStart + 4
+#define IdtDesc GdtDesc + 6
+#define FlatSs IdtDesc + 6
+#define FlatEsp FlatSs + 4
+#define LowCodeSelector FlatEsp + 4
+#define LowDataSelector LowCodeSelector + 4
+#define LowStack LowDataSelector + 4
+#define RealModeIdtDesc LowStack + 4
+#define RealModeGdt RealModeIdtDesc + 6
+#define RealModeGdtDesc RealModeGdt + (8 * NUM_REAL_GDT_ENTRIES)
+#define RevRealDs RealModeGdtDesc + 6
+#define RevRealSs RevRealDs + 2
+#define RevRealEsp RevRealSs + 2
+#define RevRealIdtDesc RevRealEsp + 4
+#define RevFlatDataSelector RevRealIdtDesc + 6
+#define RevFlatStack RevFlatDataSelector + 2
+#define Stack RevFlatStack + 4
+#define RevThunkStack Stack + LOW_STACK_SIZE
+
+#define EfiToLegacy16InitTable RevThunkStack + LOW_STACK_SIZE
+#define InitTableBiosLessThan1MB EfiToLegacy16InitTable
+#define InitTableHiPmmMemory InitTableBiosLessThan1MB + 4
+#define InitTablePmmMemorySizeInBytes InitTableHiPmmMemory + 4
+#define InitTableReverseThunkCallSegment InitTablePmmMemorySizeInBytes + 4
+#define InitTableReverseThunkCallOffset InitTableReverseThunkCallSegment + 2
+#define InitTableNumberE820Entries InitTableReverseThunkCallOffset + 2
+#define InitTableOsMemoryAbove1Mb InitTableNumberE820Entries + 4
+#define InitTableThunkStart InitTableOsMemoryAbove1Mb + 4
+#define InitTableThunkSizeInBytes InitTableThunkStart + 4
+#define InitTable16InitTableEnd InitTableThunkSizeInBytes + 4
+
+#define EfiToLegacy16BootTable InitTable16InitTableEnd
+#define BootTableBiosLessThan1MB EfiToLegacy16BootTable
+#define BootTableHiPmmMemory BootTableBiosLessThan1MB + 4
+#define BootTablePmmMemorySizeInBytes BootTableHiPmmMemory + 4
+#define BootTableReverseThunkCallSegment BootTablePmmMemorySizeInBytes + 4
+#define BootTableReverseThunkCallOffset BootTableReverseThunkCallSegment + 2
+#define BootTableNumberE820Entries BootTableReverseThunkCallOffset + 2
+#define BootTableOsMemoryAbove1Mb BootTableNumberE820Entries + 4
+#define BootTableThunkStart BootTableOsMemoryAbove1Mb + 4
+#define BootTableThunkSizeInBytes BootTableThunkStart + 4
+#define EfiToLegacy16BootTableEnd BootTableThunkSizeInBytes + 4
+
+#define InterruptRedirectionCode EfiToLegacy16BootTableEnd
+#define PciHandler InterruptRedirectionCode + 32
+
+
+//
+// Register Sets (16 Bit)
+//
+
+#define AX 0
+#define BX 2
+#define CX 4
+#define DX 6
+#define SI 8
+#define DI 10
+#define Flags 12
+#define ES 14
+#define CS 16
+#define SS 18
+#define DS 20
+#define BP 22
+
+
+
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.s b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.s new file mode 100644 index 0000000..d08f781 --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.s @@ -0,0 +1,524 @@ +//// @file +// +// Copyright (c) 1999 - 2008, Intel Corporation. All rights reserved.<BR> +// +// 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. +// +//// + +.file "IpfThunk.s" + +#include "IpfMacro.i" +#include "Ipf/IpfThunk.i" + +.align 0x10 +//----------------------------------------------------------------------------- +//++ +// EfiIaEntryPoint +// +// Register physical address of Esal Data Area +// +// On Entry : +// in1 = ptr to legacy bios reg +// in2 = ptr to Call Stack +// in3 = Call Stack Size +// +// Return Value: +// r8 = SAL_SUCCESS +// +// As per static calling conventions. +// +//-- +//--------------------------------------------------------------------------- +PROCEDURE_ENTRY(EfiIaEntryPoint) + + alloc loc0 = 8,10,8,0;; + + mov out0 = r0;; + mov out1 = r0;; + mov out2 = r0;; + mov out3 = r0;; + mov out4 = r0;; + mov out5 = r0;; + mov out6 = r0;; + mov out7 = r0;; + + mov loc1 = b0;; // save efi (b0) + mov loc2 = psr;; // save efi (PSR) + mov loc3 = gp;; // save efi (GP) + mov loc4 = pr;; // save efi (PR) + mov loc5 = sp;; // save efi (SP) + mov loc6 = r13;; // save efi (TP) + mov loc7 = ar.lc;; // save efi (LC) + mov loc8 = ar.fpsr;; // save efi (FPSR) + + mov r8 = r0;; // return status + mov r9 = r0;; // return value + mov r10 = r0;; // return value + mov r11 = r0;; // return value + +bios_int_func:: + rsm 0x4000;; // i(14)=0, disable interrupt + srlz.d;; + srlz.i;; + +//---------------------// +// save fp registers // +//---------------------// + + dep sp = 0,sp,0,4;; // align 16 + add sp = -16,sp;; // post decrement + +int_ip_1x:: + mov r2 = ip;; + add r2 = (int_ip_1y - int_ip_1x),r2;; + mov b7 = r2;; + br save_fp_registers;; + +int_ip_1y:: + add sp = 16,sp;; // adjust (SP) + mov loc9 = sp;; // save (SP) + adds sp = 0x10,in1;; // in1 + 0x10 = SP + ld4 sp = [sp];; // SP + adds r17 = 0x32,in1;; // in1 + 0x32 = SS + ld2 r17 = [r17];; // SS + movl r2 = 0xffffffff;; // if no SS:SP, then define new SS:SP + cmp.ne p6,p0 = sp,r2;; + movl r2 = 0xffff;; + cmp.ne.or p6,p0 = r17,r2;; + (p6) br.sptk bif_1;; + + mov sp = in3;; // 16-bit stack pointer + mov r2 = psr;; + tbit.z p6,p7 = r2,17;; // psr.dt (Physical OR Virtual) + +bif_ip1x:: + mov r2 = in2;; // ia32 callback stack top + mov r3 = in3;; // 16-bit stack pointer + sub r2 = r2,r3;; + shr.u r17 = r2,4;; // 16-bit stack segment + +bif_1:: + extr.u sp = sp,0,16;; // SP (16-bit sp for legacy code) + dep sp = 0,sp,0,3;; // align 8 + cmp.eq p6,p0 = 0,sp;; // if SP=0000 then wrap to 0x10000 + (p6) dep sp = -1,sp,16,1;; + shladd r2 = r17,4,sp;; // ESP = SS<<4+SP + add r2 = -8,r2;; // post decrement 64 bit pointer + add sp = -8,sp;; // post decrement SP + +sale_ip1x:: + mov r18 = ip;; + adds r18 = (sale_ip1y - sale_ip1x),r18;; + sub r18 = r18,r2;; // return address - CS base + add r18 = r18,sp;; // adjustment for stack + shl r18 = r18,32;; + movl r19 = 0xb80f66fa;; // CLI, JMPE xxxxxxxx + or r18 = r18,r19;; + st8 [r2] = r18;; // (FA,66,0F,B8,xx,xx,xx,xx) + + cmp.eq p6,p0 = 0,sp;; // if SP=0000 then wrap to 0x10000 + (p6) dep sp = -1,sp,16,1;; + shladd r2 = r17,4,sp;; // ESP=SS<<4+SP + add r2 = -2,r2;; // post decrement 64 bit pointer + add sp = -2,sp;; // post decrement SP + + movl r18 = 0x8000000000000100;; // CALL FAR function + cmp.eq p6,p7 = in0,r18;; + (p6) add r19 = 0x28,in1;; // in1 + 0x28 = CS + (p6) ld2 r18 = [r19],-4;; // CS + (p6) st2 [r2] = r18,-2;; // in1 + 0x24 = EIP + (p6) ld2 r18 = [r19];; // EIP + (p6) st2 [r2] = r18,-2;; // + (p6) movl r18 = 0x9a90;; // nop, CALLFAR xxxx:yyyy + + (p7) movl r18 = 0xcd;; // INT xx + (p7) dep r18 = in0,r18,8,8;; + st2 [r2] = r18;; // (CD,xx) + + mov r18 = r2;; // EIP for legacy execution + +//------------------------------// +// flush 32 bytes legacy code // +//------------------------------// + + dep r2 = 0,r2,0,5;; // align to 32 + fc r2;; + sync.i;; + srlz.i;; + srlz.d;; + +//------------------------------// +// load legacy registers // +//------------------------------// + mov r2 = in1;; // IA32 BIOS register state + ld4 r8 = [r2],4;; // in1 + 0 = EAX + ld4 r9 = [r2],4;; // in1 + 4 = ECX + ld4 r10 = [r2],4;; // in1 + 8 = EDX + ld4 r11 = [r2],4;; // in1 + 12 = EBX + + add r2 = 4,r2;; // in1 + 16 = ESP (skip) + + ld4 r13 = [r2],4;; // in1 + 20 = EBP + ld4 r14 = [r2],4;; // in1 + 24 = ESI + ld4 r15 = [r2],4;; // in1 + 28 = EDI + ld4 r3 = [r2],4;; // in1 + 32 = EFLAGS + mov ar.eflag = r3;; + + add r2 = 4,r2;; // in1 + 36 = EIP (skip) + add r2 = 2,r2;; // in1 + 40 = CS (skip) + + ld2 r16 = [r2],2;; // in1 + 42 = DS, (r16 = GS,FS,ES,DS) + movl r27 = 0xc93fffff00000000;; + dep r27 = r16,r27,4,16;; // r27 = DSD + + ld2 r19 = [r2],2;; // in1 + 44 = ES + dep r16 = r19,r16,16,16;; + movl r24 = 0xc93fffff00000000;; + dep r24 = r19,r24,4,16;; // r24 = ESD + + ld2 r19 = [r2],2;; // in1 + 46 = FS + dep r16 = r19,r16,32,16;; + movl r28 = 0xc93fffff00000000;; + dep r28 = r19,r28,4,16;; // r28 = FSD + + ld2 r19 = [r2],2;; // in1 + 48 = GS + dep r16 = r19,r16,48,16;; + movl r29 = 0xc93fffff00000000;; + dep r29 = r19,r29,4,16;; // r29 = GSD + + mov r30 = r0;; // r30 = LDTD, clear NaT + mov r31 = r0;; // r31 = GDTD, clear NaT + + dep r17 = r17,r17,16,16;; // CS = SS, (r17 = TSS,LDT,SS,CS) + + movl r3 = 0x0930ffff00000000;; + dep r3 = r17,r3,4,16;; + mov ar.csd = r3;; // ar25 = CSD + mov ar.ssd = r3;; // ar26 = SSD + +//------------------------------// +// give control to INT function // +//------------------------------// + + br.call.sptk b0 = execute_int_function;; + +//------------------------------// +// store legacy registers // +//------------------------------// + + mov r2 = in1;; + st4 [r2] = r8,4;; // EAX + st4 [r2] = r9,4;; // ECX + st4 [r2] = r10,4;; // EDX + st4 [r2] = r11,4;; // EBX + + add r2 = 4,r2;; // ESP (skip) + + st4 [r2] = r13,4;; // EBP + st4 [r2] = r14,4;; // ESI + st4 [r2] = r15,4;; // EDI + + mov r3 = ar.eflag;; + st4 [r2] = r3,4;; // EFLAGS + + add r2 = 4,r2;; // EIP (skip) + add r2 = 2,r2;; // CS (skip) + + st2 [r2] = r16,2;; // DS, (r16 = GS,FS,ES,DS) + + extr.u r3 = r16,16,16;; + st2 [r2] = r3,2;; // ES + + extr.u r3 = r16,32,16;; + st2 [r2] = r3,2;; // FS + + extr.u r3 = r16,48,16;; + st2 [r2] = r3,2;; // GS + +//------------------------------// +// restore fp registers // +//------------------------------// + mov sp = loc9;; // restore (SP) +int_ip_2x:: + mov r2 = ip;; + add r2 = (int_ip_2y - int_ip_2x),r2;; + mov b7 = r2;; + br restore_fp_registers;; + +int_ip_2y:: + mov r8 = r0;; // return status + mov r9 = r0;; // return value + mov r10 = r0;; // return value + mov r11 = r0;; // return value + + mov ar.fpsr = loc8;; // restore efi (FPSR) + mov ar.lc = loc7;; // restore efi (LC) + mov r13 = loc6;; // restore efi (TP) + mov sp = loc5;; // restore efi (SP) + mov pr = loc4;; // restore efi (PR) + mov gp = loc3;; // restore efi (GP) + mov psr.l = loc2;; // restore efi (PSR) + srlz.d;; + srlz.i;; + mov b0 = loc1;; // restore efi (b0) + mov ar.pfs = loc0;; + br.ret.sptk b0;; // return to efi + +PROCEDURE_EXIT (EfiIaEntryPoint) + +//==============================// +// EXECUTE_INT_FUNCTION // +//==============================// +// switch to virtual address // +//------------------------------// + +execute_int_function:: + + alloc r2 = 0,0,0,0;; // cfm.sof=0 + flushrs;; + + rsm 0x2000;; // ic(13)=0 for control register programming + srlz.d;; + srlz.i;; + + mov r2 = psr;; + dep r2 = -1,r2,34,1;; // set is(34) + dep r2 = -1,r2,44,1;; // set bn(44) + dep r2 = -1,r2,36,1;; // set it(36) + dep r2 = -1,r2,27,1;; // set rt(27) + dep r2 = -1,r2,17,1;; // set dt(17) + dep r2 = 0,r2,3,1;; // reset ac(3) + dep r2 = -1,r2,13,1;; // set ic(13) + + mov cr.ipsr = r2;; + mov cr.ifs = r0;; // clear interruption function state register + mov cr.iip = r18;; + + rfi;; // go to legacy code execution + +//------------------------------// +// back from legacy code // +//------------------------------// +// switch to physical address // +//------------------------------// + +sale_ip1y:: + rsm 0x6000;; // i(14)=0,ic(13)=0 for control reg programming + srlz.d;; + srlz.i;; + + mov r2 = psr;; + dep r2 = -1,r2,44,1;; // set bn(44) + dep r2 = 0,r2,36,1;; // reset it(36) + dep r2 = 0,r2,27,1;; // reset rt(27) + dep r2 = 0,r2,17,1;; // reset dt(17) + dep r2 = -1,r2,13,1;; // set ic(13) + mov cr.ipsr = r2;; + +sale_ip2x:: + mov r2 = ip;; + add r2 = (sale_ip2y - sale_ip2x),r2;; + mov cr.ifs = r0;; // clear interruption function state register + mov cr.iip = r2;; + rfi;; + +sale_ip2y:: + br.ret.sptk b0;; // return to SAL + +//------------------------------// +// store fp registers // +//------------------------------// +save_fp_registers:: + stf.spill [sp]=f2,-16;; stf.spill [sp]=f3,-16;; + stf.spill [sp]=f4,-16;; stf.spill [sp]=f5,-16;; stf.spill [sp]=f6,-16;; stf.spill [sp]=f7,-16;; + stf.spill [sp]=f8,-16;; stf.spill [sp]=f9,-16;; stf.spill [sp]=f10,-16;; stf.spill [sp]=f11,-16;; + stf.spill [sp]=f12,-16;; stf.spill [sp]=f13,-16;; stf.spill [sp]=f14,-16;; stf.spill [sp]=f15,-16;; + stf.spill [sp]=f16,-16;; stf.spill [sp]=f17,-16;; stf.spill [sp]=f18,-16;; stf.spill [sp]=f19,-16;; + stf.spill [sp]=f20,-16;; stf.spill [sp]=f21,-16;; stf.spill [sp]=f22,-16;; stf.spill [sp]=f23,-16;; + stf.spill [sp]=f24,-16;; stf.spill [sp]=f25,-16;; stf.spill [sp]=f26,-16;; stf.spill [sp]=f27,-16;; + stf.spill [sp]=f28,-16;; stf.spill [sp]=f29,-16;; stf.spill [sp]=f30,-16;; stf.spill [sp]=f31,-16;; + stf.spill [sp]=f32,-16;; stf.spill [sp]=f33,-16;; stf.spill [sp]=f34,-16;; stf.spill [sp]=f35,-16;; + stf.spill [sp]=f36,-16;; stf.spill [sp]=f37,-16;; stf.spill [sp]=f38,-16;; stf.spill [sp]=f39,-16;; + stf.spill [sp]=f40,-16;; stf.spill [sp]=f41,-16;; stf.spill [sp]=f42,-16;; stf.spill [sp]=f43,-16;; + stf.spill [sp]=f44,-16;; stf.spill [sp]=f45,-16;; stf.spill [sp]=f46,-16;; stf.spill [sp]=f47,-16;; + stf.spill [sp]=f48,-16;; stf.spill [sp]=f49,-16;; stf.spill [sp]=f50,-16;; stf.spill [sp]=f51,-16;; + stf.spill [sp]=f52,-16;; stf.spill [sp]=f53,-16;; stf.spill [sp]=f54,-16;; stf.spill [sp]=f55,-16;; + stf.spill [sp]=f56,-16;; stf.spill [sp]=f57,-16;; stf.spill [sp]=f58,-16;; stf.spill [sp]=f59,-16;; + stf.spill [sp]=f60,-16;; stf.spill [sp]=f61,-16;; stf.spill [sp]=f62,-16;; stf.spill [sp]=f63,-16;; + stf.spill [sp]=f64,-16;; stf.spill [sp]=f65,-16;; stf.spill [sp]=f66,-16;; stf.spill [sp]=f67,-16;; + stf.spill [sp]=f68,-16;; stf.spill [sp]=f69,-16;; stf.spill [sp]=f70,-16;; stf.spill [sp]=f71,-16;; + stf.spill [sp]=f72,-16;; stf.spill [sp]=f73,-16;; stf.spill [sp]=f74,-16;; stf.spill [sp]=f75,-16;; + stf.spill [sp]=f76,-16;; stf.spill [sp]=f77,-16;; stf.spill [sp]=f78,-16;; stf.spill [sp]=f79,-16;; + stf.spill [sp]=f80,-16;; stf.spill [sp]=f81,-16;; stf.spill [sp]=f82,-16;; stf.spill [sp]=f83,-16;; + stf.spill [sp]=f84,-16;; stf.spill [sp]=f85,-16;; stf.spill [sp]=f86,-16;; stf.spill [sp]=f87,-16;; + stf.spill [sp]=f88,-16;; stf.spill [sp]=f89,-16;; stf.spill [sp]=f90,-16;; stf.spill [sp]=f91,-16;; + stf.spill [sp]=f92,-16;; stf.spill [sp]=f93,-16;; stf.spill [sp]=f94,-16;; stf.spill [sp]=f95,-16;; + stf.spill [sp]=f96,-16;; stf.spill [sp]=f97,-16;; stf.spill [sp]=f98,-16;; stf.spill [sp]=f99,-16;; + stf.spill [sp]=f100,-16;;stf.spill [sp]=f101,-16;;stf.spill [sp]=f102,-16;;stf.spill [sp]=f103,-16;; + stf.spill [sp]=f104,-16;;stf.spill [sp]=f105,-16;;stf.spill [sp]=f106,-16;;stf.spill [sp]=f107,-16;; + stf.spill [sp]=f108,-16;;stf.spill [sp]=f109,-16;;stf.spill [sp]=f110,-16;;stf.spill [sp]=f111,-16;; + stf.spill [sp]=f112,-16;;stf.spill [sp]=f113,-16;;stf.spill [sp]=f114,-16;;stf.spill [sp]=f115,-16;; + stf.spill [sp]=f116,-16;;stf.spill [sp]=f117,-16;;stf.spill [sp]=f118,-16;;stf.spill [sp]=f119,-16;; + stf.spill [sp]=f120,-16;;stf.spill [sp]=f121,-16;;stf.spill [sp]=f122,-16;;stf.spill [sp]=f123,-16;; + stf.spill [sp]=f124,-16;;stf.spill [sp]=f125,-16;;stf.spill [sp]=f126,-16;;stf.spill [sp]=f127,-16;; + invala;; + br b7;; + +//------------------------------// +// restore fp registers // +//------------------------------// +restore_fp_registers:: + ldf.fill f127=[sp],16;;ldf.fill f126=[sp],16;;ldf.fill f125=[sp],16;;ldf.fill f124=[sp],16;; + ldf.fill f123=[sp],16;;ldf.fill f122=[sp],16;;ldf.fill f121=[sp],16;;ldf.fill f120=[sp],16;; + ldf.fill f119=[sp],16;;ldf.fill f118=[sp],16;;ldf.fill f117=[sp],16;;ldf.fill f116=[sp],16;; + ldf.fill f115=[sp],16;;ldf.fill f114=[sp],16;;ldf.fill f113=[sp],16;;ldf.fill f112=[sp],16;; + ldf.fill f111=[sp],16;;ldf.fill f110=[sp],16;;ldf.fill f109=[sp],16;;ldf.fill f108=[sp],16;; + ldf.fill f107=[sp],16;;ldf.fill f106=[sp],16;;ldf.fill f105=[sp],16;;ldf.fill f104=[sp],16;; + ldf.fill f103=[sp],16;;ldf.fill f102=[sp],16;;ldf.fill f101=[sp],16;;ldf.fill f100=[sp],16;; + ldf.fill f99=[sp],16;; ldf.fill f98=[sp],16;; ldf.fill f97=[sp],16;; ldf.fill f96=[sp],16;; + ldf.fill f95=[sp],16;; ldf.fill f94=[sp],16;; ldf.fill f93=[sp],16;; ldf.fill f92=[sp],16;; + ldf.fill f91=[sp],16;; ldf.fill f90=[sp],16;; ldf.fill f89=[sp],16;; ldf.fill f88=[sp],16;; + ldf.fill f87=[sp],16;; ldf.fill f86=[sp],16;; ldf.fill f85=[sp],16;; ldf.fill f84=[sp],16;; + ldf.fill f83=[sp],16;; ldf.fill f82=[sp],16;; ldf.fill f81=[sp],16;; ldf.fill f80=[sp],16;; + ldf.fill f79=[sp],16;; ldf.fill f78=[sp],16;; ldf.fill f77=[sp],16;; ldf.fill f76=[sp],16;; + ldf.fill f75=[sp],16;; ldf.fill f74=[sp],16;; ldf.fill f73=[sp],16;; ldf.fill f72=[sp],16;; + ldf.fill f71=[sp],16;; ldf.fill f70=[sp],16;; ldf.fill f69=[sp],16;; ldf.fill f68=[sp],16;; + ldf.fill f67=[sp],16;; ldf.fill f66=[sp],16;; ldf.fill f65=[sp],16;; ldf.fill f64=[sp],16;; + ldf.fill f63=[sp],16;; ldf.fill f62=[sp],16;; ldf.fill f61=[sp],16;; ldf.fill f60=[sp],16;; + ldf.fill f59=[sp],16;; ldf.fill f58=[sp],16;; ldf.fill f57=[sp],16;; ldf.fill f56=[sp],16;; + ldf.fill f55=[sp],16;; ldf.fill f54=[sp],16;; ldf.fill f53=[sp],16;; ldf.fill f52=[sp],16;; + ldf.fill f51=[sp],16;; ldf.fill f50=[sp],16;; ldf.fill f49=[sp],16;; ldf.fill f48=[sp],16;; + ldf.fill f47=[sp],16;; ldf.fill f46=[sp],16;; ldf.fill f45=[sp],16;; ldf.fill f44=[sp],16;; + ldf.fill f43=[sp],16;; ldf.fill f42=[sp],16;; ldf.fill f41=[sp],16;; ldf.fill f40=[sp],16;; + ldf.fill f39=[sp],16;; ldf.fill f38=[sp],16;; ldf.fill f37=[sp],16;; ldf.fill f36=[sp],16;; + ldf.fill f35=[sp],16;; ldf.fill f34=[sp],16;; ldf.fill f33=[sp],16;; ldf.fill f32=[sp],16;; + ldf.fill f31=[sp],16;; ldf.fill f30=[sp],16;; ldf.fill f29=[sp],16;; ldf.fill f28=[sp],16;; + ldf.fill f27=[sp],16;; ldf.fill f26=[sp],16;; ldf.fill f25=[sp],16;; ldf.fill f24=[sp],16;; + ldf.fill f23=[sp],16;; ldf.fill f22=[sp],16;; ldf.fill f21=[sp],16;; ldf.fill f20=[sp],16;; + ldf.fill f19=[sp],16;; ldf.fill f18=[sp],16;; ldf.fill f17=[sp],16;; ldf.fill f16=[sp],16;; + ldf.fill f15=[sp],16;; ldf.fill f14=[sp],16;; ldf.fill f13=[sp],16;; ldf.fill f12=[sp],16;; + ldf.fill f11=[sp],16;; ldf.fill f10=[sp],16;; ldf.fill f9=[sp],16;; ldf.fill f8=[sp],16;; + ldf.fill f7=[sp],16;; ldf.fill f6=[sp],16;; ldf.fill f5=[sp],16;; ldf.fill f4=[sp],16;; + ldf.fill f3=[sp],16;; ldf.fill f2=[sp],16;; + invala;; + br b7;; + +//----------------------------------------------------------------------------- +//++ +// EsalSetSalDataArea +// +// Register physical address of Esal Data Area +// +// On Entry : +// in0 = Reverse Thunk Address +// in1 = IntThunk Address +// +// Return Value: +// r8 = SAL_SUCCESS +// +// As per static calling conventions. +// +//-- +//--------------------------------------------------------------------------- + +PROCEDURE_ENTRY (EsalSetSalDataArea) + + NESTED_SETUP (4,8,0,0) + +EsalCalcStart1_3:: + mov r8 = ip;; + add r8 = (ReverseThunkAddress - EsalCalcStart1_3), r8;; + st8 [r8] = in0;; + +EsalCalcStart1_4:: + mov r8 = ip;; + add r8 = (IntThunkAddress - EsalCalcStart1_4), r8;; + st8 [r8] = in1;; + + mov r8 = r0;; + + NESTED_RETURN + +PROCEDURE_EXIT (EsalSetSalDataArea) + +//----------------------------------------------------------------------------- +//++ +// EsagGetReverseThunkAddress +// +// Register physical address of Esal Data Area +// +// On Entry : +// out0 = CodeStart +// out1 = CodeEnd +// out1 = ReverseThunkCode +// +// Return Value: +// r8 = SAL_SUCCESS +// +// As per static calling conventions. +// +//-- +//--------------------------------------------------------------------------- + +PROCEDURE_ENTRY (EsalGetReverseThunkAddress) + + NESTED_SETUP (4,8,0,0) + +EsalCalcStart1_31:: + mov r8 = ip;; + add r8 = (Ia32CodeStart - EsalCalcStart1_31), r8;; + mov r9 = r8;; + +EsalCalcStart1_41:: + mov r8 = ip;; + add r8 = (Ia32CodeEnd - EsalCalcStart1_41), r8;; + mov r10 = r8;; + +EsalCalcStart1_51:: + mov r8 = ip;; + add r8 = (ReverseThunkAddress - EsalCalcStart1_51), r8;; + mov r11 = r8;; + mov r8 = r0;; + + NESTED_RETURN + +PROCEDURE_EXIT (EsalGetReverseThunkAddress) + + +.align 16 +PROCEDURE_ENTRY (InterruptRedirectionTemplate) + data8 0x90CFCD08 + data8 0x90CFCD09 + data8 0x90CFCD0A + data8 0x90CFCD0B + data8 0x90CFCD0C + data8 0x90CFCD0D + data8 0x90CFCD0E + data8 0x90CFCD0F +PROCEDURE_EXIT (InterruptRedirectionTemplate) + +//------------------------------// +// Reverse Thunk Code // +//------------------------------// + +Ia32CodeStart:: + br.sptk.few Ia32CodeStart;; // IPF CSM integration -Bug (Write This Code) +ReverseThunkCode:: + data8 0xb80f66fa // CLI, JMPE xxxx +ReverseThunkAddress:: + data8 0 // Return Address +IntThunkAddress:: + data8 0 // IntThunk Address +Ia32CodeEnd:: + + + + diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/Thunk.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/Thunk.c new file mode 100644 index 0000000..ca59b97 --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/Thunk.c @@ -0,0 +1,550 @@ +/** @file
+ Call into 16-bit BIOS code
+
+ BugBug: Thunker does A20 gate. Can we get rid of this code or
+ put it into Legacy16 code.
+
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>
+
+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.
+
+**/
+
+#include "LegacyBiosInterface.h"
+#include "IpfThunk.h"
+
+/**
+ Gets the current flat GDT and IDT descriptors and store them in
+ Private->IntThunk. These values are used by the Thunk code.
+ This method must be called before every thunk in order to assure
+ that the correct GDT and IDT are restored after the thunk.
+
+ @param Private Private context for Legacy BIOS
+
+ @retval EFI_SUCCESS Should only pass.
+
+**/
+EFI_STATUS
+LegacyBiosGetFlatDescs (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ BIOS interrupt call function.
+
+ @param BiosInt Int number of BIOS call
+ @param Segment Segment number
+ @param Offset Offset in segment
+ @param Regs IA32 Register set.
+ @param Stack Base address of stack
+ @param StackSize Size of stack
+
+ @retval EFI_SUCCESS BIOS interrupt call succeeds.
+
+**/
+EFI_STATUS
+BiosIntCall (
+ IN UINT16 BiosInt,
+ IN UINT16 Segment,
+ IN UINT16 Offset,
+ IN EFI_IA32_REGISTER_SET *Regs,
+ IN VOID *Stack,
+ IN UINTN StackSize
+ )
+{
+ IPF_DWORD_REGS DwordRegs;
+ UINT64 IntTypeVariable;
+
+ IntTypeVariable = 0x8000000000000000;
+ IntTypeVariable |= BiosInt;
+
+ DwordRegs.Cs = Segment;
+ DwordRegs.Eip = Offset;
+
+ DwordRegs.Ds = Regs->X.DS;
+ DwordRegs.Es = Regs->X.ES;
+ DwordRegs.Fs = Regs->X.ES;
+ DwordRegs.Gs = Regs->X.ES;
+ DwordRegs.Ss = 0xFFFF;
+
+ DwordRegs.Eax = Regs->X.AX;
+ DwordRegs.Ebx = Regs->X.BX;
+ //
+ // Sometimes, ECX is used to pass in 32 bit data. For example, INT 1Ah, AX = B10Dh is
+ // "PCI BIOS v2.0c + Write Configuration DWORD" and ECX has the dword to write.
+ //
+ DwordRegs.Ecx = Regs->E.ECX;
+ DwordRegs.Edx = Regs->X.DX;
+
+ DwordRegs.Ebp = Regs->X.BP;
+ DwordRegs.Eflag = *((UINT16 *) &Regs->X.Flags);
+
+ DwordRegs.Edi = Regs->X.DI;
+ DwordRegs.Esi = Regs->X.SI;
+ DwordRegs.Esp = 0xFFFFFFFF;
+
+ EfiIaEntryPoint (IntTypeVariable, &DwordRegs, ((UINTN) Stack + StackSize), StackSize);
+
+ Regs->X.CS = DwordRegs.Cs;
+
+ Regs->X.DS = (UINT16) DwordRegs.Ds;
+ Regs->X.SS = (UINT16) DwordRegs.Ss;
+
+ Regs->E.EAX = DwordRegs.Eax;
+ Regs->E.EBX = DwordRegs.Ebx;
+ Regs->E.ECX = DwordRegs.Ecx;
+ Regs->E.EDX = DwordRegs.Edx;
+
+ Regs->E.EBP = DwordRegs.Ebp;
+ CopyMem (&Regs->X.Flags, &DwordRegs.Eflag, sizeof (EFI_FLAGS_REG));
+
+ Regs->E.EDI = DwordRegs.Edi;
+ Regs->E.ESI = DwordRegs.Esi;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Template of real mode code.
+
+ @param CodeStart Start address of code.
+ @param CodeEnd End address of code
+ @param ReverseThunkStart Start of reverse thunk.
+ @param IntThunk Low memory thunk.
+
+**/
+VOID
+RealModeTemplate (
+ OUT UINTN *CodeStart,
+ OUT UINTN *CodeEnd,
+ OUT UINTN *ReverseThunkStart,
+ LOW_MEMORY_THUNK *IntThunk
+ )
+{
+ SAL_RETURN_REGS SalStatus;
+
+ SalStatus = EsalGetReverseThunkAddress ();
+
+ *CodeStart = SalStatus.r9;
+ *CodeEnd = SalStatus.r10;
+ *ReverseThunkStart = SalStatus.r11;
+
+}
+
+
+/**
+ Allocate memory < 1 MB and copy the thunker code into low memory. Se up
+ all the descriptors.
+
+ @param Private Private context for Legacy BIOS
+
+ @retval EFI_SUCCESS Should only pass.
+
+**/
+EFI_STATUS
+LegacyBiosInitializeThunk (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ GDT32 *CodeGdt;
+ GDT32 *DataGdt;
+ UINTN CodeStart;
+ UINTN CodeEnd;
+ UINTN ReverseThunkStart;
+ UINT32 Base;
+ LOW_MEMORY_THUNK *IntThunk;
+ UINTN TempData;
+
+ ASSERT (Private);
+
+ IntThunk = Private->IntThunk;
+
+ //
+ // Clear the reserved descriptor
+ //
+ ZeroMem (&(IntThunk->RealModeGdt[0]), sizeof (GDT32));
+
+ //
+ // Setup a descriptor for real-mode code
+ //
+ CodeGdt = &(IntThunk->RealModeGdt[1]);
+
+ //
+ // Fill in the descriptor with our real-mode segment value
+ //
+ CodeGdt->Type = 0xA;
+ //
+ // code/read
+ //
+ CodeGdt->System = 1;
+ CodeGdt->Dpl = 0;
+ CodeGdt->Present = 1;
+ CodeGdt->Software = 0;
+ CodeGdt->Reserved = 0;
+ CodeGdt->DefaultSize = 0;
+ //
+ // 16 bit operands
+ //
+ CodeGdt->Granularity = 0;
+
+ CodeGdt->LimitHi = 0;
+ CodeGdt->LimitLo = 0xffff;
+
+ Base = (*((UINT32 *) &IntThunk->Code));
+ CodeGdt->BaseHi = (Base >> 24) & 0xFF;
+ CodeGdt->BaseMid = (Base >> 16) & 0xFF;
+ CodeGdt->BaseLo = Base & 0xFFFF;
+
+ //
+ // Setup a descriptor for read-mode data
+ //
+ DataGdt = &(IntThunk->RealModeGdt[2]);
+ CopyMem (DataGdt, CodeGdt, sizeof (GDT32));
+
+ DataGdt->Type = 0x2;
+ //
+ // read/write data
+ //
+ DataGdt->BaseHi = 0x0;
+ //
+ // Base = 0
+ //
+ DataGdt->BaseMid = 0x0;
+ //
+ DataGdt->BaseLo = 0x0;
+ //
+ DataGdt->LimitHi = 0x0F;
+ //
+ // Limit = 4Gb
+ //
+ DataGdt->LimitLo = 0xFFFF;
+ //
+ DataGdt->Granularity = 0x1;
+ //
+ //
+ // Compute selector value
+ //
+ IntThunk->RealModeGdtDesc.Limit = (UINT16) (sizeof (IntThunk->RealModeGdt) - 1);
+ CopyMem (&IntThunk->RealModeGdtDesc.Base, (UINT32 *) &IntThunk->RealModeGdt, sizeof (UINT32));
+ //
+ // IntThunk->RealModeGdtDesc.Base = *((UINT32*) &IntThunk->RealModeGdt);
+ //
+ IntThunk->RealModeIdtDesc.Limit = 0xFFFF;
+ IntThunk->RealModeIdtDesc.Base = 0;
+ IntThunk->LowCodeSelector = (UINT32) ((UINTN) CodeGdt - IntThunk->RealModeGdtDesc.Base);
+ IntThunk->LowDataSelector = (UINT32) ((UINTN) DataGdt - IntThunk->RealModeGdtDesc.Base);
+
+ //
+ // Initialize low real-mode code thunk
+ //
+ RealModeTemplate (&CodeStart, &CodeEnd, &ReverseThunkStart, IntThunk);
+
+ TempData = (UINTN) &(IntThunk->Code);
+ IntThunk->LowReverseThunkStart = ((UINT32) TempData + (UINT32) (ReverseThunkStart - CodeStart));
+
+ EsalSetSalDataArea (TempData, (UINTN) IntThunk);
+ CopyMem (IntThunk->Code, (VOID *) CodeStart, CodeEnd - CodeStart);
+
+ IntThunk->EfiToLegacy16InitTable.ReverseThunkCallSegment = EFI_SEGMENT (*((UINT32 *) &IntThunk->LowReverseThunkStart));
+ IntThunk->EfiToLegacy16InitTable.ReverseThunkCallOffset = EFI_OFFSET (*((UINT32 *) &IntThunk->LowReverseThunkStart));
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ 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.
+
+ @param This Protocol instance pointer.
+ @param BiosInt Processor interrupt vector to invoke
+ @param Regs Register contexted passed into (and returned) from
+ thunk to 16-bit mode
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in the
+ target code. See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+LegacyBiosInt86 (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT8 BiosInt,
+ IN EFI_IA32_REGISTER_SET *Regs
+ )
+{
+ EFI_STATUS Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ LOW_MEMORY_THUNK *IntThunk;
+ UINT16 *Stack16;
+ EFI_TPL OriginalTpl;
+ UINTN IaSegment;
+ UINTN IaOffset;
+ UINTN *Address;
+ UINTN TempData;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ IntThunk = Private->IntThunk;
+
+ //
+ // Get the current flat GDT, IDT, and SS and store them in Private->IntThunk.
+ //
+ Status = LegacyBiosGetFlatDescs (Private);
+ ASSERT_EFI_ERROR (Status);
+
+ 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;
+ //
+ // Clear the error flag; thunk code may set it.
+ //
+ Stack16 = (UINT16 *) (IntThunk->Stack + LOW_STACK_SIZE);
+
+ //
+ // Copy regs to low memory stack
+ //
+ Stack16 -= sizeof (EFI_IA32_REGISTER_SET) / sizeof (UINT16);
+ CopyMem (Stack16, Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ //
+ // Provide low stack esp
+ //
+ TempData = ((UINTN) Stack16) - ((UINTN) IntThunk);
+ IntThunk->LowStack = *((UINT32 *) &TempData);
+
+ //
+ // Stack for reverse thunk flat mode.
+ // It must point to top of stack (end of stack space).
+ //
+ TempData = ((UINTN) IntThunk->RevThunkStack) + LOW_STACK_SIZE;
+ IntThunk->RevFlatStack = *((UINT32 *) &TempData);
+
+ //
+ // The call to Legacy16 is a critical section to EFI
+ //
+ OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ //
+ // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
+ //
+ Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259LegacyMode, NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Call the real mode thunk code
+ //
+ TempData = BiosInt * 4;
+ Address = (UINTN *) TempData;
+ IaOffset = 0xFFFF & (*Address);
+ IaSegment = 0xFFFF & ((*Address) >> 16);
+
+ Status = BiosIntCall (
+ BiosInt,
+ (UINT16) IaSegment,
+ (UINT16) IaOffset,
+ (EFI_IA32_REGISTER_SET *) Stack16,
+ IntThunk,
+ IntThunk->LowStack
+ );
+
+ //
+ // Check for errors with the thunk
+ //
+ switch (Status) {
+ case THUNK_OK:
+ break;
+
+ case THUNK_ERR_A20_UNSUP:
+ case THUNK_ERR_A20_FAILED:
+ default:
+ //
+ // For all errors, set EFLAGS.CF (used by legacy BIOS to indicate error).
+ //
+ Regs->X.Flags.CF = 1;
+ break;
+ }
+
+ Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259ProtectedMode, NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // End critical section
+ //
+ gBS->RestoreTPL (OriginalTpl);
+
+ //
+ // Return the resulting registers
+ //
+ CopyMem (Regs, Stack16, sizeof (EFI_IA32_REGISTER_SET));
+
+ return (BOOLEAN) (Regs->X.Flags.CF != 0);
+}
+
+
+/**
+ Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the
+ 16-bit register context on entry and exit. Arguments can be passed on
+ the Stack argument
+
+ @param This Protocol instance pointer.
+ @param Segment Segemnt of 16-bit mode call
+ @param Offset Offset of 16-bit mdoe call
+ @param Regs Register contexted passed into (and returned) from
+ thunk to 16-bit mode
+ @param Stack Caller allocated stack used to pass arguments
+ @param StackSize Size of Stack in bytes
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in the
+ target code. See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+LegacyBiosFarCall86 (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT16 Segment,
+ IN UINT16 Offset,
+ IN EFI_IA32_REGISTER_SET *Regs,
+ IN VOID *Stack,
+ IN UINTN StackSize
+ )
+{
+ EFI_STATUS Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ LOW_MEMORY_THUNK *IntThunk;
+ UINT16 *Stack16;
+ EFI_TPL OriginalTpl;
+ UINTN IaSegment;
+ UINTN IaOffset;
+ UINTN TempData;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ IntThunk = Private->IntThunk;
+ IaSegment = Segment;
+ IaOffset = Offset;
+
+ //
+ // Get the current flat GDT and IDT and store them in Private->IntThunk.
+ //
+ Status = LegacyBiosGetFlatDescs (Private);
+ ASSERT_EFI_ERROR (Status);
+
+ 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;
+ //
+ // Clear the error flag; thunk code may set it.
+ //
+ Stack16 = (UINT16 *) (IntThunk->Stack + LOW_STACK_SIZE);
+ if (Stack != NULL && StackSize != 0) {
+ //
+ // Copy Stack to low memory stack
+ //
+ Stack16 -= StackSize / sizeof (UINT16);
+ CopyMem (Stack16, Stack, StackSize);
+ }
+ //
+ // Copy regs to low memory stack
+ //
+ Stack16 -= sizeof (EFI_IA32_REGISTER_SET) / sizeof (UINT16);
+ CopyMem (Stack16, Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ //
+ // Provide low stack esp
+ //
+ TempData = ((UINTN) Stack16) - ((UINTN) IntThunk);
+ IntThunk->LowStack = *((UINT32 *) &TempData);
+
+ //
+ // The call to Legacy16 is a critical section to EFI
+ //
+ OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ //
+ // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
+ //
+ Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259LegacyMode, NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Call the real mode thunk code
+ //
+ Status = BiosIntCall (
+ 0x100,
+ (UINT16) IaSegment,
+ (UINT16) IaOffset,
+ (EFI_IA32_REGISTER_SET *) Stack16,
+ IntThunk,
+ IntThunk->LowStack
+ );
+
+ //
+ // Check for errors with the thunk
+ //
+ switch (Status) {
+ case THUNK_OK:
+ break;
+
+ case THUNK_ERR_A20_UNSUP:
+ case THUNK_ERR_A20_FAILED:
+ default:
+ //
+ // For all errors, set EFLAGS.CF (used by legacy BIOS to indicate error).
+ //
+ Regs->X.Flags.CF = 1;
+ break;
+ }
+ //
+ // Restore protected mode interrupt state
+ //
+ Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259ProtectedMode, NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // End critical section
+ //
+ gBS->RestoreTPL (OriginalTpl);
+
+ //
+ // Return the resulting registers
+ //
+ CopyMem (Regs, Stack16, sizeof (EFI_IA32_REGISTER_SET));
+ Stack16 += sizeof (EFI_IA32_REGISTER_SET) / sizeof (UINT16);
+
+ if (Stack != NULL && StackSize != 0) {
+ //
+ // Copy low memory stack to Stack
+ //
+ CopyMem (Stack, Stack16, StackSize);
+ Stack16 += StackSize / sizeof (UINT16);
+ }
+
+ return (BOOLEAN) (Regs->X.Flags.CF != 0);
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBbs.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBbs.c new file mode 100644 index 0000000..c15e599 --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBbs.c @@ -0,0 +1,384 @@ +/** @file
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+
+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.
+
+**/
+
+#include "LegacyBiosInterface.h"
+#include <IndustryStandard/Pci.h>
+
+// Give floppy 3 states
+// FLOPPY_PRESENT_WITH_MEDIA = Floppy controller present and media is inserted
+// FLOPPY_NOT_PRESENT = No floppy controller present
+// FLOPPY_PRESENT_NO_MEDIA = Floppy controller present but no media inserted
+//
+#define FLOPPY_NOT_PRESENT 0
+#define FLOPPY_PRESENT_WITH_MEDIA 1
+#define FLOPPY_PRESENT_NO_MEDIA 2
+
+BBS_TABLE *mBbsTable;
+BOOLEAN mBbsTableDoneFlag = FALSE;
+BOOLEAN IsHaveMediaInFloppy = TRUE;
+
+/**
+ Checks the state of the floppy and if media is inserted.
+
+ This routine checks the state of the floppy and if media is inserted.
+ There are 3 cases:
+ No floppy present - Set BBS entry to ignore
+ Floppy present & no media - Set BBS entry to lowest priority. We cannot
+ set it to ignore since 16-bit CSM will
+ indicate no floppy and thus drive A: is
+ unusable. CSM-16 will not try floppy since
+ lowest priority and thus not incur boot
+ time penality.
+ Floppy present & media - Set BBS entry to some priority.
+
+ @return State of floppy media
+
+**/
+UINT8
+HasMediaInFloppy (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+
+ HandleBuffer = NULL;
+ HandleCount = 0;
+
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiIsaIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ //
+ // If don't find any ISA/IO protocol assume no floppy. Need for floppy
+ // free system
+ //
+ if (HandleCount == 0) {
+ return FLOPPY_NOT_PRESENT;
+ }
+
+ ASSERT (HandleBuffer != NULL);
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x604)) {
+ continue;
+ }
+ //
+ // Update blockio in case the floppy is inserted in during BdsTimeout
+ //
+ Status = gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (BlkIo->Media->MediaPresent) {
+ FreePool (HandleBuffer);
+ return FLOPPY_PRESENT_WITH_MEDIA;
+ } else {
+ FreePool (HandleBuffer);
+ return FLOPPY_PRESENT_NO_MEDIA;
+ }
+ }
+
+ FreePool (HandleBuffer);
+
+ return FLOPPY_NOT_PRESENT;
+
+}
+
+
+/**
+ Complete build of BBS TABLE.
+
+ @param Private Legacy BIOS Instance data
+ @param BbsTable BBS Table passed to 16-bit code
+
+ @retval EFI_SUCCESS Removable media not present
+
+**/
+EFI_STATUS
+LegacyBiosBuildBbs (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN BBS_TABLE *BbsTable
+ )
+{
+ UINTN BbsIndex;
+ HDD_INFO *HddInfo;
+ UINTN HddIndex;
+ UINTN Index;
+
+ //
+ // First entry is floppy.
+ // Next 2*MAX_IDE_CONTROLLER entries are for onboard IDE.
+ // Next n entries are filled in after each ROM is dispatched.
+ // Entry filled in if follow BBS spec. See LegacyPci.c
+ // Next entries are for non-BBS compliant ROMS. They are filled in by
+ // 16-bit code during Legacy16UpdateBbs invocation. Final BootPriority
+ // occurs after that invocation.
+ //
+ // Floppy
+ // Set default state.
+ //
+ IsHaveMediaInFloppy = HasMediaInFloppy ();
+ if (IsHaveMediaInFloppy == FLOPPY_PRESENT_WITH_MEDIA) {
+ BbsTable[0].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ } else {
+ if (IsHaveMediaInFloppy == FLOPPY_PRESENT_NO_MEDIA) {
+ BbsTable[0].BootPriority = BBS_LOWEST_PRIORITY;
+ } else {
+ BbsTable[0].BootPriority = BBS_IGNORE_ENTRY;
+ }
+ }
+
+ BbsTable[0].Bus = 0xff;
+ BbsTable[0].Device = 0xff;
+ BbsTable[0].Function = 0xff;
+ BbsTable[0].DeviceType = BBS_FLOPPY;
+ BbsTable[0].Class = 01;
+ BbsTable[0].SubClass = 02;
+ BbsTable[0].StatusFlags.OldPosition = 0;
+ BbsTable[0].StatusFlags.Reserved1 = 0;
+ BbsTable[0].StatusFlags.Enabled = 0;
+ BbsTable[0].StatusFlags.Failed = 0;
+ BbsTable[0].StatusFlags.MediaPresent = 0;
+ BbsTable[0].StatusFlags.Reserved2 = 0;
+
+ //
+ // Onboard HDD - Note Each HDD controller controls 2 drives
+ // Master & Slave
+ //
+ HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];
+ //
+ // Get IDE Drive Info
+ //
+ LegacyBiosBuildIdeData (Private, &HddInfo, 0);
+
+ for (HddIndex = 0; HddIndex < MAX_IDE_CONTROLLER; HddIndex++) {
+
+ BbsIndex = HddIndex * 2 + 1;
+ for (Index = 0; Index < 2; ++Index) {
+
+ BbsTable[BbsIndex + Index].Bus = HddInfo[HddIndex].Bus;
+ BbsTable[BbsIndex + Index].Device = HddInfo[HddIndex].Device;
+ BbsTable[BbsIndex + Index].Function = HddInfo[HddIndex].Function;
+ BbsTable[BbsIndex + Index].Class = 01;
+ BbsTable[BbsIndex + Index].SubClass = 01;
+ BbsTable[BbsIndex + Index].StatusFlags.OldPosition = 0;
+ BbsTable[BbsIndex + Index].StatusFlags.Reserved1 = 0;
+ BbsTable[BbsIndex + Index].StatusFlags.Enabled = 0;
+ BbsTable[BbsIndex + Index].StatusFlags.Failed = 0;
+ BbsTable[BbsIndex + Index].StatusFlags.MediaPresent = 0;
+ BbsTable[BbsIndex + Index].StatusFlags.Reserved2 = 0;
+
+ //
+ // If no controller found or no device found set to ignore
+ // else set to unprioritized and set device type
+ //
+ if (HddInfo[HddIndex].CommandBaseAddress == 0) {
+ BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY;
+ } else {
+ if (Index == 0) {
+ if ((HddInfo[HddIndex].Status & (HDD_MASTER_IDE | HDD_MASTER_ATAPI_CDROM | HDD_MASTER_ATAPI_ZIPDISK)) != 0) {
+ BbsTable[BbsIndex + Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ if ((HddInfo[HddIndex].Status & HDD_MASTER_IDE) != 0) {
+ BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;
+ } else if ((HddInfo[HddIndex].Status & HDD_MASTER_ATAPI_CDROM) != 0) {
+ BbsTable[BbsIndex + Index].DeviceType = BBS_CDROM;
+ } else {
+ //
+ // for ZIPDISK
+ //
+ BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;
+ }
+ } else {
+ BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY;
+ }
+ } else {
+ if ((HddInfo[HddIndex].Status & (HDD_SLAVE_IDE | HDD_SLAVE_ATAPI_CDROM | HDD_SLAVE_ATAPI_ZIPDISK)) != 0) {
+ BbsTable[BbsIndex + Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ if ((HddInfo[HddIndex].Status & HDD_SLAVE_IDE) != 0) {
+ BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;
+ } else if ((HddInfo[HddIndex].Status & HDD_SLAVE_ATAPI_CDROM) != 0) {
+ BbsTable[BbsIndex + Index].DeviceType = BBS_CDROM;
+ } else {
+ //
+ // for ZIPDISK
+ //
+ BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;
+ }
+ } else {
+ BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY;
+ }
+ }
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ Get all BBS info
+
+ @param This Protocol instance pointer.
+ @param HddCount Number of HDD_INFO structures
+ @param HddInfo Onboard IDE controller information
+ @param BbsCount Number of BBS_TABLE structures
+ @param BbsTable List BBS entries
+
+ @retval EFI_SUCCESS Tables returned
+ @retval EFI_NOT_FOUND resource not found
+ @retval EFI_DEVICE_ERROR can not get BBS table
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosGetBbsInfo (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ OUT UINT16 *HddCount,
+ OUT HDD_INFO **HddInfo,
+ OUT UINT16 *BbsCount,
+ OUT BBS_TABLE **BbsTable
+ )
+{
+ LEGACY_BIOS_INSTANCE *Private;
+ EFI_IA32_REGISTER_SET Regs;
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
+// HDD_INFO *LocalHddInfo;
+// IN BBS_TABLE *LocalBbsTable;
+ UINTN NumHandles;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ UINTN TempData;
+ UINT32 Granularity;
+
+ HandleBuffer = NULL;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
+// LocalHddInfo = EfiToLegacy16BootTable->HddInfo;
+// LocalBbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
+
+ if (!mBbsTableDoneFlag) {
+ mBbsTable = Private->BbsTablePtr;
+
+ //
+ // Always enable disk controllers so 16-bit CSM code has valid information for all
+ // drives.
+ //
+ //
+ // Get PciRootBridgeIO protocol
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ NULL,
+ &NumHandles,
+ &HandleBuffer
+ );
+
+ if (NumHandles == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ mBbsTableDoneFlag = TRUE;
+ for (Index = 0; Index < NumHandles; Index++) {
+ //
+ // Connect PciRootBridgeIO protocol handle with FALSE parameter to let
+ // PCI bus driver enumerate all subsequent handles
+ //
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);
+
+ }
+
+ LegacyBiosBuildBbs (Private, mBbsTable);
+
+ Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xe0000, 0x20000, &Granularity);
+
+ //
+ // Call into Legacy16 code to add to BBS table for non BBS compliant OPROMs.
+ //
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16UpdateBbs;
+
+ //
+ // Pass in handoff data
+ //
+ TempData = (UINTN) EfiToLegacy16BootTable;
+ Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);
+ Regs.X.BX = EFI_OFFSET ((UINT32) TempData);
+
+ Private->LegacyBios.FarCall86 (
+ This,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
+ Private->LegacyRegion->Lock (Private->LegacyRegion, 0xe0000, 0x20000, &Granularity);
+
+ if (Regs.X.AX != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ *HddCount = MAX_IDE_CONTROLLER;
+ *HddInfo = EfiToLegacy16BootTable->HddInfo;
+ *BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
+ *BbsCount = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE));
+ return EFI_SUCCESS;
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBda.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBda.c new file mode 100644 index 0000000..c45d5d4 --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBda.c @@ -0,0 +1,66 @@ +/** @file
+ This code fills in BDA (0x400) and EBDA (pointed to by 0x4xx)
+ information. There is support for doing initializeation before
+ Legacy16 is loaded and before a legacy boot is attempted.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+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.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+/**
+ Fill in the standard BDA and EBDA stuff before Legacy16 load
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosInitBda (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ BDA_STRUC *Bda;
+ UINT8 *Ebda;
+
+ Bda = (BDA_STRUC *) ((UINTN) 0x400);
+ Ebda = (UINT8 *) ((UINTN) 0x9fc00);
+
+ ZeroMem (Bda, 0x100);
+ ZeroMem (Ebda, 0x400);
+ //
+ // 640k-1k for EBDA
+ //
+ Bda->MemSize = 0x27f;
+ Bda->KeyHead = 0x1e;
+ Bda->KeyTail = 0x1e;
+ Bda->FloppyData = 0x00;
+ Bda->FloppyTimeout = 0xff;
+
+ Bda->KeyStart = 0x001E;
+ Bda->KeyEnd = 0x003E;
+ Bda->KeyboardStatus = 0x10;
+ Bda->Ebda = 0x9fc0;
+
+ //
+ // Move LPT time out here and zero out LPT4 since some SCSI OPROMS
+ // use this as scratch pad (LPT4 is Reserved)
+ //
+ Bda->Lpt1_2Timeout = 0x1414;
+ Bda->Lpt3_4Timeout = 0x1400;
+
+ *Ebda = 0x01;
+
+ return EFI_SUCCESS;
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c new file mode 100644 index 0000000..75add5e --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c @@ -0,0 +1,1007 @@ +/** @file
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+
+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.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+#define PHYSICAL_ADDRESS_TO_POINTER(Address) ((VOID *) ((UINTN) Address))
+
+//
+// define maximum number of HDD system supports
+//
+#define MAX_HDD_ENTRIES 0x30
+
+//
+// Module Global:
+// Since this driver will only ever produce one instance of the Private Data
+// protocol you are not required to dynamically allocate the PrivateData.
+//
+LEGACY_BIOS_INSTANCE mPrivateData;
+
+//
+// The end of OPROM shadow address
+//
+UINTN mEndOpromShadowAddress = 0;
+
+/**
+ Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode
+ memory.
+
+ @param AllocateType Allocated Legacy Memory Type
+ @param StartPageAddress Start address of range
+ @param Pages Number of pages to allocate
+ @param Result Result of allocation
+
+ @retval EFI_SUCCESS Legacy16 code loaded
+ @retval Other No protocol installed, unload driver.
+
+**/
+EFI_STATUS
+AllocateLegacyMemory (
+ IN EFI_ALLOCATE_TYPE AllocateType,
+ IN EFI_PHYSICAL_ADDRESS StartPageAddress,
+ IN UINTN Pages,
+ OUT EFI_PHYSICAL_ADDRESS *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS MemPage;
+
+ //
+ // Allocate Pages of memory less <= StartPageAddress
+ //
+ MemPage = (EFI_PHYSICAL_ADDRESS) (UINTN) StartPageAddress;
+ Status = gBS->AllocatePages (
+ AllocateType,
+ EfiBootServicesCode,
+ Pages,
+ &MemPage
+ );
+ //
+ // Do not ASSERT on Status error but let caller decide since some cases
+ // memory is already taken but that is ok.
+ //
+ if (!EFI_ERROR (Status)) {
+ *Result = (EFI_PHYSICAL_ADDRESS) (UINTN) MemPage;
+ }
+ //
+ // If reach here the status = EFI_SUCCESS
+ //
+ return Status;
+}
+
+
+/**
+ This function is called when EFI needs to reserve an area in the 0xE0000 or 0xF0000
+ 64 KB blocks.
+
+ Note: inconsistency with the Framework CSM spec. Per the spec, this function may be
+ invoked only once. This limitation is relaxed to allow multiple calls in this implemenation.
+
+ @param This Protocol instance pointer.
+ @param LegacyMemorySize Size of required region
+ @param Region Region to use. 00 = Either 0xE0000 or 0xF0000
+ block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000
+ block
+ @param Alignment Address alignment. Bit mapped. First non-zero
+ bit from right is alignment.
+ @param LegacyMemoryAddress Region Assigned
+
+ @retval EFI_SUCCESS Region assigned
+ @retval EFI_ACCESS_DENIED Procedure previously invoked
+ @retval Other Region not assigned
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosGetLegacyRegion (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINTN LegacyMemorySize,
+ IN UINTN Region,
+ IN UINTN Alignment,
+ OUT VOID **LegacyMemoryAddress
+ )
+{
+
+ LEGACY_BIOS_INSTANCE *Private;
+ EFI_IA32_REGISTER_SET Regs;
+ EFI_STATUS Status;
+ UINT32 Granularity;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16GetTableAddress;
+ Regs.X.BX = (UINT16) Region;
+ Regs.X.CX = (UINT16) LegacyMemorySize;
+ Regs.X.DX = (UINT16) Alignment;
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ if (Regs.X.AX == 0) {
+ *LegacyMemoryAddress = (VOID *) (UINTN) ((Regs.X.DS << 4) + Regs.X.BX);
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
+ Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
+
+ return Status;
+}
+
+
+/**
+ This function is called when copying data to the region assigned by
+ EFI_LEGACY_BIOS_PROTOCOL.GetLegacyRegion().
+
+ @param This Protocol instance pointer.
+ @param LegacyMemorySize Size of data to copy
+ @param LegacyMemoryAddress Legacy Region destination address Note: must
+ be in region assigned by
+ LegacyBiosGetLegacyRegion
+ @param LegacyMemorySourceAddress Source of data
+
+ @retval EFI_SUCCESS The data was copied successfully.
+ @retval EFI_ACCESS_DENIED Either the starting or ending address is out of bounds.
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosCopyLegacyRegion (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINTN LegacyMemorySize,
+ IN VOID *LegacyMemoryAddress,
+ IN VOID *LegacyMemorySourceAddress
+ )
+{
+
+ LEGACY_BIOS_INSTANCE *Private;
+ UINT32 Granularity;
+
+ if ((LegacyMemoryAddress < (VOID *)(UINTN)0xE0000 ) ||
+ ((UINTN) LegacyMemoryAddress + LegacyMemorySize > (UINTN) 0x100000)
+ ) {
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // There is no protection from writes over lapping if this function is
+ // called multiple times.
+ //
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
+ CopyMem (LegacyMemoryAddress, LegacyMemorySourceAddress, LegacyMemorySize);
+
+ Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
+ Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find
+ the $EFI table in the shadow area. Thunk into the Legacy16 code after it had
+ been shadowed.
+
+ @param Private Legacy BIOS context data
+
+ @retval EFI_SUCCESS Legacy16 code loaded
+ @retval Other No protocol installed, unload driver.
+
+**/
+EFI_STATUS
+ShadowAndStartLegacy16 (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Ptr;
+ UINT8 *PtrEnd;
+ BOOLEAN Done;
+ EFI_COMPATIBILITY16_TABLE *Table;
+ UINT8 CheckSum;
+ EFI_IA32_REGISTER_SET Regs;
+ EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable;
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
+ VOID *LegacyBiosImage;
+ UINTN LegacyBiosImageSize;
+ UINTN E820Size;
+ UINT32 *ClearPtr;
+ BBS_TABLE *BbsTable;
+ LEGACY_EFI_HDD_TABLE *LegacyEfiHddTable;
+ UINTN Index;
+ UINT32 TpmPointer;
+ VOID *TpmBinaryImage;
+ UINTN TpmBinaryImageSize;
+ UINTN Location;
+ UINTN Alignment;
+ UINTN TempData;
+ EFI_PHYSICAL_ADDRESS Address;
+ UINT16 OldMask;
+ UINT16 NewMask;
+ UINT32 Granularity;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+
+ Location = 0;
+ Alignment = 0;
+
+ //
+ // we allocate the C/D/E/F segment as RT code so no one will use it any more.
+ //
+ Address = 0xC0000;
+ gDS->GetMemorySpaceDescriptor (Address, &Descriptor);
+ if (Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {
+ //
+ // If it is already reserved, we should be safe, or else we allocate it.
+ //
+ Status = gBS->AllocatePages (
+ AllocateAddress,
+ EfiRuntimeServicesCode,
+ 0x40000/EFI_PAGE_SIZE,
+ &Address
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Bugbug: need to figure out whether C/D/E/F segment should be marked as reserved memory.
+ //
+ DEBUG ((DEBUG_ERROR, "Failed to allocate the C/D/E/F segment Status = %r", Status));
+ }
+ }
+
+ //
+ // start testtest
+ // GetTimerValue (&Ticker);
+ //
+ // gRT->SetVariable (L"StartLegacy",
+ // &gEfiGlobalVariableGuid,
+ // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ // sizeof (UINT64),
+ // (VOID *)&Ticker
+ // );
+ // end testtest
+ //
+ EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
+ Status = Private->LegacyBiosPlatform->GetPlatformInfo (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformBinarySystemRom,
+ &LegacyBiosImage,
+ &LegacyBiosImageSize,
+ &Location,
+ &Alignment,
+ 0,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private->BiosStart = (UINT32) (0x100000 - LegacyBiosImageSize);
+ Private->OptionRom = 0xc0000;
+ Private->LegacyBiosImageSize = (UINT32) LegacyBiosImageSize;
+
+ //
+ // Can only shadow into memory allocated for legacy useage.
+ //
+ ASSERT (Private->BiosStart > Private->OptionRom);
+
+ //
+ // Shadow Legacy BIOS. Turn on memory and copy image
+ //
+ Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity);
+
+ ClearPtr = (VOID *) ((UINTN) 0xc0000);
+
+ //
+ // Initialize region from 0xc0000 to start of BIOS to all ffs. This allows unused
+ // regions to be used by EMM386 etc.
+ //
+ SetMem ((VOID *) ClearPtr, (UINTN) (0x40000 - LegacyBiosImageSize), 0xff);
+
+ TempData = Private->BiosStart;
+
+ CopyMem (
+ (VOID *) TempData,
+ LegacyBiosImage,
+ (UINTN) LegacyBiosImageSize
+ );
+
+ Private->Cpu->FlushDataCache (Private->Cpu, 0xc0000, 0x40000, EfiCpuFlushTypeWriteBackInvalidate);
+
+ //
+ // Search for Legacy16 table in Shadowed ROM
+ //
+ Done = FALSE;
+ Table = NULL;
+ for (Ptr = (UINT8 *) TempData; Ptr < (UINT8 *) ((UINTN) 0x100000) && !Done; Ptr += 0x10) {
+ if (*(UINT32 *) Ptr == SIGNATURE_32 ('I', 'F', 'E', '$')) {
+ Table = (EFI_COMPATIBILITY16_TABLE *) Ptr;
+ PtrEnd = Ptr + Table->TableLength;
+ for (CheckSum = 0; Ptr < PtrEnd; Ptr++) {
+ CheckSum = (UINT8) (CheckSum +*Ptr);
+ }
+
+ Done = TRUE;
+ }
+ }
+
+ if (Table == NULL) {
+ DEBUG ((EFI_D_ERROR, "No Legacy16 table found\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ if (!Done) {
+ //
+ // Legacy16 table header checksum error.
+ //
+ DEBUG ((EFI_D_ERROR, "Legacy16 table found with bad talbe header checksum\n"));
+ }
+
+ //
+ // Remember location of the Legacy16 table
+ //
+ Private->Legacy16Table = Table;
+ Private->Legacy16CallSegment = Table->Compatibility16CallSegment;
+ Private->Legacy16CallOffset = Table->Compatibility16CallOffset;
+ EfiToLegacy16InitTable = &Private->IntThunk->EfiToLegacy16InitTable;
+ Private->Legacy16InitPtr = EfiToLegacy16InitTable;
+ Private->Legacy16BootPtr = &Private->IntThunk->EfiToLegacy16BootTable;
+ Private->InternalIrqRoutingTable = NULL;
+ Private->NumberIrqRoutingEntries = 0;
+ Private->BbsTablePtr = NULL;
+ Private->LegacyEfiHddTable = NULL;
+ Private->DiskEnd = 0;
+ Private->Disk4075 = 0;
+ Private->HddTablePtr = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo;
+ Private->NumberHddControllers = MAX_IDE_CONTROLLER;
+ Private->Dump[0] = 'D';
+ Private->Dump[1] = 'U';
+ Private->Dump[2] = 'M';
+ Private->Dump[3] = 'P';
+
+ ZeroMem (
+ Private->Legacy16BootPtr,
+ sizeof (EFI_TO_COMPATIBILITY16_BOOT_TABLE)
+ );
+
+ //
+ // Store away a copy of the EFI System Table
+ //
+ Table->EfiSystemTable = (UINT32) (UINTN) gST;
+
+ //
+ // Get the end of OPROM shadow address
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformInfo (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformEndOpromShadowAddr,
+ NULL,
+ NULL,
+ &mEndOpromShadowAddress,
+ NULL,
+ 0,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ mEndOpromShadowAddress = 0xDFFFF;
+ }
+
+ //
+ // IPF CSM integration -Bug
+ //
+ // Construct the Legacy16 boot memory map. This sets up number of
+ // E820 entries.
+ //
+ LegacyBiosBuildE820 (Private, &E820Size);
+ //
+ // Initialize BDA and EBDA standard values needed to load Legacy16 code
+ //
+ LegacyBiosInitBda (Private);
+ LegacyBiosInitCmos (Private);
+
+ //
+ // All legacy interrupt should be masked when do initialization work from legacy 16 code.
+ //
+ Private->Legacy8259->GetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL);
+ NewMask = 0xFFFF;
+ Private->Legacy8259->SetMask(Private->Legacy8259, &NewMask, NULL, NULL, NULL);
+
+ //
+ // Call into Legacy16 code to do an INIT
+ //
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16InitializeYourself;
+ Regs.X.ES = EFI_SEGMENT (*((UINT32 *) &EfiToLegacy16InitTable));
+ Regs.X.BX = EFI_OFFSET (*((UINT32 *) &EfiToLegacy16InitTable));
+
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Table->Compatibility16CallSegment,
+ Table->Compatibility16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ //
+ // Restore original legacy interrupt mask value
+ //
+ Private->Legacy8259->SetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL);
+
+ if (Regs.X.AX != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // start testtest
+ // GetTimerValue (&Ticker);
+ //
+ // gRT->SetVariable (L"BackFromInitYourself",
+ // &gEfiGlobalVariableGuid,
+ // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ // sizeof (UINT64),
+ // (VOID *)&Ticker
+ // );
+ // end testtest
+ //
+ // Copy E820 table after InitializeYourself is completed
+ //
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16GetTableAddress;
+ Regs.X.CX = (UINT16) E820Size;
+ Regs.X.DX = 1;
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Table->Compatibility16CallSegment,
+ Table->Compatibility16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ Table->E820Pointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
+ Table->E820Length = (UINT32) E820Size;
+ if (Regs.X.AX != 0) {
+ DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n"));
+ } else {
+ TempData = Table->E820Pointer;
+ CopyMem ((VOID *) TempData, Private->E820Table, E820Size);
+ }
+ //
+ // Get PnPInstallationCheck Info.
+ //
+ Private->PnPInstallationCheckSegment = Table->PnPInstallationCheckSegment;
+ Private->PnPInstallationCheckOffset = Table->PnPInstallationCheckOffset;
+
+ //
+ // Check if PCI Express is supported. If yes, Save base address.
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformInfo (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformPciExpressBase,
+ NULL,
+ NULL,
+ &Location,
+ &Alignment,
+ 0,
+ 0
+ );
+ if (!EFI_ERROR (Status)) {
+ Private->Legacy16Table->PciExpressBase = (UINT32)Location;
+ Location = 0;
+ }
+ //
+ // Check if TPM is supported. If yes get a region in E0000,F0000 to copy it
+ // into, copy it and update pointer to binary image. This needs to be
+ // done prior to any OPROM for security purposes.
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformInfo (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformBinaryTpmBinary,
+ &TpmBinaryImage,
+ &TpmBinaryImageSize,
+ &Location,
+ &Alignment,
+ 0,
+ 0
+ );
+ if (!EFI_ERROR (Status)) {
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16GetTableAddress;
+ Regs.X.CX = (UINT16) TpmBinaryImageSize;
+ Regs.X.DX = 1;
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Table->Compatibility16CallSegment,
+ Table->Compatibility16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ TpmPointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
+ if (Regs.X.AX != 0) {
+ DEBUG ((EFI_D_ERROR, "TPM cannot be loaded\n"));
+ } else {
+ CopyMem ((VOID *) (UINTN)TpmPointer, TpmBinaryImage, TpmBinaryImageSize);
+ Table->TpmSegment = Regs.X.DS;
+ Table->TpmOffset = Regs.X.BX;
+
+ }
+ }
+ //
+ // Lock the Legacy BIOS region
+ //
+ Private->Cpu->FlushDataCache (Private->Cpu, Private->BiosStart, (UINT32) LegacyBiosImageSize, EfiCpuFlushTypeWriteBackInvalidate);
+ Private->LegacyRegion->Lock (Private->LegacyRegion, Private->BiosStart, (UINT32) LegacyBiosImageSize, &Granularity);
+
+ //
+ // Get the BbsTable from LOW_MEMORY_THUNK
+ //
+ BbsTable = (BBS_TABLE *)(UINTN)Private->IntThunk->BbsTable;
+ ZeroMem ((VOID *)BbsTable, sizeof (Private->IntThunk->BbsTable));
+
+ EfiToLegacy16BootTable->BbsTable = (UINT32)(UINTN)BbsTable;
+ Private->BbsTablePtr = (VOID *) BbsTable;
+ //
+ // Skip Floppy and possible onboard IDE drives
+ //
+ EfiToLegacy16BootTable->NumberBbsEntries = 1 + 2 * MAX_IDE_CONTROLLER;
+
+ for (Index = 0; Index < (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE)); Index++) {
+ BbsTable[Index].BootPriority = BBS_IGNORE_ENTRY;
+ }
+ //
+ // Allocate space for Legacy HDD table
+ //
+ LegacyEfiHddTable = (LEGACY_EFI_HDD_TABLE *) AllocateZeroPool ((UINTN) MAX_HDD_ENTRIES * sizeof (LEGACY_EFI_HDD_TABLE));
+ ASSERT (LegacyEfiHddTable);
+
+ Private->LegacyEfiHddTable = LegacyEfiHddTable;
+ Private->LegacyEfiHddTableIndex = 0x00;
+
+ //
+ // start testtest
+ // GetTimerValue (&Ticker);
+ //
+ // gRT->SetVariable (L"EndOfLoadFv",
+ // &gEfiGlobalVariableGuid,
+ // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ // sizeof (UINT64),
+ // (VOID *)&Ticker
+ // );
+ // end testtest
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Shadow all legacy16 OPROMs that haven't been shadowed.
+ Warning: Use this with caution. This routine disconnects all EFI
+ drivers. If used externally then caller must re-connect EFI
+ drivers.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS OPROMs shadowed
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosShadowAllLegacyOproms (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This
+ )
+{
+ LEGACY_BIOS_INSTANCE *Private;
+
+ //
+ // EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
+ // EFI_LEGACY16_TABLE *Legacy16Table;
+ //
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+
+ //
+ // LegacyBiosPlatform = Private->LegacyBiosPlatform;
+ // Legacy16Table = Private->Legacy16Table;
+ //
+ // Shadow PCI ROMs. We must do this near the end since this will kick
+ // of Native EFI drivers that may be needed to collect info for Legacy16
+ //
+ // WARNING: PciIo is gone after this call.
+ //
+ PciProgramAllInterruptLineRegisters (Private);
+
+ PciShadowRoms (Private);
+
+ //
+ // Shadow PXE base code, BIS etc.
+ //
+ // LegacyBiosPlatform->ShadowServiceRoms (LegacyBiosPlatform,
+ // &Private->OptionRom,
+ // Legacy16Table);
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the PCI BIOS interface version.
+
+ @param Private Driver private data.
+
+ @return The PCI interface version number in Binary Coded Decimal (BCD) format.
+ E.g.: 0x0210 indicates 2.10, 0x0300 indicates 3.00
+
+**/
+UINT16
+GetPciInterfaceVersion (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_IA32_REGISTER_SET Reg;
+ BOOLEAN ThunkFailed;
+ UINT16 PciInterfaceVersion;
+
+ PciInterfaceVersion = 0;
+
+ Reg.X.AX = 0xB101;
+ Reg.E.EDI = 0;
+
+ ThunkFailed = Private->LegacyBios.Int86 (&Private->LegacyBios, 0x1A, &Reg);
+ if (!ThunkFailed) {
+ //
+ // From PCI Firmware 3.0 Specification:
+ // If the CARRY FLAG [CF] is cleared and AH is set to 00h, it is still necessary to examine the
+ // contents of [EDX] for the presence of the string "PCI" + (trailing space) to fully validate the
+ // presence of the PCI function set. [BX] will further indicate the version level, with enough
+ // granularity to allow for incremental changes in the code that don't affect the function interface.
+ // Version numbers are stored as Binary Coded Decimal (BCD) values. For example, Version 2.10
+ // would be returned as a 02h in the [BH] registers and 10h in the [BL] registers.
+ //
+ if ((Reg.X.Flags.CF == 0) && (Reg.H.AH == 0) && (Reg.E.EDX == SIGNATURE_32 ('P', 'C', 'I', ' '))) {
+ PciInterfaceVersion = Reg.X.BX;
+ }
+ }
+ return PciInterfaceVersion;
+}
+
+/**
+ Install Driver to produce Legacy BIOS protocol.
+
+ @param ImageHandle Handle of driver image.
+ @param SystemTable Pointer to system table.
+
+ @retval EFI_SUCCESS Legacy BIOS protocol installed
+ @retval No protocol installed, unload driver.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosInstall (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable;
+ EFI_PHYSICAL_ADDRESS MemoryAddress;
+ VOID *MemoryPtr;
+ EFI_PHYSICAL_ADDRESS MemoryAddressUnder1MB;
+ UINTN Index;
+ UINT32 *BaseVectorMaster;
+ EFI_PHYSICAL_ADDRESS StartAddress;
+ UINT32 *ClearPtr;
+ EFI_PHYSICAL_ADDRESS MemStart;
+ UINT32 IntRedirCode;
+ UINT32 Granularity;
+ BOOLEAN DecodeOn;
+ UINT32 MemorySize;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+ UINT64 Length;
+
+ //
+ // Load this driver's image to memory
+ //
+ Status = RelocateImageUnder4GIfNeeded (ImageHandle, SystemTable);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private = &mPrivateData;
+ ZeroMem (Private, sizeof (LEGACY_BIOS_INSTANCE));
+
+ //
+ // Grab a copy of all the protocols we depend on. Any error would
+ // be a dispatcher bug!.
+ //
+ Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Private->Cpu);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (&gEfiLegacyRegion2ProtocolGuid, NULL, (VOID **) &Private->LegacyRegion);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosPlatformProtocolGuid, NULL, (VOID **) &Private->LegacyBiosPlatform);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &Private->Legacy8259);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (&gEfiLegacyInterruptProtocolGuid, NULL, (VOID **) &Private->LegacyInterrupt);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Locate Memory Test Protocol if exists
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiGenericMemTestProtocolGuid,
+ NULL,
+ (VOID **) &Private->GenericMemoryTest
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Make sure all memory from 0-640K is tested
+ //
+ for (StartAddress = 0; StartAddress < 0xa0000; ) {
+ gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);
+ if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {
+ StartAddress = Descriptor.BaseAddress + Descriptor.Length;
+ continue;
+ }
+ Length = MIN (Descriptor.Length, 0xa0000 - StartAddress);
+ Private->GenericMemoryTest->CompatibleRangeTest (
+ Private->GenericMemoryTest,
+ StartAddress,
+ Length
+ );
+ StartAddress = StartAddress + Length;
+ }
+ //
+ // Make sure all memory from 1MB to 16MB is tested and added to memory map
+ //
+ for (StartAddress = BASE_1MB; StartAddress < BASE_16MB; ) {
+ gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);
+ if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {
+ StartAddress = Descriptor.BaseAddress + Descriptor.Length;
+ continue;
+ }
+ Length = MIN (Descriptor.Length, BASE_16MB - StartAddress);
+ Private->GenericMemoryTest->CompatibleRangeTest (
+ Private->GenericMemoryTest,
+ StartAddress,
+ Length
+ );
+ StartAddress = StartAddress + Length;
+ }
+
+ Private->Signature = LEGACY_BIOS_INSTANCE_SIGNATURE;
+
+ Private->LegacyBios.Int86 = LegacyBiosInt86;
+ Private->LegacyBios.FarCall86 = LegacyBiosFarCall86;
+ Private->LegacyBios.CheckPciRom = LegacyBiosCheckPciRom;
+ Private->LegacyBios.InstallPciRom = LegacyBiosInstallPciRom;
+ Private->LegacyBios.LegacyBoot = LegacyBiosLegacyBoot;
+ Private->LegacyBios.UpdateKeyboardLedStatus = LegacyBiosUpdateKeyboardLedStatus;
+ Private->LegacyBios.GetBbsInfo = LegacyBiosGetBbsInfo;
+ Private->LegacyBios.ShadowAllLegacyOproms = LegacyBiosShadowAllLegacyOproms;
+ Private->LegacyBios.PrepareToBootEfi = LegacyBiosPrepareToBootEfi;
+ Private->LegacyBios.GetLegacyRegion = LegacyBiosGetLegacyRegion;
+ Private->LegacyBios.CopyLegacyRegion = LegacyBiosCopyLegacyRegion;
+ Private->LegacyBios.BootUnconventionalDevice = LegacyBiosBootUnconventionalDevice;
+
+ Private->ImageHandle = ImageHandle;
+
+ //
+ // Enable read attribute of legacy region.
+ //
+ DecodeOn = TRUE;
+ Private->LegacyRegion->Decode (
+ Private->LegacyRegion,
+ 0xc0000,
+ 0x40000,
+ &Granularity,
+ &DecodeOn
+ );
+ //
+ // Set Cachebility for legacy region
+ // BUGBUG: Comments about this legacy region cacheability setting
+ // This setting will make D865GCHProduction CSM Unhappy
+ //
+ if (PcdGetBool (PcdLegacyBiosCacheLegacyRegion)) {
+ gDS->SetMemorySpaceAttributes (
+ 0x0,
+ 0xA0000,
+ EFI_MEMORY_WB
+ );
+ gDS->SetMemorySpaceAttributes (
+ 0xc0000,
+ 0x40000,
+ EFI_MEMORY_WB
+ );
+ }
+
+ gDS->SetMemorySpaceAttributes (
+ 0xA0000,
+ 0x20000,
+ EFI_MEMORY_UC
+ );
+
+ //
+ // Allocate 0 - 4K for real mode interupt vectors and BDA.
+ //
+ AllocateLegacyMemory (
+ AllocateAddress,
+ 0,
+ 1,
+ &MemoryAddress
+ );
+ ASSERT (MemoryAddress == 0x000000000);
+
+ ClearPtr = (VOID *) ((UINTN) 0x0000);
+
+ //
+ // Initialize region from 0x0000 to 4k. This initializes interrupt vector
+ // range.
+ //
+ gBS->SetMem ((VOID *) ClearPtr, 0x400, INITIAL_VALUE_BELOW_1K);
+ ZeroMem ((VOID *) ((UINTN)ClearPtr + 0x400), 0xC00);
+
+ //
+ // Allocate pages for OPROM usage
+ //
+ MemorySize = PcdGet32 (PcdEbdaReservedMemorySize);
+ ASSERT ((MemorySize & 0xFFF) == 0);
+
+ Status = AllocateLegacyMemory (
+ AllocateAddress,
+ CONVENTIONAL_MEMORY_TOP - MemorySize,
+ EFI_SIZE_TO_PAGES (MemorySize),
+ &MemoryAddress
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ZeroMem ((VOID *) ((UINTN) MemoryAddress), MemorySize);
+
+ //
+ // Allocate all 32k chunks from 0x60000 ~ 0x88000 for Legacy OPROMs that
+ // don't use PMM but look for zeroed memory. Note that various non-BBS
+ // SCSIs expect different areas to be free
+ //
+ for (MemStart = 0x60000; MemStart < 0x88000; MemStart += 0x1000) {
+ Status = AllocateLegacyMemory (
+ AllocateAddress,
+ MemStart,
+ 1,
+ &MemoryAddress
+ );
+ if (!EFI_ERROR (Status)) {
+ MemoryPtr = (VOID *) ((UINTN) MemoryAddress);
+ ZeroMem (MemoryPtr, 0x1000);
+ } else {
+ DEBUG ((EFI_D_ERROR, "WARNING: Allocate legacy memory fail for SCSI card - %x\n", MemStart));
+ }
+ }
+
+ //
+ // Allocate a 64k area (16 4k pages) for 16-bit code for scratch pad and zero it out
+ //
+ Status = AllocateLegacyMemory (
+ AllocateMaxAddress,
+ CONVENTIONAL_MEMORY_TOP,
+ 16,
+ &MemoryAddressUnder1MB
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ZeroMem ((VOID *) ((UINTN) MemoryAddressUnder1MB), 0x10000);
+
+ //
+ // Allocate space for thunker and Init Thunker
+ //
+ Status = AllocateLegacyMemory (
+ AllocateMaxAddress,
+ CONVENTIONAL_MEMORY_TOP,
+ (sizeof (LOW_MEMORY_THUNK) / EFI_PAGE_SIZE) + 2,
+ &MemoryAddress
+ );
+ ASSERT_EFI_ERROR (Status);
+ Private->IntThunk = (LOW_MEMORY_THUNK *) (UINTN) MemoryAddress;
+ EfiToLegacy16InitTable = &Private->IntThunk->EfiToLegacy16InitTable;
+ EfiToLegacy16InitTable->ThunkStart = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress;
+ EfiToLegacy16InitTable->ThunkSizeInBytes = (UINT32) (sizeof (LOW_MEMORY_THUNK));
+
+ Status = LegacyBiosInitializeThunk (Private);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Init the legacy memory map in memory < 1 MB.
+ //
+ EfiToLegacy16InitTable->BiosLessThan1MB = (UINT32) MemoryAddressUnder1MB;
+ EfiToLegacy16InitTable->LowPmmMemory = (UINT32) MemoryAddressUnder1MB;
+ EfiToLegacy16InitTable->LowPmmMemorySizeInBytes = 0x10000;
+
+ //
+ // Allocate 4 MB of PMM Memory under 16 MB
+ //
+ Status = AllocateLegacyMemory (
+ AllocateMaxAddress,
+ 0x1000000,
+ 0x400,
+ &MemoryAddress
+ );
+ if (!EFI_ERROR (Status)) {
+ EfiToLegacy16InitTable->HiPmmMemory = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress;
+ EfiToLegacy16InitTable->HiPmmMemorySizeInBytes = PMM_MEMORY_SIZE;
+ }
+
+ //
+ // ShutdownAPs();
+ //
+ // Start the Legacy BIOS;
+ //
+ Status = ShadowAndStartLegacy16 (Private);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Initialize interrupt redirection code and entries;
+ // IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.
+ //
+ CopyMem (
+ Private->IntThunk->InterruptRedirectionCode,
+ (VOID *) (UINTN) InterruptRedirectionTemplate,
+ sizeof (Private->IntThunk->InterruptRedirectionCode)
+ );
+
+ //
+ // Save Unexpected interrupt vector so can restore it just prior to boot
+ //
+ BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
+ Private->BiosUnexpectedInt = BaseVectorMaster[0];
+ IntRedirCode = (UINT32) (UINTN) Private->IntThunk->InterruptRedirectionCode;
+ for (Index = 0; Index < 8; Index++) {
+ BaseVectorMaster[Index] = (EFI_SEGMENT (IntRedirCode + Index * 4) << 16) | EFI_OFFSET (IntRedirCode + Index * 4);
+ }
+ //
+ // Save EFI value
+ //
+ Private->ThunkSeg = (UINT16) (EFI_SEGMENT (IntRedirCode));
+
+ //
+ // Make a new handle and install the protocol
+ //
+ Private->Handle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &Private->Handle,
+ &gEfiLegacyBiosProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Private->LegacyBios
+ );
+ Private->Csm16PciInterfaceVersion = GetPciInterfaceVersion (Private);
+
+ DEBUG ((EFI_D_INFO, "CSM16 PCI BIOS Interface Version: %02x.%02x\n",
+ (UINT8) (Private->Csm16PciInterfaceVersion >> 8),
+ (UINT8) Private->Csm16PciInterfaceVersion
+ ));
+ ASSERT (Private->Csm16PciInterfaceVersion != 0);
+ return Status;
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf new file mode 100644 index 0000000..4e310aa --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf @@ -0,0 +1,143 @@ +## @file
+# Legacy Bios Module to support CSM.
+#
+# This driver installs Legacy Bios Protocol to support CSM module work in EFI system.
+#
+# Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+#
+# 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.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LegacyBiosDxe
+ FILE_GUID = F122A15C-C10B-4d54-8F48-60F4F06DD1AD
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = LegacyBiosInstall
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ LegacyCmos.c
+ LegacyIde.c
+ LegacyBios.c
+ LegacyBda.c
+ LegacyBiosInterface.h
+ LegacyPci.c
+
+[Sources.Ia32]
+ IA32/InterruptTable.S
+ IA32/InterruptTable.asm
+ Thunk.c
+ LegacyBootSupport.c
+ LegacyBbs.c
+ LegacySio.c
+
+[Sources.X64]
+ X64/InterruptTable.asm
+ X64/InterruptTable.S
+ Thunk.c
+ LegacyBootSupport.c
+ LegacyBbs.c
+ LegacySio.c
+
+[Sources.IPF]
+ Ipf/IpfThunk.s
+ Ipf/Thunk.c
+ Ipf/IpfThunk.i
+ Ipf/IpfBootSupport.c
+ Ipf/IpfThunk.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+
+[LibraryClasses]
+ DevicePathLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ UefiLib
+ DebugLib
+ DxeServicesTableLib
+ PcdLib
+ ReportStatusCodeLib
+ PeCoffLib
+ CacheMaintenanceLib
+ DebugAgentLib
+
+[LibraryClasses.IA32]
+ IoLib
+ HobLib
+ UefiRuntimeServicesTableLib
+ BaseLib
+
+[LibraryClasses.X64]
+ IoLib
+ HobLib
+ UefiRuntimeServicesTableLib
+ BaseLib
+
+[LibraryClasses.IPF]
+ IoLib
+ UefiRuntimeServicesTableLib
+
+
+[Guids]
+ gEfiDiskInfoIdeInterfaceGuid # ALWAYS_CONSUMED
+ gEfiLegacyBiosGuid # ALWAYS_PRODUCED
+
+[Guids.IA32]
+ gEfiSmbiosTableGuid # ALWAYS_CONSUMED
+ gEfiAcpi20TableGuid # ALWAYS_CONSUMED
+ gEfiAcpi10TableGuid # ALWAYS_CONSUMED
+
+[Guids.X64]
+ gEfiSmbiosTableGuid # ALWAYS_CONSUMED
+ gEfiAcpi20TableGuid # ALWAYS_CONSUMED
+ gEfiAcpi10TableGuid # ALWAYS_CONSUMED
+
+
+[Protocols]
+ gEfiLoadedImageProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiPciRootBridgeIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiCpuArchProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiIsaIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiBlockIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiPciIoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiGenericMemTestProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiDiskInfoProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiSimpleTextInProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiLegacy8259ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiLegacyBiosPlatformProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiLegacyInterruptProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiLegacyRegion2ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiLegacyBiosProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+ gEfiTimerArchProtocolGuid # PROTOCOL ALWAYS_PRODUCED
+
+[Pcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLegacyBiosCacheLegacyRegion
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdEbdaReservedMemorySize
+
+[Depex]
+ gEfiLegacyRegion2ProtocolGuid AND gEfiLegacyInterruptProtocolGuid AND gEfiLegacyBiosPlatformProtocolGuid AND gEfiLegacy8259ProtocolGuid AND gEfiGenericMemTestProtocolGuid AND gEfiCpuArchProtocolGuid
+
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h new file mode 100644 index 0000000..c398d1e --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h @@ -0,0 +1,1501 @@ +/** @file
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+
+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.
+
+**/
+
+#ifndef _LEGACY_BIOS_INTERFACE_
+#define _LEGACY_BIOS_INTERFACE_
+
+
+#include <FrameworkDxe.h>
+
+#include <Guid/SmBios.h>
+#include <Guid/Acpi.h>
+#include <Guid/DxeServices.h>
+#include <Guid/LegacyBios.h>
+#include <Guid/StatusCodeDataTypeId.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/IsaIo.h>
+#include <Protocol/LegacyRegion2.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/LegacyInterrupt.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/DiskInfo.h>
+#include <Protocol/GenericMemoryTest.h>
+#include <Protocol/LegacyBiosPlatform.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Legacy8259.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/Timer.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugAgentLib.h>
+
+//
+// System Tickers
+//
+#define DEFAULT_LAGACY_TIMER_TICK_DURATION 549254
+// BUGBUG: This entry maybe changed to PCD in future and wait for
+// redesign of BDS library
+//
+#define MAX_BBS_ENTRIES 0x100
+
+//
+// Thunk Status Codes
+// (These apply only to errors with the thunk and not to the code that was
+// thunked to.)
+//
+#define THUNK_OK 0x00
+#define THUNK_ERR_A20_UNSUP 0x01
+#define THUNK_ERR_A20_FAILED 0x02
+
+//
+// Vector base definitions
+//
+//
+// 8259 Hardware definitions
+//
+#define LEGACY_MODE_BASE_VECTOR_MASTER 0x08
+#define LEGACY_MODE_BASE_VECTOR_SLAVE 0x70
+
+//
+// The original PC used INT8-F for master PIC. Since these mapped over
+// processor exceptions TIANO moved the master PIC to INT68-6F.
+//
+// The vector base for slave PIC is set as 0x70 for PC-AT compatibility.
+//
+#define PROTECTED_MODE_BASE_VECTOR_MASTER 0x68
+#define PROTECTED_MODE_BASE_VECTOR_SLAVE 0x70
+
+//
+// Trace defines
+//
+//
+#define LEGACY_BDA_TRACE 0x000
+#define LEGACY_BIOS_TRACE 0x040
+#define LEGACY_BOOT_TRACE 0x080
+#define LEGACY_CMOS_TRACE 0x0C0
+#define LEGACY_IDE_TRACE 0x100
+#define LEGACY_MP_TRACE 0x140
+#define LEGACY_PCI_TRACE 0x180
+#define LEGACY_SIO_TRACE 0x1C0
+
+#define LEGACY_PCI_TRACE_000 LEGACY_PCI_TRACE + 0x00
+#define LEGACY_PCI_TRACE_001 LEGACY_PCI_TRACE + 0x01
+#define LEGACY_PCI_TRACE_002 LEGACY_PCI_TRACE + 0x02
+#define LEGACY_PCI_TRACE_003 LEGACY_PCI_TRACE + 0x03
+#define LEGACY_PCI_TRACE_004 LEGACY_PCI_TRACE + 0x04
+#define LEGACY_PCI_TRACE_005 LEGACY_PCI_TRACE + 0x05
+#define LEGACY_PCI_TRACE_006 LEGACY_PCI_TRACE + 0x06
+#define LEGACY_PCI_TRACE_007 LEGACY_PCI_TRACE + 0x07
+#define LEGACY_PCI_TRACE_008 LEGACY_PCI_TRACE + 0x08
+#define LEGACY_PCI_TRACE_009 LEGACY_PCI_TRACE + 0x09
+#define LEGACY_PCI_TRACE_00A LEGACY_PCI_TRACE + 0x0A
+#define LEGACY_PCI_TRACE_00B LEGACY_PCI_TRACE + 0x0B
+#define LEGACY_PCI_TRACE_00C LEGACY_PCI_TRACE + 0x0C
+#define LEGACY_PCI_TRACE_00D LEGACY_PCI_TRACE + 0x0D
+#define LEGACY_PCI_TRACE_00E LEGACY_PCI_TRACE + 0x0E
+#define LEGACY_PCI_TRACE_00F LEGACY_PCI_TRACE + 0x0F
+
+
+typedef struct {
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+ UINT32 ShadowAddress;
+ UINT32 ShadowedSize;
+ UINT8 DiskStart;
+ UINT8 DiskEnd;
+} ROM_INSTANCE_ENTRY;
+
+//
+// Values for RealModeGdt
+//
+#if defined (MDE_CPU_IA32)
+
+#define NUM_REAL_GDT_ENTRIES 3
+#define CONVENTIONAL_MEMORY_TOP 0xA0000 // 640 KB
+#define INITIAL_VALUE_BELOW_1K 0x0
+
+#elif defined (MDE_CPU_X64)
+
+#define NUM_REAL_GDT_ENTRIES 8
+#define CONVENTIONAL_MEMORY_TOP 0xA0000 // 640 KB
+#define INITIAL_VALUE_BELOW_1K 0x0
+
+#elif defined (MDE_CPU_IPF)
+
+#define NUM_REAL_GDT_ENTRIES 3
+#define CONVENTIONAL_MEMORY_TOP 0x80000 // 512 KB
+#define INITIAL_VALUE_BELOW_1K 0xff
+
+#endif
+
+//
+// Miscellaneous numbers
+//
+#define PMM_MEMORY_SIZE 0x400000 // 4 MB
+
+#pragma pack(1)
+
+//
+// Define what a processor GDT looks like
+//
+typedef struct {
+ UINT32 LimitLo : 16;
+ UINT32 BaseLo : 16;
+ UINT32 BaseMid : 8;
+ UINT32 Type : 4;
+ UINT32 System : 1;
+ UINT32 Dpl : 2;
+ UINT32 Present : 1;
+ UINT32 LimitHi : 4;
+ UINT32 Software : 1;
+ UINT32 Reserved : 1;
+ UINT32 DefaultSize : 1;
+ UINT32 Granularity : 1;
+ UINT32 BaseHi : 8;
+} GDT32;
+
+typedef struct {
+ UINT16 LimitLow;
+ UINT16 BaseLow;
+ UINT8 BaseMid;
+ UINT8 Attribute;
+ UINT8 LimitHi;
+ UINT8 BaseHi;
+} GDT64;
+
+//
+// Define what a processor descriptor looks like
+// This data structure must be kept in sync with ASM STRUCT in Thunk.inc
+//
+typedef struct {
+ UINT16 Limit;
+ UINT64 Base;
+} DESCRIPTOR64;
+
+typedef struct {
+ UINT16 Limit;
+ UINT32 Base;
+} DESCRIPTOR32;
+
+//
+// Low stub lay out
+//
+#define LOW_STACK_SIZE (8 * 1024) // 8k?
+#define EFI_MAX_E820_ENTRY 100
+#define FIRST_INSTANCE 1
+#define NOT_FIRST_INSTANCE 0
+
+#if defined (MDE_CPU_IA32)
+typedef struct {
+ //
+ // Space for the code
+ // The address of Code is also the beginning of the relocated Thunk code
+ //
+ CHAR8 Code[4096]; // ?
+ //
+ // The address of the Reverse Thunk code
+ // Note that this member CONTAINS the address of the relocated reverse thunk
+ // code unlike the member variable 'Code', which IS the address of the Thunk
+ // code.
+ //
+ UINT32 LowReverseThunkStart;
+
+ //
+ // Data for the code (cs releative)
+ //
+ DESCRIPTOR32 GdtDesc; // Protected mode GDT
+ DESCRIPTOR32 IdtDesc; // Protected mode IDT
+ UINT32 FlatSs;
+ UINT32 FlatEsp;
+
+ UINT32 LowCodeSelector; // Low code selector in GDT
+ UINT32 LowDataSelector; // Low data selector in GDT
+ UINT32 LowStack;
+ DESCRIPTOR32 RealModeIdtDesc;
+
+ //
+ // real-mode GDT (temporary GDT with two real mode segment descriptors)
+ //
+ GDT32 RealModeGdt[NUM_REAL_GDT_ENTRIES];
+ DESCRIPTOR32 RealModeGdtDesc;
+
+ //
+ // Members specifically for the reverse thunk
+ // The RevReal* members are used to store the current state of real mode
+ // before performing the reverse thunk. The RevFlat* members must be set
+ // before calling the reverse thunk assembly code.
+ //
+ UINT16 RevRealDs;
+ UINT16 RevRealSs;
+ UINT32 RevRealEsp;
+ DESCRIPTOR32 RevRealIdtDesc;
+ UINT16 RevFlatDataSelector; // Flat data selector in GDT
+ UINT32 RevFlatStack;
+
+ //
+ // A low memory stack
+ //
+ CHAR8 Stack[LOW_STACK_SIZE];
+
+ //
+ // Stack for flat mode after reverse thunk
+ // @bug - This may no longer be necessary if the reverse thunk interface
+ // is changed to have the flat stack in a different location.
+ //
+ CHAR8 RevThunkStack[LOW_STACK_SIZE];
+
+ //
+ // Legacy16 Init memory map info
+ //
+ EFI_TO_COMPATIBILITY16_INIT_TABLE EfiToLegacy16InitTable;
+
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE EfiToLegacy16BootTable;
+
+ CHAR8 InterruptRedirectionCode[32];
+ EFI_LEGACY_INSTALL_PCI_HANDLER PciHandler;
+ EFI_DISPATCH_OPROM_TABLE DispatchOpromTable;
+ BBS_TABLE BbsTable[MAX_BBS_ENTRIES];
+} LOW_MEMORY_THUNK;
+
+#elif defined (MDE_CPU_X64)
+
+typedef struct {
+ //
+ // Space for the code
+ // The address of Code is also the beginning of the relocated Thunk code
+ //
+ CHAR8 Code[4096]; // ?
+
+ //
+ // Data for the code (cs releative)
+ //
+ DESCRIPTOR64 X64GdtDesc; // Protected mode GDT
+ DESCRIPTOR64 X64IdtDesc; // Protected mode IDT
+ UINTN X64Ss;
+ UINTN X64Esp;
+
+ UINTN RealStack;
+ DESCRIPTOR32 RealModeIdtDesc;
+ DESCRIPTOR32 RealModeGdtDesc;
+
+ //
+ // real-mode GDT (temporary GDT with two real mode segment descriptors)
+ //
+ GDT64 RealModeGdt[NUM_REAL_GDT_ENTRIES];
+ UINT64 PageMapLevel4;
+
+ //
+ // A low memory stack
+ //
+ CHAR8 Stack[LOW_STACK_SIZE];
+
+ //
+ // Legacy16 Init memory map info
+ //
+ EFI_TO_COMPATIBILITY16_INIT_TABLE EfiToLegacy16InitTable;
+
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE EfiToLegacy16BootTable;
+
+ CHAR8 InterruptRedirectionCode[32];
+ EFI_LEGACY_INSTALL_PCI_HANDLER PciHandler;
+ EFI_DISPATCH_OPROM_TABLE DispatchOpromTable;
+ BBS_TABLE BbsTable[MAX_BBS_ENTRIES];
+} LOW_MEMORY_THUNK;
+
+#elif defined (MDE_CPU_IPF)
+
+typedef struct {
+ //
+ // Space for the code
+ // The address of Code is also the beginning of the relocated Thunk code
+ //
+ CHAR8 Code[4096]; // ?
+ //
+ // The address of the Reverse Thunk code
+ // Note that this member CONTAINS the address of the relocated reverse thunk
+ // code unlike the member variable 'Code', which IS the address of the Thunk
+ // code.
+ //
+ UINT32 LowReverseThunkStart;
+
+ //
+ // Data for the code (cs releative)
+ //
+ DESCRIPTOR32 GdtDesc; // Protected mode GDT
+ DESCRIPTOR32 IdtDesc; // Protected mode IDT
+ UINT32 FlatSs;
+ UINT32 FlatEsp;
+
+ UINT32 LowCodeSelector; // Low code selector in GDT
+ UINT32 LowDataSelector; // Low data selector in GDT
+ UINT32 LowStack;
+ DESCRIPTOR32 RealModeIdtDesc;
+
+ //
+ // real-mode GDT (temporary GDT with two real mode segment descriptors)
+ //
+ GDT32 RealModeGdt[NUM_REAL_GDT_ENTRIES];
+ DESCRIPTOR32 RealModeGdtDesc;
+
+ //
+ // Members specifically for the reverse thunk
+ // The RevReal* members are used to store the current state of real mode
+ // before performing the reverse thunk. The RevFlat* members must be set
+ // before calling the reverse thunk assembly code.
+ //
+ UINT16 RevRealDs;
+ UINT16 RevRealSs;
+ UINT32 RevRealEsp;
+ DESCRIPTOR32 RevRealIdtDesc;
+ UINT16 RevFlatDataSelector; // Flat data selector in GDT
+ UINT32 RevFlatStack;
+
+ //
+ // A low memory stack
+ //
+ CHAR8 Stack[LOW_STACK_SIZE];
+
+ //
+ // Stack for flat mode after reverse thunk
+ // @bug - This may no longer be necessary if the reverse thunk interface
+ // is changed to have the flat stack in a different location.
+ //
+ CHAR8 RevThunkStack[LOW_STACK_SIZE];
+
+ //
+ // Legacy16 Init memory map info
+ //
+ EFI_TO_COMPATIBILITY16_INIT_TABLE EfiToLegacy16InitTable;
+
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE EfiToLegacy16BootTable;
+
+ CHAR8 InterruptRedirectionCode[32];
+ EFI_LEGACY_INSTALL_PCI_HANDLER PciHandler;
+ EFI_DISPATCH_OPROM_TABLE DispatchOpromTable;
+ BBS_TABLE BbsTable[MAX_BBS_ENTRIES];
+} LOW_MEMORY_THUNK;
+
+#endif
+
+//
+// PnP Expansion Header
+//
+typedef struct {
+ UINT32 PnpSignature;
+ UINT8 Revision;
+ UINT8 Length;
+ UINT16 NextHeader;
+ UINT8 Reserved1;
+ UINT8 Checksum;
+ UINT32 DeviceId;
+ UINT16 MfgPointer;
+ UINT16 ProductNamePointer;
+ UINT8 Class;
+ UINT8 SubClass;
+ UINT8 Interface;
+ UINT8 DeviceIndicators;
+ UINT16 Bcv;
+ UINT16 DisconnectVector;
+ UINT16 Bev;
+ UINT16 Reserved2;
+ UINT16 StaticResourceVector;
+} LEGACY_PNP_EXPANSION_HEADER;
+
+typedef struct {
+ UINT8 PciSegment;
+ UINT8 PciBus;
+ UINT8 PciDevice;
+ UINT8 PciFunction;
+ UINT16 Vid;
+ UINT16 Did;
+ UINT16 SysSid;
+ UINT16 SVid;
+ UINT8 Class;
+ UINT8 SubClass;
+ UINT8 Interface;
+ UINT8 Reserved;
+ UINTN RomStart;
+ UINTN ManufacturerString;
+ UINTN ProductNameString;
+} LEGACY_ROM_AND_BBS_TABLE;
+
+//
+// Structure how EFI has mapped a devices HDD drive numbers.
+// Boot to EFI aware OS or shell requires this mapping when
+// 16-bit CSM assigns drive numbers.
+// This mapping is ignored booting to a legacy OS.
+//
+typedef struct {
+ UINT8 PciSegment;
+ UINT8 PciBus;
+ UINT8 PciDevice;
+ UINT8 PciFunction;
+ UINT8 StartDriveNumber;
+ UINT8 EndDriveNumber;
+} LEGACY_EFI_HDD_TABLE;
+
+//
+// This data is passed to Leacy16Boot
+//
+typedef enum {
+ EfiAcpiAddressRangeMemory = 1,
+ EfiAcpiAddressRangeReserved = 2,
+ EfiAcpiAddressRangeACPI = 3,
+ EfiAcpiAddressRangeNVS = 4
+} EFI_ACPI_MEMORY_TYPE;
+
+typedef struct {
+ UINT64 BaseAddr;
+ UINT64 Length;
+ EFI_ACPI_MEMORY_TYPE Type;
+} EFI_E820_ENTRY64;
+
+typedef struct {
+ UINT32 BassAddrLow;
+ UINT32 BaseAddrHigh;
+ UINT32 LengthLow;
+ UINT32 LengthHigh;
+ EFI_ACPI_MEMORY_TYPE Type;
+} EFI_E820_ENTRY;
+
+#pragma pack()
+
+extern BBS_TABLE *mBbsTable;
+
+extern EFI_GENERIC_MEMORY_TEST_PROTOCOL *gGenMemoryTest;
+
+extern UINTN mEndOpromShadowAddress;
+
+#define PORT_70 0x70
+#define PORT_71 0x71
+
+#define CMOS_0A 0x0a ///< Status register A
+#define CMOS_0D 0x0d ///< Status register D
+#define CMOS_0E 0x0e ///< Diagnostic Status
+#define CMOS_0F 0x0f ///< Shutdown status
+#define CMOS_10 0x10 ///< Floppy type
+#define CMOS_12 0x12 ///< IDE type
+#define CMOS_14 0x14 ///< Same as BDA 40:10
+#define CMOS_15 0x15 ///< Low byte of base memory in 1k increments
+#define CMOS_16 0x16 ///< High byte of base memory in 1k increments
+#define CMOS_17 0x17 ///< Low byte of 1MB+ memory in 1k increments - max 15 MB
+#define CMOS_18 0x18 ///< High byte of 1MB+ memory in 1k increments - max 15 MB
+#define CMOS_19 0x19 ///< C: extended drive type
+#define CMOS_1A 0x1a ///< D: extended drive type
+#define CMOS_2E 0x2e ///< Most significient byte of standard checksum
+#define CMOS_2F 0x2f ///< Least significient byte of standard checksum
+#define CMOS_30 0x30 ///< CMOS 0x17
+#define CMOS_31 0x31 ///< CMOS 0x18
+#define CMOS_32 0x32 ///< Century byte
+
+
+#define LEGACY_BIOS_INSTANCE_SIGNATURE SIGNATURE_32 ('L', 'B', 'I', 'T')
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE Handle;
+ EFI_LEGACY_BIOS_PROTOCOL LegacyBios;
+
+ EFI_HANDLE ImageHandle;
+
+ //
+ // CPU Architectural Protocol
+ //
+ EFI_CPU_ARCH_PROTOCOL *Cpu;
+
+ //
+ // Protocol to Lock and Unlock 0xc0000 - 0xfffff
+ //
+ EFI_LEGACY_REGION2_PROTOCOL *LegacyRegion;
+
+ EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
+
+ //
+ // Interrupt control for thunk and PCI IRQ
+ //
+ EFI_LEGACY_8259_PROTOCOL *Legacy8259;
+
+ //
+ // PCI Interrupt PIRQ control
+ //
+ EFI_LEGACY_INTERRUPT_PROTOCOL *LegacyInterrupt;
+
+ //
+ // Generic Memory Test
+ //
+ EFI_GENERIC_MEMORY_TEST_PROTOCOL *GenericMemoryTest;
+
+ //
+ // TRUE if PCI Interupt Line registers have been programmed.
+ //
+ BOOLEAN PciInterruptLine;
+
+ //
+ // Code space below 1MB needed by thunker to transition to real mode.
+ // Contains stack and real mode code fragments
+ //
+ LOW_MEMORY_THUNK *IntThunk;
+
+ //
+ // Starting shadow address of the Legacy BIOS
+ //
+ UINT32 BiosStart;
+ UINT32 LegacyBiosImageSize;
+
+ //
+ // Start of variables used by CsmItp.mac ITP macro file and/os LegacyBios
+ //
+ UINT8 Dump[4];
+
+ //
+ // $EFI Legacy16 code entry info in memory < 1 MB;
+ //
+ EFI_COMPATIBILITY16_TABLE *Legacy16Table;
+ VOID *Legacy16InitPtr;
+ VOID *Legacy16BootPtr;
+ VOID *InternalIrqRoutingTable;
+ UINT32 NumberIrqRoutingEntries;
+ VOID *BbsTablePtr;
+ VOID *HddTablePtr;
+ UINT32 NumberHddControllers;
+
+ //
+ // Cached copy of Legacy16 entry point
+ //
+ UINT16 Legacy16CallSegment;
+ UINT16 Legacy16CallOffset;
+
+ //
+ // Returned from $EFI and passed in to OPROMS
+ //
+ UINT16 PnPInstallationCheckSegment;
+ UINT16 PnPInstallationCheckOffset;
+
+ //
+ // E820 table
+ //
+ EFI_E820_ENTRY E820Table[EFI_MAX_E820_ENTRY];
+ UINT32 NumberE820Entries;
+
+ //
+ // True if legacy VGA INT 10h handler installed
+ //
+ BOOLEAN VgaInstalled;
+
+ //
+ // Number of IDE drives
+ //
+ UINT8 IdeDriveCount;
+
+ //
+ // Current Free Option ROM space. An option ROM must NOT go past
+ // BiosStart.
+ //
+ UINT32 OptionRom;
+
+ //
+ // Save Legacy16 unexpected interrupt vector. Reprogram INT 68-6F from
+ // EFI values to legacy value just before boot.
+ //
+ UINT32 BiosUnexpectedInt;
+ UINT32 ThunkSavedInt[8];
+ UINT16 ThunkSeg;
+ LEGACY_EFI_HDD_TABLE *LegacyEfiHddTable;
+ UINT16 LegacyEfiHddTableIndex;
+ UINT8 DiskEnd;
+ UINT8 Disk4075;
+ UINT16 TraceIndex;
+ UINT16 Trace[0x200];
+
+ //
+ // Indicate that whether GenericLegacyBoot is entered or not
+ //
+ BOOLEAN LegacyBootEntered;
+
+ //
+ // CSM16 PCI Interface Version
+ //
+ UINT16 Csm16PciInterfaceVersion;
+
+} LEGACY_BIOS_INSTANCE;
+
+
+#pragma pack(1)
+
+/*
+ 40:00-01 Com1
+ 40:02-03 Com2
+ 40:04-05 Com3
+ 40:06-07 Com4
+ 40:08-09 Lpt1
+ 40:0A-0B Lpt2
+ 40:0C-0D Lpt3
+ 40:0E-0E Ebda segment
+ 40:10-11 MachineConfig
+ 40:12 Bda12 - skip
+ 40:13-14 MemSize below 1MB
+ 40:15-16 Bda15_16 - skip
+ 40:17 Keyboard Shift status
+ 40:18-19 Bda18_19 - skip
+ 40:1A-1B Key buffer head
+ 40:1C-1D Key buffer tail
+ 40:1E-3D Bda1E_3D- key buffer -skip
+ 40:3E-3F FloppyData 3E = Calibration status 3F = Motor status
+ 40:40 FloppyTimeout
+ 40:41-74 Bda41_74 - skip
+ 40:75 Number of HDD drives
+ 40:76-77 Bda76_77 - skip
+ 40:78-79 78 = Lpt1 timeout, 79 = Lpt2 timeout
+ 40:7A-7B 7A = Lpt3 timeout, 7B = Lpt4 timeout
+ 40:7C-7D 7C = Com1 timeout, 7D = Com2 timeout
+ 40:7E-7F 7E = Com3 timeout, 7F = Com4 timeout
+ 40:80-81 Pointer to start of key buffer
+ 40:82-83 Pointer to end of key buffer
+ 40:84-87 Bda84_87 - skip
+ 40:88 HDD Data Xmit rate
+ 40:89-8f skip
+ 40:90 Floppy data rate
+ 40:91-95 skip
+ 40:96 Keyboard Status
+ 40:97 LED Status
+ 40:98-101 skip
+*/
+typedef struct {
+ UINT16 Com1;
+ UINT16 Com2;
+ UINT16 Com3;
+ UINT16 Com4;
+ UINT16 Lpt1;
+ UINT16 Lpt2;
+ UINT16 Lpt3;
+ UINT16 Ebda;
+ UINT16 MachineConfig;
+ UINT8 Bda12;
+ UINT16 MemSize;
+ UINT8 Bda15_16[0x02];
+ UINT8 ShiftStatus;
+ UINT8 Bda18_19[0x02];
+ UINT16 KeyHead;
+ UINT16 KeyTail;
+ UINT16 Bda1E_3D[0x10];
+ UINT16 FloppyData;
+ UINT8 FloppyTimeout;
+ UINT8 Bda41_74[0x34];
+ UINT8 NumberOfDrives;
+ UINT8 Bda76_77[0x02];
+ UINT16 Lpt1_2Timeout;
+ UINT16 Lpt3_4Timeout;
+ UINT16 Com1_2Timeout;
+ UINT16 Com3_4Timeout;
+ UINT16 KeyStart;
+ UINT16 KeyEnd;
+ UINT8 Bda84_87[0x4];
+ UINT8 DataXmit;
+ UINT8 Bda89_8F[0x07];
+ UINT8 FloppyXRate;
+ UINT8 Bda91_95[0x05];
+ UINT8 KeyboardStatus;
+ UINT8 LedStatus;
+} BDA_STRUC;
+#pragma pack()
+
+#define LEGACY_BIOS_INSTANCE_FROM_THIS(this) CR (this, LEGACY_BIOS_INSTANCE, LegacyBios, LEGACY_BIOS_INSTANCE_SIGNATURE)
+
+/**
+ 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.
+
+ @param This Protocol instance pointer.
+ @param BiosInt Processor interrupt vector to invoke
+ @param Regs Register contexted passed into (and returned) from thunk to
+ 16-bit mode
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in the target code.
+ See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+LegacyBiosInt86 (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT8 BiosInt,
+ IN EFI_IA32_REGISTER_SET *Regs
+ );
+
+
+/**
+ Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the
+ 16-bit register context on entry and exit. Arguments can be passed on
+ the Stack argument
+
+ @param This Protocol instance pointer.
+ @param Segment Segemnt of 16-bit mode call
+ @param Offset Offset of 16-bit mdoe call
+ @param Regs Register contexted passed into (and returned) from
+ thunk to 16-bit mode
+ @param Stack Caller allocated stack used to pass arguments
+ @param StackSize Size of Stack in bytes
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in
+ the target code. See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+LegacyBiosFarCall86 (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT16 Segment,
+ IN UINT16 Offset,
+ IN EFI_IA32_REGISTER_SET *Regs,
+ IN VOID *Stack,
+ IN UINTN StackSize
+ );
+
+
+/**
+ Test to see if a legacy PCI ROM exists for this device. Optionally return
+ the Legacy ROM instance for this PCI device.
+
+ @param This Protocol instance pointer.
+ @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will
+ be loaded
+ @param RomImage Return the legacy PCI ROM for this device
+ @param RomSize Size of ROM Image
+ @param Flags Indicates if ROM found and if PC-AT.
+
+ @retval EFI_SUCCESS Legacy Option ROM availible for this device
+ @retval EFI_UNSUPPORTED Legacy Option ROM not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosCheckPciRom (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN EFI_HANDLE PciHandle,
+ OUT VOID **RomImage, OPTIONAL
+ OUT UINTN *RomSize, OPTIONAL
+ OUT UINTN *Flags
+ );
+
+
+/**
+ Assign drive number to legacy HDD drives prior to booting an EFI
+ aware OS so the OS can access drives without an EFI driver.
+ Note: BBS compliant drives ARE NOT available until this call by
+ either shell or EFI.
+
+ @param This Protocol instance pointer.
+ @param BbsCount Number of BBS_TABLE structures
+ @param BbsTable List BBS entries
+
+ @retval EFI_SUCCESS Drive numbers assigned
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosPrepareToBootEfi (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ OUT UINT16 *BbsCount,
+ OUT BBS_TABLE **BbsTable
+ );
+
+
+/**
+ To boot from an unconventional device like parties and/or execute
+ HDD diagnostics.
+
+ @param This Protocol instance pointer.
+ @param Attributes How to interpret the other input parameters
+ @param BbsEntry The 0-based index into the BbsTable for the parent
+ device.
+ @param BeerData Pointer to the 128 bytes of ram BEER data.
+ @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data.
+ The caller must provide a pointer to the specific
+ Service Area and not the start all Service Areas.
+ EFI_INVALID_PARAMETER if error. Does NOT return if no error.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosBootUnconventionalDevice (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UDC_ATTRIBUTES Attributes,
+ IN UINTN BbsEntry,
+ IN VOID *BeerData,
+ IN VOID *ServiceAreaData
+ );
+
+
+/**
+ Load a legacy PC-AT OPROM on the PciHandle device. Return information
+ about how many disks were added by the OPROM and the shadow address and
+ size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
+
+ @param This Protocol instance pointer.
+ @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will
+ be loaded. This value is NULL if RomImage is
+ non-NULL. This is the normal case.
+ @param RomImage A PCI PC-AT ROM image. This argument is non-NULL
+ if there is no hardware associated with the ROM
+ and thus no PciHandle, otherwise is must be NULL.
+ Example is PXE base code.
+ @param Flags Indicates if ROM found and if PC-AT.
+ @param DiskStart Disk number of first device hooked by the ROM. If
+ DiskStart is the same as DiskEnd no disked were
+ hooked.
+ @param DiskEnd Disk number of the last device hooked by the ROM.
+ @param RomShadowAddress Shadow address of PC-AT ROM
+ @param RomShadowedSize Size of RomShadowAddress in bytes
+
+ @retval EFI_SUCCESS Legacy ROM loaded for this device
+ @retval EFI_INVALID_PARAMETER PciHandle not found
+ @retval EFI_UNSUPPORTED There is no PCI ROM in the ROM BAR or no onboard
+ ROM
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosInstallPciRom (
+ IN EFI_LEGACY_BIOS_PROTOCOL * This,
+ IN EFI_HANDLE PciHandle,
+ IN VOID **RomImage,
+ OUT UINTN *Flags,
+ OUT UINT8 *DiskStart, OPTIONAL
+ OUT UINT8 *DiskEnd, OPTIONAL
+ OUT VOID **RomShadowAddress, OPTIONAL
+ OUT UINT32 *RomShadowedSize OPTIONAL
+ );
+
+
+/**
+ Fill in the standard BDA for Keyboard LEDs
+
+ @param This Protocol instance pointer.
+ @param Leds Current LED status
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosUpdateKeyboardLedStatus (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT8 Leds
+ );
+
+
+/**
+ Get all BBS info
+
+ @param This Protocol instance pointer.
+ @param HddCount Number of HDD_INFO structures
+ @param HddInfo Onboard IDE controller information
+ @param BbsCount Number of BBS_TABLE structures
+ @param BbsTable List BBS entries
+
+ @retval EFI_SUCCESS Tables returned
+ @retval EFI_NOT_FOUND resource not found
+ @retval EFI_DEVICE_ERROR can not get BBS table
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosGetBbsInfo (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ OUT UINT16 *HddCount,
+ OUT HDD_INFO **HddInfo,
+ OUT UINT16 *BbsCount,
+ OUT BBS_TABLE **BbsTable
+ );
+
+
+/**
+ Shadow all legacy16 OPROMs that haven't been shadowed.
+ Warning: Use this with caution. This routine disconnects all EFI
+ drivers. If used externally then caller must re-connect EFI
+ drivers.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS OPROMs shadowed
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosShadowAllLegacyOproms (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This
+ );
+
+
+/**
+ Attempt to legacy boot the BootOption. If the EFI contexted has been
+ compromised this function will not return.
+
+ @param This Protocol instance pointer.
+ @param BbsDevicePath EFI Device Path from BootXXXX variable.
+ @param LoadOptionsSize Size of LoadOption in size.
+ @param LoadOptions LoadOption from BootXXXX variable
+
+ @retval EFI_SUCCESS Removable media not present
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosLegacyBoot (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN BBS_BBS_DEVICE_PATH *BbsDevicePath,
+ IN UINT32 LoadOptionsSize,
+ IN VOID *LoadOptions
+ );
+
+
+/**
+ Allocate memory < 1 MB and copy the thunker code into low memory. Se up
+ all the descriptors.
+
+ @param Private Private context for Legacy BIOS
+
+ @retval EFI_SUCCESS Should only pass.
+
+**/
+EFI_STATUS
+LegacyBiosInitializeThunk (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Fill in the standard BDA and EBDA stuff before Legacy16 load
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosInitBda (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Collect IDE Inquiry data from the IDE disks
+
+ @param Private Legacy BIOS Instance data
+ @param HddInfo Hdd Information
+ @param Flag Reconnect IdeController or not
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildIdeData (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN HDD_INFO **HddInfo,
+ IN UINT16 Flag
+ );
+
+
+/**
+ Enable ide controller. This gets disabled when LegacyBoot.c is about
+ to run the Option ROMs.
+
+ @param Private Legacy BIOS Instance data
+
+
+**/
+VOID
+EnableIdeController (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ If the IDE channel is in compatibility (legacy) mode, remove all
+ PCI I/O BAR addresses from the controller.
+
+ @param IdeController The handle of target IDE controller
+
+
+**/
+VOID
+InitLegacyIdeController (
+ IN EFI_HANDLE IdeController
+ );
+
+
+/**
+ Program the interrupt routing register in all the PCI devices. On a PC AT system
+ this register contains the 8259 IRQ vector that matches it's PCI interrupt.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_ALREADY_STARTED All PCI devices have been processed.
+
+**/
+EFI_STATUS
+PciProgramAllInterruptLineRegisters (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Collect EFI Info about legacy devices.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildSioData (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Shadow all the PCI legacy ROMs. Use data from the Legacy BIOS Protocol
+ to chose the order. Skip any devices that have already have legacy
+ BIOS run.
+
+ @param Private Protocol instance pointer.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_UNSUPPORTED Cannot get VGA device handle.
+
+**/
+EFI_STATUS
+PciShadowRoms (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Fill in the standard BDA and EBDA stuff prior to legacy Boot
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosCompleteBdaBeforeBoot (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Fill in the standard CMOS stuff before Legacy16 load
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosInitCmos (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Fill in the standard CMOS stuff prior to legacy Boot
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosCompleteStandardCmosBeforeBoot (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Contains the code that is copied into low memory (below 640K).
+ This code reflects interrupts 0x68-0x6f to interrupts 0x08-0x0f.
+ This template must be copied into low memory, and the IDT entries
+ 0x68-0x6F must be point to the low memory copy of this code. Each
+ entry is 4 bytes long, so IDT entries 0x68-0x6F can be easily
+ computed.
+
+**/
+VOID
+InterruptRedirectionTemplate (
+ VOID
+ );
+
+
+/**
+ Build the E820 table.
+
+ @param Private Legacy BIOS Instance data
+ @param Size Size of E820 Table
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildE820 (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ OUT UINTN *Size
+ );
+
+/**
+ This function is to put all AP in halt state.
+
+ @param Private Legacy BIOS Instance data
+
+**/
+VOID
+ShutdownAPs (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+/**
+ Worker function for LegacyBiosGetFlatDescs, retrieving content of
+ specific registers.
+
+ @param IntThunk Pointer to IntThunk of Legacy BIOS context.
+
+**/
+VOID
+GetRegisters (
+ LOW_MEMORY_THUNK *IntThunk
+ );
+
+/**
+ Routine for calling real thunk code.
+
+ @param RealCode The address of thunk code.
+ @param BiosInt The Bios interrupt vector number.
+ @param CallAddress The address of 16-bit mode call.
+
+ @return Status returned by real thunk code
+
+**/
+UINTN
+CallRealThunkCode (
+ UINT8 *RealCode,
+ UINT8 BiosInt,
+ UINT32 CallAddress
+ );
+
+/**
+ Routine for generating soft interrupt.
+
+ @param Vector The interrupt vector number.
+
+**/
+VOID
+GenerateSoftInit (
+ UINT8 Vector
+ );
+
+/**
+ Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode
+ memory.
+
+ @param AllocateType Allocated Legacy Memory Type
+ @param StartPageAddress Start address of range
+ @param Pages Number of pages to allocate
+ @param Result Result of allocation
+
+ @retval EFI_SUCCESS Legacy16 code loaded
+ @retval Other No protocol installed, unload driver.
+
+**/
+EFI_STATUS
+AllocateLegacyMemory (
+ IN EFI_ALLOCATE_TYPE AllocateType,
+ IN EFI_PHYSICAL_ADDRESS StartPageAddress,
+ IN UINTN Pages,
+ OUT EFI_PHYSICAL_ADDRESS *Result
+ );
+
+/**
+ Get a region from the LegacyBios for Tiano usage. Can only be invoked once.
+
+ @param This Protocol instance pointer.
+ @param LegacyMemorySize Size of required region
+ @param Region Region to use. 00 = Either 0xE0000 or 0xF0000
+ block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000
+ block
+ @param Alignment Address alignment. Bit mapped. First non-zero
+ bit from right is alignment.
+ @param LegacyMemoryAddress Region Assigned
+
+ @retval EFI_SUCCESS Region assigned
+ @retval EFI_ACCESS_DENIED Procedure previously invoked
+ @retval Other Region not assigned
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosGetLegacyRegion (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINTN LegacyMemorySize,
+ IN UINTN Region,
+ IN UINTN Alignment,
+ OUT VOID **LegacyMemoryAddress
+ );
+
+/**
+ Get a region from the LegacyBios for Tiano usage. Can only be invoked once.
+
+ @param This Protocol instance pointer.
+ @param LegacyMemorySize Size of data to copy
+ @param LegacyMemoryAddress Legacy Region destination address Note: must
+ be in region assigned by
+ LegacyBiosGetLegacyRegion
+ @param LegacyMemorySourceAddress Source of data
+
+ @retval EFI_SUCCESS Region assigned
+ @retval EFI_ACCESS_DENIED Destination outside assigned region
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosCopyLegacyRegion (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINTN LegacyMemorySize,
+ IN VOID *LegacyMemoryAddress,
+ IN VOID *LegacyMemorySourceAddress
+ );
+
+/**
+ Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find
+ the $EFI table in the shadow area. Thunk into the Legacy16 code after it had
+ been shadowed.
+
+ @param Private Legacy BIOS context data
+
+ @retval EFI_SUCCESS Legacy16 code loaded
+ @retval Other No protocol installed, unload driver.
+
+**/
+EFI_STATUS
+ShadowAndStartLegacy16 (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+/**
+ Checks the state of the floppy and if media is inserted.
+
+ This routine checks the state of the floppy and if media is inserted.
+ There are 3 cases:
+ No floppy present - Set BBS entry to ignore
+ Floppy present & no media - Set BBS entry to lowest priority. We cannot
+ set it to ignore since 16-bit CSM will
+ indicate no floppy and thus drive A: is
+ unusable. CSM-16 will not try floppy since
+ lowest priority and thus not incur boot
+ time penality.
+ Floppy present & media - Set BBS entry to some priority.
+
+ @return State of floppy media
+
+**/
+UINT8
+HasMediaInFloppy (
+ VOID
+ );
+
+/**
+ Identify drive data must be updated to actual parameters before boot.
+ This requires updating the checksum, if it exists.
+
+ @param IdentifyDriveData ATA Identify Data
+ @param Checksum checksum of the ATA Identify Data
+
+ @retval EFI_SUCCESS checksum calculated
+ @retval EFI_SECURITY_VIOLATION IdentifyData invalid
+
+**/
+EFI_STATUS
+CalculateIdentifyDriveChecksum (
+ IN UINT8 *IdentifyDriveData,
+ OUT UINT8 *Checksum
+ );
+
+/**
+ Identify drive data must be updated to actual parameters before boot.
+
+ @param IdentifyDriveData ATA Identify Data
+
+**/
+VOID
+UpdateIdentifyDriveData (
+ IN UINT8 *IdentifyDriveData
+ );
+
+/**
+ Complete build of BBS TABLE.
+
+ @param Private Legacy BIOS Instance data
+ @param BbsTable BBS Table passed to 16-bit code
+
+ @retval EFI_SUCCESS Removable media not present
+
+**/
+EFI_STATUS
+LegacyBiosBuildBbs (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN BBS_TABLE *BbsTable
+ );
+
+/**
+ Read CMOS register through index/data port.
+
+ @param[in] Index The index of the CMOS register to read.
+
+ @return The data value from the CMOS register specified by Index.
+
+**/
+UINT8
+LegacyReadStandardCmos (
+ IN UINT8 Index
+ );
+
+/**
+ Write CMOS register through index/data port.
+
+ @param[in] Index The index of the CMOS register to write.
+ @param[in] Value The value of CMOS register to write.
+
+ @return The value written to the CMOS register specified by Index.
+
+**/
+UINT8
+LegacyWriteStandardCmos (
+ IN UINT8 Index,
+ IN UINT8 Value
+ );
+
+/**
+ Calculate the new standard CMOS checksum and write it.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS Calculate 16-bit checksum successfully
+
+**/
+EFI_STATUS
+LegacyCalculateWriteStandardCmosChecksum (
+ VOID
+ );
+
+/**
+ Test to see if a legacy PCI ROM exists for this device. Optionally return
+ the Legacy ROM instance for this PCI device.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] PciHandle The PCI PC-AT OPROM from this devices ROM BAR will be loaded
+ @param[out] RomImage Return the legacy PCI ROM for this device
+ @param[out] RomSize Size of ROM Image
+ @param[out] RuntimeImageLength Runtime size of ROM Image
+ @param[out] Flags Indicates if ROM found and if PC-AT.
+ @param[out] OpromRevision Revision of the PCI Rom
+ @param[out] ConfigUtilityCodeHeaderPointer of Configuration Utility Code Header
+
+ @return EFI_SUCCESS Legacy Option ROM availible for this device
+ @return EFI_ALREADY_STARTED This device is already managed by its Oprom
+ @return EFI_UNSUPPORTED Legacy Option ROM not supported.
+
+**/
+EFI_STATUS
+LegacyBiosCheckPciRomEx (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN EFI_HANDLE PciHandle,
+ OUT VOID **RomImage, OPTIONAL
+ OUT UINTN *RomSize, OPTIONAL
+ OUT UINTN *RuntimeImageLength, OPTIONAL
+ OUT UINTN *Flags, OPTIONAL
+ OUT UINT8 *OpromRevision, OPTIONAL
+ OUT VOID **ConfigUtilityCodeHeader OPTIONAL
+ );
+
+/**
+ Relocate this image under 4G memory for IPF.
+
+ @param ImageHandle Handle of driver image.
+ @param SystemTable Pointer to system table.
+
+ @retval EFI_SUCCESS Image successfully relocated.
+ @retval EFI_ABORTED Failed to relocate image.
+
+**/
+EFI_STATUS
+RelocateImageUnder4GIfNeeded (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the
+ 16-bit register context on entry and exit. Arguments can be passed on
+ the Stack argument
+
+ @param This Protocol instance pointer.
+ @param Segment Segemnt of 16-bit mode call
+ @param Offset Offset of 16-bit mdoe call
+ @param Regs Register contexted passed into (and returned) from thunk to
+ 16-bit mode
+ @param Stack Caller allocated stack used to pass arguments
+ @param StackSize Size of Stack in bytes
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in the target code.
+ See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+InternalLegacyBiosFarCall (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT16 Segment,
+ IN UINT16 Offset,
+ IN EFI_IA32_REGISTER_SET *Regs,
+ IN VOID *Stack,
+ IN UINTN StackSize
+ );
+
+#endif
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBootSupport.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBootSupport.c new file mode 100644 index 0000000..40d027a --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBootSupport.c @@ -0,0 +1,2032 @@ +/** @file
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+
+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.
+
+**/
+
+#include "LegacyBiosInterface.h"
+#include <IndustryStandard/Pci.h>
+
+#define BOOT_LEGACY_OS 0
+#define BOOT_EFI_OS 1
+#define BOOT_UNCONVENTIONAL_DEVICE 2
+
+UINT32 mLoadOptionsSize = 0;
+UINTN mBootMode = BOOT_LEGACY_OS;
+VOID *mLoadOptions = NULL;
+BBS_BBS_DEVICE_PATH *mBbsDevicePathPtr = NULL;
+BBS_BBS_DEVICE_PATH mBbsDevicePathNode;
+UDC_ATTRIBUTES mAttributes = { 0, 0, 0, 0 };
+UINTN mBbsEntry = 0;
+VOID *mBeerData = NULL;
+VOID *mServiceAreaData = NULL;
+UINT64 mLowWater = 0xffffffffffffffffULL;
+
+extern BBS_TABLE *mBbsTable;
+
+/**
+ Print the BBS Table.
+
+ @param BbsTable The BBS table.
+
+
+**/
+VOID
+PrintBbsTable (
+ IN BBS_TABLE *BbsTable
+ )
+{
+ UINT16 Index;
+ UINT16 SubIndex;
+ CHAR8 *String;
+
+ DEBUG ((EFI_D_INFO, "\n"));
+ DEBUG ((EFI_D_INFO, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs mfgs:mfgo dess:deso\n"));
+ DEBUG ((EFI_D_INFO, "=================================================================\n"));
+ for (Index = 0; Index < MAX_BBS_ENTRIES; Index++) {
+ //
+ // Filter
+ //
+ if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
+ continue;
+ }
+
+ DEBUG ((
+ EFI_D_INFO,
+ " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x",
+ (UINTN) Index,
+ (UINTN) BbsTable[Index].BootPriority,
+ (UINTN) BbsTable[Index].Bus,
+ (UINTN) BbsTable[Index].Device,
+ (UINTN) BbsTable[Index].Function,
+ (UINTN) BbsTable[Index].Class,
+ (UINTN) BbsTable[Index].SubClass,
+ (UINTN) BbsTable[Index].DeviceType,
+ (UINTN) * (UINT16 *) &BbsTable[Index].StatusFlags
+ ));
+ DEBUG ((
+ EFI_D_INFO,
+ " %04x:%04x %04x:%04x %04x:%04x",
+ (UINTN) BbsTable[Index].BootHandlerSegment,
+ (UINTN) BbsTable[Index].BootHandlerOffset,
+ (UINTN) BbsTable[Index].MfgStringSegment,
+ (UINTN) BbsTable[Index].MfgStringOffset,
+ (UINTN) BbsTable[Index].DescStringSegment,
+ (UINTN) BbsTable[Index].DescStringOffset
+ ));
+
+ //
+ // Print DescString
+ //
+ String = (CHAR8 *)(UINTN)((BbsTable[Index].DescStringSegment << 4) + BbsTable[Index].DescStringOffset);
+ if (String != NULL) {
+ DEBUG ((EFI_D_INFO," ("));
+ for (SubIndex = 0; String[SubIndex] != 0; SubIndex++) {
+ DEBUG ((EFI_D_INFO, "%c", String[SubIndex]));
+ }
+ DEBUG ((EFI_D_INFO,")"));
+ }
+ DEBUG ((EFI_D_INFO,"\n"));
+ }
+
+ DEBUG ((EFI_D_INFO, "\n"));
+
+ return ;
+}
+
+/**
+ Print the BBS Table.
+
+ @param HddInfo The HddInfo table.
+
+
+**/
+VOID
+PrintHddInfo (
+ IN HDD_INFO *HddInfo
+ )
+{
+ UINTN Index;
+
+ DEBUG ((EFI_D_INFO, "\n"));
+ for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
+ DEBUG ((EFI_D_INFO, "Index - %04x\n", Index));
+ DEBUG ((EFI_D_INFO, " Status - %04x\n", (UINTN)HddInfo[Index].Status));
+ DEBUG ((EFI_D_INFO, " B/D/F - %02x/%02x/%02x\n", (UINTN)HddInfo[Index].Bus, (UINTN)HddInfo[Index].Device, (UINTN)HddInfo[Index].Function));
+ DEBUG ((EFI_D_INFO, " Command - %04x\n", HddInfo[Index].CommandBaseAddress));
+ DEBUG ((EFI_D_INFO, " Control - %04x\n", HddInfo[Index].ControlBaseAddress));
+ DEBUG ((EFI_D_INFO, " BusMaster - %04x\n", HddInfo[Index].BusMasterAddress));
+ DEBUG ((EFI_D_INFO, " HddIrq - %02x\n", HddInfo[Index].HddIrq));
+ DEBUG ((EFI_D_INFO, " IdentifyDrive[0].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[0].Raw[0]));
+ DEBUG ((EFI_D_INFO, " IdentifyDrive[1].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[1].Raw[0]));
+ }
+
+ DEBUG ((EFI_D_INFO, "\n"));
+
+ return ;
+}
+
+/**
+ Identify drive data must be updated to actual parameters before boot.
+
+ @param IdentifyDriveData ATA Identify Data
+
+**/
+VOID
+UpdateIdentifyDriveData (
+ IN UINT8 *IdentifyDriveData
+ );
+
+/**
+ Update SIO data.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS Removable media not present
+
+**/
+EFI_STATUS
+UpdateSioData (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN Index1;
+ UINT8 LegacyInterrupts[16];
+ EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable;
+ UINTN RoutingTableEntries;
+ EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY *IrqPriorityTable;
+ UINTN NumberPriorityEntries;
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
+ UINT8 HddIrq;
+ UINT16 LegacyInt;
+ UINT16 LegMask;
+ UINT32 Register;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+
+ LegacyInt = 0;
+ HandleBuffer = NULL;
+
+ EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
+ LegacyBiosBuildSioData (Private);
+ SetMem (LegacyInterrupts, sizeof (LegacyInterrupts), 0);
+
+ //
+ // Create list of legacy interrupts.
+ //
+ for (Index = 0; Index < 4; Index++) {
+ LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Serial[Index].Irq;
+ }
+
+ for (Index = 4; Index < 7; Index++) {
+ LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Parallel[Index - 4].Irq;
+ }
+
+ LegacyInterrupts[7] = EfiToLegacy16BootTable->SioData.Floppy.Irq;
+
+ //
+ // Get Legacy Hdd IRQs. If native mode treat as PCI
+ //
+ for (Index = 0; Index < 2; Index++) {
+ HddIrq = EfiToLegacy16BootTable->HddInfo[Index].HddIrq;
+ if ((HddIrq != 0) && ((HddIrq == 15) || (HddIrq == 14))) {
+ LegacyInterrupts[Index + 8] = HddIrq;
+ }
+ }
+
+ Private->LegacyBiosPlatform->GetRoutingTable (
+ Private->LegacyBiosPlatform,
+ (VOID *) &RoutingTable,
+ &RoutingTableEntries,
+ NULL,
+ NULL,
+ (VOID **) &IrqPriorityTable,
+ &NumberPriorityEntries
+ );
+ //
+ // Remove legacy interrupts from the list of PCI interrupts available.
+ //
+ for (Index = 0; Index <= 0x0b; Index++) {
+ for (Index1 = 0; Index1 <= NumberPriorityEntries; Index1++) {
+ if (LegacyInterrupts[Index] != 0) {
+ LegacyInt = (UINT16) (LegacyInt | (1 << LegacyInterrupts[Index]));
+ if (LegacyInterrupts[Index] == IrqPriorityTable[Index1].Irq) {
+ IrqPriorityTable[Index1].Used = LEGACY_USED;
+ }
+ }
+ }
+ }
+
+ Private->Legacy8259->GetMask (
+ Private->Legacy8259,
+ &LegMask,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ //
+ // Set SIO interrupts and disable mouse. Let mouse driver
+ // re-enable it.
+ //
+ LegMask = (UINT16) ((LegMask &~LegacyInt) | 0x1000);
+ Private->Legacy8259->SetMask (
+ Private->Legacy8259,
+ &LegMask,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ //
+ // Disable mouse in keyboard controller
+ //
+ Register = 0xA7;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiIsaIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo
+ );
+ ASSERT_EFI_ERROR (Status);
+ IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, 0x64, 1, &Register);
+
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Identify drive data must be updated to actual parameters before boot.
+ This requires updating the checksum, if it exists.
+
+ @param IdentifyDriveData ATA Identify Data
+ @param Checksum checksum of the ATA Identify Data
+
+ @retval EFI_SUCCESS checksum calculated
+ @retval EFI_SECURITY_VIOLATION IdentifyData invalid
+
+**/
+EFI_STATUS
+CalculateIdentifyDriveChecksum (
+ IN UINT8 *IdentifyDriveData,
+ OUT UINT8 *Checksum
+ )
+{
+ UINTN Index;
+ UINT8 LocalChecksum;
+ LocalChecksum = 0;
+ *Checksum = 0;
+ if (IdentifyDriveData[510] != 0xA5) {
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ for (Index = 0; Index < 512; Index++) {
+ LocalChecksum = (UINT8) (LocalChecksum + IdentifyDriveData[Index]);
+ }
+
+ *Checksum = LocalChecksum;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Identify drive data must be updated to actual parameters before boot.
+
+ @param IdentifyDriveData ATA Identify Data
+
+
+**/
+VOID
+UpdateIdentifyDriveData (
+ IN UINT8 *IdentifyDriveData
+ )
+{
+ UINT16 NumberCylinders;
+ UINT16 NumberHeads;
+ UINT16 NumberSectorsTrack;
+ UINT32 CapacityInSectors;
+ UINT8 OriginalChecksum;
+ UINT8 FinalChecksum;
+ EFI_STATUS Status;
+ ATAPI_IDENTIFY *ReadInfo;
+
+ //
+ // Status indicates if Integrity byte is correct. Checksum should be
+ // 0 if valid.
+ //
+ ReadInfo = (ATAPI_IDENTIFY *) IdentifyDriveData;
+ Status = CalculateIdentifyDriveChecksum (IdentifyDriveData, &OriginalChecksum);
+ if (OriginalChecksum != 0) {
+ Status = EFI_SECURITY_VIOLATION;
+ }
+ //
+ // If NumberCylinders = 0 then do data(Controller present but don drive attached).
+ //
+ NumberCylinders = ReadInfo->Raw[1];
+ if (NumberCylinders != 0) {
+ ReadInfo->Raw[54] = NumberCylinders;
+
+ NumberHeads = ReadInfo->Raw[3];
+ ReadInfo->Raw[55] = NumberHeads;
+
+ NumberSectorsTrack = ReadInfo->Raw[6];
+ ReadInfo->Raw[56] = NumberSectorsTrack;
+
+ //
+ // Copy Multisector info and set valid bit.
+ //
+ ReadInfo->Raw[59] = (UINT16) (ReadInfo->Raw[47] + 0x100);
+ CapacityInSectors = (UINT32) ((UINT32) (NumberCylinders) * (UINT32) (NumberHeads) * (UINT32) (NumberSectorsTrack));
+ ReadInfo->Raw[57] = (UINT16) (CapacityInSectors >> 16);
+ ReadInfo->Raw[58] = (UINT16) (CapacityInSectors & 0xffff);
+ if (Status == EFI_SUCCESS) {
+ //
+ // Forece checksum byte to 0 and get new checksum.
+ //
+ ReadInfo->Raw[255] &= 0xff;
+ CalculateIdentifyDriveChecksum (IdentifyDriveData, &FinalChecksum);
+
+ //
+ // Force new checksum such that sum is 0.
+ //
+ FinalChecksum = (UINT8) ((UINT8)0 - FinalChecksum);
+ ReadInfo->Raw[255] = (UINT16) (ReadInfo->Raw[255] | (FinalChecksum << 8));
+ }
+ }
+}
+
+/**
+ Identify drive data must be updated to actual parameters before boot.
+ Do for all drives.
+
+ @param Private Legacy BIOS Instance data
+
+
+**/
+VOID
+UpdateAllIdentifyDriveData (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ UINTN Index;
+ HDD_INFO *HddInfo;
+
+ HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];
+
+ for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
+ //
+ // Each controller can have 2 devices. Update for each device
+ //
+ if ((HddInfo[Index].Status & HDD_MASTER_IDE) != 0) {
+ UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[0].Raw[0]));
+ }
+
+ if ((HddInfo[Index].Status & HDD_SLAVE_IDE) != 0) {
+ UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[1].Raw[0]));
+ }
+ }
+}
+
+/**
+ Enable ide controller. This gets disabled when LegacyBoot.c is about
+ to run the Option ROMs.
+
+ @param Private Legacy BIOS Instance data
+
+
+**/
+VOID
+EnableIdeController (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ EFI_HANDLE IdeController;
+ UINT8 ByteBuffer;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIdeHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ IdeController = HandleBuffer[0];
+ Status = gBS->HandleProtocol (
+ IdeController,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ByteBuffer = 0x1f;
+ if (!EFI_ERROR (Status)) {
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x04, 1, &ByteBuffer);
+ }
+ }
+}
+
+
+/**
+ Enable ide controller. This gets disabled when LegacyBoot.c is about
+ to run the Option ROMs.
+
+ @param Private Legacy BIOS Instance data
+
+
+**/
+VOID
+EnableAllControllers (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE01 PciConfigHeader;
+ EFI_STATUS Status;
+
+ //
+ //
+ //
+ EnableIdeController (Private);
+
+ //
+ // Assumption is table is built from low bus to high bus numbers.
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+
+ //
+ // We do not enable PPB here. This is for HotPlug Consideration.
+ // The Platform HotPlug Driver is responsible for Padding enough hot plug
+ // resources. It is also responsible for enable this bridge. If it
+ // does not pad it. It will cause some early Windows fail to installation.
+ // If the platform driver does not pad resource for PPB, PPB should be in
+ // un-enabled state to let Windows know that this PPB is not configured by
+ // BIOS. So Windows will allocate default resource for PPB.
+ //
+ // The reason for why we enable the command register is:
+ // The CSM will use the IO bar to detect some IRQ status, if the command
+ // is disabled, the IO resource will be out of scope.
+ // For example:
+ // We installed a legacy IRQ handle for a PCI IDE controller. When IRQ
+ // comes up, the handle will check the IO space to identify is the
+ // controller generated the IRQ source.
+ // If the IO command is not enabled, the IRQ handler will has wrong
+ // information. It will cause IRQ storm when the correctly IRQ handler fails
+ // to run.
+ //
+ if (!(IS_PCI_VGA (&PciConfigHeader) ||
+ IS_PCI_OLD_VGA (&PciConfigHeader) ||
+ IS_PCI_IDE (&PciConfigHeader) ||
+ IS_PCI_P2P (&PciConfigHeader) ||
+ IS_PCI_P2P_SUB (&PciConfigHeader) ||
+ IS_PCI_LPC (&PciConfigHeader) )) {
+
+ PciConfigHeader.Hdr.Command |= 0x1f;
+
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 4, 1, &PciConfigHeader.Hdr.Command);
+ }
+ }
+}
+
+/**
+ The following routines are identical in operation, so combine
+ for code compaction:
+ EfiGetPlatformBinaryGetMpTable
+ EfiGetPlatformBinaryGetOemIntData
+ EfiGetPlatformBinaryGetOem32Data
+ EfiGetPlatformBinaryGetOem16Data
+
+ @param This Protocol instance pointer.
+ @param Id Table/Data identifier
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER Invalid ID
+ @retval EFI_OUT_OF_RESOURCES no resource to get data or table
+
+**/
+EFI_STATUS
+LegacyGetDataOrTable (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN EFI_GET_PLATFORM_INFO_MODE Id
+ )
+{
+ VOID *Table;
+ UINT32 TablePtr;
+ UINTN TableSize;
+ UINTN Alignment;
+ UINTN Location;
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
+ EFI_COMPATIBILITY16_TABLE *Legacy16Table;
+ EFI_IA32_REGISTER_SET Regs;
+ LEGACY_BIOS_INSTANCE *Private;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+
+ LegacyBiosPlatform = Private->LegacyBiosPlatform;
+ Legacy16Table = Private->Legacy16Table;
+
+ //
+ // Phase 1 - get an address allocated in 16-bit code
+ //
+ while (TRUE) {
+ switch (Id) {
+ case EfiGetPlatformBinaryMpTable:
+ case EfiGetPlatformBinaryOemIntData:
+ case EfiGetPlatformBinaryOem32Data:
+ case EfiGetPlatformBinaryOem16Data:
+ {
+ Status = LegacyBiosPlatform->GetPlatformInfo (
+ LegacyBiosPlatform,
+ Id,
+ (VOID *) &Table,
+ &TableSize,
+ &Location,
+ &Alignment,
+ 0,
+ 0
+ );
+ DEBUG ((EFI_D_INFO, "LegacyGetDataOrTable - ID: %x, %r\n", (UINTN)Id, Status));
+ DEBUG ((EFI_D_INFO, " Table - %x, Size - %x, Location - %x, Alignment - %x\n", (UINTN)Table, (UINTN)TableSize, (UINTN)Location, (UINTN)Alignment));
+ break;
+ }
+
+ default:
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16GetTableAddress;
+ Regs.X.CX = (UINT16) TableSize;
+ Regs.X.BX = (UINT16) Location;
+ Regs.X.DX = (UINT16) Alignment;
+ Private->LegacyBios.FarCall86 (
+ This,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ if (Regs.X.AX != 0) {
+ DEBUG ((EFI_D_ERROR, "Table ID %x length insufficient\n", Id));
+ return EFI_OUT_OF_RESOURCES;
+ } else {
+ break;
+ }
+ }
+ //
+ // Phase 2 Call routine second time with address to allow address adjustment
+ //
+ Status = LegacyBiosPlatform->GetPlatformInfo (
+ LegacyBiosPlatform,
+ Id,
+ (VOID *) &Table,
+ &TableSize,
+ &Location,
+ &Alignment,
+ Regs.X.DS,
+ Regs.X.BX
+ );
+ switch (Id) {
+ case EfiGetPlatformBinaryMpTable:
+ {
+ Legacy16Table->MpTablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
+ Legacy16Table->MpTableLength = (UINT32)TableSize;
+ DEBUG ((EFI_D_INFO, "MP table in legacy region - %x\n", (UINTN)Legacy16Table->MpTablePtr));
+ break;
+ }
+
+ case EfiGetPlatformBinaryOemIntData:
+ {
+
+ Legacy16Table->OemIntSegment = Regs.X.DS;
+ Legacy16Table->OemIntOffset = Regs.X.BX;
+ DEBUG ((EFI_D_INFO, "OemInt table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->OemIntSegment, (UINTN)Legacy16Table->OemIntOffset));
+ break;
+ }
+
+ case EfiGetPlatformBinaryOem32Data:
+ {
+ Legacy16Table->Oem32Segment = Regs.X.DS;
+ Legacy16Table->Oem32Offset = Regs.X.BX;
+ DEBUG ((EFI_D_INFO, "Oem32 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem32Segment, (UINTN)Legacy16Table->Oem32Offset));
+ break;
+ }
+
+ case EfiGetPlatformBinaryOem16Data:
+ {
+ //
+ // Legacy16Table->Oem16Segment = Regs.X.DS;
+ // Legacy16Table->Oem16Offset = Regs.X.BX;
+ DEBUG ((EFI_D_INFO, "Oem16 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem16Segment, (UINTN)Legacy16Table->Oem16Offset));
+ break;
+ }
+
+ default:
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Phase 3 Copy table to final location
+ //
+ TablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
+
+ CopyMem (
+ (VOID *) (UINTN)TablePtr,
+ Table,
+ TableSize
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Assign drive number to legacy HDD drives prior to booting an EFI
+ aware OS so the OS can access drives without an EFI driver.
+ Note: BBS compliant drives ARE NOT available until this call by
+ either shell or EFI.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS Drive numbers assigned
+
+**/
+EFI_STATUS
+GenericLegacyBoot (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ EFI_IA32_REGISTER_SET Regs;
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
+ EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
+ UINTN CopySize;
+ VOID *AcpiPtr;
+ HDD_INFO *HddInfo;
+ HDD_INFO *LocalHddInfo;
+ UINTN Index;
+ EFI_COMPATIBILITY16_TABLE *Legacy16Table;
+ UINT32 *BdaPtr;
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ BBS_TABLE *LocalBbsTable;
+ UINT32 *BaseVectorMaster;
+ EFI_TIME BootTime;
+ UINT32 LocalTime;
+ EFI_HANDLE IdeController;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ VOID *SmbiosTable;
+ VOID *AcpiTable;
+ UINTN ShadowAddress;
+ UINT32 Granularity;
+ EFI_TIMER_ARCH_PROTOCOL *Timer;
+ UINT64 TimerPeriod;
+
+ LocalHddInfo = NULL;
+ HddCount = 0;
+ BbsCount = 0;
+ LocalBbsTable = NULL;
+ TimerPeriod = 0;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ DEBUG_CODE (
+ DEBUG ((EFI_D_ERROR, "Start of legacy boot\n"));
+ );
+
+ Legacy16Table = Private->Legacy16Table;
+ EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
+ HddInfo = &EfiToLegacy16BootTable->HddInfo[0];
+
+ LegacyBiosPlatform = Private->LegacyBiosPlatform;
+
+ EfiToLegacy16BootTable->MajorVersion = EFI_TO_LEGACY_MAJOR_VERSION;
+ EfiToLegacy16BootTable->MinorVersion = EFI_TO_LEGACY_MINOR_VERSION;
+
+ //
+ // Before starting the Legacy boot check the system ticker.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiTimerArchProtocolGuid,
+ NULL,
+ (VOID **) &Timer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Timer->GetTimerPeriod (
+ Timer,
+ &TimerPeriod
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (TimerPeriod != DEFAULT_LAGACY_TIMER_TICK_DURATION) {
+ Status = Timer->SetTimerPeriod (
+ Timer,
+ DEFAULT_LAGACY_TIMER_TICK_DURATION
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // If booting to a legacy OS then force HDD drives to the appropriate
+ // boot mode by calling GetIdeHandle.
+ // A reconnect -r can force all HDDs back to native mode.
+ //
+ IdeController = NULL;
+ if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
+ Status = LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIdeHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ IdeController = HandleBuffer[0];
+ }
+ }
+ //
+ // Unlock the Legacy BIOS region
+ //
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+
+ //
+ // Reconstruct the Legacy16 boot memory map
+ //
+ LegacyBiosBuildE820 (Private, &CopySize);
+ if (CopySize > Private->Legacy16Table->E820Length) {
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16GetTableAddress;
+ Regs.X.CX = (UINT16) CopySize;
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Private->Legacy16Table->Compatibility16CallSegment,
+ Private->Legacy16Table->Compatibility16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ Private->Legacy16Table->E820Pointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
+ Private->Legacy16Table->E820Length = (UINT32) CopySize;
+ if (Regs.X.AX != 0) {
+ DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n"));
+ } else {
+ CopyMem (
+ (VOID *)(UINTN) Private->Legacy16Table->E820Pointer,
+ Private->E820Table,
+ CopySize
+ );
+ }
+ } else {
+ CopyMem (
+ (VOID *)(UINTN) Private->Legacy16Table->E820Pointer,
+ Private->E820Table,
+ CopySize
+ );
+ Private->Legacy16Table->E820Length = (UINT32) CopySize;
+ }
+ //
+ // Get SMBIOS and ACPI table pointers
+ //
+ SmbiosTable = NULL;
+ EfiGetSystemConfigurationTable (
+ &gEfiSmbiosTableGuid,
+ &SmbiosTable
+ );
+ //
+ // We do not ASSERT if SmbiosTable not found. It is possbile that a platform does not produce SmbiosTable.
+ //
+ if (SmbiosTable == NULL) {
+ DEBUG ((EFI_D_INFO, "Smbios table is not found!\n"));
+ }
+ EfiToLegacy16BootTable->SmbiosTable = (UINT32)(UINTN)SmbiosTable;
+
+ AcpiTable = NULL;
+ Status = EfiGetSystemConfigurationTable (
+ &gEfiAcpi20TableGuid,
+ &AcpiTable
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EfiGetSystemConfigurationTable (
+ &gEfiAcpi10TableGuid,
+ &AcpiTable
+ );
+ }
+ //
+ // We do not ASSERT if AcpiTable not found. It is possbile that a platform does not produce AcpiTable.
+ //
+ if (AcpiTable == NULL) {
+ DEBUG ((EFI_D_INFO, "ACPI table is not found!\n"));
+ }
+ EfiToLegacy16BootTable->AcpiTable = (UINT32)(UINTN)AcpiTable;
+
+ //
+ // Get RSD Ptr table rev at offset 15 decimal
+ // Rev = 0 Length is 20 decimal
+ // Rev != 0 Length is UINT32 at offset 20 decimal
+ //
+ if (AcpiTable != NULL) {
+
+ AcpiPtr = AcpiTable;
+ if (*((UINT8 *) AcpiPtr + 15) == 0) {
+ CopySize = 20;
+ } else {
+ AcpiPtr = ((UINT8 *) AcpiPtr + 20);
+ CopySize = (*(UINT32 *) AcpiPtr);
+ }
+
+ CopyMem (
+ (VOID *)(UINTN) Private->Legacy16Table->AcpiRsdPtrPointer,
+ AcpiTable,
+ CopySize
+ );
+ }
+ //
+ // Make sure all PCI Interrupt Line register are programmed to match 8259
+ //
+ PciProgramAllInterruptLineRegisters (Private);
+
+ //
+ // Unlock the Legacy BIOS region as PciProgramAllInterruptLineRegisters
+ // can lock it.
+ //
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ Private->BiosStart,
+ Private->LegacyBiosImageSize,
+ &Granularity
+ );
+
+ //
+ // Configure Legacy Device Magic
+ //
+ // Only do this code if booting legacy OS
+ //
+ if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
+ UpdateSioData (Private);
+ }
+ //
+ // Setup BDA and EBDA standard areas before Legacy Boot
+ //
+ LegacyBiosCompleteBdaBeforeBoot (Private);
+ LegacyBiosCompleteStandardCmosBeforeBoot (Private);
+
+ //
+ // We must build IDE data, if it hasn't been done, before PciShadowRoms
+ // to insure EFI drivers are connected.
+ //
+ LegacyBiosBuildIdeData (Private, &HddInfo, 1);
+ UpdateAllIdentifyDriveData (Private);
+
+ //
+ // Clear IO BAR, if IDE controller in legacy mode.
+ //
+ InitLegacyIdeController (IdeController);
+
+ //
+ // Generate number of ticks since midnight for BDA. DOS requires this
+ // for its time. We have to make assumptions as to how long following
+ // code takes since after PciShadowRoms PciIo is gone. Place result in
+ // 40:6C-6F
+ //
+ // Adjust value by 1 second.
+ //
+ gRT->GetTime (&BootTime, NULL);
+ LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second;
+ LocalTime += 1;
+
+ //
+ // Multiply result by 18.2 for number of ticks since midnight.
+ // Use 182/10 to avoid floating point math.
+ //
+ LocalTime = (LocalTime * 182) / 10;
+ BdaPtr = (UINT32 *) (UINTN)0x46C;
+ *BdaPtr = LocalTime;
+
+ //
+ // Shadow PCI ROMs. We must do this near the end since this will kick
+ // of Native EFI drivers that may be needed to collect info for Legacy16
+ //
+ // WARNING: PciIo is gone after this call.
+ //
+ PciShadowRoms (Private);
+
+ //
+ // Shadow PXE base code, BIS etc.
+ //
+ Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity);
+ ShadowAddress = Private->OptionRom;
+ Private->LegacyBiosPlatform->PlatformHooks (
+ Private->LegacyBiosPlatform,
+ EfiPlatformHookShadowServiceRoms,
+ 0,
+ 0,
+ &ShadowAddress,
+ Legacy16Table,
+ NULL
+ );
+ Private->OptionRom = (UINT32)ShadowAddress;
+ //
+ // Register Legacy SMI Handler
+ //
+ LegacyBiosPlatform->SmmInit (
+ LegacyBiosPlatform,
+ EfiToLegacy16BootTable
+ );
+
+ //
+ // Let platform code know the boot options
+ //
+ LegacyBiosGetBbsInfo (
+ This,
+ &HddCount,
+ &LocalHddInfo,
+ &BbsCount,
+ &LocalBbsTable
+ );
+
+ PrintBbsTable (LocalBbsTable);
+ PrintHddInfo (LocalHddInfo);
+
+ //
+ // If drive wasn't spun up then BuildIdeData may have found new drives.
+ // Need to update BBS boot priority.
+ //
+ for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
+ if ((LocalHddInfo[Index].IdentifyDrive[0].Raw[0] != 0) &&
+ (LocalBbsTable[2 * Index + 1].BootPriority == BBS_IGNORE_ENTRY)
+ ) {
+ LocalBbsTable[2 * Index + 1].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ }
+
+ if ((LocalHddInfo[Index].IdentifyDrive[1].Raw[0] != 0) &&
+ (LocalBbsTable[2 * Index + 2].BootPriority == BBS_IGNORE_ENTRY)
+ ) {
+ LocalBbsTable[2 * Index + 2].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ }
+ }
+
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ 0xc0000,
+ 0x40000,
+ &Granularity
+ );
+
+ LegacyBiosPlatform->PrepareToBoot (
+ LegacyBiosPlatform,
+ mBbsDevicePathPtr,
+ mBbsTable,
+ mLoadOptionsSize,
+ mLoadOptions,
+ (VOID *) &Private->IntThunk->EfiToLegacy16BootTable
+ );
+
+ //
+ // If no boot device return to BDS
+ //
+ if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
+ for (Index = 0; Index < BbsCount; Index++){
+ if ((LocalBbsTable[Index].BootPriority != BBS_DO_NOT_BOOT_FROM) &&
+ (LocalBbsTable[Index].BootPriority != BBS_UNPRIORITIZED_ENTRY) &&
+ (LocalBbsTable[Index].BootPriority != BBS_IGNORE_ENTRY)) {
+ break;
+ }
+ }
+ if (Index == BbsCount) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // Let the Legacy16 code know the device path type for legacy boot
+ //
+ EfiToLegacy16BootTable->DevicePathType = mBbsDevicePathPtr->DeviceType;
+
+ //
+ // Copy MP table, if it exists.
+ //
+ LegacyGetDataOrTable (This, EfiGetPlatformBinaryMpTable);
+
+ if (!Private->LegacyBootEntered) {
+ //
+ // Copy OEM INT Data, if it exists. Note: This code treats any data
+ // as a bag of bits and knows nothing of the contents nor cares.
+ // Contents are IBV specific.
+ //
+ LegacyGetDataOrTable (This, EfiGetPlatformBinaryOemIntData);
+
+ //
+ // Copy OEM16 Data, if it exists.Note: This code treats any data
+ // as a bag of bits and knows nothing of the contents nor cares.
+ // Contents are IBV specific.
+ //
+ LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem16Data);
+
+ //
+ // Copy OEM32 Data, if it exists.Note: This code treats any data
+ // as a bag of bits and knows nothing of the contents nor cares.
+ // Contents are IBV specific.
+ //
+ LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem32Data);
+ }
+
+ //
+ // Call into Legacy16 code to prepare for INT 19h
+ //
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16PrepareToBoot;
+
+ //
+ // Pass in handoff data
+ //
+ Regs.X.ES = EFI_SEGMENT ((UINTN)EfiToLegacy16BootTable);
+ Regs.X.BX = EFI_OFFSET ((UINTN)EfiToLegacy16BootTable);
+
+ Private->LegacyBios.FarCall86 (
+ This,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ if (Regs.X.AX != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Lock the Legacy BIOS region
+ //
+ Private->LegacyRegion->Lock (
+ Private->LegacyRegion,
+ 0xc0000,
+ 0x40000,
+ &Granularity
+ );
+ //
+ // Lock attributes of the Legacy Region if chipset supports
+ //
+ Private->LegacyRegion->BootLock (
+ Private->LegacyRegion,
+ 0xc0000,
+ 0x40000,
+ &Granularity
+ );
+
+ //
+ // Call into Legacy16 code to do the INT 19h
+ //
+ EnableAllControllers (Private);
+ if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
+ //
+ // Signal all the events that are waiting on EVT_SIGNAL_LEGACY_BOOT
+ //
+ EfiSignalEventLegacyBoot ();
+ DEBUG ((EFI_D_INFO, "Legacy INT19 Boot...\n"));
+ //
+ // Raise TPL to high level to disable CPU interrupts
+ //
+ gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ //
+ // Put the 8259 into its legacy mode by reprogramming the vector bases
+ //
+ Private->Legacy8259->SetVectorBase (Private->Legacy8259, LEGACY_MODE_BASE_VECTOR_MASTER, LEGACY_MODE_BASE_VECTOR_SLAVE);
+ //
+ // PC History
+ // The original PC used INT8-F for master PIC. Since these mapped over
+ // processor exceptions TIANO moved the master PIC to INT68-6F.
+ // We need to set these back to the Legacy16 unexpected interrupt(saved
+ // in LegacyBios.c) since some OS see that these have values different from
+ // what is expected and invoke them. Since the legacy OS corrupts EFI
+ // memory, there is no handler for these interrupts and OS blows up.
+ //
+ // We need to save the TIANO values for the rare case that the Legacy16
+ // code cannot boot but knows memory hasn't been destroyed.
+ //
+ // To compound the problem, video takes over one of these INTS and must be
+ // be left.
+ // @bug - determine if video hooks INT(in which case we must find new
+ // set of TIANO vectors) or takes it over.
+ //
+ //
+ BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
+ for (Index = 0; Index < 8; Index++) {
+ Private->ThunkSavedInt[Index] = BaseVectorMaster[Index];
+ if (Private->ThunkSeg == (UINT16) (BaseVectorMaster[Index] >> 16)) {
+ BaseVectorMaster[Index] = (UINT32) (Private->BiosUnexpectedInt);
+ }
+ }
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16Boot;
+
+ Private->LegacyBios.FarCall86 (
+ This,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
+ for (Index = 0; Index < 8; Index++) {
+ BaseVectorMaster[Index] = Private->ThunkSavedInt[Index];
+ }
+ }
+ Private->LegacyBootEntered = TRUE;
+ if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
+ //
+ // Should never return unless never passed control to 0:7c00(first stage
+ // OS loader) and only then if no bootable device found.
+ //
+ return EFI_DEVICE_ERROR;
+ } else {
+ //
+ // If boot to EFI then expect to return to caller
+ //
+ return EFI_SUCCESS;
+ }
+}
+
+
+/**
+ Assign drive number to legacy HDD drives prior to booting an EFI
+ aware OS so the OS can access drives without an EFI driver.
+ Note: BBS compliant drives ARE NOT available until this call by
+ either shell or EFI.
+
+ @param This Protocol instance pointer.
+ @param BbsCount Number of BBS_TABLE structures
+ @param BbsTable List BBS entries
+
+ @retval EFI_SUCCESS Drive numbers assigned
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosPrepareToBootEfi (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ OUT UINT16 *BbsCount,
+ OUT BBS_TABLE **BbsTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
+ LEGACY_BIOS_INSTANCE *Private;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
+ mBootMode = BOOT_EFI_OS;
+ mBbsDevicePathPtr = NULL;
+ Status = GenericLegacyBoot (This);
+ *BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
+ *BbsCount = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE));
+ return Status;
+}
+
+/**
+ To boot from an unconventional device like parties and/or execute HDD diagnostics.
+
+ @param This Protocol instance pointer.
+ @param Attributes How to interpret the other input parameters
+ @param BbsEntry The 0-based index into the BbsTable for the parent
+ device.
+ @param BeerData Pointer to the 128 bytes of ram BEER data.
+ @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The
+ caller must provide a pointer to the specific Service
+ Area and not the start all Service Areas.
+
+ @retval EFI_INVALID_PARAMETER if error. Does NOT return if no error.
+
+***/
+EFI_STATUS
+EFIAPI
+LegacyBiosBootUnconventionalDevice (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UDC_ATTRIBUTES Attributes,
+ IN UINTN BbsEntry,
+ IN VOID *BeerData,
+ IN VOID *ServiceAreaData
+ )
+{
+ EFI_STATUS Status;
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
+ LEGACY_BIOS_INSTANCE *Private;
+ UD_TABLE *UcdTable;
+ UINTN Index;
+ UINT16 BootPriority;
+ BBS_TABLE *BbsTable;
+
+ BootPriority = 0;
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ mBootMode = BOOT_UNCONVENTIONAL_DEVICE;
+ mBbsDevicePathPtr = &mBbsDevicePathNode;
+ mAttributes = Attributes;
+ mBbsEntry = BbsEntry;
+ mBeerData = BeerData, mServiceAreaData = ServiceAreaData;
+
+ EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
+
+ //
+ // Do input parameter checking
+ //
+ if ((Attributes.DirectoryServiceValidity == 0) &&
+ (Attributes.RabcaUsedFlag == 0) &&
+ (Attributes.ExecuteHddDiagnosticsFlag == 0)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((Attributes.DirectoryServiceValidity != 0) && (ServiceAreaData == NULL)) ||
+ (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag) != 0) && (BeerData == NULL))
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UcdTable = (UD_TABLE *) AllocatePool (
+ sizeof (UD_TABLE)
+ );
+ if (NULL == UcdTable) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ EfiToLegacy16BootTable->UnconventionalDeviceTable = (UINT32)(UINTN)UcdTable;
+ UcdTable->Attributes = Attributes;
+ UcdTable->BbsTableEntryNumberForParentDevice = (UINT8) BbsEntry;
+ //
+ // Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM
+ // to assign drive numbers but bot boot from. Only newly created entries
+ // will be valid.
+ //
+ BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
+ for (Index = 0; Index < EfiToLegacy16BootTable->NumberBbsEntries; Index++) {
+ BbsTable[Index].BootPriority = BBS_DO_NOT_BOOT_FROM;
+ }
+ //
+ // If parent is onboard IDE then assign controller & device number
+ // else they are 0.
+ //
+ if (BbsEntry < MAX_IDE_CONTROLLER * 2) {
+ UcdTable->DeviceNumber = (UINT8) ((BbsEntry - 1) % 2);
+ }
+
+ if (BeerData != NULL) {
+ CopyMem (
+ (VOID *) UcdTable->BeerData,
+ BeerData,
+ (UINTN) 128
+ );
+ }
+
+ if (ServiceAreaData != NULL) {
+ CopyMem (
+ (VOID *) UcdTable->ServiceAreaData,
+ ServiceAreaData,
+ (UINTN) 64
+ );
+ }
+ //
+ // For each new entry do the following:
+ // 1. Increment current number of BBS entries
+ // 2. Copy parent entry to new entry.
+ // 3. Zero out BootHandler Offset & segment
+ // 4. Set appropriate device type. BEV(0x80) for HDD diagnostics
+ // and Floppy(0x01) for PARTIES boot.
+ // 5. Assign new priority.
+ //
+ if ((Attributes.ExecuteHddDiagnosticsFlag) != 0) {
+ EfiToLegacy16BootTable->NumberBbsEntries += 1;
+
+ CopyMem (
+ (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,
+ (VOID *) &BbsTable[BbsEntry].BootPriority,
+ sizeof (BBS_TABLE)
+ );
+
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0;
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x80;
+
+ UcdTable->BbsTableEntryNumberForHddDiag = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1);
+
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;
+ BootPriority += 1;
+
+ //
+ // Set device type as BBS_TYPE_DEV for PARTIES diagnostic
+ //
+ mBbsDevicePathNode.DeviceType = BBS_TYPE_BEV;
+ }
+
+ if (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag)) != 0) {
+ EfiToLegacy16BootTable->NumberBbsEntries += 1;
+ CopyMem (
+ (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,
+ (VOID *) &BbsTable[BbsEntry].BootPriority,
+ sizeof (BBS_TABLE)
+ );
+
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0;
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x01;
+ UcdTable->BbsTableEntryNumberForBoot = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1);
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;
+
+ //
+ // Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy
+ //
+ mBbsDevicePathNode.DeviceType = BBS_TYPE_FLOPPY;
+ }
+ //
+ // Build the BBS Device Path for this boot selection
+ //
+ mBbsDevicePathNode.Header.Type = BBS_DEVICE_PATH;
+ mBbsDevicePathNode.Header.SubType = BBS_BBS_DP;
+ SetDevicePathNodeLength (&mBbsDevicePathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));
+ mBbsDevicePathNode.StatusFlag = 0;
+ mBbsDevicePathNode.String[0] = 0;
+
+ Status = GenericLegacyBoot (This);
+ return Status;
+}
+
+/**
+ Attempt to legacy boot the BootOption. If the EFI contexted has been
+ compromised this function will not return.
+
+ @param This Protocol instance pointer.
+ @param BbsDevicePath EFI Device Path from BootXXXX variable.
+ @param LoadOptionsSize Size of LoadOption in size.
+ @param LoadOptions LoadOption from BootXXXX variable
+
+ @retval EFI_SUCCESS Removable media not present
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosLegacyBoot (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN BBS_BBS_DEVICE_PATH *BbsDevicePath,
+ IN UINT32 LoadOptionsSize,
+ IN VOID *LoadOptions
+ )
+{
+ EFI_STATUS Status;
+
+ mBbsDevicePathPtr = BbsDevicePath;
+ mLoadOptionsSize = LoadOptionsSize;
+ mLoadOptions = LoadOptions;
+ mBootMode = BOOT_LEGACY_OS;
+ Status = GenericLegacyBoot (This);
+
+ return Status;
+}
+
+/**
+ Convert EFI Memory Type to E820 Memory Type.
+
+ @param Type EFI Memory Type
+
+ @return ACPI Memory Type for EFI Memory Type
+
+**/
+EFI_ACPI_MEMORY_TYPE
+EfiMemoryTypeToE820Type (
+ IN UINT32 Type
+ )
+{
+ switch (Type) {
+ case EfiLoaderCode:
+ case EfiLoaderData:
+ case EfiBootServicesCode:
+ case EfiBootServicesData:
+ case EfiConventionalMemory:
+ case EfiRuntimeServicesCode:
+ case EfiRuntimeServicesData:
+ return EfiAcpiAddressRangeMemory;
+
+ case EfiACPIReclaimMemory:
+ return EfiAcpiAddressRangeACPI;
+
+ case EfiACPIMemoryNVS:
+ return EfiAcpiAddressRangeNVS;
+
+ //
+ // All other types map to reserved.
+ // Adding the code just waists FLASH space.
+ //
+ // case EfiReservedMemoryType:
+ // case EfiUnusableMemory:
+ // case EfiMemoryMappedIO:
+ // case EfiMemoryMappedIOPortSpace:
+ // case EfiPalCode:
+ //
+ default:
+ return EfiAcpiAddressRangeReserved;
+ }
+}
+
+/**
+ Build the E820 table.
+
+ @param Private Legacy BIOS Instance data
+ @param Size Size of E820 Table
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildE820 (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ OUT UINTN *Size
+ )
+{
+ EFI_STATUS Status;
+ EFI_E820_ENTRY64 *E820Table;
+ EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;
+ EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd;
+ EFI_MEMORY_DESCRIPTOR *EfiEntry;
+ EFI_MEMORY_DESCRIPTOR *NextEfiEntry;
+ EFI_MEMORY_DESCRIPTOR TempEfiEntry;
+ UINTN EfiMemoryMapSize;
+ UINTN EfiMapKey;
+ UINTN EfiDescriptorSize;
+ UINT32 EfiDescriptorVersion;
+ UINTN Index;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
+ UINTN TempIndex;
+ UINTN IndexSort;
+ UINTN TempNextIndex;
+ EFI_E820_ENTRY64 TempE820;
+ EFI_ACPI_MEMORY_TYPE TempType;
+ BOOLEAN ChangedFlag;
+ UINTN Above1MIndex;
+ UINT64 MemoryBlockLength;
+
+ E820Table = (EFI_E820_ENTRY64 *) Private->E820Table;
+
+ //
+ // Get the EFI memory map.
+ //
+ EfiMemoryMapSize = 0;
+ EfiMemoryMap = NULL;
+ Status = gBS->GetMemoryMap (
+ &EfiMemoryMapSize,
+ EfiMemoryMap,
+ &EfiMapKey,
+ &EfiDescriptorSize,
+ &EfiDescriptorVersion
+ );
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+
+ do {
+ //
+ // Use size returned back plus 1 descriptor for the AllocatePool.
+ // We don't just multiply by 2 since the "for" loop below terminates on
+ // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize
+ // we process bogus entries and create bogus E820 entries.
+ //
+ EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize);
+ ASSERT (EfiMemoryMap != NULL);
+ Status = gBS->GetMemoryMap (
+ &EfiMemoryMapSize,
+ EfiMemoryMap,
+ &EfiMapKey,
+ &EfiDescriptorSize,
+ &EfiDescriptorVersion
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (EfiMemoryMap);
+ }
+ } while (Status == EFI_BUFFER_TOO_SMALL);
+
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Punch in the E820 table for memory less than 1 MB.
+ // Assume ZeroMem () has been done on data structure.
+ //
+ //
+ // First entry is 0 to (640k - EBDA)
+ //
+ E820Table[0].BaseAddr = 0;
+ E820Table[0].Length = (UINT64) ((*(UINT16 *) (UINTN)0x40E) << 4);
+ E820Table[0].Type = EfiAcpiAddressRangeMemory;
+
+ //
+ // Second entry is (640k - EBDA) to 640k
+ //
+ E820Table[1].BaseAddr = E820Table[0].Length;
+ E820Table[1].Length = (UINT64) ((640 * 1024) - E820Table[0].Length);
+ E820Table[1].Type = EfiAcpiAddressRangeReserved;
+
+ //
+ // Third Entry is legacy BIOS
+ // DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas
+ // to page in memory under 1MB.
+ // Omit region from 0xE0000 to start of BIOS, if any. This can be
+ // used for a multiple reasons including OPROMS.
+ //
+
+ //
+ // The CSM binary image size is not the actually size that CSM binary used,
+ // to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary.
+ //
+ E820Table[2].BaseAddr = 0xE0000;
+ E820Table[2].Length = 0x20000;
+ E820Table[2].Type = EfiAcpiAddressRangeReserved;
+
+ Above1MIndex = 2;
+
+ //
+ // Process the EFI map to produce E820 map;
+ //
+
+ //
+ // Sort memory map from low to high
+ //
+ EfiEntry = EfiMemoryMap;
+ NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+ EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
+ while (EfiEntry < EfiMemoryMapEnd) {
+ while (NextEfiEntry < EfiMemoryMapEnd) {
+ if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {
+ CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+ CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+ CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+ }
+
+ NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize);
+ }
+
+ EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+ NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+ }
+
+ EfiEntry = EfiMemoryMap;
+ EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
+ for (Index = Above1MIndex; (EfiEntry < EfiMemoryMapEnd) && (Index < EFI_MAX_E820_ENTRY - 1); ) {
+ MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12));
+ if ((EfiEntry->PhysicalStart + MemoryBlockLength) < 0x100000) {
+ //
+ // Skip the memory block is under 1MB
+ //
+ } else {
+ if (EfiEntry->PhysicalStart < 0x100000) {
+ //
+ // When the memory block spans below 1MB, ensure the memory block start address is at least 1MB
+ //
+ MemoryBlockLength -= 0x100000 - EfiEntry->PhysicalStart;
+ EfiEntry->PhysicalStart = 0x100000;
+ }
+
+ //
+ // Convert memory type to E820 type
+ //
+ TempType = EfiMemoryTypeToE820Type (EfiEntry->Type);
+
+ if ((E820Table[Index].Type == TempType) && (EfiEntry->PhysicalStart == (E820Table[Index].BaseAddr + E820Table[Index].Length))) {
+ //
+ // Grow an existing entry
+ //
+ E820Table[Index].Length += MemoryBlockLength;
+ } else {
+ //
+ // Make a new entry
+ //
+ ++Index;
+ E820Table[Index].BaseAddr = EfiEntry->PhysicalStart;
+ E820Table[Index].Length = MemoryBlockLength;
+ E820Table[Index].Type = TempType;
+ }
+ }
+ EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+ }
+
+ FreePool (EfiMemoryMap);
+
+ //
+ // Process the reserved memory map to produce E820 map ;
+ //
+ for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
+ if (Hob.Raw != NULL && GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ ResourceHob = Hob.ResourceDescriptor;
+ if (((ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO) ||
+ (ResourceHob->ResourceType == EFI_RESOURCE_FIRMWARE_DEVICE) ||
+ (ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_RESERVED) ) &&
+ (ResourceHob->PhysicalStart > 0x100000) &&
+ (Index < EFI_MAX_E820_ENTRY - 1)) {
+ ++Index;
+ E820Table[Index].BaseAddr = ResourceHob->PhysicalStart;
+ E820Table[Index].Length = ResourceHob->ResourceLength;
+ E820Table[Index].Type = EfiAcpiAddressRangeReserved;
+ }
+ }
+ }
+
+ Index ++;
+ Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;
+ Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;
+ Private->NumberE820Entries = (UINT32)Index;
+ *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64));
+
+ //
+ // Sort E820Table from low to high
+ //
+ for (TempIndex = 0; TempIndex < Index; TempIndex++) {
+ ChangedFlag = FALSE;
+ for (TempNextIndex = 1; TempNextIndex < Index - TempIndex; TempNextIndex++) {
+ if (E820Table[TempNextIndex - 1].BaseAddr > E820Table[TempNextIndex].BaseAddr) {
+ ChangedFlag = TRUE;
+ TempE820.BaseAddr = E820Table[TempNextIndex - 1].BaseAddr;
+ TempE820.Length = E820Table[TempNextIndex - 1].Length;
+ TempE820.Type = E820Table[TempNextIndex - 1].Type;
+
+ E820Table[TempNextIndex - 1].BaseAddr = E820Table[TempNextIndex].BaseAddr;
+ E820Table[TempNextIndex - 1].Length = E820Table[TempNextIndex].Length;
+ E820Table[TempNextIndex - 1].Type = E820Table[TempNextIndex].Type;
+
+ E820Table[TempNextIndex].BaseAddr = TempE820.BaseAddr;
+ E820Table[TempNextIndex].Length = TempE820.Length;
+ E820Table[TempNextIndex].Type = TempE820.Type;
+ }
+ }
+
+ if (!ChangedFlag) {
+ break;
+ }
+ }
+
+ //
+ // Remove the overlap range
+ //
+ for (TempIndex = 1; TempIndex < Index; TempIndex++) {
+ if (E820Table[TempIndex - 1].BaseAddr <= E820Table[TempIndex].BaseAddr &&
+ ((E820Table[TempIndex - 1].BaseAddr + E820Table[TempIndex - 1].Length) >=
+ (E820Table[TempIndex].BaseAddr +E820Table[TempIndex].Length))) {
+ //
+ //Overlap range is found
+ //
+ ASSERT (E820Table[TempIndex - 1].Type == E820Table[TempIndex].Type);
+
+ if (TempIndex == Index - 1) {
+ E820Table[TempIndex].BaseAddr = 0;
+ E820Table[TempIndex].Length = 0;
+ E820Table[TempIndex].Type = (EFI_ACPI_MEMORY_TYPE) 0;
+ Index--;
+ break;
+ } else {
+ for (IndexSort = TempIndex; IndexSort < Index - 1; IndexSort ++) {
+ E820Table[IndexSort].BaseAddr = E820Table[IndexSort + 1].BaseAddr;
+ E820Table[IndexSort].Length = E820Table[IndexSort + 1].Length;
+ E820Table[IndexSort].Type = E820Table[IndexSort + 1].Type;
+ }
+ Index--;
+ }
+ }
+ }
+
+
+
+ Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;
+ Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;
+ Private->NumberE820Entries = (UINT32)Index;
+ *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64));
+
+ //
+ // Determine OS usable memory above 1Mb
+ //
+ Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb = 0x0000;
+ for (TempIndex = Above1MIndex; TempIndex < Index; TempIndex++) {
+ if (E820Table[TempIndex].BaseAddr >= 0x100000 && E820Table[TempIndex].BaseAddr < 0x100000000ULL) { // not include above 4G memory
+ //
+ // ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables.
+ //
+ if ((E820Table[TempIndex].Type == EfiAcpiAddressRangeMemory) || (E820Table[TempIndex].Type == EfiAcpiAddressRangeACPI)) {
+ Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb += (UINT32) (E820Table[TempIndex].Length);
+ } else {
+ break; // break at first not normal memory, because SMM may use reserved memory.
+ }
+ }
+ }
+
+ Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb = Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb;
+
+ //
+ // Print DEBUG information
+ //
+ for (TempIndex = 0; TempIndex < Index; TempIndex++) {
+ DEBUG((EFI_D_INFO, "E820[%2d]: 0x%16lx ---- 0x%16lx, Type = 0x%x \n",
+ TempIndex,
+ E820Table[TempIndex].BaseAddr,
+ (E820Table[TempIndex].BaseAddr + E820Table[TempIndex].Length),
+ E820Table[TempIndex].Type
+ ));
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Fill in the standard BDA and EBDA stuff prior to legacy Boot
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosCompleteBdaBeforeBoot (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ BDA_STRUC *Bda;
+ UINT16 MachineConfig;
+ DEVICE_PRODUCER_DATA_HEADER *SioPtr;
+
+ Bda = (BDA_STRUC *) ((UINTN) 0x400);
+ MachineConfig = 0;
+
+ SioPtr = &(Private->IntThunk->EfiToLegacy16BootTable.SioData);
+ Bda->Com1 = SioPtr->Serial[0].Address;
+ Bda->Com2 = SioPtr->Serial[1].Address;
+ Bda->Com3 = SioPtr->Serial[2].Address;
+ Bda->Com4 = SioPtr->Serial[3].Address;
+
+ if (SioPtr->Serial[0].Address != 0x00) {
+ MachineConfig += 0x200;
+ }
+
+ if (SioPtr->Serial[1].Address != 0x00) {
+ MachineConfig += 0x200;
+ }
+
+ if (SioPtr->Serial[2].Address != 0x00) {
+ MachineConfig += 0x200;
+ }
+
+ if (SioPtr->Serial[3].Address != 0x00) {
+ MachineConfig += 0x200;
+ }
+
+ Bda->Lpt1 = SioPtr->Parallel[0].Address;
+ Bda->Lpt2 = SioPtr->Parallel[1].Address;
+ Bda->Lpt3 = SioPtr->Parallel[2].Address;
+
+ if (SioPtr->Parallel[0].Address != 0x00) {
+ MachineConfig += 0x4000;
+ }
+
+ if (SioPtr->Parallel[1].Address != 0x00) {
+ MachineConfig += 0x4000;
+ }
+
+ if (SioPtr->Parallel[2].Address != 0x00) {
+ MachineConfig += 0x4000;
+ }
+
+ Bda->NumberOfDrives = (UINT8) (Bda->NumberOfDrives + Private->IdeDriveCount);
+ if (SioPtr->Floppy.NumberOfFloppy != 0x00) {
+ MachineConfig = (UINT16) (MachineConfig + 0x01 + (SioPtr->Floppy.NumberOfFloppy - 1) * 0x40);
+ Bda->FloppyXRate = 0x07;
+ }
+
+ Bda->Lpt1_2Timeout = 0x1414;
+ Bda->Lpt3_4Timeout = 0x1414;
+ Bda->Com1_2Timeout = 0x0101;
+ Bda->Com3_4Timeout = 0x0101;
+
+ //
+ // Force VGA and Coprocessor, indicate 101/102 keyboard
+ //
+ MachineConfig = (UINT16) (MachineConfig + 0x00 + 0x02 + (SioPtr->MousePresent * 0x04));
+ Bda->MachineConfig = MachineConfig;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Fill in the standard BDA for Keyboard LEDs
+
+ @param This Protocol instance pointer.
+ @param Leds Current LED status
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosUpdateKeyboardLedStatus (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT8 Leds
+ )
+{
+ LEGACY_BIOS_INSTANCE *Private;
+ BDA_STRUC *Bda;
+ UINT8 LocalLeds;
+ EFI_IA32_REGISTER_SET Regs;
+
+ Bda = (BDA_STRUC *) ((UINTN) 0x400);
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ LocalLeds = Leds;
+ Bda->LedStatus = (UINT8) ((Bda->LedStatus &~0x07) | LocalLeds);
+ LocalLeds = (UINT8) (LocalLeds << 4);
+ Bda->ShiftStatus = (UINT8) ((Bda->ShiftStatus &~0x70) | LocalLeds);
+ LocalLeds = (UINT8) (Leds & 0x20);
+ Bda->KeyboardStatus = (UINT8) ((Bda->KeyboardStatus &~0x20) | LocalLeds);
+ //
+ // Call into Legacy16 code to allow it to do any processing
+ //
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16SetKeyboardLeds;
+ Regs.H.CL = Leds;
+
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Private->Legacy16Table->Compatibility16CallSegment,
+ Private->Legacy16Table->Compatibility16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Fill in the standard CMOS stuff prior to legacy Boot
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosCompleteStandardCmosBeforeBoot (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ UINT8 Bda;
+ UINT8 Floppy;
+ UINT32 Size;
+
+ //
+ // Update CMOS locations
+ // 10 floppy
+ // 12,19,1A - ignore as OS don't use them and there is no standard due
+ // to large capacity drives
+ // CMOS 14 = BDA 40:10 plus bit 3(display enabled)
+ //
+ Bda = (UINT8)(*((UINT8 *)((UINTN)0x410)) | BIT3);
+
+ //
+ // Force display enabled
+ //
+ Floppy = 0x00;
+ if ((Bda & BIT0) != 0) {
+ Floppy = BIT6;
+ }
+
+ //
+ // Check if 2.88MB floppy set
+ //
+ if ((Bda & (BIT7 | BIT6)) != 0) {
+ Floppy = (UINT8)(Floppy | BIT1);
+ }
+
+ LegacyWriteStandardCmos (CMOS_10, Floppy);
+ LegacyWriteStandardCmos (CMOS_14, Bda);
+
+ //
+ // Force Status Register A to set rate selection bits and divider
+ //
+ LegacyWriteStandardCmos (CMOS_0A, 0x26);
+
+ //
+ // redo memory size since it can change
+ //
+ Size = 15 * SIZE_1MB;
+ if (Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb < (15 * SIZE_1MB)) {
+ Size = Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb >> 10;
+ }
+
+ LegacyWriteStandardCmos (CMOS_17, (UINT8)(Size & 0xFF));
+ LegacyWriteStandardCmos (CMOS_30, (UINT8)(Size & 0xFF));
+ LegacyWriteStandardCmos (CMOS_18, (UINT8)(Size >> 8));
+ LegacyWriteStandardCmos (CMOS_31, (UINT8)(Size >> 8));
+
+ LegacyCalculateWriteStandardCmosChecksum ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Relocate this image under 4G memory for IPF.
+
+ @param ImageHandle Handle of driver image.
+ @param SystemTable Pointer to system table.
+
+ @retval EFI_SUCCESS Image successfully relocated.
+ @retval EFI_ABORTED Failed to relocate image.
+
+**/
+EFI_STATUS
+RelocateImageUnder4GIfNeeded (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EFI_SUCCESS;
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyCmos.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyCmos.c new file mode 100644 index 0000000..0fbf902 --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyCmos.c @@ -0,0 +1,124 @@ +/** @file
+ This code fills in standard CMOS values and updates the standard CMOS
+ checksum. The Legacy16 code or LegacyBiosPlatform.c is responsible for
+ non-standard CMOS locations and non-standard checksums.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+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.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+/**
+ Read CMOS register through index/data port.
+
+ @param[in] Index The index of the CMOS register to read.
+
+ @return The data value from the CMOS register specified by Index.
+
+**/
+UINT8
+LegacyReadStandardCmos (
+ IN UINT8 Index
+ )
+{
+ IoWrite8 (PORT_70, Index);
+ return IoRead8 (PORT_71);
+}
+
+/**
+ Write CMOS register through index/data port.
+
+ @param[in] Index The index of the CMOS register to write.
+ @param[in] Value The value of CMOS register to write.
+
+ @return The value written to the CMOS register specified by Index.
+
+**/
+UINT8
+LegacyWriteStandardCmos (
+ IN UINT8 Index,
+ IN UINT8 Value
+ )
+{
+ IoWrite8 (PORT_70, Index);
+ return IoWrite8 (PORT_71, Value);
+}
+
+/**
+ Calculate the new standard CMOS checksum and write it.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS Calculate 16-bit checksum successfully
+
+**/
+EFI_STATUS
+LegacyCalculateWriteStandardCmosChecksum (
+ VOID
+ )
+{
+ UINT8 Register;
+ UINT16 Checksum;
+
+ for (Checksum = 0, Register = 0x10; Register < 0x2e; Register++) {
+ Checksum = (UINT16)(Checksum + LegacyReadStandardCmos (Register));
+ }
+ LegacyWriteStandardCmos (CMOS_2E, (UINT8)(Checksum >> 8));
+ LegacyWriteStandardCmos (CMOS_2F, (UINT8)(Checksum & 0xff));
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Fill in the standard CMOS stuff before Legacy16 load
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosInitCmos (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ UINT32 Size;
+
+ //
+ // Clear all errors except RTC lost power
+ //
+ LegacyWriteStandardCmos (CMOS_0E, (UINT8)(LegacyReadStandardCmos (CMOS_0E) & BIT7));
+
+ //
+ // Update CMOS locations 15,16,17,18,30,31 and 32
+ // CMOS 16,15 = 640Kb = 0x280
+ // CMOS 18,17 = 31,30 = 15Mb max in 1Kb increments =0x3C00 max
+ // CMOS 32 = 0x20
+ //
+ LegacyWriteStandardCmos (CMOS_15, 0x80);
+ LegacyWriteStandardCmos (CMOS_16, 0x02);
+
+ Size = 15 * SIZE_1MB;
+ if (Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb < (15 * SIZE_1MB)) {
+ Size = Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb >> 10;
+ }
+
+ LegacyWriteStandardCmos (CMOS_17, (UINT8)(Size & 0xFF));
+ LegacyWriteStandardCmos (CMOS_30, (UINT8)(Size & 0xFF));
+ LegacyWriteStandardCmos (CMOS_18, (UINT8)(Size >> 8));
+ LegacyWriteStandardCmos (CMOS_31, (UINT8)(Size >> 8));
+
+ LegacyCalculateWriteStandardCmosChecksum ();
+
+ return EFI_SUCCESS;
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyIde.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyIde.c new file mode 100644 index 0000000..4e52fe9 --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyIde.c @@ -0,0 +1,300 @@ +/** @file
+ Collect IDE information from Native EFI Driver
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+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.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+BOOLEAN mIdeDataBuiltFlag = FALSE;
+
+/**
+ Collect IDE Inquiry data from the IDE disks
+
+ @param Private Legacy BIOS Instance data
+ @param HddInfo Hdd Information
+ @param Flag Reconnect IdeController or not
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildIdeData (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN HDD_INFO **HddInfo,
+ IN UINT16 Flag
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE IdeController;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ EFI_DISK_INFO_PROTOCOL *DiskInfo;
+ UINT32 IdeChannel;
+ UINT32 IdeDevice;
+ UINT32 Size;
+ UINT8 *InquiryData;
+ UINT32 InquiryDataSize;
+ HDD_INFO *LocalHddInfo;
+ UINT32 PciIndex;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode;
+ PCI_DEVICE_PATH *PciDevicePath;
+
+ //
+ // Only build data once
+ // We have a problem with GetBbsInfo in that it can be invoked two
+ // places. Once in BDS, when all EFI drivers are connected and once in
+ // LegacyBoot after all EFI drivers are disconnected causing this routine
+ // to hang. In LegacyBoot this function is also called before EFI drivers
+ // are disconnected.
+ // Cases covered
+ // GetBbsInfo invoked in BDS. Both invocations in LegacyBoot ignored.
+ // GetBbsInfo not invoked in BDS. First invocation of this function
+ // proceeds normally and second via GetBbsInfo ignored.
+ //
+ PciDevicePath = NULL;
+ LocalHddInfo = *HddInfo;
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIdeHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ (VOID *) &LocalHddInfo
+ );
+ if (!EFI_ERROR (Status)) {
+ IdeController = HandleBuffer[0];
+ //
+ // Force IDE drive spin up!
+ //
+ if (Flag != 0) {
+ gBS->DisconnectController (
+ IdeController,
+ NULL,
+ NULL
+ );
+ }
+
+ gBS->ConnectController (IdeController, NULL, NULL, FALSE);
+
+ //
+ // Do GetIdeHandle twice since disconnect/reconnect will switch to native mode
+ // And GetIdeHandle will switch to Legacy mode, if required.
+ //
+ Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIdeHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ (VOID *) &LocalHddInfo
+ );
+ }
+
+ mIdeDataBuiltFlag = TRUE;
+
+ //
+ // Get Identity command from all drives
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiDiskInfoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ Private->IdeDriveCount = (UINT8) HandleCount;
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiDiskInfoProtocolGuid,
+ (VOID **) &DiskInfo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) {
+ //
+ // Locate which PCI device
+ //
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ (VOID *) &DevicePath
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DevicePathNode = DevicePath;
+ while (!IsDevicePathEnd (DevicePathNode)) {
+ TempDevicePathNode = NextDevicePathNode (DevicePathNode);
+ if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
+ ( DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&
+ ( DevicePathType(TempDevicePathNode) == MESSAGING_DEVICE_PATH) &&
+ ( DevicePathSubType(TempDevicePathNode) == MSG_ATAPI_DP) ) {
+ PciDevicePath = (PCI_DEVICE_PATH *) DevicePathNode;
+ break;
+ }
+ DevicePathNode = NextDevicePathNode (DevicePathNode);
+ }
+
+ if (PciDevicePath == NULL) {
+ continue;
+ }
+
+ //
+ // Find start of PCI device in HddInfo. The assumption of the data
+ // structure is 2 controllers(channels) per PCI device and each
+ // controller can have 2 drives(devices).
+ // HddInfo[PciIndex+0].[0] = Channel[0].Device[0] Primary Master
+ // HddInfo[PciIndex+0].[1] = Channel[0].Device[1] Primary Slave
+ // HddInfo[PciIndex+1].[0] = Channel[1].Device[0] Secondary Master
+ // HddInfo[PciIndex+1].[1] = Channel[1].Device[1] Secondary Slave
+ // @bug eventually need to pass in max number of entries
+ // for end of for loop
+ //
+ for (PciIndex = 0; PciIndex < 8; PciIndex++) {
+ if ((PciDevicePath->Device == LocalHddInfo[PciIndex].Device) &&
+ (PciDevicePath->Function == LocalHddInfo[PciIndex].Function)
+ ) {
+ break;
+ }
+ }
+
+ if (PciIndex == 8) {
+ continue;
+ }
+
+ Status = DiskInfo->WhichIde (DiskInfo, &IdeChannel, &IdeDevice);
+ if (!EFI_ERROR (Status)) {
+ Size = sizeof (ATAPI_IDENTIFY);
+ DiskInfo->Identify (
+ DiskInfo,
+ &LocalHddInfo[PciIndex + IdeChannel].IdentifyDrive[IdeDevice],
+ &Size
+ );
+ if (IdeChannel == 0) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_PRIMARY;
+ } else if (IdeChannel == 1) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SECONDARY;
+ }
+
+ InquiryData = NULL;
+ InquiryDataSize = 0;
+ Status = DiskInfo->Inquiry (
+ DiskInfo,
+ NULL,
+ &InquiryDataSize
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ InquiryData = (UINT8 *) AllocatePool (
+ InquiryDataSize
+ );
+ if (InquiryData != NULL) {
+ Status = DiskInfo->Inquiry (
+ DiskInfo,
+ InquiryData,
+ &InquiryDataSize
+ );
+ }
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ //
+ // If ATAPI device then Inquiry will pass and ATA fail.
+ //
+ if (!EFI_ERROR (Status)) {
+ ASSERT (InquiryData != NULL);
+ //
+ // If IdeDevice = 0 then set master bit, else slave bit
+ //
+ if (IdeDevice == 0) {
+ if ((InquiryData[0] & 0x1f) == 0x05) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_CDROM;
+ } else if ((InquiryData[0] & 0x1f) == 0x00) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_ZIPDISK;
+ }
+ } else {
+ if ((InquiryData[0] & 0x1f) == 0x05) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_CDROM;
+ } else if ((InquiryData[0] & 0x1f) == 0x00) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_ZIPDISK;
+ }
+ }
+ FreePool (InquiryData);
+ } else {
+ if (IdeDevice == 0) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_IDE;
+ } else {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_IDE;
+ }
+ }
+ }
+ }
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ If the IDE channel is in compatibility (legacy) mode, remove all
+ PCI I/O BAR addresses from the controller.
+
+ @param IdeController The handle of target IDE controller
+
+
+**/
+VOID
+InitLegacyIdeController (
+ IN EFI_HANDLE IdeController
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Pi;
+ UINT32 IOBarClear;
+ EFI_STATUS Status;
+
+ //
+ // If the IDE channel is in compatibility (legacy) mode, remove all
+ // PCI I/O BAR addresses from the controller. Some software gets
+ // confused if an IDE controller is in compatibility (legacy) mode
+ // and has PCI I/O resources allocated
+ //
+ Status = gBS->HandleProtocol (
+ IdeController,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (!EFI_ERROR (Status)) {
+ IOBarClear = 0x00;
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 1, &Pi);
+ if ((Pi & 0x01) == 0) {
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x10, 1, &IOBarClear);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x14, 1, &IOBarClear);
+ }
+ if ((Pi & 0x04) == 0) {
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x18, 1, &IOBarClear);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1C, 1, &IOBarClear);
+ }
+ }
+
+ return ;
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyPci.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyPci.c new file mode 100644 index 0000000..a53b57a --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyPci.c @@ -0,0 +1,2901 @@ +/** @file
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+
+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.
+
+**/
+
+#include "LegacyBiosInterface.h"
+#include <IndustryStandard/Pci30.h>
+
+#define PCI_START_ADDRESS(x) (((x) + 0x7ff) & ~0x7ff)
+
+#define MAX_BRIDGE_INDEX 0x20
+typedef struct {
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+ UINT8 PrimaryBus;
+ UINT8 SecondaryBus;
+ UINT8 SubordinateBus;
+} BRIDGE_TABLE;
+
+#define ROM_MAX_ENTRIES 24
+BRIDGE_TABLE Bridges[MAX_BRIDGE_INDEX];
+UINTN SortedBridgeIndex[MAX_BRIDGE_INDEX];
+UINTN NumberOfBridges;
+LEGACY_PNP_EXPANSION_HEADER *mBasePnpPtr;
+UINT16 mBbsRomSegment;
+UINTN mHandleCount;
+EFI_HANDLE mVgaHandle;
+BOOLEAN mIgnoreBbsUpdateFlag;
+BOOLEAN mVgaInstallationInProgress = FALSE;
+UINT32 mRomCount = 0x00;
+ROM_INSTANCE_ENTRY mRomEntry[ROM_MAX_ENTRIES];
+
+
+/**
+ Query shadowed legacy ROM parameters registered by RomShadow() previously.
+
+ @param PciHandle PCI device whos ROM has been shadowed
+ @param DiskStart DiskStart value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
+ @param DiskEnd DiskEnd value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
+ @param RomShadowAddress Address where ROM was shadowed
+ @param ShadowedSize Runtime size of ROM
+
+ @retval EFI_SUCCESS Query Logging successful.
+ @retval EFI_NOT_FOUND No logged data found about PciHandle.
+
+**/
+EFI_STATUS
+GetShadowedRomParameters (
+ IN EFI_HANDLE PciHandle,
+ OUT UINT8 *DiskStart, OPTIONAL
+ OUT UINT8 *DiskEnd, OPTIONAL
+ OUT VOID **RomShadowAddress, OPTIONAL
+ OUT UINTN *ShadowedSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN Index;
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+
+ //
+ // Get the PCI I/O Protocol on PciHandle
+ //
+ Status = gBS->HandleProtocol (
+ PciHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the location of the PCI device
+ //
+ PciIo->GetLocation (
+ PciIo,
+ &PciSegment,
+ &PciBus,
+ &PciDevice,
+ &PciFunction
+ );
+
+ for(Index = 0; Index < mRomCount; Index++) {
+ if ((mRomEntry[Index].PciSegment == PciSegment) &&
+ (mRomEntry[Index].PciBus == PciBus) &&
+ (mRomEntry[Index].PciDevice == PciDevice) &&
+ (mRomEntry[Index].PciFunction == PciFunction)) {
+ break;
+ }
+ }
+
+ if (Index == mRomCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (DiskStart != NULL) {
+ *DiskStart = mRomEntry[Index].DiskStart;
+ }
+
+ if (DiskEnd != NULL) {
+ *DiskEnd = mRomEntry[Index].DiskEnd;
+ }
+
+ if (RomShadowAddress != NULL) {
+ *RomShadowAddress = (VOID *)(UINTN)mRomEntry[Index].ShadowAddress;
+ }
+
+ if (ShadowedSize != NULL) {
+ *ShadowedSize = mRomEntry[Index].ShadowedSize;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Every legacy ROM that is shadowed by the Legacy BIOS driver will be
+ registered into this API so that the policy code can know what has
+ happend
+
+ @param PciHandle PCI device whos ROM is being shadowed
+ @param ShadowAddress Address that ROM was shadowed
+ @param ShadowedSize Runtime size of ROM
+ @param DiskStart DiskStart value from
+ EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
+ @param DiskEnd DiskEnd value from
+ EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
+
+ @retval EFI_SUCCESS Logging successful.
+ @retval EFI_OUT_OF_RESOURCES No remaining room for registering another option
+ ROM.
+
+**/
+EFI_STATUS
+RomShadow (
+ IN EFI_HANDLE PciHandle,
+ IN UINT32 ShadowAddress,
+ IN UINT32 ShadowedSize,
+ IN UINT8 DiskStart,
+ IN UINT8 DiskEnd
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ //
+ // See if there is room to register another option ROM
+ //
+ if (mRomCount >= ROM_MAX_ENTRIES) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Get the PCI I/O Protocol on PciHandle
+ //
+ Status = gBS->HandleProtocol (
+ PciHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the location of the PCI device
+ //
+ PciIo->GetLocation (
+ PciIo,
+ &mRomEntry[mRomCount].PciSegment,
+ &mRomEntry[mRomCount].PciBus,
+ &mRomEntry[mRomCount].PciDevice,
+ &mRomEntry[mRomCount].PciFunction
+ );
+ mRomEntry[mRomCount].ShadowAddress = ShadowAddress;
+ mRomEntry[mRomCount].ShadowedSize = ShadowedSize;
+ mRomEntry[mRomCount].DiskStart = DiskStart;
+ mRomEntry[mRomCount].DiskEnd = DiskEnd;
+
+ mRomCount++;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return EFI_SUCCESS if PciHandle has had a legacy BIOS ROM shadowed. This
+ information represents every call to RomShadow ()
+
+ @param PciHandle PCI device to get status for
+
+ @retval EFI_SUCCESS Legacy ROM loaded for this device
+ @retval EFI_NOT_FOUND No Legacy ROM loaded for this device
+
+**/
+EFI_STATUS
+IsLegacyRom (
+ IN EFI_HANDLE PciHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN Index;
+ UINTN Segment;
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+
+ //
+ // Get the PCI I/O Protocol on PciHandle
+ //
+ Status = gBS->HandleProtocol (
+ PciHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the location of the PCI device
+ //
+ PciIo->GetLocation (
+ PciIo,
+ &Segment,
+ &Bus,
+ &Device,
+ &Function
+ );
+
+ //
+ // See if the option ROM from PciHandle has been previously posted
+ //
+ for (Index = 0; Index < mRomCount; Index++) {
+ if (mRomEntry[Index].PciSegment == Segment &&
+ mRomEntry[Index].PciBus == Bus &&
+ mRomEntry[Index].PciDevice == Device &&
+ mRomEntry[Index].PciFunction == Function
+ ) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Find the PC-AT ROM Image in the raw PCI Option ROM. Also return the
+ related information from the header.
+
+ @param Csm16Revision The PCI interface version of underlying CSM16
+ @param VendorId Vendor ID of the PCI device
+ @param DeviceId Device ID of the PCI device
+ @param Rom On input pointing to beginning of the raw PCI OpROM
+ On output pointing to the first legacy PCI OpROM
+ @param ImageSize On input is the size of Raw PCI Rom
+ On output is the size of the first legacy PCI ROM
+ @param MaxRuntimeImageLength The max runtime image length only valid if OpRomRevision >= 3
+ @param OpRomRevision Revision of the PCI Rom
+ @param ConfigUtilityCodeHeader Pointer to Configuration Utility Code Header
+
+ @retval EFI_SUCCESS Successfully find the legacy PCI ROM
+ @retval EFI_NOT_FOUND Failed to find the legacy PCI ROM
+
+**/
+EFI_STATUS
+GetPciLegacyRom (
+ IN UINT16 Csm16Revision,
+ IN UINT16 VendorId,
+ IN UINT16 DeviceId,
+ IN OUT VOID **Rom,
+ IN OUT UINTN *ImageSize,
+ OUT UINTN *MaxRuntimeImageLength, OPTIONAL
+ OUT UINT8 *OpRomRevision, OPTIONAL
+ OUT VOID **ConfigUtilityCodeHeader OPTIONAL
+ )
+{
+ BOOLEAN Match;
+ UINT16 *DeviceIdList;
+ EFI_PCI_ROM_HEADER RomHeader;
+ PCI_3_0_DATA_STRUCTURE *Pcir;
+ VOID *BackupImage;
+ VOID *BestImage;
+
+
+ if (*ImageSize < sizeof (EFI_PCI_ROM_HEADER)) {
+ return EFI_NOT_FOUND;
+ }
+
+ BestImage = NULL;
+ BackupImage = NULL;
+ RomHeader.Raw = *Rom;
+ while (RomHeader.Generic->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
+ if (*ImageSize <
+ RomHeader.Raw - (UINT8 *) *Rom + RomHeader.Generic->PcirOffset + sizeof (PCI_DATA_STRUCTURE)
+ ) {
+ return EFI_NOT_FOUND;
+ }
+
+ Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset);
+
+ if (Pcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
+ Match = FALSE;
+ if (Pcir->VendorId == VendorId) {
+ if (Pcir->DeviceId == DeviceId) {
+ Match = TRUE;
+ } else if ((Pcir->Revision >= 3) && (Pcir->DeviceListOffset != 0)) {
+ DeviceIdList = (UINT16 *)(((UINT8 *) Pcir) + Pcir->DeviceListOffset);
+ //
+ // Checking the device list
+ //
+ while (*DeviceIdList != 0) {
+ if (*DeviceIdList == DeviceId) {
+ Match = TRUE;
+ break;
+ }
+ DeviceIdList ++;
+ }
+ }
+ }
+
+ if (Match) {
+ if (Csm16Revision >= 0x0300) {
+ //
+ // Case 1: CSM16 3.0
+ //
+ if (Pcir->Revision >= 3) {
+ //
+ // case 1.1: meets OpRom 3.0
+ // Perfect!!!
+ //
+ BestImage = RomHeader.Raw;
+ break;
+ } else {
+ //
+ // case 1.2: meets OpRom 2.x
+ // Store it and try to find the OpRom 3.0
+ //
+ BackupImage = RomHeader.Raw;
+ }
+ } else {
+ //
+ // Case 2: CSM16 2.x
+ //
+ if (Pcir->Revision >= 3) {
+ //
+ // case 2.1: meets OpRom 3.0
+ // Store it and try to find the OpRom 2.x
+ //
+ BackupImage = RomHeader.Raw;
+ } else {
+ //
+ // case 2.2: meets OpRom 2.x
+ // Perfect!!!
+ //
+ BestImage = RomHeader.Raw;
+ break;
+ }
+ }
+ } else {
+ DEBUG ((EFI_D_ERROR, "GetPciLegacyRom - OpRom not match (%04x-%04x)\n", (UINTN)VendorId, (UINTN)DeviceId));
+ }
+ }
+
+ if ((Pcir->Indicator & 0x80) == 0x80) {
+ break;
+ } else {
+ RomHeader.Raw += 512 * Pcir->ImageLength;
+ }
+ }
+
+ if (BestImage == NULL) {
+ if (BackupImage == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // The versions of CSM16 and OpRom don't match exactly
+ //
+ BestImage = BackupImage;
+ }
+ RomHeader.Raw = BestImage;
+ Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset);
+ *Rom = BestImage;
+ *ImageSize = Pcir->ImageLength * 512;
+
+ if (MaxRuntimeImageLength != NULL) {
+ if (Pcir->Revision < 3) {
+ *MaxRuntimeImageLength = 0;
+ } else {
+ *MaxRuntimeImageLength = Pcir->MaxRuntimeImageLength * 512;
+ }
+ }
+
+ if (OpRomRevision != NULL) {
+ //
+ // Optional return PCI Data Structure revision
+ //
+ if (Pcir->Length >= 0x1C) {
+ *OpRomRevision = Pcir->Revision;
+ } else {
+ *OpRomRevision = 0;
+ }
+ }
+
+ if (ConfigUtilityCodeHeader != NULL) {
+ //
+ // Optional return ConfigUtilityCodeHeaderOffset supported by the PC-AT ROM
+ //
+ if ((Pcir->Revision < 3) || (Pcir->ConfigUtilityCodeHeaderOffset == 0)) {
+ *ConfigUtilityCodeHeader = NULL;
+ } else {
+ *ConfigUtilityCodeHeader = RomHeader.Raw + Pcir->ConfigUtilityCodeHeaderOffset;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Build a table of bridge info for PIRQ translation.
+
+ @param RoutingTable RoutingTable obtained from Platform.
+ @param RoutingTableEntries Number of RoutingTable entries.
+
+ @retval EFI_SUCCESS New Subordinate bus.
+ @retval EFI_NOT_FOUND No more Subordinate busses.
+
+**/
+EFI_STATUS
+CreateBridgeTable (
+ IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable,
+ IN UINTN RoutingTableEntries
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN BridgeIndex;
+ UINTN Index;
+ UINTN Index1;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE01 PciConfigHeader;
+ BRIDGE_TABLE SlotBridges[MAX_BRIDGE_INDEX];
+ UINTN SlotBridgeIndex;
+
+ BridgeIndex = 0x00;
+ SlotBridgeIndex = 0x00;
+
+ //
+ // Assumption is table is built from low bus to high bus numbers.
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+
+ if (IS_PCI_P2P (&PciConfigHeader) && (BridgeIndex < MAX_BRIDGE_INDEX)) {
+ PciIo->GetLocation (
+ PciIo,
+ &Bridges[BridgeIndex].PciSegment,
+ &Bridges[BridgeIndex].PciBus,
+ &Bridges[BridgeIndex].PciDevice,
+ &Bridges[BridgeIndex].PciFunction
+ );
+
+ Bridges[BridgeIndex].PrimaryBus = PciConfigHeader.Bridge.PrimaryBus;
+
+ Bridges[BridgeIndex].SecondaryBus = PciConfigHeader.Bridge.SecondaryBus;
+
+ Bridges[BridgeIndex].SubordinateBus = PciConfigHeader.Bridge.SubordinateBus;
+
+ for (Index1 = 0; Index1 < RoutingTableEntries; Index1++){
+ //
+ // Test whether we have found the Bridge in the slot, must be the one that directly interfaced to the board
+ // Once we find one, store it in the SlotBridges[]
+ //
+ if ((RoutingTable[Index1].Slot != 0) && (Bridges[BridgeIndex].PrimaryBus == RoutingTable[Index1].Bus)
+ && ((Bridges[BridgeIndex].PciDevice << 3) == RoutingTable[Index1].Device)) {
+ CopyMem (&SlotBridges[SlotBridgeIndex], &Bridges[BridgeIndex], sizeof (BRIDGE_TABLE));
+ SlotBridgeIndex++;
+
+ break;
+ }
+ }
+
+ ++BridgeIndex;
+ }
+ }
+
+ //
+ // Pack up Bridges by removing those useless ones
+ //
+ for (Index = 0; Index < BridgeIndex;){
+ for (Index1 = 0; Index1 < SlotBridgeIndex; Index1++) {
+ if (((Bridges[Index].PciBus == SlotBridges[Index1].PrimaryBus) && (Bridges[Index].PciDevice == SlotBridges[Index1].PciDevice)) ||
+ ((Bridges[Index].PciBus >= SlotBridges[Index1].SecondaryBus) && (Bridges[Index].PciBus <= SlotBridges[Index1].SubordinateBus))) {
+ //
+ // We have found one that meets our criteria
+ //
+ Index++;
+ break;
+ }
+ }
+
+ //
+ // This one doesn't meet criteria, pack it
+ //
+ if (Index1 >= SlotBridgeIndex) {
+ for (Index1 = Index; BridgeIndex > 1 && Index1 < BridgeIndex - 1 ; Index1++) {
+ CopyMem (&Bridges[Index1], &Bridges[Index1 + 1], sizeof (BRIDGE_TABLE));
+ }
+
+ BridgeIndex--;
+ }
+ }
+
+ NumberOfBridges = BridgeIndex;
+
+ //
+ // Sort bridges low to high by Secondary bus followed by subordinate bus
+ //
+ if (NumberOfBridges > 1) {
+ Index = 0;
+ do {
+ SortedBridgeIndex[Index] = Index;
+ ++Index;
+ } while (Index < NumberOfBridges);
+
+ for (Index = 0; Index < NumberOfBridges - 1; Index++) {
+ for (Index1 = Index + 1; Index1 < NumberOfBridges; Index1++) {
+ if (Bridges[Index].SecondaryBus > Bridges[Index1].SecondaryBus) {
+ SortedBridgeIndex[Index] = Index1;
+ SortedBridgeIndex[Index1] = Index;
+ }
+
+ if ((Bridges[Index].SecondaryBus == Bridges[Index1].SecondaryBus) &&
+ (Bridges[Index].SubordinateBus > Bridges[Index1].SubordinateBus)
+ ) {
+ SortedBridgeIndex[Index] = Index1;
+ SortedBridgeIndex[Index1] = Index;
+ }
+ }
+ }
+ }
+ FreePool (HandleBuffer);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Find base Bridge for device.
+
+ @param Private Legacy BIOS Instance data
+ @param PciBus Input = Bus of device.
+ @param PciDevice Input = Device.
+ @param RoutingTable The platform specific routing table
+ @param RoutingTableEntries Number of entries in table
+
+ @retval EFI_SUCCESS At base bus.
+ @retval EFI_NOT_FOUND Behind a bridge.
+
+**/
+EFI_STATUS
+GetBaseBus (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN UINTN PciBus,
+ IN UINTN PciDevice,
+ IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable,
+ IN UINTN RoutingTableEntries
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < RoutingTableEntries; Index++) {
+ if ((RoutingTable[Index].Bus == PciBus) && (RoutingTable[Index].Device == (PciDevice << 3))) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Translate PIRQ through busses
+
+ @param Private Legacy BIOS Instance data
+ @param PciBus Input = Bus of device. Output = Translated Bus
+ @param PciDevice Input = Device. Output = Translated Device
+ @param PciFunction Input = Function. Output = Translated Function
+ @param PirqIndex Input = Original PIRQ index. If single function
+ device then 0, otherwise 0-3.
+ Output = Translated Index
+
+ @retval EFI_SUCCESS Pirq successfully translated.
+ @retval EFI_NOT_FOUND The device is not behind any known bridge.
+
+**/
+EFI_STATUS
+TranslateBusPirq (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN OUT UINTN *PciBus,
+ IN OUT UINTN *PciDevice,
+ IN OUT UINTN *PciFunction,
+ IN OUT UINT8 *PirqIndex
+ )
+{
+ /*
+ This routine traverses the PCI busses from base slot
+ and translates the PIRQ register to the appropriate one.
+
+ Example:
+
+ Bus 0, Device 1 is PCI-PCI bridge that all PCI slots reside on.
+ Primary bus# = 0
+ Secondary bus # = 1
+ Subordinate bus # is highest bus # behind this bus
+ Bus 1, Device 0 is Slot 0 and is not a bridge.
+ Bus 1, Device 1 is Slot 1 and is a bridge.
+ Slot PIRQ routing is A,B,C,D.
+ Primary bus # = 1
+ Secondary bus # = 2
+ Subordinate bus # = 5
+ Bus 2, Device 6 is a bridge. It has no bridges behind it.
+ Primary bus # = 2
+ Secondary bus # = 3
+ Subordinate bus # = 3
+ Bridge PIRQ routing is C,D,A,B
+ Bus 2, Device 7 is a bridge. It has 1 bridge behind it.
+ Primary bus # = 2
+ Secondary bus = 4 Device 6 takes bus 2.
+ Subordinate bus = 5.
+ Bridge PIRQ routing is D,A,B,C
+ Bus 4, Device 2 is a bridge. It has no bridges behind it.
+ Primary bus # = 4
+ Secondary bus # = 5
+ Subordinate bus = 5
+ Bridge PIRQ routing is B,C,D,A
+ Bus 5, Device 1 is to be programmed.
+ Device PIRQ routing is C,D,A,B
+
+
+Search busses starting from slot bus for final bus >= Secondary bus and
+final bus <= Suborninate bus. Assumption is bus entries increase in bus
+number.
+Starting PIRQ is A,B,C,D.
+Bus 2, Device 7 satisfies search criteria. Rotate (A,B,C,D) left by device
+ 7 modulo 4 giving (D,A,B,C).
+Bus 4, Device 2 satisfies search criteria. Rotate (D,A,B,C) left by 2 giving
+ (B,C,D,A).
+No other busses match criteria. Device to be programmed is Bus 5, Device 1.
+Rotate (B,C,D,A) by 1 giving C,D,A,B. Translated PIRQ is C.
+
+*/
+ UINTN LocalBus;
+ UINTN LocalDevice;
+ UINTN BaseBus;
+ UINTN BaseDevice;
+ UINTN BaseFunction;
+ UINT8 LocalPirqIndex;
+ BOOLEAN BaseIndexFlag;
+ UINTN BridgeIndex;
+ UINTN SBridgeIndex;
+ BaseIndexFlag = FALSE;
+ BridgeIndex = 0x00;
+
+ LocalPirqIndex = *PirqIndex;
+ LocalBus = *PciBus;
+ LocalDevice = *PciDevice;
+ BaseBus = *PciBus;
+ BaseDevice = *PciDevice;
+ BaseFunction = *PciFunction;
+
+ //
+ // LocalPirqIndex list PIRQs in rotated fashion
+ // = 0 A,B,C,D
+ // = 1 B,C,D,A
+ // = 2 C,D,A,B
+ // = 3 D,A,B,C
+ //
+
+ for (BridgeIndex = 0; BridgeIndex < NumberOfBridges; BridgeIndex++) {
+ SBridgeIndex = SortedBridgeIndex[BridgeIndex];
+ //
+ // Check if device behind this bridge
+ //
+ if ((LocalBus >= Bridges[SBridgeIndex].SecondaryBus) && (LocalBus <= Bridges[SBridgeIndex].SubordinateBus)) {
+ //
+ // If BaseIndexFlag = FALSE then have found base bridge, i.e
+ // bridge in slot. Save info for use by IRQ routing table.
+ //
+ if (!BaseIndexFlag) {
+ BaseBus = Bridges[SBridgeIndex].PciBus;
+ BaseDevice = Bridges[SBridgeIndex].PciDevice;
+ BaseFunction = Bridges[SBridgeIndex].PciFunction;
+ BaseIndexFlag = TRUE;
+ } else {
+ LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8)Bridges[SBridgeIndex].PciDevice)%4);
+ }
+
+ //
+ // Check if at device. If not get new PCI location & PIRQ
+ //
+ if (Bridges[SBridgeIndex].SecondaryBus == (UINT8) LocalBus) {
+ //
+ // Translate PIRQ
+ //
+ LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8) (LocalDevice)) % 4);
+ break;
+ }
+ }
+ }
+
+ //
+ // In case we fail to find the Bridge just above us, this is some potential error and we want to warn the user
+ //
+ if(BridgeIndex >= NumberOfBridges){
+ DEBUG ((EFI_D_ERROR, "Cannot Find IRQ Routing for Bus %d, Device %d, Function %d\n", *PciBus, *PciDevice, *PciFunction));
+ }
+
+ *PirqIndex = LocalPirqIndex;
+ *PciBus = BaseBus;
+ *PciDevice = BaseDevice;
+ *PciFunction = BaseFunction;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Copy the $PIR table as required.
+
+ @param Private Legacy BIOS Instance data
+ @param RoutingTable Pointer to IRQ routing table
+ @param RoutingTableEntries IRQ routing table entries
+ @param PirqTable Pointer to $PIR table
+ @param PirqTableSize Length of table
+
+**/
+VOID
+CopyPirqTable (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable,
+ IN UINTN RoutingTableEntries,
+ IN EFI_LEGACY_PIRQ_TABLE_HEADER *PirqTable,
+ IN UINTN PirqTableSize
+ )
+{
+ EFI_IA32_REGISTER_SET Regs;
+ UINT32 Granularity;
+
+ //
+ // Copy $PIR table, if it exists.
+ //
+ if (PirqTable != NULL) {
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+
+ Private->InternalIrqRoutingTable = RoutingTable;
+ Private->NumberIrqRoutingEntries = (UINT16) (RoutingTableEntries);
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ Regs.X.AX = Legacy16GetTableAddress;
+ Regs.X.CX = (UINT16) PirqTableSize;
+ //
+ // Allocate at F segment according to PCI IRQ Routing Table Specification
+ //
+ Regs.X.BX = (UINT16) 0x1;
+ //
+ // 16-byte boundary alignment requirement according to
+ // PCI IRQ Routing Table Specification
+ //
+ Regs.X.DX = 0x10;
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ Private->Legacy16Table->IrqRoutingTablePointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
+ if (Regs.X.AX != 0) {
+ DEBUG ((EFI_D_ERROR, "PIRQ table length insufficient - %x\n", PirqTableSize));
+ } else {
+ DEBUG ((EFI_D_INFO, "PIRQ table in legacy region - %x\n", Private->Legacy16Table->IrqRoutingTablePointer));
+ Private->Legacy16Table->IrqRoutingTableLength = (UINT32)PirqTableSize;
+ CopyMem (
+ (VOID *) (UINTN)Private->Legacy16Table->IrqRoutingTablePointer,
+ PirqTable,
+ PirqTableSize
+ );
+ }
+
+ Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
+ Private->LegacyRegion->Lock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+ }
+
+ Private->PciInterruptLine = TRUE;
+ mHandleCount = 0;
+}
+
+/**
+ Dump EFI_LEGACY_INSTALL_PCI_HANDLER structure information.
+
+ @param PciHandle The pointer to EFI_LEGACY_INSTALL_PCI_HANDLER structure
+
+**/
+VOID
+DumpPciHandle (
+ IN EFI_LEGACY_INSTALL_PCI_HANDLER *PciHandle
+ )
+{
+ DEBUG ((EFI_D_INFO, "PciBus - %02x\n", (UINTN)PciHandle->PciBus));
+ DEBUG ((EFI_D_INFO, "PciDeviceFun - %02x\n", (UINTN)PciHandle->PciDeviceFun));
+ DEBUG ((EFI_D_INFO, "PciSegment - %02x\n", (UINTN)PciHandle->PciSegment));
+ DEBUG ((EFI_D_INFO, "PciClass - %02x\n", (UINTN)PciHandle->PciClass));
+ DEBUG ((EFI_D_INFO, "PciSubclass - %02x\n", (UINTN)PciHandle->PciSubclass));
+ DEBUG ((EFI_D_INFO, "PciInterface - %02x\n", (UINTN)PciHandle->PciInterface));
+
+ DEBUG ((EFI_D_INFO, "PrimaryIrq - %02x\n", (UINTN)PciHandle->PrimaryIrq));
+ DEBUG ((EFI_D_INFO, "PrimaryReserved - %02x\n", (UINTN)PciHandle->PrimaryReserved));
+ DEBUG ((EFI_D_INFO, "PrimaryControl - %04x\n", (UINTN)PciHandle->PrimaryControl));
+ DEBUG ((EFI_D_INFO, "PrimaryBase - %04x\n", (UINTN)PciHandle->PrimaryBase));
+ DEBUG ((EFI_D_INFO, "PrimaryBusMaster - %04x\n", (UINTN)PciHandle->PrimaryBusMaster));
+
+ DEBUG ((EFI_D_INFO, "SecondaryIrq - %02x\n", (UINTN)PciHandle->SecondaryIrq));
+ DEBUG ((EFI_D_INFO, "SecondaryReserved - %02x\n", (UINTN)PciHandle->SecondaryReserved));
+ DEBUG ((EFI_D_INFO, "SecondaryControl - %04x\n", (UINTN)PciHandle->SecondaryControl));
+ DEBUG ((EFI_D_INFO, "SecondaryBase - %04x\n", (UINTN)PciHandle->SecondaryBase));
+ DEBUG ((EFI_D_INFO, "SecondaryBusMaster - %04x\n", (UINTN)PciHandle->SecondaryBusMaster));
+ return;
+}
+
+/**
+ Copy the $PIR table as required.
+
+ @param Private Legacy BIOS Instance data
+ @param PciIo Pointer to PCI_IO protocol
+ @param PciIrq Pci IRQ number
+ @param PciConfigHeader Type00 Pci configuration header
+
+**/
+VOID
+InstallLegacyIrqHandler (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 PciIrq,
+ IN PCI_TYPE00 *PciConfigHeader
+ )
+{
+ EFI_IA32_REGISTER_SET Regs;
+ UINT16 LegMask;
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+ EFI_LEGACY_8259_PROTOCOL *Legacy8259;
+ UINT16 PrimaryMaster;
+ UINT16 SecondaryMaster;
+ UINTN TempData;
+ UINTN RegisterAddress;
+ UINT32 Granularity;
+
+ PrimaryMaster = 0;
+ SecondaryMaster = 0;
+ Legacy8259 = Private->Legacy8259;
+ //
+ // Disable interrupt in PIC, in case shared, to prevent an
+ // interrupt from occuring.
+ //
+ Legacy8259->GetMask (
+ Legacy8259,
+ &LegMask,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ LegMask = (UINT16) (LegMask | (UINT16) (1 << PciIrq));
+
+ Legacy8259->SetMask (
+ Legacy8259,
+ &LegMask,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ PciIo->GetLocation (
+ PciIo,
+ &PciSegment,
+ &PciBus,
+ &PciDevice,
+ &PciFunction
+ );
+ Private->IntThunk->PciHandler.PciBus = (UINT8) PciBus;
+ Private->IntThunk->PciHandler.PciDeviceFun = (UINT8) ((PciDevice << 3) + PciFunction);
+ Private->IntThunk->PciHandler.PciSegment = (UINT8) PciSegment;
+ Private->IntThunk->PciHandler.PciClass = PciConfigHeader->Hdr.ClassCode[2];
+ Private->IntThunk->PciHandler.PciSubclass = PciConfigHeader->Hdr.ClassCode[1];
+ Private->IntThunk->PciHandler.PciInterface = PciConfigHeader->Hdr.ClassCode[0];
+
+ //
+ // Use native mode base address registers in two cases:
+ // 1. Programming Interface (PI) register indicates Primary Controller is
+ // in native mode OR
+ // 2. PCI device Sub Class Code is not IDE
+ //
+ Private->IntThunk->PciHandler.PrimaryBusMaster = (UINT16)(PciConfigHeader->Device.Bar[4] & 0xfffc);
+ if (((PciConfigHeader->Hdr.ClassCode[0] & 0x01) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {
+ Private->IntThunk->PciHandler.PrimaryIrq = PciIrq;
+ Private->IntThunk->PciHandler.PrimaryBase = (UINT16) (PciConfigHeader->Device.Bar[0] & 0xfffc);
+ Private->IntThunk->PciHandler.PrimaryControl = (UINT16) ((PciConfigHeader->Device.Bar[1] & 0xfffc) + 2);
+ } else {
+ Private->IntThunk->PciHandler.PrimaryIrq = 14;
+ Private->IntThunk->PciHandler.PrimaryBase = 0x1f0;
+ Private->IntThunk->PciHandler.PrimaryControl = 0x3f6;
+ }
+ //
+ // Secondary controller data
+ //
+ if (Private->IntThunk->PciHandler.PrimaryBusMaster != 0) {
+ Private->IntThunk->PciHandler.SecondaryBusMaster = (UINT16) ((PciConfigHeader->Device.Bar[4] & 0xfffc) + 8);
+ PrimaryMaster = (UINT16) (Private->IntThunk->PciHandler.PrimaryBusMaster + 2);
+ SecondaryMaster = (UINT16) (Private->IntThunk->PciHandler.SecondaryBusMaster + 2);
+
+ //
+ // Clear pending interrupts in Bus Master registers
+ //
+ IoWrite16 (PrimaryMaster, 0x04);
+ IoWrite16 (SecondaryMaster, 0x04);
+
+ }
+
+ //
+ // Use native mode base address registers in two cases:
+ // 1. Programming Interface (PI) register indicates Secondary Controller is
+ // in native mode OR
+ // 2. PCI device Sub Class Code is not IDE
+ //
+ if (((PciConfigHeader->Hdr.ClassCode[0] & 0x04) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {
+ Private->IntThunk->PciHandler.SecondaryIrq = PciIrq;
+ Private->IntThunk->PciHandler.SecondaryBase = (UINT16) (PciConfigHeader->Device.Bar[2] & 0xfffc);
+ Private->IntThunk->PciHandler.SecondaryControl = (UINT16) ((PciConfigHeader->Device.Bar[3] & 0xfffc) + 2);
+ } else {
+
+ Private->IntThunk->PciHandler.SecondaryIrq = 15;
+ Private->IntThunk->PciHandler.SecondaryBase = 0x170;
+ Private->IntThunk->PciHandler.SecondaryControl = 0x376;
+ }
+
+ //
+ // Clear pending interrupts in IDE Command Block Status reg before we
+ // Thunk to CSM16 below. Don't want a pending Interrupt before we
+ // install the handlers as wierd corruption would occur and hang system.
+ //
+ //
+ // Read IDE CMD blk status reg to clear out any pending interrupts.
+ // Do here for Primary and Secondary IDE channels
+ //
+ RegisterAddress = (UINT16)Private->IntThunk->PciHandler.PrimaryBase + 0x07;
+ IoRead8 (RegisterAddress);
+ RegisterAddress = (UINT16)Private->IntThunk->PciHandler.SecondaryBase + 0x07;
+ IoRead8 (RegisterAddress);
+
+ Private->IntThunk->PciHandler.PrimaryReserved = 0;
+ Private->IntThunk->PciHandler.SecondaryReserved = 0;
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+
+ Regs.X.AX = Legacy16InstallPciHandler;
+ TempData = (UINTN) &Private->IntThunk->PciHandler;
+ Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);
+ Regs.X.BX = EFI_OFFSET ((UINT32) TempData);
+
+ DumpPciHandle (&Private->IntThunk->PciHandler);
+
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
+ Private->LegacyRegion->Lock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+
+}
+
+
+/**
+ Program the interrupt routing register in all the PCI devices. On a PC AT system
+ this register contains the 8259 IRQ vector that matches it's PCI interrupt.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_ALREADY_STARTED All PCI devices have been processed.
+
+**/
+EFI_STATUS
+PciProgramAllInterruptLineRegisters (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_LEGACY_8259_PROTOCOL *Legacy8259;
+ EFI_LEGACY_INTERRUPT_PROTOCOL *LegacyInterrupt;
+ EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
+ UINT8 InterruptPin;
+ UINTN Index;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN MassStorageHandleCount;
+ EFI_HANDLE *MassStorageHandleBuffer;
+ UINTN MassStorageHandleIndex;
+ UINT8 PciIrq;
+ UINT16 Command;
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+ EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable;
+ UINTN RoutingTableEntries;
+ UINT16 LegMask;
+ UINT16 LegEdgeLevel;
+ PCI_TYPE00 PciConfigHeader;
+ EFI_LEGACY_PIRQ_TABLE_HEADER *PirqTable;
+ UINTN PirqTableSize;
+ UINTN Flags;
+ HDD_INFO *HddInfo;
+ UINT64 Supports;
+
+ //
+ // Note - This routine use to return immediately if Private->PciInterruptLine
+ // was true. Routine changed since resets etc can cause not all
+ // PciIo protocols to be registered the first time through.
+ // New algorithm is to do the copy $PIR table on first pass and save
+ // HandleCount on first pass. If subsequent passes LocateHandleBuffer gives
+ // a larger handle count then proceed with body of function else return
+ // EFI_ALREADY_STARTED. In addition check if PCI device InterruptLine != 0.
+ // If zero then function unprogrammed else skip function.
+ //
+ Legacy8259 = Private->Legacy8259;
+ LegacyInterrupt = Private->LegacyInterrupt;
+ LegacyBiosPlatform = Private->LegacyBiosPlatform;
+
+ LegacyBiosPlatform->GetRoutingTable (
+ Private->LegacyBiosPlatform,
+ (VOID *) &RoutingTable,
+ &RoutingTableEntries,
+ (VOID *) &PirqTable,
+ &PirqTableSize,
+ NULL,
+ NULL
+ );
+ CreateBridgeTable (RoutingTable, RoutingTableEntries);
+
+ if (!Private->PciInterruptLine) {
+ CopyPirqTable (
+ Private,
+ RoutingTable,
+ RoutingTableEntries,
+ PirqTable,
+ PirqTableSize
+ );
+ }
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ if (HandleCount == mHandleCount) {
+ FreePool (HandleBuffer);
+ return EFI_ALREADY_STARTED;
+ }
+
+ if (mHandleCount == 0x00) {
+ mHandleCount = HandleCount;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ //
+ // If VGA then only do VGA to allow drives fore time to spin up
+ // otherwise assign PCI IRQs to all potential devices.
+ //
+ if ((mVgaInstallationInProgress) && (HandleBuffer[Index] != mVgaHandle)) {
+ continue;
+ } else {
+ //
+ // Force code to go through all handles next time called if video.
+ // This will catch case where HandleCount doesn't change but want
+ // to get drive info etc.
+ //
+ mHandleCount = 0x00;
+ }
+
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Test whether the device can be enabled or not.
+ // If it can't be enabled, then just skip it to avoid further operation.
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+ Command = PciConfigHeader.Hdr.Command;
+
+ //
+ // Note PciIo->Attributes does not program the PCI command register
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+ }
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x04, 1, &Command);
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ InterruptPin = PciConfigHeader.Device.InterruptPin;
+
+ if ((InterruptPin != 0) && (PciConfigHeader.Device.InterruptLine == PCI_INT_LINE_UNKNOWN)) {
+ PciIo->GetLocation (
+ PciIo,
+ &PciSegment,
+ &PciBus,
+ &PciDevice,
+ &PciFunction
+ );
+ //
+ // Translate PIRQ index back thru busses to slot bus with InterruptPin
+ // zero based
+ //
+ InterruptPin -= 1;
+
+ Status = GetBaseBus (
+ Private,
+ PciBus,
+ PciDevice,
+ RoutingTable,
+ RoutingTableEntries
+ );
+
+ if (Status == EFI_NOT_FOUND) {
+ TranslateBusPirq (
+ Private,
+ &PciBus,
+ &PciDevice,
+ &PciFunction,
+ &InterruptPin
+ );
+ }
+ //
+ // Translate InterruptPin(0-3) into PIRQ
+ //
+ Status = LegacyBiosPlatform->TranslatePirq (
+ LegacyBiosPlatform,
+ PciBus,
+ (PciDevice << 3),
+ PciFunction,
+ &InterruptPin,
+ &PciIrq
+ );
+ //
+ // TranslatePirq() should never fail or we are in trouble
+ // If it does return failure status, check your PIRQ routing table to see if some item is missing or incorrect
+ //
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Translate Pirq Failed - Status = %r\n ", Status));
+ continue;
+ }
+
+ LegacyInterrupt->WritePirq (
+ LegacyInterrupt,
+ InterruptPin,
+ PciIrq
+ );
+
+ //
+ // Check if device has an OPROM associated with it.
+ // If not invoke special 16-bit function, to allow 16-bit
+ // code to install an interrupt handler.
+ //
+ Status = LegacyBiosCheckPciRom (
+ &Private->LegacyBios,
+ HandleBuffer[Index],
+ NULL,
+ NULL,
+ &Flags
+ );
+ if ((EFI_ERROR (Status)) && (PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE)) {
+ //
+ // Device has no OPROM associated with it and is a mass storage
+ // device. It needs to have an PCI IRQ handler installed. To
+ // correctly install the handler we need to insure device is
+ // connected. The device may just have register itself but not
+ // been connected. Re-read PCI config space after as it can
+ // change
+ //
+ //
+ // Get IDE Handle. If matches handle then skip ConnectController
+ // since ConnectController may force native mode and we don't
+ // want that for primary IDE controller
+ //
+ MassStorageHandleCount = 0;
+ MassStorageHandleBuffer = NULL;
+ LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIdeHandle,
+ 0,
+ &MassStorageHandleBuffer,
+ &MassStorageHandleCount,
+ NULL
+ );
+
+ HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];
+
+ LegacyBiosBuildIdeData (Private, &HddInfo, 0);
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+
+ for (MassStorageHandleIndex = 0; MassStorageHandleIndex < MassStorageHandleCount; MassStorageHandleIndex++) {
+ if (MassStorageHandleBuffer[MassStorageHandleIndex] == HandleBuffer[Index]) {
+ //
+ // InstallLegacyIrqHandler according to Platform requirement
+ //
+ InstallLegacyIrqHandler (
+ Private,
+ PciIo,
+ PciIrq,
+ &PciConfigHeader
+ );
+ break;
+ }
+ }
+ }
+ //
+ // Write InterruptPin and enable 8259.
+ //
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0x3c,
+ 1,
+ &PciIrq
+ );
+ Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask = (UINT16) (Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask | (UINT16) (1 << PciIrq));
+
+ Legacy8259->GetMask (
+ Legacy8259,
+ &LegMask,
+ &LegEdgeLevel,
+ NULL,
+ NULL
+ );
+
+ LegMask = (UINT16) (LegMask & (UINT16)~(1 << PciIrq));
+ LegEdgeLevel = (UINT16) (LegEdgeLevel | (UINT16) (1 << PciIrq));
+ Legacy8259->SetMask (
+ Legacy8259,
+ &LegMask,
+ &LegEdgeLevel,
+ NULL,
+ NULL
+ );
+ }
+ }
+ FreePool (HandleBuffer);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Find & verify PnP Expansion header in ROM image
+
+ @param Private Protocol instance pointer.
+ @param FirstHeader 1 = Find first header, 0 = Find successive headers
+ @param PnpPtr Input Rom start if FirstHeader =1, Current Header
+ otherwise Output Next header, if it exists
+
+ @retval EFI_SUCCESS Next Header found at BasePnpPtr
+ @retval EFI_NOT_FOUND No more headers
+
+**/
+EFI_STATUS
+FindNextPnpExpansionHeader (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN BOOLEAN FirstHeader,
+ IN OUT LEGACY_PNP_EXPANSION_HEADER **PnpPtr
+
+ )
+{
+ UINTN TempData;
+ LEGACY_PNP_EXPANSION_HEADER *LocalPnpPtr;
+ LocalPnpPtr = *PnpPtr;
+ if (FirstHeader == FIRST_INSTANCE) {
+ mBasePnpPtr = LocalPnpPtr;
+ mBbsRomSegment = (UINT16) ((UINTN) mBasePnpPtr >> 4);
+ //
+ // Offset 0x1a gives offset to PnP expansion header for the first
+ // instance, there after the structure gives the offset to the next
+ // structure
+ //
+ LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) ((UINT8 *) LocalPnpPtr + 0x1a);
+ TempData = (*((UINT16 *) LocalPnpPtr));
+ } else {
+ TempData = (UINT16) LocalPnpPtr->NextHeader;
+ }
+
+ LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) (((UINT8 *) mBasePnpPtr + TempData));
+
+ //
+ // Search for PnP table in Shadowed ROM
+ //
+ *PnpPtr = LocalPnpPtr;
+ if (*(UINT32 *) LocalPnpPtr == SIGNATURE_32 ('$', 'P', 'n', 'P')) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
+
+
+/**
+ Update list of Bev or BCV table entries.
+
+ @param Private Protocol instance pointer.
+ @param RomStart Table of ROM start address in RAM/ROM. PciIo _
+ Handle to PCI IO for this device
+ @param PciIo Instance of PCI I/O Protocol
+
+ @retval EFI_SUCCESS Always should succeed.
+
+**/
+EFI_STATUS
+UpdateBevBcvTable (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN EFI_LEGACY_EXPANSION_ROM_HEADER *RomStart,
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ VOID *RomEnd;
+ BBS_TABLE *BbsTable;
+ UINTN BbsIndex;
+ EFI_LEGACY_EXPANSION_ROM_HEADER *PciPtr;
+ LEGACY_PNP_EXPANSION_HEADER *PnpPtr;
+ BOOLEAN Instance;
+ EFI_STATUS Status;
+ UINTN Segment;
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+ UINT8 Class;
+ UINT16 DeviceType;
+ Segment = 0;
+ Bus = 0;
+ Device = 0;
+ Function = 0;
+ Class = 0;
+ DeviceType = BBS_UNKNOWN;
+
+ //
+ // Skip floppy and 2*onboard IDE controller entries(Master/Slave per
+ // controller).
+ //
+ BbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
+
+ BbsTable = (BBS_TABLE*)(UINTN) Private->IntThunk->EfiToLegacy16BootTable.BbsTable;
+ PnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) RomStart;
+ PciPtr = (EFI_LEGACY_EXPANSION_ROM_HEADER *) RomStart;
+
+ RomEnd = (VOID *) (PciPtr->Size512 * 512 + (UINTN) PciPtr);
+ Instance = FIRST_INSTANCE;
+ //
+ // OPROMs like PXE may not be tied to a piece of hardware and thus
+ // don't have a PciIo associated with them
+ //
+ if (PciIo != NULL) {
+ PciIo->GetLocation (
+ PciIo,
+ &Segment,
+ &Bus,
+ &Device,
+ &Function
+ );
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0x0b,
+ 1,
+ &Class
+ );
+
+ if (Class == PCI_CLASS_MASS_STORAGE) {
+ DeviceType = BBS_HARDDISK;
+ } else {
+ if (Class == PCI_CLASS_NETWORK) {
+ DeviceType = BBS_EMBED_NETWORK;
+ }
+ }
+ }
+
+ if (PciPtr >= (EFI_LEGACY_EXPANSION_ROM_HEADER *) ((UINTN) 0xc8000)) {
+ while (TRUE) {
+ Status = FindNextPnpExpansionHeader (Private, Instance, &PnpPtr);
+ Instance = NOT_FIRST_INSTANCE;
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ //
+ // There can be additional $PnP headers within the OPROM.
+ // Example: SCSI can have one per drive.
+ //
+ BbsTable[BbsIndex].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ BbsTable[BbsIndex].DeviceType = DeviceType;
+ BbsTable[BbsIndex].Bus = (UINT32) Bus;
+ BbsTable[BbsIndex].Device = (UINT32) Device;
+ BbsTable[BbsIndex].Function = (UINT32) Function;
+ BbsTable[BbsIndex].StatusFlags.OldPosition = 0;
+ BbsTable[BbsIndex].StatusFlags.Reserved1 = 0;
+ BbsTable[BbsIndex].StatusFlags.Enabled = 0;
+ BbsTable[BbsIndex].StatusFlags.Failed = 0;
+ BbsTable[BbsIndex].StatusFlags.MediaPresent = 0;
+ BbsTable[BbsIndex].StatusFlags.Reserved2 = 0;
+ BbsTable[BbsIndex].Class = PnpPtr->Class;
+ BbsTable[BbsIndex].SubClass = PnpPtr->SubClass;
+ BbsTable[BbsIndex].DescStringOffset = PnpPtr->ProductNamePointer;
+ BbsTable[BbsIndex].DescStringSegment = mBbsRomSegment;
+ BbsTable[BbsIndex].MfgStringOffset = PnpPtr->MfgPointer;
+ BbsTable[BbsIndex].MfgStringSegment = mBbsRomSegment;
+ BbsTable[BbsIndex].BootHandlerSegment = mBbsRomSegment;
+
+ //
+ // Have seen case where PXE base code have PnP expansion ROM
+ // header but no Bcv or Bev vectors.
+ //
+ if (PnpPtr->Bcv != 0) {
+ BbsTable[BbsIndex].BootHandlerOffset = PnpPtr->Bcv;
+ ++BbsIndex;
+ }
+
+ if (PnpPtr->Bev != 0) {
+ BbsTable[BbsIndex].BootHandlerOffset = PnpPtr->Bev;
+ BbsTable[BbsIndex].DeviceType = BBS_BEV_DEVICE;
+ ++BbsIndex;
+ }
+
+ if ((PnpPtr == (LEGACY_PNP_EXPANSION_HEADER *) PciPtr) || (PnpPtr > (LEGACY_PNP_EXPANSION_HEADER *) RomEnd)) {
+ break;
+ }
+ }
+ }
+
+ BbsTable[BbsIndex].BootPriority = BBS_IGNORE_ENTRY;
+ Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries = (UINT32) BbsIndex;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Shadow all the PCI legacy ROMs. Use data from the Legacy BIOS Protocol
+ to chose the order. Skip any devices that have already have legacy
+ BIOS run.
+
+ @param Private Protocol instance pointer.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_UNSUPPORTED Cannot get VGA device handle.
+
+**/
+EFI_STATUS
+PciShadowRoms (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+ UINTN Index;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ EFI_HANDLE VgaHandle;
+ EFI_HANDLE FirstHandle;
+ VOID **RomStart;
+ UINTN Flags;
+ PCI_TYPE00 PciConfigHeader;
+ UINT16 *Command;
+ UINT64 Supports;
+
+ //
+ // Make the VGA device first
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformVgaHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ VgaHandle = HandleBuffer[0];
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Place the VGA handle as first.
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+ if (HandleBuffer[Index] == VgaHandle) {
+ FirstHandle = HandleBuffer[0];
+ HandleBuffer[0] = HandleBuffer[Index];
+ HandleBuffer[Index] = FirstHandle;
+ break;
+ }
+ }
+ //
+ // Allocate memory to save Command WORD from each device. We do this
+ // to restore devices to same state as EFI after switching to legacy.
+ //
+ Command = (UINT16 *) AllocatePool (
+ sizeof (UINT16) * (HandleCount + 1)
+ );
+ if (NULL == Command) {
+ FreePool (HandleBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Disconnect all EFI devices first. This covers cases where alegacy BIOS
+ // may control multiple PCI devices.
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Save command register for "connect" loop
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+ Command[Index] = PciConfigHeader.Hdr.Command;
+ //
+ // Skip any device that already has a legacy ROM run
+ //
+ Status = IsLegacyRom (HandleBuffer[Index]);
+ if (!EFI_ERROR (Status)) {
+ continue;
+ }
+ //
+ // Stop EFI Drivers with oprom.
+ //
+ gBS->DisconnectController (
+ HandleBuffer[Index],
+ NULL,
+ NULL
+ );
+ }
+ //
+ // For every device that has not had a legacy ROM started. Start a legacy ROM.
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Here make sure if one VGA have been shadowed,
+ // then wil not shadowed another one.
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+
+ //
+ // Only one Video OPROM can be given control in BIOS phase. If there are multiple Video devices,
+ // one will work in legacy mode (OPROM will be given control) and
+ // other Video devices will work in native mode (OS driver will handle these devices).
+ //
+ if (IS_PCI_DISPLAY (&Pci) && Index != 0) {
+ continue;
+ }
+ //
+ // Skip any device that already has a legacy ROM run
+ //
+ Status = IsLegacyRom (HandleBuffer[Index]);
+ if (!EFI_ERROR (Status)) {
+ continue;
+ }
+ //
+ // Install legacy ROM
+ //
+ Status = LegacyBiosInstallPciRom (
+ &Private->LegacyBios,
+ HandleBuffer[Index],
+ NULL,
+ &Flags,
+ NULL,
+ NULL,
+ (VOID **) &RomStart,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ if (!((Status == EFI_UNSUPPORTED) && (Flags == NO_ROM))) {
+ continue;
+ }
+ }
+ //
+ // Restore Command register so legacy has same devices enabled or disabled
+ // as EFI.
+ // If Flags = NO_ROM use command register as is. This covers the
+ // following cases:
+ // Device has no ROMs associated with it.
+ // Device has ROM associated with it but was already
+ // installed.
+ // = ROM_FOUND but not VALID_LEGACY_ROM, disable it.
+ // = ROM_FOUND and VALID_LEGACY_ROM, enable it.
+ //
+ if ((Flags & ROM_FOUND) == ROM_FOUND) {
+ if ((Flags & VALID_LEGACY_ROM) == 0) {
+ Command[Index] = 0;
+ } else {
+ //
+ // For several VGAs, only one of them can be enabled.
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+ }
+ if (!EFI_ERROR (Status)) {
+ Command[Index] = 0x1f;
+ }
+ }
+ }
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0x04,
+ 1,
+ &Command[Index]
+ );
+ }
+
+ FreePool (Command);
+ FreePool (HandleBuffer);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Test to see if a legacy PCI ROM exists for this device. Optionally return
+ the Legacy ROM instance for this PCI device.
+
+ @param This Protocol instance pointer.
+ @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will
+ be loaded
+ @param RomImage Return the legacy PCI ROM for this device
+ @param RomSize Size of ROM Image
+ @param Flags Indicates if ROM found and if PC-AT.
+
+ @retval EFI_SUCCESS Legacy Option ROM availible for this device
+ @retval EFI_UNSUPPORTED Legacy Option ROM not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosCheckPciRom (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN EFI_HANDLE PciHandle,
+ OUT VOID **RomImage, OPTIONAL
+ OUT UINTN *RomSize, OPTIONAL
+ OUT UINTN *Flags
+ )
+{
+ return LegacyBiosCheckPciRomEx (
+ This,
+ PciHandle,
+ RomImage,
+ RomSize,
+ NULL,
+ Flags,
+ NULL,
+ NULL
+ );
+
+}
+
+/**
+
+ Routine Description:
+ Test to see if a legacy PCI ROM exists for this device. Optionally return
+ the Legacy ROM instance for this PCI device.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] PciHandle The PCI PC-AT OPROM from this devices ROM BAR will be loaded
+ @param[out] RomImage Return the legacy PCI ROM for this device
+ @param[out] RomSize Size of ROM Image
+ @param[out] RuntimeImageLength Runtime size of ROM Image
+ @param[out] Flags Indicates if ROM found and if PC-AT.
+ @param[out] OpromRevision Revision of the PCI Rom
+ @param[out] ConfigUtilityCodeHeaderPointer of Configuration Utility Code Header
+
+ @return EFI_SUCCESS Legacy Option ROM availible for this device
+ @return EFI_ALREADY_STARTED This device is already managed by its Oprom
+ @return EFI_UNSUPPORTED Legacy Option ROM not supported.
+
+**/
+EFI_STATUS
+LegacyBiosCheckPciRomEx (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN EFI_HANDLE PciHandle,
+ OUT VOID **RomImage, OPTIONAL
+ OUT UINTN *RomSize, OPTIONAL
+ OUT UINTN *RuntimeImageLength, OPTIONAL
+ OUT UINTN *Flags, OPTIONAL
+ OUT UINT8 *OpromRevision, OPTIONAL
+ OUT VOID **ConfigUtilityCodeHeader OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN LocalRomSize;
+ VOID *LocalRomImage;
+ PCI_TYPE00 PciConfigHeader;
+ VOID *LocalConfigUtilityCodeHeader;
+
+ *Flags = NO_ROM;
+ Status = gBS->HandleProtocol (
+ PciHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // See if the option ROM for PciHandle has already been executed
+ //
+ Status = IsLegacyRom (PciHandle);
+ if (!EFI_ERROR (Status)) {
+ *Flags |= (ROM_FOUND | VALID_LEGACY_ROM);
+ return EFI_SUCCESS;
+ }
+ //
+ // Check for PCI ROM Bar
+ //
+ LocalRomSize = (UINTN) PciIo->RomSize;
+ LocalRomImage = PciIo->RomImage;
+ if (LocalRomSize != 0) {
+ *Flags |= ROM_FOUND;
+ }
+
+ //
+ // PCI specification states you should check VendorId and Device Id.
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ Status = GetPciLegacyRom (
+ Private->Csm16PciInterfaceVersion,
+ PciConfigHeader.Hdr.VendorId,
+ PciConfigHeader.Hdr.DeviceId,
+ &LocalRomImage,
+ &LocalRomSize,
+ RuntimeImageLength,
+ OpromRevision,
+ &LocalConfigUtilityCodeHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *Flags |= VALID_LEGACY_ROM;
+
+ //
+ // See if Configuration Utility Code Header valid
+ //
+ if (LocalConfigUtilityCodeHeader != NULL) {
+ *Flags |= ROM_WITH_CONFIG;
+ }
+
+ if (ConfigUtilityCodeHeader != NULL) {
+ *ConfigUtilityCodeHeader = LocalConfigUtilityCodeHeader;
+ }
+
+ if (RomImage != NULL) {
+ *RomImage = LocalRomImage;
+ }
+
+ if (RomSize != NULL) {
+ *RomSize = LocalRomSize;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Load a legacy PC-AT OPROM on the PciHandle device. Return information
+ about how many disks were added by the OPROM and the shadow address and
+ size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
+
+ @retval EFI_SUCCESS Legacy ROM loaded for this device
+ @retval EFI_NOT_FOUND No PS2 Keyboard found
+
+**/
+EFI_STATUS
+EnablePs2Keyboard (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ UINTN Index;
+
+ //
+ // Get SimpleTextIn and find PS2 controller
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleTextInProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ for (Index = 0; Index < HandleCount; Index++) {
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ HandleBuffer[Index],
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ NULL,
+ HandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Use the ISA I/O Protocol to see if Controller is the Keyboard
+ // controller
+ //
+ if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ gBS->CloseProtocol (
+ HandleBuffer[Index],
+ &gEfiIsaIoProtocolGuid,
+ NULL,
+ HandleBuffer[Index]
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);
+ }
+ }
+ FreePool (HandleBuffer);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Load a legacy PC-AT OpROM for VGA controller.
+
+ @param Private Driver private data.
+
+ @retval EFI_SUCCESS Legacy ROM successfully installed for this device.
+ @retval EFI_DEVICE_ERROR No VGA device handle found, or native EFI video
+ driver cannot be successfully disconnected, or VGA
+ thunk driver cannot be successfully connected.
+
+**/
+EFI_STATUS
+LegacyBiosInstallVgaRom (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE VgaHandle;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ EFI_HANDLE *ConnectHandleBuffer;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 PciConfigHeader;
+ UINT64 Supports;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ UINTN EntryCount;
+ UINTN Index;
+ VOID *Interface;
+
+ //
+ // EfiLegacyBiosGuild attached to a device implies that there is a legacy
+ // BIOS associated with that device.
+ //
+ // There are 3 cases to consider.
+ // Case 1: No EFI driver is controlling the video.
+ // Action: Return EFI_SUCCESS from DisconnectController, search
+ // video thunk driver, and connect it.
+ // Case 2: EFI driver is controlling the video and EfiLegacyBiosGuid is
+ // not on the image handle.
+ // Action: Disconnect EFI driver.
+ // ConnectController for video thunk
+ // Case 3: EFI driver is controlling the video and EfiLegacyBiosGuid is
+ // on the image handle.
+ // Action: Do nothing and set Private->VgaInstalled = TRUE.
+ // Then this routine is not called any more.
+ //
+ //
+ // Get the VGA device.
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformVgaHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ VgaHandle = HandleBuffer[0];
+
+ //
+ // Check whether video thunk driver already starts.
+ //
+ Status = gBS->OpenProtocolInformation (
+ VgaHandle,
+ &gEfiPciIoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < EntryCount; Index++) {
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ Status = gBS->HandleProtocol (
+ OpenInfoBuffer[Index].AgentHandle,
+ &gEfiLegacyBiosGuid,
+ (VOID **) &Interface
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // This should be video thunk driver which is managing video device
+ // So it need not start again
+ //
+ DEBUG ((EFI_D_INFO, "Video thunk driver already start! Return!\n"));
+ Private->VgaInstalled = TRUE;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Kick off the native EFI driver
+ //
+ Status = gBS->DisconnectController (
+ VgaHandle,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_NOT_FOUND) {
+ return EFI_DEVICE_ERROR;
+ } else {
+ return Status;
+ }
+ }
+ //
+ // Find all the Thunk Driver
+ //
+ HandleBuffer = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLegacyBiosGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ ConnectHandleBuffer = (EFI_HANDLE *) AllocatePool (sizeof (EFI_HANDLE) * (HandleCount + 1));
+ ASSERT (ConnectHandleBuffer != NULL);
+
+ CopyMem (
+ ConnectHandleBuffer,
+ HandleBuffer,
+ sizeof (EFI_HANDLE) * HandleCount
+ );
+ ConnectHandleBuffer[HandleCount] = NULL;
+
+ FreePool (HandleBuffer);
+
+ //
+ // Enable the device and make sure VGA cycles are being forwarded to this VGA device
+ //
+ Status = gBS->HandleProtocol (
+ VgaHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | \
+ EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+ }
+
+ if (Status == EFI_SUCCESS) {
+ Private->VgaInstalled = TRUE;
+
+ //
+ // Attach the VGA thunk driver.
+ // Assume the video is installed. This prevents potential of infinite recursion.
+ //
+ Status = gBS->ConnectController (
+ VgaHandle,
+ ConnectHandleBuffer,
+ NULL,
+ TRUE
+ );
+ }
+
+ FreePool (ConnectHandleBuffer);
+
+ if (EFI_ERROR (Status)) {
+
+ Private->VgaInstalled = FALSE;
+
+ //
+ // Reconnect the EFI VGA driver.
+ //
+ gBS->ConnectController (VgaHandle, NULL, NULL, TRUE);
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Load a legacy PC-AT OpROM.
+
+ @param This Protocol instance pointer.
+ @param Private Driver's private data.
+ @param PciHandle The EFI handle for the PCI device. It could be
+ NULL if the OpROM image is not associated with
+ any device.
+ @param OpromRevision The revision of PCI PC-AT ROM image.
+ @param RomImage Pointer to PCI PC-AT ROM image header. It must not
+ be NULL.
+ @param ImageSize Size of the PCI PC-AT ROM image.
+ @param RuntimeImageLength On input is the max runtime image length indicated by the PCIR structure
+ On output is the actual runtime image length
+ @param DiskStart Disk number of first device hooked by the ROM. If
+ DiskStart is the same as DiskEnd no disked were
+ hooked.
+ @param DiskEnd Disk number of the last device hooked by the ROM.
+ @param RomShadowAddress Shadow address of PC-AT ROM
+
+ @retval EFI_SUCCESS Legacy ROM loaded for this device
+ @retval EFI_OUT_OF_RESOURCES No more space for this ROM
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosInstallRom (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN EFI_HANDLE PciHandle,
+ IN UINT8 OpromRevision,
+ IN VOID *RomImage,
+ IN UINTN ImageSize,
+ IN OUT UINTN *RuntimeImageLength,
+ OUT UINT8 *DiskStart, OPTIONAL
+ OUT UINT8 *DiskEnd, OPTIONAL
+ OUT VOID **RomShadowAddress OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS PciEnableStatus;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 LocalDiskStart;
+ UINT8 LocalDiskEnd;
+ UINTN Segment;
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+ EFI_IA32_REGISTER_SET Regs;
+ UINT8 VideoMode;
+ EFI_TIME BootTime;
+ UINT32 *BdaPtr;
+ UINT32 LocalTime;
+ UINT32 StartBbsIndex;
+ UINT32 EndBbsIndex;
+ UINTN TempData;
+ UINTN InitAddress;
+ UINTN RuntimeAddress;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ UINT32 Granularity;
+
+ PciIo = NULL;
+ LocalDiskStart = 0;
+ LocalDiskEnd = 0;
+ Segment = 0;
+ Bus = 0;
+ Device = 0;
+ Function = 0;
+ VideoMode = 0;
+ PhysicalAddress = 0;
+
+ PciProgramAllInterruptLineRegisters (Private);
+
+ if ((OpromRevision >= 3) && (Private->Csm16PciInterfaceVersion >= 0x0300)) {
+ //
+ // CSM16 3.0 meets PCI 3.0 OpROM
+ // first test if there is enough space for its INIT code
+ //
+ PhysicalAddress = CONVENTIONAL_MEMORY_TOP;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiBootServicesCode,
+ EFI_SIZE_TO_PAGES (ImageSize),
+ &PhysicalAddress
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ InitAddress = (UINTN) PhysicalAddress;
+ //
+ // then test if there is enough space for its RT code
+ //
+ RuntimeAddress = Private->OptionRom;
+ if (RuntimeAddress + *RuntimeImageLength > mEndOpromShadowAddress) {
+ DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));
+ gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ // CSM16 3.0 meets PCI 2.x OpROM
+ // CSM16 2.x meets PCI 2.x/3.0 OpROM
+ // test if there is enough space for its INIT code
+ //
+ InitAddress = PCI_START_ADDRESS (Private->OptionRom);
+ if (InitAddress + ImageSize > mEndOpromShadowAddress) {
+ DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ RuntimeAddress = InitAddress;
+ }
+
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ (UINT32) RuntimeAddress,
+ (UINT32) ImageSize,
+ &Granularity
+ );
+
+ DEBUG ((EFI_D_INFO, " Shadowing OpROM init/runtime/isize = %x/%x/%x\n", InitAddress, RuntimeAddress, ImageSize));
+
+ CopyMem ((VOID *) InitAddress, RomImage, ImageSize);
+
+ //
+ // Read the highest disk number "installed: and assume a new disk will
+ // show up on the first drive past the current value.
+ // There are several considerations here:
+ // 1. Non-BBS compliant drives will change 40:75 but 16-bit CSM will undo
+ // the change until boot selection time frame.
+ // 2. BBS compliants drives will not change 40:75 until boot time.
+ // 3. Onboard IDE controllers will change 40:75
+ //
+ LocalDiskStart = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);
+ if ((Private->Disk4075 + 0x80) < LocalDiskStart) {
+ //
+ // Update table since onboard IDE drives found
+ //
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment = 0xff;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus = 0xff;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice = 0xff;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction = 0xff;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber = (UINT8) (Private->Disk4075 + 0x80);
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = LocalDiskStart;
+ Private->LegacyEfiHddTableIndex ++;
+ Private->Disk4075 = (UINT8) (LocalDiskStart & 0x7f);
+ Private->DiskEnd = LocalDiskStart;
+ }
+
+ if (PciHandle != mVgaHandle) {
+
+ EnablePs2Keyboard ();
+
+ //
+ // Store current mode settings since PrepareToScanRom may change mode.
+ //
+ VideoMode = *(UINT8 *) ((UINTN) 0x449);
+ }
+ //
+ // Notify the platform that we are about to scan the ROM
+ //
+ Status = Private->LegacyBiosPlatform->PlatformHooks (
+ Private->LegacyBiosPlatform,
+ EfiPlatformHookPrepareToScanRom,
+ 0,
+ PciHandle,
+ &InitAddress,
+ NULL,
+ NULL
+ );
+
+ //
+ // If Status returned is EFI_UNSUPPORTED then abort due to platform
+ // policy.
+ //
+ if (Status == EFI_UNSUPPORTED) {
+ goto Done;
+ }
+
+ //
+ // Report corresponding status code
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_CSM_LEGACY_ROM_INIT)
+ );
+
+ //
+ // Generate number of ticks since midnight for BDA. Some OPROMs require
+ // this. Place result in 40:6C-6F
+ //
+ gRT->GetTime (&BootTime, NULL);
+ LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second;
+
+ //
+ // Multiply result by 18.2 for number of ticks since midnight.
+ // Use 182/10 to avoid floating point math.
+ //
+ LocalTime = (LocalTime * 182) / 10;
+ BdaPtr = (UINT32 *) ((UINTN) 0x46C);
+ *BdaPtr = LocalTime;
+
+ //
+ // Pass in handoff data
+ //
+ PciEnableStatus = EFI_UNSUPPORTED;
+ ZeroMem (&Regs, sizeof (Regs));
+ if (PciHandle != NULL) {
+
+ Status = gBS->HandleProtocol (
+ PciHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Enable command register.
+ //
+ PciEnableStatus = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+
+ PciIo->GetLocation (
+ PciIo,
+ &Segment,
+ &Bus,
+ &Device,
+ &Function
+ );
+ DEBUG ((EFI_D_INFO, "Shadowing OpROM on the PCI device %x/%x/%x\n", Bus, Device, Function));
+ }
+
+ mIgnoreBbsUpdateFlag = FALSE;
+ Regs.X.AX = Legacy16DispatchOprom;
+
+ //
+ // Generate DispatchOpRomTable data
+ //
+ Private->IntThunk->DispatchOpromTable.PnPInstallationCheckSegment = Private->Legacy16Table->PnPInstallationCheckSegment;
+ Private->IntThunk->DispatchOpromTable.PnPInstallationCheckOffset = Private->Legacy16Table->PnPInstallationCheckOffset;
+ Private->IntThunk->DispatchOpromTable.OpromSegment = (UINT16) (InitAddress >> 4);
+ Private->IntThunk->DispatchOpromTable.PciBus = (UINT8) Bus;
+ Private->IntThunk->DispatchOpromTable.PciDeviceFunction = (UINT8) ((Device << 3) | Function);
+ Private->IntThunk->DispatchOpromTable.NumberBbsEntries = (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
+ Private->IntThunk->DispatchOpromTable.BbsTablePointer = (UINT32) (UINTN) Private->BbsTablePtr;
+ Private->IntThunk->DispatchOpromTable.RuntimeSegment = (UINT16)((OpromRevision < 3) ? 0xffff : (RuntimeAddress >> 4));
+ TempData = (UINTN) &Private->IntThunk->DispatchOpromTable;
+ Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);
+ Regs.X.BX = EFI_OFFSET ((UINT32) TempData);
+ //
+ // Skip dispatching ROM for those PCI devices that can not be enabled by PciIo->Attributes
+ // Otherwise, it may cause the system to hang in some cases
+ //
+ if (!EFI_ERROR (PciEnableStatus)) {
+ DEBUG ((EFI_D_INFO, " Legacy16DispatchOprom - %02x/%02x/%02x\n", Bus, Device, Function));
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+ } else {
+ Regs.X.BX = 0;
+ }
+
+ if (Private->IntThunk->DispatchOpromTable.NumberBbsEntries != (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries) {
+ Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries = (UINT8) Private->IntThunk->DispatchOpromTable.NumberBbsEntries;
+ mIgnoreBbsUpdateFlag = TRUE;
+ }
+ //
+ // Check if non-BBS compliant drives found
+ //
+ if (Regs.X.BX != 0) {
+ LocalDiskEnd = (UINT8) (LocalDiskStart + Regs.H.BL);
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment = (UINT8) Segment;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus = (UINT8) Bus;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice = (UINT8) Device;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction = (UINT8) Function;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber = Private->DiskEnd;
+ Private->DiskEnd = LocalDiskEnd;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd;
+ Private->LegacyEfiHddTableIndex += 1;
+ }
+ //
+ // Skip video mode set, if installing VGA
+ //
+ if (PciHandle != mVgaHandle) {
+ //
+ // Set mode settings since PrepareToScanRom may change mode
+ //
+ Regs.H.AH = 0x00;
+ Regs.H.AL = VideoMode;
+ Private->LegacyBios.Int86 (&Private->LegacyBios, 0x10, &Regs);
+ }
+ //
+ // Regs.X.AX from the adapter initializion is ignored since some adapters
+ // do not follow the standard of setting AX = 0 on success.
+ //
+ //
+ // The ROM could have updated it's size so we need to read again.
+ //
+ *RuntimeImageLength = ((EFI_LEGACY_EXPANSION_ROM_HEADER *) (RuntimeAddress))->Size512 * 512;
+ DEBUG ((EFI_D_INFO, " fsize = %x\n", *RuntimeImageLength));
+
+ //
+ // If OpROM runs in 2.0 mode
+ //
+ if (PhysicalAddress == 0) {
+ if (*RuntimeImageLength < ImageSize) {
+ //
+ // Make area from end of shadowed rom to end of original rom all ffs
+ //
+ gBS->SetMem ((VOID *) (InitAddress + *RuntimeImageLength), ImageSize - *RuntimeImageLength, 0xff);
+ }
+ }
+
+ LocalDiskEnd = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);
+
+ //
+ // Allow platform to perform any required actions after the
+ // OPROM has been initialized.
+ //
+ Status = Private->LegacyBiosPlatform->PlatformHooks (
+ Private->LegacyBiosPlatform,
+ EfiPlatformHookAfterRomInit,
+ 0,
+ PciHandle,
+ &RuntimeAddress,
+ NULL,
+ NULL
+ );
+ if (PciHandle != NULL) {
+ //
+ // If no PCI Handle then no header or Bevs.
+ //
+ if ((*RuntimeImageLength != 0) && (!mIgnoreBbsUpdateFlag)) {
+ StartBbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
+ TempData = RuntimeAddress;
+ UpdateBevBcvTable (
+ Private,
+ (EFI_LEGACY_EXPANSION_ROM_HEADER *) TempData,
+ PciIo
+ );
+ EndBbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
+ LocalDiskEnd = (UINT8) (LocalDiskStart + (UINT8) (EndBbsIndex - StartBbsIndex));
+ if (LocalDiskEnd != LocalDiskStart) {
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment = (UINT8) Segment;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus = (UINT8) Bus;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice = (UINT8) Device;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction = (UINT8) Function;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber = Private->DiskEnd;
+ Private->DiskEnd = LocalDiskEnd;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd;
+ Private->LegacyEfiHddTableIndex += 1;
+ }
+ }
+ //
+ // Mark PCI device as having a legacy BIOS ROM loaded.
+ //
+ RomShadow (
+ PciHandle,
+ (UINT32) RuntimeAddress,
+ (UINT32) *RuntimeImageLength,
+ LocalDiskStart,
+ LocalDiskEnd
+ );
+ }
+
+ //
+ // Stuff caller's OPTIONAL return parameters.
+ //
+ if (RomShadowAddress != NULL) {
+ *RomShadowAddress = (VOID *) RuntimeAddress;
+ }
+
+ if (DiskStart != NULL) {
+ *DiskStart = LocalDiskStart;
+ }
+
+ if (DiskEnd != NULL) {
+ *DiskEnd = LocalDiskEnd;
+ }
+
+ Private->OptionRom = (UINT32) (RuntimeAddress + *RuntimeImageLength);
+
+ Status = EFI_SUCCESS;
+
+Done:
+ if (PhysicalAddress != 0) {
+ //
+ // Free pages when OpROM is 3.0
+ //
+ gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize));
+ }
+
+ //
+ // Insure all shadowed areas are locked
+ //
+ Private->LegacyRegion->Lock (
+ Private->LegacyRegion,
+ 0xC0000,
+ 0x40000,
+ &Granularity
+ );
+
+ return Status;
+}
+
+/**
+ Load a legacy PC-AT OPROM on the PciHandle device. Return information
+ about how many disks were added by the OPROM and the shadow address and
+ size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
+
+ @param This Protocol instance pointer.
+ @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will
+ be loaded. This value is NULL if RomImage is
+ non-NULL. This is the normal case.
+ @param RomImage A PCI PC-AT ROM image. This argument is non-NULL
+ if there is no hardware associated with the ROM
+ and thus no PciHandle, otherwise is must be NULL.
+ Example is PXE base code.
+ @param Flags Indicates if ROM found and if PC-AT.
+ @param DiskStart Disk number of first device hooked by the ROM. If
+ DiskStart is the same as DiskEnd no disked were
+ hooked.
+ @param DiskEnd Disk number of the last device hooked by the ROM.
+ @param RomShadowAddress Shadow address of PC-AT ROM
+ @param RomShadowedSize Size of RomShadowAddress in bytes
+
+ @retval EFI_SUCCESS Legacy ROM loaded for this device
+ @retval EFI_INVALID_PARAMETER PciHandle not found
+ @retval EFI_UNSUPPORTED There is no PCI ROM in the ROM BAR or no onboard
+ ROM
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosInstallPciRom (
+ IN EFI_LEGACY_BIOS_PROTOCOL * This,
+ IN EFI_HANDLE PciHandle,
+ IN VOID **RomImage,
+ OUT UINTN *Flags,
+ OUT UINT8 *DiskStart, OPTIONAL
+ OUT UINT8 *DiskEnd, OPTIONAL
+ OUT VOID **RomShadowAddress, OPTIONAL
+ OUT UINT32 *RomShadowedSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ VOID *LocalRomImage;
+ UINTN ImageSize;
+ UINTN RuntimeImageLength;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE01 PciConfigHeader;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+ UINTN LastBus;
+ UINTN Index;
+ UINT8 OpromRevision;
+ UINT32 Granularity;
+ PCI_3_0_DATA_STRUCTURE *Pcir;
+
+ OpromRevision = 0;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ if (Private->Legacy16Table->LastPciBus == 0) {
+ //
+ // Get last bus number if not already found
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ LastBus = 0;
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = PciIo->GetLocation (
+ PciIo,
+ &PciSegment,
+ &PciBus,
+ &PciDevice,
+ &PciFunction
+ );
+ if (PciBus > LastBus) {
+ LastBus = PciBus;
+ }
+ }
+
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+ Private->Legacy16Table->LastPciBus = (UINT8) LastBus;
+ Private->LegacyRegion->Lock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+ }
+
+ *Flags = 0;
+ if ((PciHandle != NULL) && (RomImage == NULL)) {
+ //
+ // If PciHandle has OpRom to Execute
+ // and OpRom are all associated with Hardware
+ //
+ Status = gBS->HandleProtocol (
+ PciHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+
+ if (!EFI_ERROR (Status)) {
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+
+ //
+ // if video installed & OPROM is video return
+ //
+ if (
+ (
+ ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_OLD) &&
+ (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_OLD_VGA))
+ ||
+ ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_DISPLAY) &&
+ (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_DISPLAY_VGA))
+ )
+ &&
+ (!Private->VgaInstalled)
+ ) {
+ mVgaInstallationInProgress = TRUE;
+
+ //
+ // return EFI_UNSUPPORTED;
+ //
+ }
+ }
+ //
+ // To run any legacy image, the VGA needs to be installed first.
+ // if installing the video, then don't need the thunk as already installed.
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformVgaHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ mVgaHandle = HandleBuffer[0];
+ if ((!Private->VgaInstalled) && (PciHandle != mVgaHandle)) {
+ //
+ // A return status of EFI_NOT_FOUND is considered valid (No EFI
+ // driver is controlling video.
+ //
+ mVgaInstallationInProgress = TRUE;
+ Status = LegacyBiosInstallVgaRom (Private);
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_NOT_FOUND) {
+ mVgaInstallationInProgress = FALSE;
+ return Status;
+ }
+ } else {
+ mVgaInstallationInProgress = FALSE;
+ }
+ }
+ }
+ //
+ // See if the option ROM for PciHandle has already been executed
+ //
+ Status = IsLegacyRom (PciHandle);
+
+ if (!EFI_ERROR (Status)) {
+ mVgaInstallationInProgress = FALSE;
+ GetShadowedRomParameters (
+ PciHandle,
+ DiskStart,
+ DiskEnd,
+ RomShadowAddress,
+ (UINTN *) RomShadowedSize
+ );
+ return EFI_SUCCESS;
+ }
+
+ Status = LegacyBiosCheckPciRomEx (
+ &Private->LegacyBios,
+ PciHandle,
+ &LocalRomImage,
+ &ImageSize,
+ &RuntimeImageLength,
+ Flags,
+ &OpromRevision,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // There is no PCI ROM in the ROM BAR or no onboard ROM
+ //
+ mVgaInstallationInProgress = FALSE;
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ if (*RomImage == NULL) {
+ //
+ // If PciHandle is NULL, and no OpRom is to be associated
+ //
+ mVgaInstallationInProgress = FALSE;
+ return EFI_UNSUPPORTED;
+ }
+
+ LocalRomImage = *RomImage;
+ Pcir = (PCI_3_0_DATA_STRUCTURE *)
+ ((UINT8 *) LocalRomImage + ((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset);
+ ImageSize = Pcir->ImageLength * 512;
+ if (Pcir->Length >= 0x1C) {
+ OpromRevision = Pcir->Revision;
+ } else {
+ OpromRevision = 0;
+ }
+ if (Pcir->Revision < 3) {
+ RuntimeImageLength = 0;
+ } else {
+ RuntimeImageLength = Pcir->MaxRuntimeImageLength * 512;
+ }
+ }
+ //
+ // Shadow and initialize the OpROM.
+ //
+ ASSERT (Private->TraceIndex < 0x200);
+ Private->Trace[Private->TraceIndex] = LEGACY_PCI_TRACE_000;
+ Private->TraceIndex ++;
+ Private->TraceIndex = (UINT16) (Private->TraceIndex % 0x200);
+ Status = LegacyBiosInstallRom (
+ This,
+ Private,
+ PciHandle,
+ OpromRevision,
+ LocalRomImage,
+ ImageSize,
+ &RuntimeImageLength,
+ DiskStart,
+ DiskEnd,
+ RomShadowAddress
+ );
+ if (RomShadowedSize != NULL) {
+ *RomShadowedSize = (UINT32) RuntimeImageLength;
+ }
+
+ mVgaInstallationInProgress = FALSE;
+ return Status;
+}
+
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacySio.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacySio.c new file mode 100644 index 0000000..f82121c --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacySio.c @@ -0,0 +1,234 @@ +/** @file
+ Collect Sio information from Native EFI Drivers.
+ Sio is floppy, parallel, serial, ... hardware
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+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.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+
+/**
+ Collect EFI Info about legacy devices.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildSioData (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ DEVICE_PRODUCER_DATA_HEADER *SioPtr;
+ DEVICE_PRODUCER_SERIAL *Sio1Ptr;
+ DEVICE_PRODUCER_PARALLEL *Sio2Ptr;
+ DEVICE_PRODUCER_FLOPPY *Sio3Ptr;
+ EFI_HANDLE IsaBusController;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ UINTN ResourceIndex;
+ UINTN ChildIndex;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ EFI_ISA_ACPI_RESOURCE_LIST *ResourceList;
+ EFI_ISA_ACPI_RESOURCE *IoResource;
+ EFI_ISA_ACPI_RESOURCE *DmaResource;
+ EFI_ISA_ACPI_RESOURCE *InterruptResource;
+ UINTN EntryCount;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ //
+ // Get the pointer to the SIO data structure
+ //
+ SioPtr = &Private->IntThunk->EfiToLegacy16BootTable.SioData;
+
+ //
+ // Zero the data in the SIO data structure
+ //
+ gBS->SetMem (SioPtr, sizeof (DEVICE_PRODUCER_DATA_HEADER), 0);
+
+ //
+ // Find the ISA Bus Controller used for legacy
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIsaBusHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+ IsaBusController = HandleBuffer[0];
+ if (!EFI_ERROR (Status)) {
+ //
+ // Force ISA Bus Controller to produce all ISA devices
+ //
+ gBS->ConnectController (IsaBusController, NULL, NULL, TRUE);
+ }
+ //
+ // Get the list of ISA controllers in the system
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiIsaIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+ //
+ // Collect legacy information from each of the ISA controllers in the system
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+
+ Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiIsaIoProtocolGuid, (VOID **) &IsaIo);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ ResourceList = IsaIo->ResourceList;
+
+ if (ResourceList == NULL) {
+ continue;
+ }
+ //
+ // Collect the resource types neededto fill in the SIO data structure
+ //
+ IoResource = NULL;
+ DmaResource = NULL;
+ InterruptResource = NULL;
+ for (ResourceIndex = 0;
+ ResourceList->ResourceItem[ResourceIndex].Type != EfiIsaAcpiResourceEndOfList;
+ ResourceIndex++
+ ) {
+ switch (ResourceList->ResourceItem[ResourceIndex].Type) {
+ case EfiIsaAcpiResourceIo:
+ IoResource = &ResourceList->ResourceItem[ResourceIndex];
+ break;
+
+ case EfiIsaAcpiResourceMemory:
+ break;
+
+ case EfiIsaAcpiResourceDma:
+ DmaResource = &ResourceList->ResourceItem[ResourceIndex];
+ break;
+
+ case EfiIsaAcpiResourceInterrupt:
+ InterruptResource = &ResourceList->ResourceItem[ResourceIndex];
+ break;
+
+ default:
+ break;
+ }
+ }
+ //
+ // See if this is an ISA serial port
+ //
+ // Ignore DMA resource since it is always returned NULL
+ //
+ if (ResourceList->Device.HID == EISA_PNP_ID (0x500) || ResourceList->Device.HID == EISA_PNP_ID (0x501)) {
+
+ if (ResourceList->Device.UID <= 3 &&
+ IoResource != NULL &&
+ InterruptResource != NULL
+ ) {
+ //
+ // Get the handle of the child device that has opened the ISA I/O Protocol
+ //
+ Status = gBS->OpenProtocolInformation (
+ HandleBuffer[Index],
+ &gEfiIsaIoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ //
+ // We want resource for legacy even if no 32-bit driver installed
+ //
+ for (ChildIndex = 0; ChildIndex < EntryCount; ChildIndex++) {
+ Sio1Ptr = &SioPtr->Serial[ResourceList->Device.UID];
+ Sio1Ptr->Address = (UINT16) IoResource->StartRange;
+ Sio1Ptr->Irq = (UINT8) InterruptResource->StartRange;
+ Sio1Ptr->Mode = DEVICE_SERIAL_MODE_NORMAL | DEVICE_SERIAL_MODE_DUPLEX_HALF;
+ }
+
+ FreePool (OpenInfoBuffer);
+ }
+ }
+ //
+ // See if this is an ISA parallel port
+ //
+ // Ignore DMA resource since it is always returned NULL, port
+ // only used in output mode.
+ //
+ if (ResourceList->Device.HID == EISA_PNP_ID (0x400) || ResourceList->Device.HID == EISA_PNP_ID (0x401)) {
+ if (ResourceList->Device.UID <= 2 &&
+ IoResource != NULL &&
+ InterruptResource != NULL &&
+ DmaResource != NULL
+ ) {
+ Sio2Ptr = &SioPtr->Parallel[ResourceList->Device.UID];
+ Sio2Ptr->Address = (UINT16) IoResource->StartRange;
+ Sio2Ptr->Irq = (UINT8) InterruptResource->StartRange;
+ Sio2Ptr->Dma = (UINT8) DmaResource->StartRange;
+ Sio2Ptr->Mode = DEVICE_PARALLEL_MODE_MODE_OUTPUT_ONLY;
+ }
+ }
+ //
+ // See if this is an ISA floppy controller
+ //
+ if (ResourceList->Device.HID == EISA_PNP_ID (0x604)) {
+ if (IoResource != NULL && InterruptResource != NULL && DmaResource != NULL) {
+ Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ if (!EFI_ERROR (Status)) {
+ Sio3Ptr = &SioPtr->Floppy;
+ Sio3Ptr->Address = (UINT16) IoResource->StartRange;
+ Sio3Ptr->Irq = (UINT8) InterruptResource->StartRange;
+ Sio3Ptr->Dma = (UINT8) DmaResource->StartRange;
+ Sio3Ptr->NumberOfFloppy++;
+ }
+ }
+ }
+ //
+ // See if this is a mouse
+ // Always set mouse found so USB hot plug will work
+ //
+ // Ignore lower byte of HID. Pnp0fxx is any type of mouse.
+ //
+ // Hid = ResourceList->Device.HID & 0xff00ffff;
+ // PnpId = EISA_PNP_ID(0x0f00);
+ // if (Hid == PnpId) {
+ // if (ResourceList->Device.UID == 1) {
+ // Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimplePointerProtocolGuid, &SimplePointer);
+ // if (!EFI_ERROR (Status)) {
+ //
+ SioPtr->MousePresent = 0x01;
+ //
+ // }
+ // }
+ // }
+ //
+ }
+
+ FreePool (HandleBuffer);
+
+ return EFI_SUCCESS;
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c new file mode 100644 index 0000000..c33288a --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c @@ -0,0 +1,284 @@ +/** @file
+ Call into 16-bit BIOS code, Use AsmThunk16 function of BaseLib.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+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.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+THUNK_CONTEXT mThunkContext;
+
+/**
+ 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.
+
+ @param This Protocol instance pointer.
+ @param BiosInt Processor interrupt vector to invoke
+ @param Regs Register contexted passed into (and returned) from thunk to
+ 16-bit mode
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in the target code.
+ See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+LegacyBiosInt86 (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT8 BiosInt,
+ IN EFI_IA32_REGISTER_SET *Regs
+ )
+{
+ 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 = 0;
+ Regs->X.Flags.TF = 0;
+ Regs->X.Flags.CF = 0;
+
+ return InternalLegacyBiosFarCall (
+ This,
+ (UINT16) (((UINT32 *)NULL)[BiosInt] >> 16),
+ (UINT16) ((UINT32 *)NULL)[BiosInt],
+ Regs,
+ &Regs->X.Flags,
+ sizeof (Regs->X.Flags)
+ );
+}
+
+/**
+ Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the
+ 16-bit register context on entry and exit. Arguments can be passed on
+ the Stack argument
+
+ @param This Protocol instance pointer.
+ @param Segment Segemnt of 16-bit mode call
+ @param Offset Offset of 16-bit mdoe call
+ @param Regs Register contexted passed into (and returned) from
+ thunk to 16-bit mode
+ @param Stack Caller allocated stack used to pass arguments
+ @param StackSize Size of Stack in bytes
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in
+ the target code. See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+LegacyBiosFarCall86 (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT16 Segment,
+ IN UINT16 Offset,
+ IN EFI_IA32_REGISTER_SET *Regs,
+ IN VOID *Stack,
+ IN UINTN StackSize
+ )
+{
+ 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;
+
+ return InternalLegacyBiosFarCall (This, Segment, Offset, Regs, Stack, StackSize);
+}
+
+/**
+ Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the
+ 16-bit register context on entry and exit. Arguments can be passed on
+ the Stack argument
+
+ @param This Protocol instance pointer.
+ @param Segment Segemnt of 16-bit mode call
+ @param Offset Offset of 16-bit mdoe call
+ @param Regs Register contexted passed into (and returned) from thunk to
+ 16-bit mode
+ @param Stack Caller allocated stack used to pass arguments
+ @param StackSize Size of Stack in bytes
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in the target code.
+ See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+InternalLegacyBiosFarCall (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT16 Segment,
+ IN UINT16 Offset,
+ IN EFI_IA32_REGISTER_SET *Regs,
+ IN VOID *Stack,
+ IN UINTN StackSize
+ )
+{
+ UINTN Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ UINT16 *Stack16;
+ EFI_TPL OriginalTpl;
+ IA32_REGISTER_SET ThunkRegSet;
+ BOOLEAN InterruptState;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+
+ ZeroMem (&ThunkRegSet, sizeof (ThunkRegSet));
+ ThunkRegSet.X.DI = Regs->X.DI;
+ ThunkRegSet.X.SI = Regs->X.SI;
+ ThunkRegSet.X.BP = Regs->X.BP;
+ ThunkRegSet.X.BX = Regs->X.BX;
+ ThunkRegSet.X.DX = Regs->X.DX;
+ //
+ // Sometimes, ECX is used to pass in 32 bit data. For example, INT 1Ah, AX = B10Dh is
+ // "PCI BIOS v2.0c + Write Configuration DWORD" and ECX has the dword to write.
+ //
+ ThunkRegSet.E.ECX = Regs->E.ECX;
+ ThunkRegSet.X.AX = Regs->X.AX;
+ ThunkRegSet.E.DS = Regs->X.DS;
+ ThunkRegSet.E.ES = Regs->X.ES;
+
+ CopyMem (&(ThunkRegSet.E.EFLAGS.UintN), &(Regs->X.Flags), sizeof (Regs->X.Flags));
+
+ //
+ // Clear the error flag; thunk code may set it. Stack16 should be the high address
+ // Make Statk16 address the low 16 bit must be not zero.
+ //
+ Stack16 = (UINT16 *)((UINT8 *) mThunkContext.RealModeBuffer + mThunkContext.RealModeBufferSize - sizeof (UINT16));
+
+ //
+ // Save and disable interrutp of debug timer
+ //
+ InterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
+
+ //
+ // The call to Legacy16 is a critical section to EFI
+ //
+ OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ if (Stack != NULL && StackSize != 0) {
+ //
+ // Copy Stack to low memory stack
+ //
+ Stack16 -= StackSize / sizeof (UINT16);
+ CopyMem (Stack16, Stack, StackSize);
+ }
+
+ ThunkRegSet.E.SS = (UINT16) (((UINTN) Stack16 >> 16) << 12);
+ ThunkRegSet.E.ESP = (UINT16) (UINTN) Stack16;
+ ThunkRegSet.E.CS = Segment;
+ ThunkRegSet.E.Eip = Offset;
+
+ mThunkContext.RealModeState = &ThunkRegSet;
+
+ //
+ // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
+ //
+ Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259LegacyMode, NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ AsmThunk16 (&mThunkContext);
+
+ //
+ // OPROM may allocate EBDA range by itself and change EBDA base and EBDA size.
+ // Get the current EBDA base address, and compared with pre-allocate minimum
+ // EBDA base address, if the current EBDA base address is smaller, it indicates
+ // PcdEbdaReservedMemorySize should be adjusted to larger for more OPROMs.
+ //
+ DEBUG_CODE (
+ {
+ UINTN EbdaBaseAddress;
+ UINTN ReservedEbdaBaseAddress;
+
+ EbdaBaseAddress = (*(UINT16 *) (UINTN) 0x40E) << 4;
+ ReservedEbdaBaseAddress = CONVENTIONAL_MEMORY_TOP - PcdGet32 (PcdEbdaReservedMemorySize);
+ ASSERT (ReservedEbdaBaseAddress <= EbdaBaseAddress);
+ }
+ );
+
+ if (Stack != NULL && StackSize != 0) {
+ //
+ // Copy low memory stack to Stack
+ //
+ CopyMem (Stack, Stack16, StackSize);
+ }
+
+ //
+ // Restore protected mode interrupt state
+ //
+ Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259ProtectedMode, NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ mThunkContext.RealModeState = NULL;
+
+ //
+ // End critical section
+ //
+ gBS->RestoreTPL (OriginalTpl);
+
+ //
+ // Restore interrutp of debug timer
+ //
+ SaveAndSetDebugTimerInterrupt (InterruptState);
+
+ 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->X.SS = ThunkRegSet.E.SS;
+ Regs->X.CS = ThunkRegSet.E.CS;
+ Regs->X.DS = ThunkRegSet.E.DS;
+ Regs->X.ES = ThunkRegSet.E.ES;
+
+ CopyMem (&(Regs->X.Flags), &(ThunkRegSet.E.EFLAGS.UintN), sizeof (Regs->X.Flags));
+
+ return (BOOLEAN) (Regs->X.Flags.CF == 1);
+}
+
+/**
+ Allocate memory < 1 MB and copy the thunker code into low memory. Se up
+ all the descriptors.
+
+ @param Private Private context for Legacy BIOS
+
+ @retval EFI_SUCCESS Should only pass.
+
+**/
+EFI_STATUS
+LegacyBiosInitializeThunk (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_PHYSICAL_ADDRESS MemoryAddress;
+
+ MemoryAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) Private->IntThunk;
+
+ mThunkContext.RealModeBuffer = (VOID *) (UINTN) (MemoryAddress + ((sizeof (LOW_MEMORY_THUNK) / EFI_PAGE_SIZE) + 1) * EFI_PAGE_SIZE);
+ mThunkContext.RealModeBufferSize = EFI_PAGE_SIZE;
+ mThunkContext.ThunkAttributes = THUNK_ATTRIBUTE_BIG_REAL_MODE | THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15;
+
+ AsmPrepareThunk16 (&mThunkContext);
+
+ return EFI_SUCCESS;
+}
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.S b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.S new file mode 100644 index 0000000..95a0888 --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.S @@ -0,0 +1,72 @@ +## @file +# Interrupt Redirection Template +# +# Copyright (c) 2006, Intel Corporation. All rights reserved.<BR> +# +# 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. +# +## + +#text SEGMENT + + +#---------------------------------------------------------------------------- +# Procedure: InterruptRedirectionTemplate: Redirects interrupts 0x68-0x6F +# +# Input: None +# +# Output: None +# +# Prototype: VOID +# InterruptRedirectionTemplate ( +# VOID +# ); +# +# Saves: None +# +# Modified: None +# +# Description: Contains the code that is copied into low memory (below 640K). +# This code reflects interrupts 0x68-0x6f to interrupts 0x08-0x0f. +# This template must be copied into low memory, and the IDT entries +# 0x68-0x6F must be point to the low memory copy of this code. Each +# entry is 4 bytes long, so IDT entries 0x68-0x6F can be easily +# computed. +# +#---------------------------------------------------------------------------- + +ASM_GLOBAL ASM_PFX(InterruptRedirectionTemplate) +ASM_PFX(InterruptRedirectionTemplate): + int $0x08 + .byte 0x0cf # IRET + nop + int $0x09 + .byte 0x0cf # IRET + nop + int $0x0a + .byte 0x0cf # IRET + nop + int $0x0b + .byte 0x0cf # IRET + nop + int $0x0c + .byte 0x0cf # IRET + nop + int $0x0d + .byte 0x0cf # IRET + nop + int $0x0e + .byte 0x0cf # IRET + nop + int $0x0f + .byte 0x0cf # IRET + nop + +#END diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.asm b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.asm new file mode 100644 index 0000000..750423e --- /dev/null +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.asm @@ -0,0 +1,71 @@ +;; @file
+; Interrupt Redirection Template
+;
+; Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
+;
+; 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.
+;
+;;
+
+text SEGMENT
+
+;----------------------------------------------------------------------------
+; Procedure: InterruptRedirectionTemplate: Redirects interrupts 0x68-0x6F
+;
+; Input: None
+;
+; Output: None
+;
+; Prototype: VOID
+; InterruptRedirectionTemplate (
+; VOID
+; );
+;
+; Saves: None
+;
+; Modified: None
+;
+; Description: Contains the code that is copied into low memory (below 640K).
+; This code reflects interrupts 0x68-0x6f to interrupts 0x08-0x0f.
+; This template must be copied into low memory, and the IDT entries
+; 0x68-0x6F must be point to the low memory copy of this code. Each
+; entry is 4 bytes long, so IDT entries 0x68-0x6F can be easily
+; computed.
+;
+;----------------------------------------------------------------------------
+
+InterruptRedirectionTemplate PROC
+ int 08h
+ DB 0cfh ; IRET
+ nop
+ int 09h
+ DB 0cfh ; IRET
+ nop
+ int 0ah
+ DB 0cfh ; IRET
+ nop
+ int 0bh
+ DB 0cfh ; IRET
+ nop
+ int 0ch
+ DB 0cfh ; IRET
+ nop
+ int 0dh
+ DB 0cfh ; IRET
+ nop
+ int 0eh
+ DB 0cfh ; IRET
+ nop
+ int 0fh
+ DB 0cfh ; IRET
+ nop
+InterruptRedirectionTemplate ENDP
+
+END
\ No newline at end of file |