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