2 Provide legacy thunk interface for accessing Bios Video Rom.
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
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.
15 #include "BiosVideo.h"
17 #define EFI_CPU_EFLAGS_IF 0x200
20 Initialize legacy environment for BIOS INI caller.
22 @param ThunkContext the instance pointer of THUNK_CONTEXT
25 InitializeBiosIntCaller (
26 THUNK_CONTEXT
*ThunkContext
30 UINT32 RealModeBufferSize
;
31 UINT32 ExtraStackSize
;
32 EFI_PHYSICAL_ADDRESS LegacyRegionBase
;
37 AsmGetThunk16Properties (&RealModeBufferSize
, &ExtraStackSize
);
39 LegacyRegionBase
= 0x100000;
40 Status
= gBS
->AllocatePages (
43 EFI_SIZE_TO_PAGES(RealModeBufferSize
+ ExtraStackSize
+ 200),
46 ASSERT_EFI_ERROR (Status
);
48 ThunkContext
->RealModeBuffer
= (VOID
*)(UINTN
)LegacyRegionBase
;
49 ThunkContext
->RealModeBufferSize
= EFI_PAGES_TO_SIZE (RealModeBufferSize
);
50 ThunkContext
->ThunkAttributes
= 3;
51 AsmPrepareThunk16(ThunkContext
);
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
62 @param Legacy8259 Instance pointer for EFI_LEGACY_8259_PROTOCOL.
66 InitializeInterruptRedirection (
67 IN EFI_LEGACY_8259_PROTOCOL
*Legacy8259
71 EFI_PHYSICAL_ADDRESS LegacyRegionBase
;
72 UINTN LegacyRegionLength
;
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
90 LegacyRegionLength
= sizeof(InterruptRedirectionCode
);
91 LegacyRegionBase
= 0x100000;
92 Status
= gBS
->AllocatePages (
95 EFI_SIZE_TO_PAGES(LegacyRegionLength
),
98 ASSERT_EFI_ERROR (Status
);
101 // Copy code to legacy region
103 CopyMem ((VOID
*)(UINTN
)LegacyRegionBase
, InterruptRedirectionCode
, sizeof (InterruptRedirectionCode
));
106 // Get VectorBase, it should be 0x68
108 Status
= Legacy8259
->GetVector (Legacy8259
, Efi8259Irq0
, &ProtectedModeBaseVector
);
109 ASSERT_EFI_ERROR (Status
);
112 // Patch IVT 0x68 ~ 0x6f
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));
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
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
131 @retval TRUE Thunk completed, and there were no BIOS errors in the target code.
133 @retval FALSE There was a BIOS erro in the target code.
138 IN BIOS_VIDEO_DEV
*BiosDev
,
140 IN EFI_IA32_REGISTER_SET
*Regs
145 IA32_REGISTER_SET ThunkRegSet
;
149 Regs
->X
.Flags
.Reserved1
= 1;
150 Regs
->X
.Flags
.Reserved2
= 0;
151 Regs
->X
.Flags
.Reserved3
= 0;
152 Regs
->X
.Flags
.Reserved4
= 0;
153 Regs
->X
.Flags
.IOPL
= 3;
154 Regs
->X
.Flags
.NT
= 0;
155 Regs
->X
.Flags
.IF
= 1;
156 Regs
->X
.Flags
.TF
= 0;
157 Regs
->X
.Flags
.CF
= 0;
159 ZeroMem (&ThunkRegSet
, sizeof (ThunkRegSet
));
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
;
170 CopyMem (&(ThunkRegSet
.E
.EFLAGS
), &(Regs
->E
.EFlags
), sizeof (UINT32
));
173 // The call to Legacy16 is a critical section to EFI
175 Eflags
= AsmReadEflags ();
176 if ((Eflags
| EFI_CPU_EFLAGS_IF
) != 0) {
177 DisableInterrupts ();
181 // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
183 Status
= BiosDev
->Legacy8259
->SetMode (BiosDev
->Legacy8259
, Efi8259LegacyMode
, NULL
, NULL
);
184 ASSERT_EFI_ERROR (Status
);
186 Stack16
= (UINT16
*)((UINT8
*) BiosDev
->ThunkContext
->RealModeBuffer
+ BiosDev
->ThunkContext
->RealModeBufferSize
- sizeof (UINT16
));
187 Stack16
-= sizeof (ThunkRegSet
.E
.EFLAGS
) / sizeof (UINT16
);
188 CopyMem (Stack16
, &ThunkRegSet
.E
.EFLAGS
, sizeof (ThunkRegSet
.E
.EFLAGS
));
190 ThunkRegSet
.E
.SS
= (UINT16
) (((UINTN
) Stack16
>> 16) << 12);
191 ThunkRegSet
.E
.ESP
= (UINT16
) (UINTN
) Stack16
;
192 ThunkRegSet
.E
.Eip
= (UINT16
)((UINT32
*)NULL
)[BiosInt
];
193 ThunkRegSet
.E
.CS
= (UINT16
)(((UINT32
*)NULL
)[BiosInt
] >> 16);
194 BiosDev
->ThunkContext
->RealModeState
= &ThunkRegSet
;
195 AsmThunk16 (BiosDev
->ThunkContext
);
198 // Restore protected mode interrupt state
200 Status
= BiosDev
->Legacy8259
->SetMode (BiosDev
->Legacy8259
, Efi8259ProtectedMode
, NULL
, NULL
);
201 ASSERT_EFI_ERROR (Status
);
204 // End critical section
206 if ((Eflags
| EFI_CPU_EFLAGS_IF
) != 0) {
210 Regs
->E
.EDI
= ThunkRegSet
.E
.EDI
;
211 Regs
->E
.ESI
= ThunkRegSet
.E
.ESI
;
212 Regs
->E
.EBP
= ThunkRegSet
.E
.EBP
;
213 Regs
->E
.EBX
= ThunkRegSet
.E
.EBX
;
214 Regs
->E
.EDX
= ThunkRegSet
.E
.EDX
;
215 Regs
->E
.ECX
= ThunkRegSet
.E
.ECX
;
216 Regs
->E
.EAX
= ThunkRegSet
.E
.EAX
;
217 Regs
->E
.SS
= ThunkRegSet
.E
.SS
;
218 Regs
->E
.CS
= ThunkRegSet
.E
.CS
;
219 Regs
->E
.DS
= ThunkRegSet
.E
.DS
;
220 Regs
->E
.ES
= ThunkRegSet
.E
.ES
;
222 CopyMem (&(Regs
->E
.EFlags
), &(ThunkRegSet
.E
.EFLAGS
), sizeof (UINT32
));
224 Ret
= (BOOLEAN
) (Regs
->E
.EFlags
.CF
== 1);