1/** @file 2 Provide legacy thunk interface for accessing Bios Video Rom. 3 4Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR> 5This program and the accompanying materials 6are licensed and made available under the terms and conditions of the BSD License 7which accompanies this distribution. The full text of the license may be found at 8http://opensource.org/licenses/bsd-license.php 9 10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11WITHOUT 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**/ 24VOID 25InitializeBiosIntCaller ( 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**/ 64VOID 65InitializeInterruptRedirection ( 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**/ 134BOOLEAN 135EFIAPI 136LegacyBiosInt86 ( 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