blob: 6dc453ff0932e10dce8115a1032c9b5db7ad9731 [file] [log] [blame]
Vishal Bhoj82c80712015-12-15 21:13:33 +05301/** @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