2 X64 Instruction function.
4 Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include <Library/BaseMemoryLib.h>
12 #include <Register/Intel/Cpuid.h>
13 #include <IndustryStandard/InstructionParsing.h>
14 #include "CcInstruction.h"
16 #define MAX_INSTRUCTION_LENGTH 15
19 Return a pointer to the contents of the specified register.
21 Based upon the input register, return a pointer to the registers contents
22 in the x86 processor context.
24 @param[in] Regs x64 processor context
25 @param[in] Register Register to obtain pointer for
27 @return Pointer to the contents of the requested register
31 CcGetRegisterPointer (
32 IN EFI_SYSTEM_CONTEXT_X64
*Regs
,
97 Update the instruction parsing context for displacement bytes.
99 @param[in, out] InstructionData Instruction parsing context
100 @param[in] Size The instruction displacement size
105 UpdateForDisplacement (
106 IN OUT CC_INSTRUCTION_DATA
*InstructionData
,
110 InstructionData
->DisplacementSize
= Size
;
111 InstructionData
->Immediate
+= Size
;
112 InstructionData
->End
+= Size
;
116 Determine if an instruction address if RIP relative.
118 Examine the instruction parsing context to determine if the address offset
119 is relative to the instruction pointer.
121 @param[in] InstructionData Instruction parsing context
123 @retval TRUE Instruction addressing is RIP relative
124 @retval FALSE Instruction addressing is not RIP relative
130 IN CC_INSTRUCTION_DATA
*InstructionData
133 CC_INSTRUCTION_OPCODE_EXT
*Ext
;
135 Ext
= &InstructionData
->Ext
;
137 return ((InstructionData
->Mode
== LongMode64Bit
) &&
138 (Ext
->ModRm
.Mod
== 0) &&
139 (Ext
->ModRm
.Rm
== 5) &&
140 (InstructionData
->SibPresent
== FALSE
));
144 Return the effective address of a memory operand.
146 Examine the instruction parsing context to obtain the effective memory
147 address of a memory operand.
149 @param[in] Regs x64 processor context
150 @param[in] InstructionData Instruction parsing context
152 @return The memory operand effective address
157 GetEffectiveMemoryAddress (
158 IN EFI_SYSTEM_CONTEXT_X64
*Regs
,
159 IN CC_INSTRUCTION_DATA
*InstructionData
162 CC_INSTRUCTION_OPCODE_EXT
*Ext
;
163 UINT64 EffectiveAddress
;
165 Ext
= &InstructionData
->Ext
;
166 EffectiveAddress
= 0;
168 if (IsRipRelative (InstructionData
)) {
170 // RIP-relative displacement is a 32-bit signed value
174 RipRelative
= *(INT32
*)InstructionData
->Displacement
;
176 UpdateForDisplacement (InstructionData
, 4);
179 // Negative displacement is handled by standard UINT64 wrap-around.
181 return Regs
->Rip
+ (UINT64
)RipRelative
;
184 switch (Ext
->ModRm
.Mod
) {
186 UpdateForDisplacement (InstructionData
, 1);
187 EffectiveAddress
+= (UINT64
)(*(INT8
*)(InstructionData
->Displacement
));
190 switch (InstructionData
->AddrSize
) {
192 UpdateForDisplacement (InstructionData
, 2);
193 EffectiveAddress
+= (UINT64
)(*(INT16
*)(InstructionData
->Displacement
));
196 UpdateForDisplacement (InstructionData
, 4);
197 EffectiveAddress
+= (UINT64
)(*(INT32
*)(InstructionData
->Displacement
));
204 if (InstructionData
->SibPresent
) {
207 if (Ext
->Sib
.Index
!= 4) {
210 CcGetRegisterPointer (Regs
, Ext
->Sib
.Index
),
211 sizeof (Displacement
)
213 Displacement
*= (INT64
)(1 << Ext
->Sib
.Scale
);
216 // Negative displacement is handled by standard UINT64 wrap-around.
218 EffectiveAddress
+= (UINT64
)Displacement
;
221 if ((Ext
->Sib
.Base
!= 5) || Ext
->ModRm
.Mod
) {
222 EffectiveAddress
+= *CcGetRegisterPointer (Regs
, Ext
->Sib
.Base
);
224 UpdateForDisplacement (InstructionData
, 4);
225 EffectiveAddress
+= (UINT64
)(*(INT32
*)(InstructionData
->Displacement
));
228 EffectiveAddress
+= *CcGetRegisterPointer (Regs
, Ext
->ModRm
.Rm
);
231 return EffectiveAddress
;
237 Examine the instruction parsing context to decode a ModRM byte and the SIB
240 @param[in] Regs x64 processor context
241 @param[in, out] InstructionData Instruction parsing context
246 IN EFI_SYSTEM_CONTEXT_X64
*Regs
,
247 IN OUT CC_INSTRUCTION_DATA
*InstructionData
250 CC_INSTRUCTION_OPCODE_EXT
*Ext
;
251 INSTRUCTION_REX_PREFIX
*RexPrefix
;
252 INSTRUCTION_MODRM
*ModRm
;
253 INSTRUCTION_SIB
*Sib
;
255 RexPrefix
= &InstructionData
->RexPrefix
;
256 Ext
= &InstructionData
->Ext
;
257 ModRm
= &InstructionData
->ModRm
;
258 Sib
= &InstructionData
->Sib
;
260 InstructionData
->ModRmPresent
= TRUE
;
261 ModRm
->Uint8
= *(InstructionData
->End
);
263 InstructionData
->Displacement
++;
264 InstructionData
->Immediate
++;
265 InstructionData
->End
++;
267 Ext
->ModRm
.Mod
= ModRm
->Bits
.Mod
;
268 Ext
->ModRm
.Reg
= (RexPrefix
->Bits
.BitR
<< 3) | ModRm
->Bits
.Reg
;
269 Ext
->ModRm
.Rm
= (RexPrefix
->Bits
.BitB
<< 3) | ModRm
->Bits
.Rm
;
271 Ext
->RegData
= *CcGetRegisterPointer (Regs
, Ext
->ModRm
.Reg
);
273 if (Ext
->ModRm
.Mod
== 3) {
274 Ext
->RmData
= *CcGetRegisterPointer (Regs
, Ext
->ModRm
.Rm
);
276 if (ModRm
->Bits
.Rm
== 4) {
277 InstructionData
->SibPresent
= TRUE
;
278 Sib
->Uint8
= *(InstructionData
->End
);
280 InstructionData
->Displacement
++;
281 InstructionData
->Immediate
++;
282 InstructionData
->End
++;
284 Ext
->Sib
.Scale
= Sib
->Bits
.Scale
;
285 Ext
->Sib
.Index
= (RexPrefix
->Bits
.BitX
<< 3) | Sib
->Bits
.Index
;
286 Ext
->Sib
.Base
= (RexPrefix
->Bits
.BitB
<< 3) | Sib
->Bits
.Base
;
289 Ext
->RmData
= GetEffectiveMemoryAddress (Regs
, InstructionData
);
294 Decode instruction prefixes.
296 Parse the instruction data to track the instruction prefixes that have
299 @param[in] Regs x64 processor context
300 @param[in, out] InstructionData Instruction parsing context
302 @retval EFI_SUCCESS Successfully decode Prefixes
303 @retval Others Other error as indicated
308 IN EFI_SYSTEM_CONTEXT_X64
*Regs
,
309 IN OUT CC_INSTRUCTION_DATA
*InstructionData
312 CC_INSTRUCTION_MODE Mode
;
313 CC_INSTRUCTION_SIZE ModeDataSize
;
314 CC_INSTRUCTION_SIZE ModeAddrSize
;
321 // Always in 64-bit mode
323 Mode
= LongMode64Bit
;
324 ModeDataSize
= Size32Bits
;
325 ModeAddrSize
= Size64Bits
;
327 InstructionData
->Mode
= Mode
;
328 InstructionData
->DataSize
= ModeDataSize
;
329 InstructionData
->AddrSize
= ModeAddrSize
;
331 InstructionData
->Prefixes
= InstructionData
->Begin
;
333 Byte
= InstructionData
->Prefixes
;
334 for ( ; ParsedLength
<= MAX_INSTRUCTION_LENGTH
; Byte
++, InstructionData
->PrefixSize
++, ParsedLength
++) {
336 // Check the 0x40 to 0x4F range using an if statement here since some
337 // compilers don't like the "case 0x40 ... 0x4F:" syntax. This avoids
338 // 16 case statements below.
340 if ((*Byte
>= REX_PREFIX_START
) && (*Byte
<= REX_PREFIX_STOP
)) {
341 InstructionData
->RexPrefix
.Uint8
= *Byte
;
342 if ((*Byte
& REX_64BIT_OPERAND_SIZE_MASK
) != 0) {
343 InstructionData
->DataSize
= Size64Bits
;
350 case OVERRIDE_SEGMENT_CS
:
351 case OVERRIDE_SEGMENT_DS
:
352 case OVERRIDE_SEGMENT_ES
:
353 case OVERRIDE_SEGMENT_SS
:
354 if (Mode
!= LongMode64Bit
) {
355 InstructionData
->SegmentSpecified
= TRUE
;
356 InstructionData
->Segment
= (*Byte
>> 3) & 3;
361 case OVERRIDE_SEGMENT_FS
:
362 case OVERRIDE_SEGMENT_GS
:
363 InstructionData
->SegmentSpecified
= TRUE
;
364 InstructionData
->Segment
= *Byte
& 7;
367 case OVERRIDE_OPERAND_SIZE
:
368 if (InstructionData
->RexPrefix
.Uint8
== 0) {
369 InstructionData
->DataSize
=
370 (Mode
== LongMode64Bit
) ? Size16Bits
:
371 (Mode
== LongModeCompat32Bit
) ? Size16Bits
:
372 (Mode
== LongModeCompat16Bit
) ? Size32Bits
: 0;
377 case OVERRIDE_ADDRESS_SIZE
:
378 InstructionData
->AddrSize
=
379 (Mode
== LongMode64Bit
) ? Size32Bits
:
380 (Mode
== LongModeCompat32Bit
) ? Size16Bits
:
381 (Mode
== LongModeCompat16Bit
) ? Size32Bits
: 0;
388 InstructionData
->RepMode
= RepZ
;
392 InstructionData
->RepMode
= RepNZ
;
396 InstructionData
->OpCodes
= Byte
;
397 InstructionData
->OpCodeSize
= (*Byte
== TWO_BYTE_OPCODE_ESCAPE
) ? 2 : 1;
399 InstructionData
->End
= Byte
+ InstructionData
->OpCodeSize
;
400 InstructionData
->Displacement
= InstructionData
->End
;
401 InstructionData
->Immediate
= InstructionData
->End
;
410 Determine instruction length
412 Return the total length of the parsed instruction.
414 @param[in] InstructionData Instruction parsing context
416 @return Length of parsed instruction
420 CcInstructionLength (
421 IN CC_INSTRUCTION_DATA
*InstructionData
424 return (UINT64
)(InstructionData
->End
- InstructionData
->Begin
);
428 Initialize the instruction parsing context.
430 Initialize the instruction parsing context, which includes decoding the
431 instruction prefixes.
433 @param[in, out] InstructionData Instruction parsing context
434 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication
436 @param[in] Regs x64 processor context
438 @retval EFI_SUCCESS Successfully initialize InstructionData
439 @retval Others Other error as indicated
442 CcInitInstructionData (
443 IN OUT CC_INSTRUCTION_DATA
*InstructionData
,
445 IN EFI_SYSTEM_CONTEXT_X64
*Regs
448 SetMem (InstructionData
, sizeof (*InstructionData
), 0);
449 InstructionData
->Ghcb
= Ghcb
;
450 InstructionData
->Begin
= (UINT8
*)Regs
->Rip
;
451 InstructionData
->End
= (UINT8
*)Regs
->Rip
;
453 return DecodePrefixes (Regs
, InstructionData
);