OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
OcLegacyThunkLib.c
Go to the documentation of this file.
1
9#include <Uefi.h>
10
11#include <IndustryStandard/Pci.h>
12
13#include <Library/BaseLib.h>
14#include <Library/BaseMemoryLib.h>
15#include <Library/DebugLib.h>
16#include <Library/IoLib.h>
17#include <Library/MemoryAllocationLib.h>
20#include <Library/UefiBootServicesTableLib.h>
21#include <Library/UefiLib.h>
22
23#include <Protocol/PciIo.h>
24#include <Protocol/Timer.h>
25
26//
27// 8254 Timer registers
28//
29#define TIMER0_COUNT_PORT 0x40
30#define TIMER1_COUNT_PORT 0x41
31#define TIMER2_COUNT_PORT 0x42
32#define TIMER_CONTROL_PORT 0x43
33#define TIMER0_CONTROL_WORD 0x36
34
35//
36// Vector base definitions
37//
38//
39// 8259 Hardware definitions
40//
41#define LEGACY_MODE_BASE_VECTOR_MASTER 0x08
42#define LEGACY_MODE_BASE_VECTOR_SLAVE 0x70
43
44//
45// The original PC used INT8-F for master PIC. Since these mapped over
46// processor exceptions TIANO moved the master PIC to INT68-6F.
47//
48// The vector base for slave PIC is set as 0x70 for PC-AT compatibility.
49//
50#define PROTECTED_MODE_BASE_VECTOR_MASTER 0x68
51#define PROTECTED_MODE_BASE_VECTOR_SLAVE 0x70
52
58EFI_STATUS
60 THUNK_CONTEXT *ThunkContext
61 )
62{
63 EFI_STATUS Status;
64 UINT32 RealModeBufferSize;
65 UINT32 ExtraStackSize;
66 EFI_PHYSICAL_ADDRESS LegacyRegionBase;
67 UINT32 LegacyRegionSize;
68
69 //
70 // Get LegacyRegion
71 //
72 AsmGetThunk16Properties (&RealModeBufferSize, &ExtraStackSize);
73 LegacyRegionSize = (((RealModeBufferSize + ExtraStackSize) / EFI_PAGE_SIZE) + 1) * EFI_PAGE_SIZE;
74 LegacyRegionBase = LEGACY_REGION_BASE;
75 Status = gBS->AllocatePages (
76 AllocateMaxAddress,
77 EfiACPIMemoryNVS,
78 EFI_SIZE_TO_PAGES (LegacyRegionSize),
79 &LegacyRegionBase
80 );
81 if (EFI_ERROR (Status)) {
82 return Status;
83 }
84
85 ZeroMem ((VOID *)(UINTN)LegacyRegionBase, LegacyRegionSize);
86
87 ThunkContext->RealModeBuffer = (VOID *)(UINTN)LegacyRegionBase;
88 ThunkContext->RealModeBufferSize = LegacyRegionSize;
89 ThunkContext->ThunkAttributes = THUNK_ATTRIBUTE_BIG_REAL_MODE|THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15;
90 AsmPrepareThunk16 (ThunkContext);
91 return Status;
92}
93
104EFI_STATUS
106 IN EFI_LEGACY_8259_PROTOCOL *Legacy8259
107 )
108{
109 EFI_STATUS Status;
110 EFI_PHYSICAL_ADDRESS LegacyRegionBase;
111 UINTN LegacyRegionLength;
112 volatile UINT32 *IdtArray;
113 UINTN Index;
114 UINT8 ProtectedModeBaseVector;
115
116 STATIC CONST UINT32 InterruptRedirectionCode[] = {
117 0x90CF08CD, // INT8; IRET; NOP
118 0x90CF09CD, // INT9; IRET; NOP
119 0x90CF0ACD, // INTA; IRET; NOP
120 0x90CF0BCD, // INTB; IRET; NOP
121 0x90CF0CCD, // INTC; IRET; NOP
122 0x90CF0DCD, // INTD; IRET; NOP
123 0x90CF0ECD, // INTE; IRET; NOP
124 0x90CF0FCD // INTF; IRET; NOP
125 };
126
127 //
128 // Get LegacyRegion
129 //
130 LegacyRegionLength = sizeof (InterruptRedirectionCode);
131 LegacyRegionBase = LEGACY_REGION_BASE;
132 Status = gBS->AllocatePages (
133 AllocateMaxAddress,
134 EfiACPIMemoryNVS,
135 EFI_SIZE_TO_PAGES (LegacyRegionLength),
136 &LegacyRegionBase
137 );
138 if (EFI_ERROR (Status)) {
139 return Status;
140 }
141
142 //
143 // Copy code to legacy region
144 //
145 CopyMem ((VOID *)(UINTN)LegacyRegionBase, InterruptRedirectionCode, sizeof (InterruptRedirectionCode));
146
147 //
148 // Get VectorBase, it should be 0x68
149 //
150 Status = Legacy8259->GetVector (Legacy8259, Efi8259Irq0, &ProtectedModeBaseVector);
151 ASSERT_EFI_ERROR (Status);
152
153 //
154 // Patch IVT 0x68 ~ 0x6f
155 //
156 IdtArray = (UINT32 *)0;
157 for (Index = 0; Index < 8; Index++) {
158 IdtArray[ProtectedModeBaseVector + Index] = ((EFI_SEGMENT (LegacyRegionBase + Index * 4)) << 16) | (EFI_OFFSET (LegacyRegionBase + Index * 4));
159 }
160
161 return Status;
162}
163
167VOID
169 VOID
170 )
171{
172 EFI_STATUS Status;
173 UINTN HandleCount;
174 EFI_HANDLE *HandleBuffer;
175 UINTN Index;
176 EFI_PCI_IO_PROTOCOL *PciIo;
177 PCI_CLASSCODE ClassCode;
178
179 Status = gBS->LocateHandleBuffer (
180 ByProtocol,
181 &gEfiPciIoProtocolGuid,
182 NULL,
183 &HandleCount,
184 &HandleBuffer
185 );
186 if (EFI_ERROR (Status)) {
187 return;
188 }
189
190 for (Index = 0; Index < HandleCount; ++Index) {
191 Status = gBS->HandleProtocol (
192 HandleBuffer[Index],
193 &gEfiPciIoProtocolGuid,
194 (VOID **)&PciIo
195 );
196
197 if (EFI_ERROR (Status)) {
198 continue;
199 }
200
201 Status = PciIo->Pci.Read (
202 PciIo,
203 EfiPciIoWidthUint8,
204 PCI_CLASSCODE_OFFSET,
205 sizeof (PCI_CLASSCODE) / sizeof (UINT8),
206 &ClassCode
207 );
208 if (EFI_ERROR (Status)) {
209 continue;
210 }
211
212 if ((ClassCode.BaseCode == PCI_CLASS_DISPLAY) && (ClassCode.SubClassCode == PCI_CLASS_DISPLAY_VGA)) {
213 Status = gBS->DisconnectController (
214 HandleBuffer[Index],
215 NULL,
216 NULL
217 );
218 DEBUG ((DEBUG_INFO, "OCLT: Disconnected graphics controller - %r\n", Status));
219 }
220 }
221
222 FreePool (HandleBuffer);
223}
224
239BOOLEAN
240EFIAPI
242 IN THUNK_CONTEXT *ThunkContext,
243 IN EFI_LEGACY_8259_PROTOCOL *Legacy8259,
244 IN UINT8 BiosInt,
245 IN IA32_REGISTER_SET *Regs
246 )
247{
248 UINTN Status;
249 IA32_REGISTER_SET ThunkRegSet;
250 BOOLEAN Ret;
251 UINT16 *Stack16;
252 BOOLEAN Enabled;
253
254 ZeroMem (&ThunkRegSet, sizeof (ThunkRegSet));
255 ThunkRegSet.E.EFLAGS.Bits.Reserved_0 = 1;
256 ThunkRegSet.E.EFLAGS.Bits.Reserved_1 = 0;
257 ThunkRegSet.E.EFLAGS.Bits.Reserved_2 = 0;
258 ThunkRegSet.E.EFLAGS.Bits.Reserved_3 = 0;
259 ThunkRegSet.E.EFLAGS.Bits.IOPL = 3;
260 ThunkRegSet.E.EFLAGS.Bits.NT = 0;
261 ThunkRegSet.E.EFLAGS.Bits.IF = 1;
262 ThunkRegSet.E.EFLAGS.Bits.TF = 0;
263 ThunkRegSet.E.EFLAGS.Bits.CF = 0;
264
265 ThunkRegSet.E.EDI = Regs->E.EDI;
266 ThunkRegSet.E.ESI = Regs->E.ESI;
267 ThunkRegSet.E.EBP = Regs->E.EBP;
268 ThunkRegSet.E.EBX = Regs->E.EBX;
269 ThunkRegSet.E.EDX = Regs->E.EDX;
270 ThunkRegSet.E.ECX = Regs->E.ECX;
271 ThunkRegSet.E.EAX = Regs->E.EAX;
272 ThunkRegSet.E.DS = Regs->E.DS;
273 ThunkRegSet.E.ES = Regs->E.ES;
274
275 //
276 // The call to Legacy16 is a critical section to EFI
277 //
278 Enabled = SaveAndDisableInterrupts ();
279
280 //
281 // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
282 //
283 Status = Legacy8259->SetMode (Legacy8259, Efi8259LegacyMode, NULL, NULL);
284 ASSERT_EFI_ERROR (Status);
285
286 Stack16 = (UINT16 *)((UINT8 *)ThunkContext->RealModeBuffer + ThunkContext->RealModeBufferSize - sizeof (UINT16));
287
288 ThunkRegSet.E.SS = (UINT16)(((UINTN)Stack16 >> 16) << 12);
289 ThunkRegSet.E.ESP = (UINT16)(UINTN)Stack16;
290
291 ThunkRegSet.E.Eip = (UINT16)((volatile UINT32 *)NULL)[BiosInt];
292 ThunkRegSet.E.CS = (UINT16)(((volatile UINT32 *)NULL)[BiosInt] >> 16);
293 ThunkContext->RealModeState = &ThunkRegSet;
294 AsmThunk16 (ThunkContext);
295
296 //
297 // Restore protected mode interrupt state
298 //
299 Status = Legacy8259->SetMode (Legacy8259, Efi8259ProtectedMode, NULL, NULL);
300 ASSERT_EFI_ERROR (Status);
301
302 //
303 // End critical section
304 //
305 SetInterruptState (Enabled);
306
307 Regs->E.EDI = ThunkRegSet.E.EDI;
308 Regs->E.ESI = ThunkRegSet.E.ESI;
309 Regs->E.EBP = ThunkRegSet.E.EBP;
310 Regs->E.EBX = ThunkRegSet.E.EBX;
311 Regs->E.EDX = ThunkRegSet.E.EDX;
312 Regs->E.ECX = ThunkRegSet.E.ECX;
313 Regs->E.EAX = ThunkRegSet.E.EAX;
314 Regs->E.SS = ThunkRegSet.E.SS;
315 Regs->E.CS = ThunkRegSet.E.CS;
316 Regs->E.DS = ThunkRegSet.E.DS;
317 Regs->E.ES = ThunkRegSet.E.ES;
318
319 CopyMem (&(Regs->E.EFLAGS), &(ThunkRegSet.E.EFLAGS), sizeof (UINT32));
320
321 Ret = (BOOLEAN)(Regs->E.EFLAGS.Bits.CF == 1);
322
323 return Ret;
324}
325
326BOOLEAN
327EFIAPI
329 IN THUNK_CONTEXT *ThunkContext,
330 IN EFI_LEGACY_8259_PROTOCOL *Legacy8259,
331 IN UINT16 Segment,
332 IN UINT16 Offset,
333 IN IA32_REGISTER_SET *Regs,
334 IN VOID *Stack,
335 IN UINTN StackSize
336 )
337{
338 UINTN Status;
339 UINT16 *Stack16;
340 IA32_REGISTER_SET ThunkRegSet;
341 BOOLEAN Ret;
342 UINT64 TimerPeriod;
343 BOOLEAN Enabled;
344
345 EFI_TIMER_ARCH_PROTOCOL *TimerProtocol;
346
347 ZeroMem (&ThunkRegSet, sizeof (ThunkRegSet));
348 ThunkRegSet.E.EFLAGS.Bits.Reserved_0 = 1;
349 ThunkRegSet.E.EFLAGS.Bits.Reserved_1 = 0;
350 ThunkRegSet.E.EFLAGS.Bits.Reserved_2 = 0;
351 ThunkRegSet.E.EFLAGS.Bits.Reserved_3 = 0;
352 ThunkRegSet.E.EFLAGS.Bits.IOPL = 3;
353 ThunkRegSet.E.EFLAGS.Bits.NT = 0;
354 ThunkRegSet.E.EFLAGS.Bits.IF = 1;
355 ThunkRegSet.E.EFLAGS.Bits.TF = 0;
356 ThunkRegSet.E.EFLAGS.Bits.CF = 0;
357
358 ThunkRegSet.E.EDI = Regs->E.EDI;
359 ThunkRegSet.E.ESI = Regs->E.ESI;
360 ThunkRegSet.E.EBP = Regs->E.EBP;
361 ThunkRegSet.E.EBX = Regs->E.EBX;
362 ThunkRegSet.E.EDX = Regs->E.EDX;
363 ThunkRegSet.E.ECX = Regs->E.ECX;
364 ThunkRegSet.E.EAX = Regs->E.EAX;
365 ThunkRegSet.E.DS = Regs->E.DS;
366 ThunkRegSet.E.ES = Regs->E.ES;
367
368 //
369 // The call to Legacy16 is a critical section to EFI
370 //
371 Enabled = SaveAndDisableInterrupts ();
372
373 //
374 // Save current rate of DXE timer and disable it
375 // while executing in real mode.
376 //
377 Status = gBS->LocateProtocol (
378 &gEfiTimerArchProtocolGuid,
379 NULL,
380 (VOID **)&TimerProtocol
381 );
382 if (!EFI_ERROR (Status)) {
383 TimerProtocol->GetTimerPeriod (TimerProtocol, &TimerPeriod);
384 TimerProtocol->SetTimerPeriod (TimerProtocol, 0);
385 } else {
386 TimerProtocol = NULL;
387 }
388
389 //
390 // Reset timer to default legacy rate of 54.9254.
391 //
395
396 //
397 // Put the 8259 into its legacy mode by reprogramming the vector bases
398 //
399 Status = Legacy8259->SetVectorBase (Legacy8259, LEGACY_MODE_BASE_VECTOR_MASTER, LEGACY_MODE_BASE_VECTOR_SLAVE);
400 ASSERT_EFI_ERROR (Status);
401
402 //
403 // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
404 //
405 Status = Legacy8259->SetMode (Legacy8259, Efi8259LegacyMode, NULL, NULL);
406 ASSERT_EFI_ERROR (Status);
407
408 //
409 // Clear the error flag; thunk code may set it. Stack16 should be the high address.
410 // Make Stack16 address the low 16 bit must be not zero.
411 //
412 Stack16 = (UINT16 *)((UINT8 *)ThunkContext->RealModeBuffer + ThunkContext->RealModeBufferSize - sizeof (UINT16));
413
414 if ((Stack != NULL) && (StackSize != 0)) {
415 //
416 // Copy Stack to low memory stack
417 //
418 Stack16 -= StackSize / sizeof (UINT16);
419 CopyMem (Stack16, Stack, StackSize);
420 }
421
422 ThunkRegSet.E.SS = (UINT16)(((UINTN)Stack16 >> 16) << 12);
423 ThunkRegSet.E.ESP = (UINT16)(UINTN)Stack16;
424 ThunkRegSet.E.CS = Segment;
425 ThunkRegSet.E.Eip = Offset;
426
427 ThunkContext->RealModeState = &ThunkRegSet;
428 AsmThunk16 (ThunkContext);
429
430 //
431 // EFI is likely trashed if we get here, but attempt to restore state.
432 //
433 if ((Stack != NULL) && (StackSize != 0)) {
434 //
435 // Copy low memory stack to Stack
436 //
437 CopyMem (Stack, Stack16, StackSize);
438 }
439
440 //
441 // Restore protected mode interrupt state
442 //
443 Status = Legacy8259->SetMode (Legacy8259, Efi8259ProtectedMode, NULL, NULL);
444 ASSERT_EFI_ERROR (Status);
445
446 ThunkContext->RealModeState = NULL;
447
448 //
449 // Enable and restore rate of DXE Timer
450 //
451 if (TimerProtocol != NULL) {
452 TimerProtocol->SetTimerPeriod (TimerProtocol, TimerPeriod);
453 }
454
455 //
456 // End critical section
457 //
458 SetInterruptState (Enabled);
459
460 Regs->E.EDI = ThunkRegSet.E.EDI;
461 Regs->E.ESI = ThunkRegSet.E.ESI;
462 Regs->E.EBP = ThunkRegSet.E.EBP;
463 Regs->E.EBX = ThunkRegSet.E.EBX;
464 Regs->E.EDX = ThunkRegSet.E.EDX;
465 Regs->E.ECX = ThunkRegSet.E.ECX;
466 Regs->E.EAX = ThunkRegSet.E.EAX;
467 Regs->E.SS = ThunkRegSet.E.SS;
468 Regs->E.CS = ThunkRegSet.E.CS;
469 Regs->E.DS = ThunkRegSet.E.DS;
470 Regs->E.ES = ThunkRegSet.E.ES;
471
472 CopyMem (&(Regs->E.EFLAGS), &(ThunkRegSet.E.EFLAGS), sizeof (UINT32));
473
474 Ret = (BOOLEAN)(Regs->E.EFLAGS.Bits.CF == 1);
475
476 return Ret;
477}
@ Efi8259Irq0
Definition Legacy8259.h:25
@ Efi8259LegacyMode
Definition Legacy8259.h:45
@ Efi8259ProtectedMode
Definition Legacy8259.h:46
EFI_BOOT_SERVICES * gBS
EFI_STATUS OcLegacyThunkInitializeInterruptRedirection(IN EFI_LEGACY_8259_PROTOCOL *Legacy8259)
#define LEGACY_MODE_BASE_VECTOR_MASTER
BOOLEAN EFIAPI OcLegacyThunkFarCall86(IN THUNK_CONTEXT *ThunkContext, IN EFI_LEGACY_8259_PROTOCOL *Legacy8259, IN UINT16 Segment, IN UINT16 Offset, IN IA32_REGISTER_SET *Regs, IN VOID *Stack, IN UINTN StackSize)
#define TIMER0_CONTROL_WORD
#define LEGACY_MODE_BASE_VECTOR_SLAVE
#define TIMER_CONTROL_PORT
BOOLEAN EFIAPI OcLegacyThunkBiosInt86(IN THUNK_CONTEXT *ThunkContext, IN EFI_LEGACY_8259_PROTOCOL *Legacy8259, IN UINT8 BiosInt, IN IA32_REGISTER_SET *Regs)
EFI_STATUS OcLegacyThunkInitializeBiosIntCaller(THUNK_CONTEXT *ThunkContext)
#define TIMER0_COUNT_PORT
VOID OcLegacyThunkDisconnectEfiGraphics(VOID)
#define LEGACY_REGION_BASE
#define EFI_OFFSET(_Adr)
#define EFI_SEGMENT(_Adr)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
UINT8 EFIAPI IoWrite8(IN UINTN Port, IN UINT8 Value)
Definition UserMisc.c:307