+\r
+#include "BiosVideo.h"\r
+\r
+#define EFI_CPU_EFLAGS_IF 0x200\r
+\r
+THUNK_CONTEXT mThunkContext;\r
+\r
+VOID\r
+InitializeBiosIntCaller (\r
+ IN BIOS_VIDEO_DEV *BiosDev\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 RealModeBufferSize;\r
+ UINT32 ExtraStackSize;\r
+ EFI_PHYSICAL_ADDRESS LegacyRegionBase;\r
+ \r
+ //\r
+ // Get LegacyRegion\r
+ //\r
+ AsmGetThunk16Properties (&RealModeBufferSize, &ExtraStackSize);\r
+\r
+ LegacyRegionBase = 0x100000;\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiACPIMemoryNVS,\r
+ EFI_SIZE_TO_PAGES(RealModeBufferSize + ExtraStackSize + 200),\r
+ &LegacyRegionBase\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ \r
+ mThunkContext.RealModeBuffer = (VOID*)(UINTN)LegacyRegionBase;\r
+ mThunkContext.RealModeBufferSize = EFI_PAGES_TO_SIZE (RealModeBufferSize);\r
+ mThunkContext.ThunkAttributes = 3;\r
+ AsmPrepareThunk16(&mThunkContext);\r
+ \r
+}\r
+\r
+VOID\r
+InitializeInterruptRedirection (\r
+ IN BIOS_VIDEO_DEV *BiosDev\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Initialize interrupt redirection code and entries, because\r
+ IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.\r
+ Or the interrupt will lost when we do thunk.\r
+ NOTE: We do not reset 8259 vector base, because it will cause pending\r
+ interrupt lost.\r
+\r
+ Arguments:\r
+ NONE\r
+\r
+ Returns:\r
+ NONE\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS LegacyRegionBase;\r
+ UINTN LegacyRegionLength;\r
+ UINT32 *IdtArray;\r
+ UINTN Index;\r
+ UINT8 ProtectedModeBaseVector;\r
+ UINT32 InterruptRedirectionCode[] = {\r
+ 0x90CF08CD, // INT8; IRET; NOP\r
+ 0x90CF09CD, // INT9; IRET; NOP\r
+ 0x90CF0ACD, // INTA; IRET; NOP\r
+ 0x90CF0BCD, // INTB; IRET; NOP\r
+ 0x90CF0CCD, // INTC; IRET; NOP\r
+ 0x90CF0DCD, // INTD; IRET; NOP\r
+ 0x90CF0ECD, // INTE; IRET; NOP\r
+ 0x90CF0FCD // INTF; IRET; NOP\r
+ };\r
+\r
+ //\r
+ // Get LegacyRegion\r
+ //\r
+ LegacyRegionLength = sizeof(InterruptRedirectionCode);\r
+ LegacyRegionBase = 0x100000;\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiACPIMemoryNVS,\r
+ EFI_SIZE_TO_PAGES(LegacyRegionLength),\r
+ &LegacyRegionBase\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Copy code to legacy region\r
+ //\r
+ CopyMem ((VOID *)(UINTN)LegacyRegionBase, InterruptRedirectionCode, sizeof (InterruptRedirectionCode));\r
+\r
+ //\r
+ // Get VectorBase, it should be 0x68\r
+ //\r
+ Status = BiosDev->Legacy8259->GetVector (BiosDev->Legacy8259, Efi8259Irq0, &ProtectedModeBaseVector);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Patch IVT 0x68 ~ 0x6f\r
+ //\r
+ IdtArray = (UINT32 *) 0;\r
+ for (Index = 0; Index < 8; Index++) {\r
+ IdtArray[ProtectedModeBaseVector + Index] = ((EFI_SEGMENT (LegacyRegionBase + Index * 4)) << 16) | (EFI_OFFSET (LegacyRegionBase + Index * 4));\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
+BOOLEAN\r
+EFIAPI\r
+LegacyBiosInt86 (\r
+ IN BIOS_VIDEO_DEV *BiosDev,\r
+ IN UINT8 BiosInt,\r
+ IN EFI_IA32_REGISTER_SET *Regs\r
+ )\r
+/*++\r
+\r
+ Routine Description:\r
+ Thunk to 16-bit real mode and execute a software interrupt with a vector \r
+ of BiosInt. Regs will contain the 16-bit register context on entry and \r
+ exit.\r
+\r
+ Arguments:\r
+ This - Protocol instance pointer.\r
+ BiosInt - Processor interrupt vector to invoke\r
+ Reg - Register contexted passed into (and returned) from thunk to \r
+ 16-bit mode\r
+\r
+ Returns:\r
+ FALSE - Thunk completed, and there were no BIOS errors in the target code.\r
+ See Regs for status.\r
+ TRUE - There was a BIOS erro in the target code.\r
+\r
+--*/\r
+{\r
+ UINTN Status;\r
+ UINTN Eflags;\r
+ IA32_REGISTER_SET ThunkRegSet;\r
+ BOOLEAN Ret;\r
+ UINT16 *Stack16;\r
+ \r
+ Regs->X.Flags.Reserved1 = 1;\r
+ Regs->X.Flags.Reserved2 = 0;\r
+ Regs->X.Flags.Reserved3 = 0;\r
+ Regs->X.Flags.Reserved4 = 0;\r
+ Regs->X.Flags.IOPL = 3;\r
+ Regs->X.Flags.NT = 0;\r
+ Regs->X.Flags.IF = 1;\r
+ Regs->X.Flags.TF = 0;\r
+ Regs->X.Flags.CF = 0;\r
+\r
+ ZeroMem (&ThunkRegSet, sizeof (ThunkRegSet));\r
+ ThunkRegSet.E.EDI = Regs->E.EDI;\r
+ ThunkRegSet.E.ESI = Regs->E.ESI;\r
+ ThunkRegSet.E.EBP = Regs->E.EBP;\r
+ ThunkRegSet.E.EBX = Regs->E.EBX;\r
+ ThunkRegSet.E.EDX = Regs->E.EDX;\r
+ ThunkRegSet.E.ECX = Regs->E.ECX;\r
+ ThunkRegSet.E.EAX = Regs->E.EAX;\r
+ ThunkRegSet.E.DS = Regs->E.DS;\r
+ ThunkRegSet.E.ES = Regs->E.ES;\r
+\r
+ CopyMem (&(ThunkRegSet.E.EFLAGS), &(Regs->E.EFlags), sizeof (UINT32));\r
+ \r
+ //\r
+ // The call to Legacy16 is a critical section to EFI\r
+ //\r
+ Eflags = AsmReadEflags ();\r
+ if ((Eflags | EFI_CPU_EFLAGS_IF) != 0) {\r
+ DisableInterrupts ();\r
+ }\r
+\r
+ //\r
+ // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.\r
+ //\r
+ Status = BiosDev->Legacy8259->SetMode (BiosDev->Legacy8259, Efi8259LegacyMode, NULL, NULL);\r
+ ASSERT_EFI_ERROR (Status);\r
+ \r
+ Stack16 = (UINT16 *)((UINT8 *) mThunkContext.RealModeBuffer + mThunkContext.RealModeBufferSize - sizeof (UINT16));\r
+ Stack16 -= sizeof (ThunkRegSet.E.EFLAGS) / sizeof (UINT16);\r
+ CopyMem (Stack16, &ThunkRegSet.E.EFLAGS, sizeof (ThunkRegSet.E.EFLAGS));\r
+\r
+ ThunkRegSet.E.SS = (UINT16) (((UINTN) Stack16 >> 16) << 12);\r
+ ThunkRegSet.E.ESP = (UINT16) (UINTN) Stack16;\r
+ ThunkRegSet.E.Eip = (UINT16)((UINT32 *)NULL)[BiosInt];\r
+ ThunkRegSet.E.CS = (UINT16)(((UINT32 *)NULL)[BiosInt] >> 16);\r
+ mThunkContext.RealModeState = &ThunkRegSet;\r
+ AsmThunk16 (&mThunkContext);\r
+\r
+ //\r
+ // Restore protected mode interrupt state\r
+ //\r
+ Status = BiosDev->Legacy8259->SetMode (BiosDev->Legacy8259, Efi8259ProtectedMode, NULL, NULL);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // End critical section\r
+ //\r
+ if ((Eflags | EFI_CPU_EFLAGS_IF) != 0) {\r
+ EnableInterrupts ();\r
+ }\r
+\r
+ Regs->E.EDI = ThunkRegSet.E.EDI; \r
+ Regs->E.ESI = ThunkRegSet.E.ESI; \r
+ Regs->E.EBP = ThunkRegSet.E.EBP; \r
+ Regs->E.EBX = ThunkRegSet.E.EBX; \r
+ Regs->E.EDX = ThunkRegSet.E.EDX; \r
+ Regs->E.ECX = ThunkRegSet.E.ECX; \r
+ Regs->E.EAX = ThunkRegSet.E.EAX;\r
+ Regs->E.SS = ThunkRegSet.E.SS;\r
+ Regs->E.CS = ThunkRegSet.E.CS; \r
+ Regs->E.DS = ThunkRegSet.E.DS; \r
+ Regs->E.ES = ThunkRegSet.E.ES;\r
+\r
+ CopyMem (&(Regs->E.EFlags), &(ThunkRegSet.E.EFLAGS), sizeof (UINT32));\r
+\r
+ Ret = (BOOLEAN) (Regs->E.EFlags.CF == 1);\r
+\r
+ return Ret;\r
+}\r
+\r
+\r