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