Home | History | Annotate | Download | only in BiosVideoThunkDxe
      1 /** @file
      2   Provide legacy thunk interface for accessing Bios Video Rom.
      3 
      4 Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "BiosVideo.h"
     16 
     17 #define EFI_CPU_EFLAGS_IF 0x200
     18 
     19 /**
     20   Initialize legacy environment for BIOS INI caller.
     21 
     22   @param ThunkContext   the instance pointer of THUNK_CONTEXT
     23 **/
     24 VOID
     25 InitializeBiosIntCaller (
     26   THUNK_CONTEXT     *ThunkContext
     27   )
     28 {
     29   EFI_STATUS            Status;
     30   UINT32                RealModeBufferSize;
     31   UINT32                ExtraStackSize;
     32   EFI_PHYSICAL_ADDRESS  LegacyRegionBase;
     33   UINT32                LegacyRegionSize;
     34   //
     35   // Get LegacyRegion
     36   //
     37   AsmGetThunk16Properties (&RealModeBufferSize, &ExtraStackSize);
     38   LegacyRegionSize = (((RealModeBufferSize + ExtraStackSize) / EFI_PAGE_SIZE) + 1) * EFI_PAGE_SIZE;
     39   LegacyRegionBase = 0x100000;
     40   Status = gBS->AllocatePages (
     41                   AllocateMaxAddress,
     42                   EfiACPIMemoryNVS,
     43                   EFI_SIZE_TO_PAGES(LegacyRegionSize),
     44                   &LegacyRegionBase
     45                   );
     46   ASSERT_EFI_ERROR (Status);
     47 
     48   ThunkContext->RealModeBuffer     = (VOID*)(UINTN)LegacyRegionBase;
     49   ThunkContext->RealModeBufferSize = LegacyRegionSize;
     50   ThunkContext->ThunkAttributes    = THUNK_ATTRIBUTE_BIG_REAL_MODE|THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15;
     51   AsmPrepareThunk16(ThunkContext);
     52 }
     53 
     54 /**
     55    Initialize interrupt redirection code and entries, because
     56    IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.
     57    Or the interrupt will lost when we do thunk.
     58    NOTE: We do not reset 8259 vector base, because it will cause pending
     59    interrupt lost.
     60 
     61    @param Legacy8259  Instance pointer for EFI_LEGACY_8259_PROTOCOL.
     62 
     63 **/
     64 VOID
     65 InitializeInterruptRedirection (
     66   IN  EFI_LEGACY_8259_PROTOCOL  *Legacy8259
     67   )
     68 {
     69   EFI_STATUS            Status;
     70   EFI_PHYSICAL_ADDRESS  LegacyRegionBase;
     71   UINTN                 LegacyRegionLength;
     72   UINT32                *IdtArray;
     73   UINTN                 Index;
     74   UINT8                 ProtectedModeBaseVector;
     75   UINT32                InterruptRedirectionCode[] = {
     76     0x90CF08CD, // INT8; IRET; NOP
     77     0x90CF09CD, // INT9; IRET; NOP
     78     0x90CF0ACD, // INTA; IRET; NOP
     79     0x90CF0BCD, // INTB; IRET; NOP
     80     0x90CF0CCD, // INTC; IRET; NOP
     81     0x90CF0DCD, // INTD; IRET; NOP
     82     0x90CF0ECD, // INTE; IRET; NOP
     83     0x90CF0FCD  // INTF; IRET; NOP
     84   };
     85 
     86   //
     87   // Get LegacyRegion
     88   //
     89   LegacyRegionLength = sizeof(InterruptRedirectionCode);
     90   LegacyRegionBase = 0x100000;
     91   Status = gBS->AllocatePages (
     92                   AllocateMaxAddress,
     93                   EfiACPIMemoryNVS,
     94                   EFI_SIZE_TO_PAGES(LegacyRegionLength),
     95                   &LegacyRegionBase
     96                   );
     97   ASSERT_EFI_ERROR (Status);
     98 
     99   //
    100   // Copy code to legacy region
    101   //
    102   CopyMem ((VOID *)(UINTN)LegacyRegionBase, InterruptRedirectionCode, sizeof (InterruptRedirectionCode));
    103 
    104   //
    105   // Get VectorBase, it should be 0x68
    106   //
    107   Status = Legacy8259->GetVector (Legacy8259, Efi8259Irq0, &ProtectedModeBaseVector);
    108   ASSERT_EFI_ERROR (Status);
    109 
    110   //
    111   // Patch IVT 0x68 ~ 0x6f
    112   //
    113   IdtArray = (UINT32 *) 0;
    114   for (Index = 0; Index < 8; Index++) {
    115     IdtArray[ProtectedModeBaseVector + Index] = ((EFI_SEGMENT (LegacyRegionBase + Index * 4)) << 16) | (EFI_OFFSET (LegacyRegionBase + Index * 4));
    116   }
    117 
    118   return ;
    119 }
    120 
    121 /**
    122   Thunk to 16-bit real mode and execute a software interrupt with a vector
    123   of BiosInt. Regs will contain the 16-bit register context on entry and
    124   exit.
    125 
    126   @param  This    Protocol instance pointer.
    127   @param  BiosInt Processor interrupt vector to invoke
    128   @param  Reg     Register contexted passed into (and returned) from thunk to 16-bit mode
    129 
    130   @retval TRUE   Thunk completed, and there were no BIOS errors in the target code.
    131                  See Regs for status.
    132   @retval FALSE  There was a BIOS erro in the target code.
    133 **/
    134 BOOLEAN
    135 EFIAPI
    136 LegacyBiosInt86 (
    137   IN  BIOS_VIDEO_DEV                 *BiosDev,
    138   IN  UINT8                           BiosInt,
    139   IN  IA32_REGISTER_SET              *Regs
    140   )
    141 {
    142   UINTN                 Status;
    143   IA32_REGISTER_SET     ThunkRegSet;
    144   BOOLEAN               Ret;
    145   UINT16                *Stack16;
    146   BOOLEAN               Enabled;
    147 
    148   ZeroMem (&ThunkRegSet, sizeof (ThunkRegSet));
    149   ThunkRegSet.E.EFLAGS.Bits.Reserved_0 = 1;
    150   ThunkRegSet.E.EFLAGS.Bits.Reserved_1 = 0;
    151   ThunkRegSet.E.EFLAGS.Bits.Reserved_2 = 0;
    152   ThunkRegSet.E.EFLAGS.Bits.Reserved_3 = 0;
    153   ThunkRegSet.E.EFLAGS.Bits.IOPL       = 3;
    154   ThunkRegSet.E.EFLAGS.Bits.NT         = 0;
    155   ThunkRegSet.E.EFLAGS.Bits.IF         = 1;
    156   ThunkRegSet.E.EFLAGS.Bits.TF         = 0;
    157   ThunkRegSet.E.EFLAGS.Bits.CF         = 0;
    158 
    159   ThunkRegSet.E.EDI  = Regs->E.EDI;
    160   ThunkRegSet.E.ESI  = Regs->E.ESI;
    161   ThunkRegSet.E.EBP  = Regs->E.EBP;
    162   ThunkRegSet.E.EBX  = Regs->E.EBX;
    163   ThunkRegSet.E.EDX  = Regs->E.EDX;
    164   ThunkRegSet.E.ECX  = Regs->E.ECX;
    165   ThunkRegSet.E.EAX  = Regs->E.EAX;
    166   ThunkRegSet.E.DS   = Regs->E.DS;
    167   ThunkRegSet.E.ES   = Regs->E.ES;
    168 
    169   //
    170   // The call to Legacy16 is a critical section to EFI
    171   //
    172   Enabled = SaveAndDisableInterrupts();
    173 
    174   //
    175   // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
    176   //
    177   Status = BiosDev->Legacy8259->SetMode (BiosDev->Legacy8259, Efi8259LegacyMode, NULL, NULL);
    178   ASSERT_EFI_ERROR (Status);
    179 
    180   Stack16 = (UINT16 *)((UINT8 *) BiosDev->ThunkContext->RealModeBuffer + BiosDev->ThunkContext->RealModeBufferSize - sizeof (UINT16));
    181 
    182   ThunkRegSet.E.SS   = (UINT16) (((UINTN) Stack16 >> 16) << 12);
    183   ThunkRegSet.E.ESP  = (UINT16) (UINTN) Stack16;
    184 
    185   ThunkRegSet.E.Eip  = (UINT16)((UINT32 *)NULL)[BiosInt];
    186   ThunkRegSet.E.CS   = (UINT16)(((UINT32 *)NULL)[BiosInt] >> 16);
    187   BiosDev->ThunkContext->RealModeState = &ThunkRegSet;
    188   AsmThunk16 (BiosDev->ThunkContext);
    189 
    190   //
    191   // Restore protected mode interrupt state
    192   //
    193   Status = BiosDev->Legacy8259->SetMode (BiosDev->Legacy8259, Efi8259ProtectedMode, NULL, NULL);
    194   ASSERT_EFI_ERROR (Status);
    195 
    196   //
    197   // End critical section
    198   //
    199   SetInterruptState (Enabled);
    200 
    201   Regs->E.EDI      = ThunkRegSet.E.EDI;
    202   Regs->E.ESI      = ThunkRegSet.E.ESI;
    203   Regs->E.EBP      = ThunkRegSet.E.EBP;
    204   Regs->E.EBX      = ThunkRegSet.E.EBX;
    205   Regs->E.EDX      = ThunkRegSet.E.EDX;
    206   Regs->E.ECX      = ThunkRegSet.E.ECX;
    207   Regs->E.EAX      = ThunkRegSet.E.EAX;
    208   Regs->E.SS       = ThunkRegSet.E.SS;
    209   Regs->E.CS       = ThunkRegSet.E.CS;
    210   Regs->E.DS       = ThunkRegSet.E.DS;
    211   Regs->E.ES       = ThunkRegSet.E.ES;
    212 
    213   CopyMem (&(Regs->E.EFLAGS), &(ThunkRegSet.E.EFLAGS), sizeof (UINT32));
    214 
    215   Ret = (BOOLEAN) (Regs->E.EFLAGS.Bits.CF == 1);
    216 
    217   return Ret;
    218 }
    219 
    220 
    221