summaryrefslogtreecommitdiff
path: root/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/Thunk.c
diff options
context:
space:
mode:
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2011-06-27 23:32:56 +0000
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2011-06-27 23:32:56 +0000
commitbcecde140a561c64e297225904afebebd62336ce (patch)
tree5f6333ccb04d851d151970e5dee6c9d8ac7ade71 /IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/Thunk.c
parenta7a0f78bd6fa1fe4684bf6de2b3e5ed5d9b5bf1c (diff)
downloadedk2-platforms-bcecde140a561c64e297225904afebebd62336ce.tar.xz
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/Ipf/Thunk.c')
-rw-r--r--IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/Thunk.c550
1 files changed, 550 insertions, 0 deletions
diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/Thunk.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/Thunk.c
new file mode 100644
index 0000000000..ca59b97ec4
--- /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);
+}