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