Vishal Bhoj | 82c8071 | 2015-12-15 21:13:33 +0530 | [diff] [blame^] | 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 |
|