2 Provide legacy thunk interface for accessing Bios Video Rom.
4 Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>
5 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
;
33 UINT32 LegacyRegionSize
;
37 AsmGetThunk16Properties (&RealModeBufferSize
, &ExtraStackSize
);
38 LegacyRegionSize
= (((RealModeBufferSize
+ ExtraStackSize
) / EFI_PAGE_SIZE
) + 1) * EFI_PAGE_SIZE
;
39 LegacyRegionBase
= 0x100000;
40 Status
= gBS
->AllocatePages (
43 EFI_SIZE_TO_PAGES(LegacyRegionSize
),
46 ASSERT_EFI_ERROR (Status
);
48 ThunkContext
->RealModeBuffer
= (VOID
*)(UINTN
)LegacyRegionBase
;
49 ThunkContext
->RealModeBufferSize
= LegacyRegionSize
;
50 ThunkContext
->ThunkAttributes
= THUNK_ATTRIBUTE_BIG_REAL_MODE
|THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15
;
51 AsmPrepareThunk16(ThunkContext
);
55 Initialize interrupt redirection code and entries, because
56 IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.
57 Or the interrupt will lost when we do thunk.
58 NOTE: We do not reset 8259 vector base, because it will cause pending
61 @param Legacy8259 Instance pointer for EFI_LEGACY_8259_PROTOCOL.
65 InitializeInterruptRedirection (
66 IN EFI_LEGACY_8259_PROTOCOL
*Legacy8259
70 EFI_PHYSICAL_ADDRESS LegacyRegionBase
;
71 UINTN LegacyRegionLength
;
74 UINT8 ProtectedModeBaseVector
;
75 UINT32 InterruptRedirectionCode
[] = {
76 0x90CF08CD, // INT8; IRET; NOP
77 0x90CF09CD, // INT9; IRET; NOP
78 0x90CF0ACD, // INTA; IRET; NOP
79 0x90CF0BCD, // INTB; IRET; NOP
80 0x90CF0CCD, // INTC; IRET; NOP
81 0x90CF0DCD, // INTD; IRET; NOP
82 0x90CF0ECD, // INTE; IRET; NOP
83 0x90CF0FCD // INTF; IRET; NOP
89 LegacyRegionLength
= sizeof(InterruptRedirectionCode
);
90 LegacyRegionBase
= 0x100000;
91 Status
= gBS
->AllocatePages (
94 EFI_SIZE_TO_PAGES(LegacyRegionLength
),
97 ASSERT_EFI_ERROR (Status
);
100 // Copy code to legacy region
102 CopyMem ((VOID
*)(UINTN
)LegacyRegionBase
, InterruptRedirectionCode
, sizeof (InterruptRedirectionCode
));
105 // Get VectorBase, it should be 0x68
107 Status
= Legacy8259
->GetVector (Legacy8259
, Efi8259Irq0
, &ProtectedModeBaseVector
);
108 ASSERT_EFI_ERROR (Status
);
111 // Patch IVT 0x68 ~ 0x6f
113 IdtArray
= (UINT32
*) 0;
114 for (Index
= 0; Index
< 8; Index
++) {
115 IdtArray
[ProtectedModeBaseVector
+ Index
] = ((EFI_SEGMENT (LegacyRegionBase
+ Index
* 4)) << 16) | (EFI_OFFSET (LegacyRegionBase
+ Index
* 4));
122 Thunk to 16-bit real mode and execute a software interrupt with a vector
123 of BiosInt. Regs will contain the 16-bit register context on entry and
126 @param This Protocol instance pointer.
127 @param BiosInt Processor interrupt vector to invoke
128 @param Reg Register contexted passed into (and returned) from thunk to 16-bit mode
130 @retval TRUE Thunk completed, and there were no BIOS errors in the target code.
132 @retval FALSE There was a BIOS erro in the target code.
137 IN BIOS_VIDEO_DEV
*BiosDev
,
139 IN IA32_REGISTER_SET
*Regs
144 IA32_REGISTER_SET ThunkRegSet
;
148 ZeroMem (&ThunkRegSet
, sizeof (ThunkRegSet
));
149 ThunkRegSet
.E
.EFLAGS
.Bits
.Reserved_0
= 1;
150 ThunkRegSet
.E
.EFLAGS
.Bits
.Reserved_1
= 0;
151 ThunkRegSet
.E
.EFLAGS
.Bits
.Reserved_2
= 0;
152 ThunkRegSet
.E
.EFLAGS
.Bits
.Reserved_3
= 0;
153 ThunkRegSet
.E
.EFLAGS
.Bits
.IOPL
= 3;
154 ThunkRegSet
.E
.EFLAGS
.Bits
.NT
= 0;
155 ThunkRegSet
.E
.EFLAGS
.Bits
.IF
= 1;
156 ThunkRegSet
.E
.EFLAGS
.Bits
.TF
= 0;
157 ThunkRegSet
.E
.EFLAGS
.Bits
.CF
= 0;
159 ThunkRegSet
.E
.EDI
= Regs
->E
.EDI
;
160 ThunkRegSet
.E
.ESI
= Regs
->E
.ESI
;
161 ThunkRegSet
.E
.EBP
= Regs
->E
.EBP
;
162 ThunkRegSet
.E
.EBX
= Regs
->E
.EBX
;
163 ThunkRegSet
.E
.EDX
= Regs
->E
.EDX
;
164 ThunkRegSet
.E
.ECX
= Regs
->E
.ECX
;
165 ThunkRegSet
.E
.EAX
= Regs
->E
.EAX
;
166 ThunkRegSet
.E
.DS
= Regs
->E
.DS
;
167 ThunkRegSet
.E
.ES
= Regs
->E
.ES
;
170 // The call to Legacy16 is a critical section to EFI
172 Eflags
= AsmReadEflags ();
173 if ((Eflags
| EFI_CPU_EFLAGS_IF
) != 0) {
174 DisableInterrupts ();
178 // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
180 Status
= BiosDev
->Legacy8259
->SetMode (BiosDev
->Legacy8259
, Efi8259LegacyMode
, NULL
, NULL
);
181 ASSERT_EFI_ERROR (Status
);
183 Stack16
= (UINT16
*)((UINT8
*) BiosDev
->ThunkContext
->RealModeBuffer
+ BiosDev
->ThunkContext
->RealModeBufferSize
- sizeof (UINT16
));
185 ThunkRegSet
.E
.SS
= (UINT16
) (((UINTN
) Stack16
>> 16) << 12);
186 ThunkRegSet
.E
.ESP
= (UINT16
) (UINTN
) Stack16
;
188 ThunkRegSet
.E
.Eip
= (UINT16
)((UINT32
*)NULL
)[BiosInt
];
189 ThunkRegSet
.E
.CS
= (UINT16
)(((UINT32
*)NULL
)[BiosInt
] >> 16);
190 BiosDev
->ThunkContext
->RealModeState
= &ThunkRegSet
;
191 AsmThunk16 (BiosDev
->ThunkContext
);
194 // Restore protected mode interrupt state
196 Status
= BiosDev
->Legacy8259
->SetMode (BiosDev
->Legacy8259
, Efi8259ProtectedMode
, NULL
, NULL
);
197 ASSERT_EFI_ERROR (Status
);
200 // End critical section
202 if ((Eflags
| EFI_CPU_EFLAGS_IF
) != 0) {
206 Regs
->E
.EDI
= ThunkRegSet
.E
.EDI
;
207 Regs
->E
.ESI
= ThunkRegSet
.E
.ESI
;
208 Regs
->E
.EBP
= ThunkRegSet
.E
.EBP
;
209 Regs
->E
.EBX
= ThunkRegSet
.E
.EBX
;
210 Regs
->E
.EDX
= ThunkRegSet
.E
.EDX
;
211 Regs
->E
.ECX
= ThunkRegSet
.E
.ECX
;
212 Regs
->E
.EAX
= ThunkRegSet
.E
.EAX
;
213 Regs
->E
.SS
= ThunkRegSet
.E
.SS
;
214 Regs
->E
.CS
= ThunkRegSet
.E
.CS
;
215 Regs
->E
.DS
= ThunkRegSet
.E
.DS
;
216 Regs
->E
.ES
= ThunkRegSet
.E
.ES
;
218 CopyMem (&(Regs
->E
.EFLAGS
), &(ThunkRegSet
.E
.EFLAGS
), sizeof (UINT32
));
220 Ret
= (BOOLEAN
) (Regs
->E
.EFLAGS
.Bits
.CF
== 1);