]> git.proxmox.com Git - mirror_edk2.git/blame - DuetPkg/BiosVideoThunkDxe/LegacyBiosThunk.c
Refine the comments for BiosVideo thunk driver.
[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
140 IN EFI_IA32_REGISTER_SET *Regs\r
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
149 Regs->X.Flags.Reserved1 = 1;\r
150 Regs->X.Flags.Reserved2 = 0;\r
151 Regs->X.Flags.Reserved3 = 0;\r
152 Regs->X.Flags.Reserved4 = 0;\r
153 Regs->X.Flags.IOPL = 3;\r
154 Regs->X.Flags.NT = 0;\r
155 Regs->X.Flags.IF = 1;\r
156 Regs->X.Flags.TF = 0;\r
157 Regs->X.Flags.CF = 0;\r
158\r
159 ZeroMem (&ThunkRegSet, sizeof (ThunkRegSet));\r
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
170 CopyMem (&(ThunkRegSet.E.EFLAGS), &(Regs->E.EFlags), sizeof (UINT32));\r
171 \r
172 //\r
173 // The call to Legacy16 is a critical section to EFI\r
174 //\r
175 Eflags = AsmReadEflags ();\r
176 if ((Eflags | EFI_CPU_EFLAGS_IF) != 0) {\r
177 DisableInterrupts ();\r
178 }\r
179\r
180 //\r
181 // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.\r
182 //\r
183 Status = BiosDev->Legacy8259->SetMode (BiosDev->Legacy8259, Efi8259LegacyMode, NULL, NULL);\r
184 ASSERT_EFI_ERROR (Status);\r
185 \r
f1294e4a 186 Stack16 = (UINT16 *)((UINT8 *) BiosDev->ThunkContext->RealModeBuffer + BiosDev->ThunkContext->RealModeBufferSize - sizeof (UINT16));\r
0d92cdc2 187 Stack16 -= sizeof (ThunkRegSet.E.EFLAGS) / sizeof (UINT16);\r
188 CopyMem (Stack16, &ThunkRegSet.E.EFLAGS, sizeof (ThunkRegSet.E.EFLAGS));\r
189\r
190 ThunkRegSet.E.SS = (UINT16) (((UINTN) Stack16 >> 16) << 12);\r
191 ThunkRegSet.E.ESP = (UINT16) (UINTN) Stack16;\r
192 ThunkRegSet.E.Eip = (UINT16)((UINT32 *)NULL)[BiosInt];\r
193 ThunkRegSet.E.CS = (UINT16)(((UINT32 *)NULL)[BiosInt] >> 16);\r
f1294e4a 194 BiosDev->ThunkContext->RealModeState = &ThunkRegSet;\r
195 AsmThunk16 (BiosDev->ThunkContext);\r
0d92cdc2 196\r
197 //\r
198 // Restore protected mode interrupt state\r
199 //\r
200 Status = BiosDev->Legacy8259->SetMode (BiosDev->Legacy8259, Efi8259ProtectedMode, NULL, NULL);\r
201 ASSERT_EFI_ERROR (Status);\r
202\r
203 //\r
204 // End critical section\r
205 //\r
206 if ((Eflags | EFI_CPU_EFLAGS_IF) != 0) {\r
207 EnableInterrupts ();\r
208 }\r
209\r
210 Regs->E.EDI = ThunkRegSet.E.EDI; \r
211 Regs->E.ESI = ThunkRegSet.E.ESI; \r
212 Regs->E.EBP = ThunkRegSet.E.EBP; \r
213 Regs->E.EBX = ThunkRegSet.E.EBX; \r
214 Regs->E.EDX = ThunkRegSet.E.EDX; \r
215 Regs->E.ECX = ThunkRegSet.E.ECX; \r
216 Regs->E.EAX = ThunkRegSet.E.EAX;\r
217 Regs->E.SS = ThunkRegSet.E.SS;\r
218 Regs->E.CS = ThunkRegSet.E.CS; \r
219 Regs->E.DS = ThunkRegSet.E.DS; \r
220 Regs->E.ES = ThunkRegSet.E.ES;\r
221\r
222 CopyMem (&(Regs->E.EFlags), &(ThunkRegSet.E.EFLAGS), sizeof (UINT32));\r
223\r
224 Ret = (BOOLEAN) (Regs->E.EFlags.CF == 1);\r
225\r
226 return Ret;\r
227}\r
228\r
229\r