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