]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - DuetPkg/BiosVideoThunkDxe/LegacyBiosThunk.c
1. Add start64.S file for X64.
[mirror_edk2.git] / DuetPkg / BiosVideoThunkDxe / LegacyBiosThunk.c
... / ...
CommitLineData
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
14\r
15#include "BiosVideo.h"\r
16\r
17#define EFI_CPU_EFLAGS_IF 0x200\r
18\r
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
24VOID\r
25InitializeBiosIntCaller (\r
26 THUNK_CONTEXT *ThunkContext\r
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
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
52 \r
53}\r
54\r
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
65VOID\r
66InitializeInterruptRedirection (\r
67 IN EFI_LEGACY_8259_PROTOCOL *Legacy8259\r
68 )\r
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
108 Status = Legacy8259->GetVector (Legacy8259, Efi8259Irq0, &ProtectedModeBaseVector);\r
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
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
135BOOLEAN\r
136EFIAPI\r
137LegacyBiosInt86 (\r
138 IN BIOS_VIDEO_DEV *BiosDev,\r
139 IN UINT8 BiosInt,\r
140 IN IA32_REGISTER_SET *Regs\r
141 )\r
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 ZeroMem (&ThunkRegSet, sizeof (ThunkRegSet));\r
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
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 //\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
184 Stack16 = (UINT16 *)((UINT8 *) BiosDev->ThunkContext->RealModeBuffer + BiosDev->ThunkContext->RealModeBufferSize - sizeof (UINT16));\r
185\r
186 ThunkRegSet.E.SS = (UINT16) (((UINTN) Stack16 >> 16) << 12);\r
187 ThunkRegSet.E.ESP = (UINT16) (UINTN) Stack16;\r
188\r
189 ThunkRegSet.E.Eip = (UINT16)((UINT32 *)NULL)[BiosInt];\r
190 ThunkRegSet.E.CS = (UINT16)(((UINT32 *)NULL)[BiosInt] >> 16);\r
191 BiosDev->ThunkContext->RealModeState = &ThunkRegSet;\r
192 AsmThunk16 (BiosDev->ThunkContext);\r
193 \r
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
219 CopyMem (&(Regs->E.EFLAGS), &(ThunkRegSet.E.EFLAGS), sizeof (UINT32));\r
220\r
221 Ret = (BOOLEAN) (Regs->E.EFLAGS.Bits.CF == 1);\r
222\r
223 return Ret;\r
224}\r
225\r
226\r