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 IA32_REGISTER_SET
*Regs
145 IA32_REGISTER_SET ThunkRegSet
;
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;
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
;
171 // The call to Legacy16 is a critical section to EFI
173 Eflags
= AsmReadEflags ();
174 if ((Eflags
| EFI_CPU_EFLAGS_IF
) != 0) {
175 DisableInterrupts ();
179 // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
181 Status
= BiosDev
->Legacy8259
->SetMode (BiosDev
->Legacy8259
, Efi8259LegacyMode
, NULL
, NULL
);
182 ASSERT_EFI_ERROR (Status
);
184 Stack16
= (UINT16
*)((UINT8
*) BiosDev
->ThunkContext
->RealModeBuffer
+ BiosDev
->ThunkContext
->RealModeBufferSize
- sizeof (UINT16
));
186 ThunkRegSet
.E
.SS
= (UINT16
) (((UINTN
) Stack16
>> 16) << 12);
187 ThunkRegSet
.E
.ESP
= (UINT16
) (UINTN
) Stack16
;
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
);
195 // Restore protected mode interrupt state
197 Status
= BiosDev
->Legacy8259
->SetMode (BiosDev
->Legacy8259
, Efi8259ProtectedMode
, NULL
, NULL
);
198 ASSERT_EFI_ERROR (Status
);
201 // End critical section
203 if ((Eflags
| EFI_CPU_EFLAGS_IF
) != 0) {
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
;
219 CopyMem (&(Regs
->E
.EFLAGS
), &(ThunkRegSet
.E
.EFLAGS
), sizeof (UINT32
));
221 Ret
= (BOOLEAN
) (Regs
->E
.EFLAGS
.Bits
.CF
== 1);