aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/MdeModulePkg/Universal/EbcDxe
diff options
context:
space:
mode:
Diffstat (limited to 'roms/edk2/MdeModulePkg/Universal/EbcDxe')
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/AArch64/EbcLowLevel.S156
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/AArch64/EbcSupport.c475
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger.inf108
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger.uni13
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EbcDebuggerConfig.c247
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.c585
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.h60
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBranch.c306
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreak.c288
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreakpoint.c542
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdExtIo.c176
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdExtPci.c145
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdGo.c76
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdHelp.c68
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdMemory.c578
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdQuit.c38
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdRegister.c118
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdScope.c99
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdStep.c156
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdSymbol.c862
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommand.c656
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommand.h115
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommon.h239
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasm.c1770
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasm.h30
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasmSupport.c1211
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasmSupport.h567
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.c833
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.h14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupport.h477
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportFile.c384
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportString.c1020
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportUI.c754
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c2230
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.h244
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfig.inf57
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfig.uni13
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfigExtra.uni12
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerExtra.uni12
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerHook.c267
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerHook.h241
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxe.inf81
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxe.uni18
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxeExtra.uni14
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcExecute.c5383
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcExecute.h135
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcInt.c1542
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcInt.h260
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/Ia32/EbcLowLevel.nasm191
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/Ia32/EbcSupport.c526
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/X64/EbcLowLevel.nasm236
-rw-r--r--roms/edk2/MdeModulePkg/Universal/EbcDxe/X64/EbcSupport.c570
52 files changed, 25198 insertions, 0 deletions
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/AArch64/EbcLowLevel.S b/roms/edk2/MdeModulePkg/Universal/EbcDxe/AArch64/EbcLowLevel.S
new file mode 100644
index 000000000..a84d5b330
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/AArch64/EbcLowLevel.S
@@ -0,0 +1,156 @@
+///** @file
+//
+// This code provides low level routines that support the Virtual Machine
+// for option ROMs.
+//
+// Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
+// Copyright (c) 2015, The Linux Foundation. All rights reserved.<BR>
+// Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+//**/
+
+ASM_GLOBAL ASM_PFX(EbcLLCALLEXNative)
+ASM_GLOBAL ASM_PFX(EbcLLEbcInterpret)
+ASM_GLOBAL ASM_PFX(EbcLLExecuteEbcImageEntryPoint)
+
+ASM_GLOBAL ASM_PFX(mEbcInstructionBufferTemplate)
+
+//****************************************************************************
+// EbcLLCALLEX
+//
+// This function is called to execute an EBC CALLEX instruction.
+// This instruction requires that we thunk out to external native
+// code. For AArch64, we copy the VM stack into the main stack and then pop
+// the first 8 arguments off according to the AArch64 Procedure Call Standard
+// On return, we restore the stack pointer to its original location.
+//
+//****************************************************************************
+// UINTN EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr)
+ASM_PFX(EbcLLCALLEXNative):
+ mov x8, x0 // Preserve x0
+ mov x9, x1 // Preserve x1
+
+ //
+ // If the EBC stack frame is smaller than or equal to 64 bytes, we know there
+ // are no stacked arguments #9 and beyond that we need to copy to the native
+ // stack. In this case, we can perform a tail call which is much more
+ // efficient, since there is no need to touch the native stack at all.
+ //
+ sub x3, x2, x1 // Length = NewStackPointer - FramePtr
+ cmp x3, #64
+ b.gt 1f
+
+ //
+ // While probably harmless in practice, we should not access the VM stack
+ // outside of the interval [NewStackPointer, FramePtr), which means we
+ // should not blindly fill all 8 argument registers with VM stack data.
+ // So instead, calculate how many argument registers we can fill based on
+ // the size of the VM stack frame, and skip the remaining ones.
+ //
+ adr x0, 0f // Take address of 'br' instruction below
+ bic x3, x3, #7 // Ensure correct alignment
+ sub x0, x0, x3, lsr #1 // Subtract 4 bytes for each arg to unstack
+ br x0 // Skip remaining argument registers
+
+ ldr x7, [x9, #56] // Call with 8 arguments
+ ldr x6, [x9, #48] // |
+ ldr x5, [x9, #40] // |
+ ldr x4, [x9, #32] // |
+ ldr x3, [x9, #24] // |
+ ldr x2, [x9, #16] // |
+ ldr x1, [x9, #8] // V
+ ldr x0, [x9] // Call with 1 argument
+
+0: br x8 // Call with no arguments
+
+ //
+ // More than 64 bytes: we need to build the full native stack frame and copy
+ // the part of the VM stack exceeding 64 bytes (which may contain stacked
+ // arguments) to the native stack
+ //
+1: stp x29, x30, [sp, #-16]!
+ mov x29, sp
+
+ //
+ // Ensure that the stack pointer remains 16 byte aligned,
+ // even if the size of the VM stack frame is not a multiple of 16
+ //
+ add x1, x1, #64 // Skip over [potential] reg params
+ tbz x3, #3, 2f // Multiple of 16?
+ ldr x4, [x2, #-8]! // No? Then push one word
+ str x4, [sp, #-16]! // ... but use two slots
+ b 3f
+
+2: ldp x4, x5, [x2, #-16]!
+ stp x4, x5, [sp, #-16]!
+3: cmp x2, x1
+ b.gt 2b
+
+ ldp x0, x1, [x9]
+ ldp x2, x3, [x9, #16]
+ ldp x4, x5, [x9, #32]
+ ldp x6, x7, [x9, #48]
+
+ blr x8
+
+ mov sp, x29
+ ldp x29, x30, [sp], #16
+ ret
+
+//****************************************************************************
+// EbcLLEbcInterpret
+//
+// This function is called by the thunk code to handle an Native to EBC call
+// This can handle up to 16 arguments (1-8 on in x0-x7, 9-16 are on the stack)
+// x16 contains the Entry point that will be the first stacked argument when
+// EBCInterpret is called.
+//
+//****************************************************************************
+ASM_PFX(EbcLLEbcInterpret):
+ stp x29, x30, [sp, #-16]!
+ mov x29, sp
+
+ // push the entry point and the address of args #9 - #16 onto the stack
+ add x17, sp, #16
+ stp x16, x17, [sp, #-16]!
+
+ // call C-code
+ bl ASM_PFX(EbcInterpret)
+
+ add sp, sp, #16
+ ldp x29, x30, [sp], #16
+ ret
+
+//****************************************************************************
+// EbcLLExecuteEbcImageEntryPoint
+//
+// This function is called by the thunk code to handle the image entry point
+// x16 contains the Entry point that will be the third argument when
+// ExecuteEbcImageEntryPoint is called.
+//
+//****************************************************************************
+ASM_PFX(EbcLLExecuteEbcImageEntryPoint):
+ mov x2, x16
+
+ // tail call to C code
+ b ASM_PFX(ExecuteEbcImageEntryPoint)
+
+//****************************************************************************
+// mEbcInstructionBufferTemplate
+//****************************************************************************
+ .section ".rodata", "a"
+ .align 3
+ASM_PFX(mEbcInstructionBufferTemplate):
+ adr x17, 0f
+ ldp x16, x17, [x17]
+ br x17
+
+ //
+ // Add a magic code here to help the VM recognize the thunk.
+ //
+ hlt #0xEBC
+
+0: .quad 0 // EBC_ENTRYPOINT_SIGNATURE
+ .quad 0 // EBC_LL_EBC_ENTRYPOINT_SIGNATURE
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/AArch64/EbcSupport.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/AArch64/EbcSupport.c
new file mode 100644
index 000000000..a9512bd85
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/AArch64/EbcSupport.c
@@ -0,0 +1,475 @@
+/** @file
+ This module contains EBC support routines that are customized based on
+ the target AArch64 processor.
+
+Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
+Copyright (c) 2015, The Linux Foundation. All rights reserved.<BR>
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EbcInt.h"
+#include "EbcExecute.h"
+#include "EbcDebuggerHook.h"
+
+//
+// Amount of space that is not used in the stack
+//
+#define STACK_REMAIN_SIZE (1024 * 4)
+
+#pragma pack(1)
+typedef struct {
+ UINT32 Instr[3];
+ UINT32 Magic;
+ UINT64 EbcEntryPoint;
+ UINT64 EbcLlEntryPoint;
+} EBC_INSTRUCTION_BUFFER;
+#pragma pack()
+
+extern CONST EBC_INSTRUCTION_BUFFER mEbcInstructionBufferTemplate;
+
+/**
+ Begin executing an EBC image.
+ This is used for Ebc Thunk call.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+EbcLLEbcInterpret (
+ VOID
+ );
+
+/**
+ Begin executing an EBC image.
+ This is used for Ebc image entrypoint.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+EbcLLExecuteEbcImageEntryPoint (
+ VOID
+ );
+
+/**
+ Pushes a 64 bit unsigned value to the VM stack.
+
+ @param VmPtr The pointer to current VM context.
+ @param Arg The value to be pushed.
+
+**/
+VOID
+PushU64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Arg
+ )
+{
+ //
+ // Advance the VM stack down, and then copy the argument to the stack.
+ // Hope it's aligned.
+ //
+ VmPtr->Gpr[0] -= sizeof (UINT64);
+ *(UINT64 *) VmPtr->Gpr[0] = Arg;
+ return;
+}
+
+
+/**
+ Begin executing an EBC image.
+
+ This is a thunk function.
+
+ @param Arg1 The 1st argument.
+ @param Arg2 The 2nd argument.
+ @param Arg3 The 3rd argument.
+ @param Arg4 The 4th argument.
+ @param Arg5 The 5th argument.
+ @param Arg6 The 6th argument.
+ @param Arg7 The 7th argument.
+ @param Arg8 The 8th argument.
+ @param EntryPoint The entrypoint of EBC code.
+ @param Args9_16[] Array containing arguments #9 to #16.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+EbcInterpret (
+ IN UINTN Arg1,
+ IN UINTN Arg2,
+ IN UINTN Arg3,
+ IN UINTN Arg4,
+ IN UINTN Arg5,
+ IN UINTN Arg6,
+ IN UINTN Arg7,
+ IN UINTN Arg8,
+ IN UINTN EntryPoint,
+ IN CONST UINTN Args9_16[]
+ )
+{
+ //
+ // Create a new VM context on the stack
+ //
+ VM_CONTEXT VmContext;
+ UINTN Addr;
+ EFI_STATUS Status;
+ UINTN StackIndex;
+
+ //
+ // Get the EBC entry point
+ //
+ Addr = EntryPoint;
+
+ //
+ // Now clear out our context
+ //
+ ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
+
+ //
+ // Set the VM instruction pointer to the correct location in memory.
+ //
+ VmContext.Ip = (VMIP) Addr;
+
+ //
+ // Initialize the stack pointer for the EBC. Get the current system stack
+ // pointer and adjust it down by the max needed for the interpreter.
+ //
+
+ //
+ // Adjust the VM's stack pointer down.
+ //
+
+ Status = GetEBCStack((EFI_HANDLE)(UINTN)-1, &VmContext.StackPool, &StackIndex);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
+ VmContext.Gpr[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
+ VmContext.HighStackBottom = (UINTN) VmContext.Gpr[0];
+ VmContext.Gpr[0] -= sizeof (UINTN);
+
+ //
+ // Align the stack on a natural boundary.
+ //
+ VmContext.Gpr[0] &= ~(VM_REGISTER)(sizeof (UINTN) - 1);
+
+ //
+ // Put a magic value in the stack gap, then adjust down again.
+ //
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) VM_STACK_KEY_VALUE;
+ VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.Gpr[0];
+
+ //
+ // The stack upper to LowStackTop is belong to the VM.
+ //
+ VmContext.LowStackTop = (UINTN) VmContext.Gpr[0];
+
+ //
+ // For the worst case, assume there are 4 arguments passed in registers, store
+ // them to VM's stack.
+ //
+ PushU64 (&VmContext, (UINT64) Args9_16[7]);
+ PushU64 (&VmContext, (UINT64) Args9_16[6]);
+ PushU64 (&VmContext, (UINT64) Args9_16[5]);
+ PushU64 (&VmContext, (UINT64) Args9_16[4]);
+ PushU64 (&VmContext, (UINT64) Args9_16[3]);
+ PushU64 (&VmContext, (UINT64) Args9_16[2]);
+ PushU64 (&VmContext, (UINT64) Args9_16[1]);
+ PushU64 (&VmContext, (UINT64) Args9_16[0]);
+ PushU64 (&VmContext, (UINT64) Arg8);
+ PushU64 (&VmContext, (UINT64) Arg7);
+ PushU64 (&VmContext, (UINT64) Arg6);
+ PushU64 (&VmContext, (UINT64) Arg5);
+ PushU64 (&VmContext, (UINT64) Arg4);
+ PushU64 (&VmContext, (UINT64) Arg3);
+ PushU64 (&VmContext, (UINT64) Arg2);
+ PushU64 (&VmContext, (UINT64) Arg1);
+
+ //
+ // Interpreter assumes 64-bit return address is pushed on the stack.
+ // AArch64 does not do this so pad the stack accordingly.
+ //
+ PushU64 (&VmContext, (UINT64) 0);
+ PushU64 (&VmContext, (UINT64) 0x1234567887654321ULL);
+
+ //
+ // For AArch64, this is where we say our return address is
+ //
+ VmContext.StackRetAddr = (UINT64) VmContext.Gpr[0];
+
+ //
+ // We need to keep track of where the EBC stack starts. This way, if the EBC
+ // accesses any stack variables above its initial stack setting, then we know
+ // it's accessing variables passed into it, which means the data is on the
+ // VM's stack.
+ // When we're called, on the stack (high to low) we have the parameters, the
+ // return address, then the saved ebp. Save the pointer to the return address.
+ // EBC code knows that's there, so should look above it for function parameters.
+ // The offset is the size of locals (VMContext + Addr + saved ebp).
+ // Note that the interpreter assumes there is a 16 bytes of return address on
+ // the stack too, so adjust accordingly.
+ // VmContext.HighStackBottom = (UINTN)(Addr + sizeof (VmContext) + sizeof (Addr));
+ //
+
+ //
+ // Begin executing the EBC code
+ //
+ EbcDebuggerHookEbcInterpret (&VmContext);
+ EbcExecute (&VmContext);
+
+ //
+ // Return the value in R[7] unless there was an error
+ //
+ ReturnEBCStack(StackIndex);
+ return (UINT64) VmContext.Gpr[7];
+}
+
+
+/**
+ Begin executing an EBC image.
+
+ @param ImageHandle image handle for the EBC application we're executing
+ @param SystemTable standard system table passed into an driver's entry
+ point
+ @param EntryPoint The entrypoint of EBC code.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+ExecuteEbcImageEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable,
+ IN UINTN EntryPoint
+ )
+{
+ //
+ // Create a new VM context on the stack
+ //
+ VM_CONTEXT VmContext;
+ UINTN Addr;
+ EFI_STATUS Status;
+ UINTN StackIndex;
+
+ //
+ // Get the EBC entry point
+ //
+ Addr = EntryPoint;
+
+ //
+ // Now clear out our context
+ //
+ ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
+
+ //
+ // Save the image handle so we can track the thunks created for this image
+ //
+ VmContext.ImageHandle = ImageHandle;
+ VmContext.SystemTable = SystemTable;
+
+ //
+ // Set the VM instruction pointer to the correct location in memory.
+ //
+ VmContext.Ip = (VMIP) Addr;
+
+ //
+ // Initialize the stack pointer for the EBC. Get the current system stack
+ // pointer and adjust it down by the max needed for the interpreter.
+ //
+
+ Status = GetEBCStack(ImageHandle, &VmContext.StackPool, &StackIndex);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
+ VmContext.Gpr[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
+ VmContext.HighStackBottom = (UINTN) VmContext.Gpr[0];
+ VmContext.Gpr[0] -= sizeof (UINTN);
+
+
+ //
+ // Put a magic value in the stack gap, then adjust down again
+ //
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) VM_STACK_KEY_VALUE;
+ VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.Gpr[0];
+
+ //
+ // Align the stack on a natural boundary
+ VmContext.Gpr[0] &= ~(VM_REGISTER)(sizeof(UINTN) - 1);
+ //
+ VmContext.LowStackTop = (UINTN) VmContext.Gpr[0];
+
+ //
+ // Simply copy the image handle and system table onto the EBC stack.
+ // Greatly simplifies things by not having to spill the args.
+ //
+ PushU64 (&VmContext, (UINT64) SystemTable);
+ PushU64 (&VmContext, (UINT64) ImageHandle);
+
+ //
+ // VM pushes 16-bytes for return address. Simulate that here.
+ //
+ PushU64 (&VmContext, (UINT64) 0);
+ PushU64 (&VmContext, (UINT64) 0x1234567887654321ULL);
+
+ //
+ // For AArch64, this is where we say our return address is
+ //
+ VmContext.StackRetAddr = (UINT64) VmContext.Gpr[0];
+
+ //
+ // Entry function needn't access high stack context, simply
+ // put the stack pointer here.
+ //
+
+ //
+ // Begin executing the EBC code
+ //
+ EbcDebuggerHookExecuteEbcImageEntryPoint (&VmContext);
+ EbcExecute (&VmContext);
+
+ //
+ // Return the value in R[7] unless there was an error
+ //
+ ReturnEBCStack(StackIndex);
+ return (UINT64) VmContext.Gpr[7];
+}
+
+
+/**
+ Create thunks for an EBC image entry point, or an EBC protocol service.
+
+ @param ImageHandle Image handle for the EBC image. If not null, then
+ we're creating a thunk for an image entry point.
+ @param EbcEntryPoint Address of the EBC code that the thunk is to call
+ @param Thunk Returned thunk we create here
+ @param Flags Flags indicating options for creating the thunk
+
+ @retval EFI_SUCCESS The thunk was created successfully.
+ @retval EFI_INVALID_PARAMETER The parameter of EbcEntryPoint is not 16-bit
+ aligned.
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory to created the EBC
+ Thunk.
+ @retval EFI_BUFFER_TOO_SMALL EBC_THUNK_SIZE is not larger enough.
+
+**/
+EFI_STATUS
+EbcCreateThunks (
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *EbcEntryPoint,
+ OUT VOID **Thunk,
+ IN UINT32 Flags
+ )
+{
+ EBC_INSTRUCTION_BUFFER *InstructionBuffer;
+
+ //
+ // Check alignment of pointer to EBC code
+ //
+ if ((UINT32) (UINTN) EbcEntryPoint & 0x01) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ InstructionBuffer = EbcAllocatePoolForThunk (sizeof (EBC_INSTRUCTION_BUFFER));
+ if (InstructionBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Give them the address of our buffer we're going to fix up
+ //
+ *Thunk = InstructionBuffer;
+
+ //
+ // Copy whole thunk instruction buffer template
+ //
+ CopyMem (InstructionBuffer, &mEbcInstructionBufferTemplate,
+ sizeof (EBC_INSTRUCTION_BUFFER));
+
+ //
+ // Patch EbcEntryPoint and EbcLLEbcInterpret
+ //
+ InstructionBuffer->EbcEntryPoint = (UINT64)EbcEntryPoint;
+ if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {
+ InstructionBuffer->EbcLlEntryPoint = (UINT64)EbcLLExecuteEbcImageEntryPoint;
+ } else {
+ InstructionBuffer->EbcLlEntryPoint = (UINT64)EbcLLEbcInterpret;
+ }
+
+ //
+ // Add the thunk to the list for this image. Do this last since the add
+ // function flushes the cache for us.
+ //
+ EbcAddImageThunk (ImageHandle, InstructionBuffer,
+ sizeof (EBC_INSTRUCTION_BUFFER));
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function is called to execute an EBC CALLEX instruction.
+ The function check the callee's content to see whether it is common native
+ code or a thunk to another piece of EBC code.
+ If the callee is common native code, use EbcLLCAllEXASM to manipulate,
+ otherwise, set the VM->IP to target EBC code directly to avoid another VM
+ be startup which cost time and stack space.
+
+ @param VmPtr Pointer to a VM context.
+ @param FuncAddr Callee's address
+ @param NewStackPointer New stack pointer after the call
+ @param FramePtr New frame pointer after the call
+ @param Size The size of call instruction
+
+**/
+VOID
+EbcLLCALLEX (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN FuncAddr,
+ IN UINTN NewStackPointer,
+ IN VOID *FramePtr,
+ IN UINT8 Size
+ )
+{
+ CONST EBC_INSTRUCTION_BUFFER *InstructionBuffer;
+
+ //
+ // Processor specific code to check whether the callee is a thunk to EBC.
+ //
+ InstructionBuffer = (EBC_INSTRUCTION_BUFFER *)FuncAddr;
+
+ if (CompareMem (InstructionBuffer, &mEbcInstructionBufferTemplate,
+ sizeof(EBC_INSTRUCTION_BUFFER) - 2 * sizeof (UINT64)) == 0) {
+ //
+ // The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and
+ // put our return address and frame pointer on the VM stack.
+ // Then set the VM's IP to new EBC code.
+ //
+ VmPtr->Gpr[0] -= 8;
+ VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], (UINTN) FramePtr);
+ VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0];
+ VmPtr->Gpr[0] -= 8;
+ VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (VmPtr->Ip + Size));
+
+ VmPtr->Ip = (VMIP) InstructionBuffer->EbcEntryPoint;
+ } else {
+ //
+ // The callee is not a thunk to EBC, call native code,
+ // and get return value.
+ //
+ VmPtr->Gpr[7] = EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr);
+
+ //
+ // Advance the IP.
+ //
+ VmPtr->Ip += Size;
+ }
+}
+
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger.inf b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger.inf
new file mode 100644
index 000000000..e94231760
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger.inf
@@ -0,0 +1,108 @@
+## @file
+# EFI Byte Code (EBC) Debugger.
+#
+# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EbcDebugger
+ MODULE_UNI_FILE = EbcDebugger.uni
+ FILE_GUID = 8296AF37-D183-4416-B3B6-19D2A80AD4A8
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeEbcDriver
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 AARCH64
+#
+
+[Sources]
+ EbcDebuggerHook.h
+ EbcInt.c
+ EbcInt.h
+ EbcExecute.c
+ EbcExecute.h
+ EbcDebugger/Edb.c
+ EbcDebugger/Edb.h
+ EbcDebugger/EdbCommon.h
+ EbcDebugger/EdbCmdBranch.c
+ EbcDebugger/EdbCmdBreak.c
+ EbcDebugger/EdbCmdBreakpoint.c
+ EbcDebugger/EdbCmdGo.c
+ EbcDebugger/EdbCmdHelp.c
+ EbcDebugger/EdbCmdMemory.c
+ EbcDebugger/EdbCmdRegister.c
+ EbcDebugger/EdbCmdQuit.c
+ EbcDebugger/EdbCmdScope.c
+ EbcDebugger/EdbCmdStep.c
+ EbcDebugger/EdbCmdSymbol.c
+ EbcDebugger/EdbCmdExtIo.c
+ EbcDebugger/EdbCmdExtPci.c
+ EbcDebugger/EdbCommand.c
+ EbcDebugger/EdbCommand.h
+ EbcDebugger/EdbDisasm.c
+ EbcDebugger/EdbDisasm.h
+ EbcDebugger/EdbDisasmSupport.c
+ EbcDebugger/EdbDisasmSupport.h
+ EbcDebugger/EdbSymbol.c
+ EbcDebugger/EdbSymbol.h
+ EbcDebugger/EdbHook.c
+ EbcDebugger/EdbHook.h
+ EbcDebugger/EdbSupport.h
+ EbcDebugger/EdbSupportUI.c
+ EbcDebugger/EdbSupportString.c
+ EbcDebugger/EdbSupportFile.c
+
+[Sources.Ia32]
+ Ia32/EbcSupport.c
+ Ia32/EbcLowLevel.nasm
+
+[Sources.X64]
+ X64/EbcSupport.c
+ X64/EbcLowLevel.nasm
+
+[Sources.AARCH64]
+ AArch64/EbcSupport.c
+ AArch64/EbcLowLevel.S
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ DebugLib
+ BaseLib
+ CacheMaintenanceLib
+ PeCoffLib
+
+[Protocols]
+ gEfiDebugSupportProtocolGuid ## PRODUCES
+ gEfiEbcProtocolGuid ## PRODUCES
+ gEfiDebuggerConfigurationProtocolGuid ## PRODUCES
+ gEfiEbcVmTestProtocolGuid ## SOMETIMES_PRODUCES
+ gEfiEbcSimpleDebuggerProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiPciRootBridgeIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiPeCoffImageEmulatorProtocolGuid ## PRODUCES
+
+[Guids]
+ gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiDebugImageInfoTableGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ EbcDebuggerExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger.uni b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger.uni
new file mode 100644
index 000000000..11776211d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger.uni
@@ -0,0 +1,13 @@
+// /** @file
+// EFI Byte Code (EBC) Debugger.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "EFI Byte Code (EBC) Debugger application"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This application enables the debugging of EBC runtimes."
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EbcDebuggerConfig.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EbcDebuggerConfig.c
new file mode 100644
index 000000000..966dfb717
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EbcDebuggerConfig.c
@@ -0,0 +1,247 @@
+/** @file
+ Configuration application for the EBC Debugger.
+
+ Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Protocol/ShellParameters.h>
+
+#include "EdbCommon.h"
+#include "EdbSupport.h"
+
+/**
+
+ The function that displays the utility usage message.
+
+**/
+VOID
+PrintUsage (
+ VOID
+ )
+{
+ Print (
+ L"EbcDebuggerConfig Version 1.0\n"
+ L"Copyright (C) Intel Corp 2007-2016. All rights reserved.\n"
+ L"\n"
+ L"Configure EbcDebugger in EFI Shell Environment.\n"
+ L"\n"
+ L"usage: EdbCfg <Command>\n"
+ L" CommandList:\n"
+ L" BO[C|CX|R|E|T|K] <ON|OFF> - Enable/Disable BOC/BOCX/BOR/BOE/BOT/BOK.\n"
+// L" SHOWINFO - Show Debugger Information.\n"
+ L"\n"
+ );
+ return;
+}
+
+/**
+
+ The function is to show some information.
+
+ @param DebuggerConfiguration Point to the EFI_DEBUGGER_CONFIGURATION_PROTOCOL.
+
+**/
+VOID
+EdbShowInfo (
+ EFI_DEBUGGER_CONFIGURATION_PROTOCOL *DebuggerConfiguration
+ )
+{
+ Print (L"Not supported!\n");
+ return ;
+}
+
+/**
+
+ EdbConfigBreak function.
+
+ @param DebuggerConfiguration Point to the EFI_DEBUGGER_CONFIGURATION_PROTOCOL.
+ @param Command Point to the command.
+ @param CommandArg The argument for this command.
+
+**/
+VOID
+EdbConfigBreak (
+ EFI_DEBUGGER_CONFIGURATION_PROTOCOL *DebuggerConfiguration,
+ CHAR16 *Command,
+ CHAR16 *CommandArg
+ )
+{
+ EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate;
+
+ DebuggerPrivate = (EFI_DEBUGGER_PRIVATE_DATA *)DebuggerConfiguration->DebuggerPrivateData;
+
+ if (StriCmp (Command, L"BOC") == 0) {
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOC) == EFI_DEBUG_FLAG_EBC_BOC) {
+ Print (L"BOC on\n");
+ } else {
+ Print (L"BOC off\n");
+ }
+ } else if (StriCmp (CommandArg, L"ON") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOC;
+ } else if (StriCmp (CommandArg, L"OFF") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOC;
+ } else {
+ Print (L"Invalid parameter\n");
+ }
+ } else if (StriCmp (Command, L"BOCX") == 0) {
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOCX) == EFI_DEBUG_FLAG_EBC_BOCX) {
+ Print (L"BOCX on\n");
+ } else {
+ Print (L"BOCX off\n");
+ }
+ } else if (StriCmp (CommandArg, L"ON") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOCX;
+ } else if (StriCmp (CommandArg, L"OFF") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOCX;
+ } else {
+ Print (L"Invalid parameter\n");
+ }
+ } else if (StriCmp (Command, L"BOR") == 0) {
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOR) == EFI_DEBUG_FLAG_EBC_BOR) {
+ Print (L"BOR on\n");
+ } else {
+ Print (L"BOR off\n");
+ }
+ } else if (StriCmp (CommandArg, L"ON") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOR;
+ } else if (StriCmp (CommandArg, L"OFF") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOR;
+ } else {
+ Print (L"Invalid parameter\n");
+ }
+ } else if (StriCmp (Command, L"BOE") == 0) {
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOE) == EFI_DEBUG_FLAG_EBC_BOE) {
+ Print (L"BOE on\n");
+ } else {
+ Print (L"BOE off\n");
+ }
+ } else if (StriCmp (CommandArg, L"ON") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOE;
+ } else if (StriCmp (CommandArg, L"OFF") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOE;
+ } else {
+ Print (L"Invalid parameter\n");
+ }
+ } else if (StriCmp (Command, L"BOT") == 0) {
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOT) == EFI_DEBUG_FLAG_EBC_BOT) {
+ Print (L"BOT on\n");
+ } else {
+ Print (L"BOT off\n");
+ }
+ } else if (StriCmp (CommandArg, L"ON") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOT;
+ } else if (StriCmp (CommandArg, L"OFF") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOT;
+ } else {
+ Print (L"Invalid parameter\n");
+ }
+ } else if (StriCmp (Command, L"BOK") == 0) {
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOK) == EFI_DEBUG_FLAG_EBC_BOK) {
+ Print (L"BOK on\n");
+ } else {
+ Print (L"BOK off\n");
+ }
+ } else if (StriCmp (CommandArg, L"ON") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOK;
+ } else if (StriCmp (CommandArg, L"OFF") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOK;
+ } else {
+ Print (L"Invalid parameter\n");
+ }
+ }
+ return ;
+}
+
+/**
+ Alter the EBC Debugger configuration.
+
+ @param[in] ImageHandle The image handle.
+ @param[in] SystemTable The system table.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_INVALID_PARAMETER Usage error.
+ @retval EFI_NOT_FOUND A running debugger cannot be located.
+**/
+EFI_STATUS
+EFIAPI
+InitializeEbcDebuggerConfig (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ UINTN Argc;
+ CHAR16 **Argv;
+ EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters;
+ EFI_DEBUGGER_CONFIGURATION_PROTOCOL *DebuggerConfiguration;
+ EFI_STATUS Status;
+
+ Status = gBS->HandleProtocol (
+ gImageHandle,
+ &gEfiShellParametersProtocolGuid,
+ (VOID**)&ShellParameters
+ );
+ if (EFI_ERROR(Status)) {
+ Print (L"Please use UEFI Shell to run this application.\n");
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Argc = ShellParameters->Argc;
+ Argv = ShellParameters->Argv;
+
+ if (Argc < 2) {
+ PrintUsage ();
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Argc == 2) {
+ if ((StrCmp (Argv[1], L"/?") == 0) ||
+ (StrCmp (Argv[1], L"-?") == 0) ||
+ (StrCmp (Argv[1], L"-h") == 0) ||
+ (StrCmp (Argv[1], L"-H") == 0) ) {
+ PrintUsage ();
+ return EFI_SUCCESS;
+ }
+ }
+
+ Status = gBS->LocateProtocol (
+ &gEfiDebuggerConfigurationProtocolGuid,
+ NULL,
+ (VOID**)&DebuggerConfiguration
+ );
+ if (EFI_ERROR(Status)) {
+ Print (L"Error: DebuggerConfiguration protocol not found.\n");
+ return EFI_NOT_FOUND;
+ }
+
+ if (StriCmp (Argv[1], L"SHOWINFO") == 0) {
+ EdbShowInfo (DebuggerConfiguration);
+ return EFI_SUCCESS;
+ }
+
+ if (((Argc == 2) || (Argc == 3)) &&
+ ((StriCmp (Argv[1], L"BOC") == 0) ||
+ (StriCmp (Argv[1], L"BOCX") == 0) ||
+ (StriCmp (Argv[1], L"BOR") == 0) ||
+ (StriCmp (Argv[1], L"BOE") == 0) ||
+ (StriCmp (Argv[1], L"BOT") == 0) ||
+ (StriCmp (Argv[1], L"BOK") == 0))) {
+ if (Argc == 3) {
+ EdbConfigBreak (DebuggerConfiguration, Argv[1], Argv[2]);
+ } else {
+ EdbConfigBreak (DebuggerConfiguration, Argv[1], NULL);
+ }
+ return EFI_SUCCESS;
+ }
+
+ Print (L"Error: Invalid Command.\n");
+ return EFI_INVALID_PARAMETER;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.c
new file mode 100644
index 000000000..611b2de5d
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.c
@@ -0,0 +1,585 @@
+/** @file
+
+Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include "Edb.h"
+
+EFI_DEBUGGER_PRIVATE_DATA mDebuggerPrivate = {
+ EFI_DEBUGGER_SIGNATURE, // Signature
+ IsaEbc, // Isa
+ (EBC_DEBUGGER_MAJOR_VERSION << 16) |
+ EBC_DEBUGGER_MINOR_VERSION, // EfiDebuggerRevision
+ (VM_MAJOR_VERSION << 16) |
+ VM_MINOR_VERSION, // EbcVmRevision
+ {
+ EFI_DEBUGGER_CONFIGURATION_VERSION,
+ &mDebuggerPrivate,
+ }, // DebuggerConfiguration
+ NULL, // DebugImageInfoTableHeader
+ NULL, // Vol
+ NULL, // PciRootBridgeIo
+ mDebuggerCommandSet, // DebuggerCommandSet
+ {0}, // DebuggerSymbolContext
+ 0, // DebuggerBreakpointCount
+ {{0}}, // DebuggerBreakpointContext
+ 0, // CallStackEntryCount
+ {{0}}, // CallStackEntry
+ 0, // TraceEntryCount
+ {{0}}, // TraceEntry
+ {0}, // StepContext
+ {0}, // GoTilContext
+ 0, // InstructionScope
+ EFI_DEBUG_DEFAULT_INSTRUCTION_NUMBER, // InstructionNumber
+ EFI_DEBUG_FLAG_EBC_BOE | EFI_DEBUG_FLAG_EBC_BOT, // FeatureFlags
+ 0, // StatusFlags
+ FALSE, // EnablePageBreak
+ NULL // BreakEvent
+};
+
+CHAR16 *mExceptionStr[] = {
+ L"EXCEPT_EBC_UNDEFINED",
+ L"EXCEPT_EBC_DIVIDE_ERROR",
+ L"EXCEPT_EBC_DEBUG",
+ L"EXCEPT_EBC_BREAKPOINT",
+ L"EXCEPT_EBC_OVERFLOW",
+ L"EXCEPT_EBC_INVALID_OPCODE",
+ L"EXCEPT_EBC_STACK_FAULT",
+ L"EXCEPT_EBC_ALIGNMENT_CHECK",
+ L"EXCEPT_EBC_INSTRUCTION_ENCODING",
+ L"EXCEPT_EBC_BAD_BREAK",
+ L"EXCEPT_EBC_SINGLE_STEP",
+};
+
+/**
+
+ Clear all the breakpoint.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param NeedRemove Whether need to remove all the breakpoint
+
+**/
+VOID
+EdbClearAllBreakpoint (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN BOOLEAN NeedRemove
+ )
+{
+ UINTN Index;
+
+ //
+ // Patch all the breakpoint
+ //
+ for (Index = 0; (Index < DebuggerPrivate->DebuggerBreakpointCount) && (Index < EFI_DEBUGGER_BREAKPOINT_MAX); Index++) {
+ if (DebuggerPrivate->DebuggerBreakpointContext[Index].State) {
+ CopyMem (
+ (VOID *)(UINTN)DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress,
+ &DebuggerPrivate->DebuggerBreakpointContext[Index].OldInstruction,
+ sizeof(UINT16)
+ );
+ }
+ }
+
+ //
+ // Zero Breakpoint context, if need to remove all breakpoint
+ //
+ if (NeedRemove) {
+ DebuggerPrivate->DebuggerBreakpointCount = 0;
+ ZeroMem (DebuggerPrivate->DebuggerBreakpointContext, sizeof(DebuggerPrivate->DebuggerBreakpointContext));
+ }
+
+ //
+ // Done
+ //
+ return ;
+}
+
+/**
+
+ Set all the breakpoint.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+
+**/
+VOID
+EdbSetAllBreakpoint (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate
+ )
+{
+ UINTN Index;
+ UINT16 Data16;
+
+ //
+ // Set all the breakpoint (BREAK(3) : 0x0300)
+ //
+ Data16 = 0x0300;
+ for (Index = 0; (Index < DebuggerPrivate->DebuggerBreakpointCount) && (Index < EFI_DEBUGGER_BREAKPOINT_MAX); Index++) {
+ if (DebuggerPrivate->DebuggerBreakpointContext[Index].State) {
+ CopyMem (
+ (VOID *)(UINTN)DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress,
+ &Data16,
+ sizeof(UINT16)
+ );
+ }
+ }
+
+ //
+ // Check if current break is caused by breakpoint set.
+ // If so, we need to patch memory back to let user see the real memory.
+ //
+ if (DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].BreakpointAddress != 0) {
+ CopyMem (
+ (VOID *)(UINTN)DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].BreakpointAddress,
+ &DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].OldInstruction,
+ sizeof(UINT16)
+ );
+ DebuggerPrivate->StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_BP;
+ }
+
+ //
+ // Done
+ //
+ return ;
+}
+
+/**
+
+ Check all the breakpoint, if match, then set status flag, and record current breakpoint.
+ Then clear all breakpoint to let user see a clean memory
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param SystemContext EBC system context.
+
+**/
+VOID
+EdbCheckBreakpoint (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINT64 Address;
+ UINTN Index;
+ BOOLEAN IsHitBreakpoint;
+
+ //
+ // Roll back IP for breakpoint instruction (BREAK(3) : 0x0300)
+ //
+ Address = SystemContext.SystemContextEbc->Ip - sizeof(UINT16);
+
+ //
+ // Check if the breakpoint is hit
+ //
+ IsHitBreakpoint = FALSE;
+ for (Index = 0; (Index < DebuggerPrivate->DebuggerBreakpointCount) && (Index < EFI_DEBUGGER_BREAKPOINT_MAX); Index++) {
+ if ((DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress == Address) &&
+ (DebuggerPrivate->DebuggerBreakpointContext[Index].State)) {
+ IsHitBreakpoint = TRUE;
+ break;
+ }
+ }
+
+ if (IsHitBreakpoint) {
+ //
+ // If hit, record current breakpoint
+ //
+ DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX] = DebuggerPrivate->DebuggerBreakpointContext[Index];
+ DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].State = TRUE;
+ //
+ // Update: IP and Instruction (NOTE: Since we not allow set breakpoint to BREAK 3, this update is safe)
+ //
+ SystemContext.SystemContextEbc->Ip = Address;
+ //
+ // Set Flags
+ //
+ DebuggerPrivate->StatusFlags |= EFI_DEBUG_FLAG_EBC_BP;
+ } else {
+ //
+ // If not hit, check whether current IP is in breakpoint list,
+ // because STEP will be triggered before execute the instruction.
+ // We should not patch it in de-init.
+ //
+ Address = SystemContext.SystemContextEbc->Ip;
+
+ //
+ // Check if the breakpoint is hit
+ //
+ IsHitBreakpoint = FALSE;
+ for (Index = 0; (Index < DebuggerPrivate->DebuggerBreakpointCount) && (Index < EFI_DEBUGGER_BREAKPOINT_MAX); Index++) {
+ if ((DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress == Address) &&
+ (DebuggerPrivate->DebuggerBreakpointContext[Index].State)) {
+ IsHitBreakpoint = TRUE;
+ break;
+ }
+ }
+
+ if (IsHitBreakpoint) {
+ //
+ // If hit, record current breakpoint
+ //
+ DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX] = DebuggerPrivate->DebuggerBreakpointContext[Index];
+ DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX].State = TRUE;
+ //
+ // Do not set Breakpoint flag. We record the address here just let it not patch breakpoint address when de-init.
+ //
+ } else {
+ //
+ // Zero current breakpoint
+ //
+ ZeroMem (
+ &DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX],
+ sizeof(DebuggerPrivate->DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX])
+ );
+ }
+ }
+
+ //
+ // Done
+ //
+ return ;
+}
+
+/**
+ clear all the symbol.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+
+**/
+VOID
+EdbClearSymbol (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate
+ )
+{
+ EFI_DEBUGGER_SYMBOL_CONTEXT *DebuggerSymbolContext;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ UINTN ObjectIndex;
+ UINTN Index;
+
+ //
+ // Go throuth each object
+ //
+ DebuggerSymbolContext = &DebuggerPrivate->DebuggerSymbolContext;
+ for (ObjectIndex = 0; ObjectIndex < DebuggerSymbolContext->ObjectCount; ObjectIndex++) {
+ Object = &DebuggerSymbolContext->Object[ObjectIndex];
+ //
+ // Go throuth each entry
+ //
+ for (Index = 0; Index < Object->EntryCount; Index++) {
+ ZeroMem (&Object->Entry[Index], sizeof(Object->Entry[Index]));
+ }
+ ZeroMem (Object->Name, sizeof(Object->Name));
+ Object->EntryCount = 0;
+ Object->BaseAddress = 0;
+ Object->StartEntrypointRVA = 0;
+ Object->MainEntrypointRVA = 0;
+ //
+ // Free source buffer
+ //
+ for (Index = 0; Object->SourceBuffer[Index] != NULL; Index++) {
+ gBS->FreePool (Object->SourceBuffer[Index]);
+ Object->SourceBuffer[Index] = NULL;
+ }
+ }
+ DebuggerSymbolContext->ObjectCount = 0;
+
+ return ;
+}
+
+/**
+
+ Initialize Debugger private data structure
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+ @param Initialized Whether the DebuggerPrivate data is initialized.
+
+**/
+EFI_STATUS
+InitDebuggerPrivateData (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ IN BOOLEAN Initialized
+ )
+{
+ //
+ // clear STEP flag in any condition.
+ //
+ if (SystemContext.SystemContextEbc->Flags & ((UINT64) VMFLAGS_STEP)) {
+ SystemContext.SystemContextEbc->Flags &= ~((UINT64) VMFLAGS_STEP);
+ }
+
+ if (!Initialized) {
+ //
+ // Initialize everything
+ //
+ DebuggerPrivate->InstructionNumber = EFI_DEBUG_DEFAULT_INSTRUCTION_NUMBER;
+
+ DebuggerPrivate->DebuggerBreakpointCount = 0;
+ ZeroMem (DebuggerPrivate->DebuggerBreakpointContext, sizeof(DebuggerPrivate->DebuggerBreakpointContext));
+
+// DebuggerPrivate->StatusFlags = 0;
+
+ DebuggerPrivate->DebuggerSymbolContext.DisplaySymbol = TRUE;
+ DebuggerPrivate->DebuggerSymbolContext.DisplayCodeOnly = FALSE;
+ DebuggerPrivate->DebuggerSymbolContext.ObjectCount = 0;
+ } else {
+ //
+ // Already initialized, just check Breakpoint here.
+ //
+ if (ExceptionType == EXCEPT_EBC_BREAKPOINT) {
+ EdbCheckBreakpoint (DebuggerPrivate, SystemContext);
+ }
+
+ //
+ // Clear all breakpoint
+ //
+ EdbClearAllBreakpoint (DebuggerPrivate, FALSE);
+ }
+
+ //
+ // Set Scope to currentl IP. (Note: Check Breakpoint may change Ip)
+ //
+ DebuggerPrivate->InstructionScope = SystemContext.SystemContextEbc->Ip;
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ De-initialize Debugger private data structure.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+ @param Initialized Whether the DebuggerPrivate data is initialized.
+
+**/
+EFI_STATUS
+DeinitDebuggerPrivateData (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ IN BOOLEAN Initialized
+ )
+{
+ if (!Initialized) {
+ //
+ // If it does not want initialized state, de-init everything
+ //
+ DebuggerPrivate->FeatureFlags = EFI_DEBUG_FLAG_EBC_BOE | EFI_DEBUG_FLAG_EBC_BOT;
+ DebuggerPrivate->CallStackEntryCount = 0;
+ DebuggerPrivate->TraceEntryCount = 0;
+ ZeroMem (DebuggerPrivate->CallStackEntry, sizeof(DebuggerPrivate->CallStackEntry));
+ ZeroMem (DebuggerPrivate->TraceEntry, sizeof(DebuggerPrivate->TraceEntry));
+
+ //
+ // Clear all breakpoint
+ //
+ EdbClearAllBreakpoint (DebuggerPrivate, TRUE);
+
+ //
+ // Clear symbol
+ //
+ EdbClearSymbol (DebuggerPrivate);
+ } else {
+ //
+ // If it wants to keep initialized state, just set breakpoint.
+ //
+ EdbSetAllBreakpoint (DebuggerPrivate);
+ }
+
+ //
+ // Clear Step context
+ //
+ ZeroMem (&mDebuggerPrivate.StepContext, sizeof(mDebuggerPrivate.StepContext));
+ DebuggerPrivate->StatusFlags = 0;
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Print the reason of current break to EbcDebugger.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+ @param Initialized Whether the DebuggerPrivate data is initialized.
+
+**/
+VOID
+PrintExceptionReason (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ IN BOOLEAN Initialized
+ )
+{
+ //
+ // Print break status
+ //
+ if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_GT) == EFI_DEBUG_FLAG_EBC_GT) {
+ EDBPrint (L"Break on GoTil\n");
+ } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOC) == EFI_DEBUG_FLAG_EBC_BOC) {
+ EDBPrint (L"Break on CALL\n");
+ } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOCX) == EFI_DEBUG_FLAG_EBC_BOCX) {
+ EDBPrint (L"Break on CALLEX\n");
+ } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOR) == EFI_DEBUG_FLAG_EBC_BOR) {
+ EDBPrint (L"Break on RET\n");
+ } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOE) == EFI_DEBUG_FLAG_EBC_BOE) {
+ EDBPrint (L"Break on Entrypoint\n");
+ } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOT) == EFI_DEBUG_FLAG_EBC_BOT) {
+ EDBPrint (L"Break on Thunk\n");
+ } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_STEPOVER) == EFI_DEBUG_FLAG_EBC_STEPOVER) {
+ EDBPrint (L"Break on StepOver\n");
+ } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_STEPOUT) == EFI_DEBUG_FLAG_EBC_STEPOUT) {
+ EDBPrint (L"Break on StepOut\n");
+ } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BP) == EFI_DEBUG_FLAG_EBC_BP) {
+ EDBPrint (L"Break on Breakpoint\n");
+ } else if ((DebuggerPrivate->StatusFlags & EFI_DEBUG_FLAG_EBC_BOK) == EFI_DEBUG_FLAG_EBC_BOK) {
+ EDBPrint (L"Break on Key\n");
+ } else {
+ EDBPrint (L"Exception Type - %x", (UINTN)ExceptionType);
+ if ((ExceptionType >= EXCEPT_EBC_UNDEFINED) && (ExceptionType <= EXCEPT_EBC_STEP)) {
+ EDBPrint (L" (%s)\n", mExceptionStr[ExceptionType]);
+ } else {
+ EDBPrint (L"\n");
+ }
+ }
+
+ return ;
+}
+
+/**
+
+ The default Exception Callback for the VM interpreter.
+ In this function, we report status code, and print debug information
+ about EBC_CONTEXT, then dead loop.
+
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+**/
+VOID
+EFIAPI
+EdbExceptionHandler (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ CHAR16 InputBuffer[EFI_DEBUG_INPUS_BUFFER_SIZE];
+ CHAR16 *CommandArg;
+ EFI_DEBUGGER_COMMAND DebuggerCommand;
+ EFI_DEBUG_STATUS DebugStatus;
+ STATIC BOOLEAN mInitialized;
+
+ mInitialized = FALSE;
+
+ DEBUG ((DEBUG_ERROR, "Hello EBC Debugger!\n"));
+
+ if (!mInitialized) {
+ //
+ // Print version
+ //
+ EDBPrint (
+ L"EBC Interpreter Version - %d.%d\n",
+ (UINTN)VM_MAJOR_VERSION,
+ (UINTN)VM_MINOR_VERSION
+ );
+ EDBPrint (
+ L"EBC Debugger Version - %d.%d\n",
+ (UINTN)EBC_DEBUGGER_MAJOR_VERSION,
+ (UINTN)EBC_DEBUGGER_MINOR_VERSION
+ );
+ }
+ //
+ // Init Private Data
+ //
+ InitDebuggerPrivateData (&mDebuggerPrivate, ExceptionType, SystemContext, mInitialized);
+
+ //
+ // EDBPrint basic info
+ //
+ PrintExceptionReason (&mDebuggerPrivate, ExceptionType, SystemContext, mInitialized);
+
+ EdbShowDisasm (&mDebuggerPrivate, SystemContext);
+ // EFI_BREAKPOINT ();
+
+ if (!mInitialized) {
+ //
+ // Interactive with user
+ //
+ EDBPrint (L"\nPlease enter command now, \'h\' for help.\n");
+ EDBPrint (L"(Using <Command> -b <...> to enable page break.)\n");
+ }
+ mInitialized = TRUE;
+
+ //
+ // Dispatch each command
+ //
+ while (TRUE) {
+ //
+ // Get user input
+ //
+ Input (L"\n\r" EFI_DEBUG_PROMPT_STRING, InputBuffer, EFI_DEBUG_INPUS_BUFFER_SIZE);
+ EDBPrint (L"\n");
+
+ //
+ // Get command
+ //
+ DebuggerCommand = MatchDebuggerCommand (InputBuffer, &CommandArg);
+ if (DebuggerCommand == NULL) {
+ EDBPrint (L"ERROR: Command not found!\n");
+ continue;
+ }
+
+ //
+ // Check PageBreak;
+ //
+ if (CommandArg != NULL) {
+ if (StriCmp (CommandArg, L"-b") == 0) {
+ CommandArg = StrGetNextTokenLine (L" ");
+ mDebuggerPrivate.EnablePageBreak = TRUE;
+ }
+ }
+
+ //
+ // Dispatch command
+ //
+ DebugStatus = DebuggerCommand (CommandArg, &mDebuggerPrivate, ExceptionType, SystemContext);
+ mDebuggerPrivate.EnablePageBreak = FALSE;
+
+ //
+ // Check command return status
+ //
+ if (DebugStatus == EFI_DEBUG_RETURN) {
+ mInitialized = FALSE;
+ break;
+ } else if (DebugStatus == EFI_DEBUG_BREAK) {
+ break;
+ } else if (DebugStatus == EFI_DEBUG_CONTINUE) {
+ continue;
+ } else {
+ ASSERT (FALSE);
+ }
+ }
+
+ //
+ // Deinit Private Data
+ //
+ DeinitDebuggerPrivateData (&mDebuggerPrivate, ExceptionType, SystemContext, mInitialized);
+
+ DEBUG ((DEBUG_ERROR, "Goodbye EBC Debugger!\n"));
+
+ return;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.h
new file mode 100644
index 000000000..34253b3a1
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/Edb.h
@@ -0,0 +1,60 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#ifndef _EFI_EDB_H_
+#define _EFI_EDB_H_
+
+#include "EdbCommon.h"
+
+#define EBC_DEBUGGER_MAJOR_VERSION 1
+#define EBC_DEBUGGER_MINOR_VERSION 0
+
+#define EFI_DEBUG_RETURN 1
+#define EFI_DEBUG_BREAK 2
+#define EFI_DEBUG_CONTINUE 3
+
+/**
+ Driver Entry point.
+
+ @param ImageHandle ImageHandle of the loaded driver.
+ @param SystemTable Pointer to the EFI System Table.
+
+**/
+EFI_STATUS
+EfiDebuggerEntrypoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+
+ The default Exception Callback for the VM interpreter.
+ In this function, we report status code, and print debug information
+ about EBC_CONTEXT, then dead loop.
+
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+**/
+VOID
+EFIAPI
+EdbExceptionHandler (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+extern EFI_DEBUGGER_PRIVATE_DATA mDebuggerPrivate;
+
+#include "EdbSupport.h"
+#include "EdbCommand.h"
+#include "EdbDisasm.h"
+#include "EdbDisasmSupport.h"
+#include "EdbSymbol.h"
+#include "EdbHook.h"
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBranch.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBranch.c
new file mode 100644
index 000000000..500bb41da
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBranch.c
@@ -0,0 +1,306 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+CHAR16 *mBranchTypeStr[] = {
+ L"(CALL)",
+ L"(CALLEX)",
+ L"(RET)",
+ L"(JMP)",
+ L"(JMP8)",
+};
+
+/**
+
+ Comvert Branch Type to string.
+
+ @param Type Branch Type
+
+ @retval String string of Branch Type.
+
+**/
+CHAR16 *
+EdbBranchTypeToStr (
+ IN EFI_DEBUGGER_BRANCH_TYPE Type
+ )
+{
+ if (Type < 0 || Type >= EfiDebuggerBranchTypeEbcMax) {
+ return L"(Unknown Type)";
+ }
+
+ return mBranchTypeStr [Type];
+}
+
+/**
+
+ DebuggerCommand - CallStack.
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerCallStack (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ INTN Index;
+ UINTN SubIndex;
+ CHAR8 *FuncName;
+ EFI_DEBUGGER_CALLSTACK_CONTEXT *CallStackEntry;
+ BOOLEAN ShowParameter;
+ UINTN ParameterNumber;
+
+ ShowParameter = FALSE;
+ ParameterNumber = EFI_DEBUGGER_CALL_DEFAULT_PARAMETER;
+
+ //
+ // Check argument
+ //
+ if (CommandArg != NULL) {
+ if (StriCmp (CommandArg, L"c") == 0) {
+ //
+ // Clear Call-Stack
+ //
+ DebuggerPrivate->CallStackEntryCount = 0;
+ ZeroMem (DebuggerPrivate->CallStackEntry, sizeof(DebuggerPrivate->CallStackEntry));
+ EDBPrint (L"Call-Stack is cleared\n");
+ return EFI_DEBUG_CONTINUE;
+ } else if (StriCmp (CommandArg, L"p") == 0) {
+ //
+ // Print Call-Stack with parameter
+ //
+ ShowParameter = TRUE;
+ CommandArg = StrGetNextTokenLine (L" ");
+ if (CommandArg != NULL) {
+ //
+ // Try to get the parameter number
+ //
+ ParameterNumber = Atoi (CommandArg);
+ if (ParameterNumber > 16) {
+ EDBPrint (L"Call-Stack argument Invalid\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ }
+ } else {
+ EDBPrint (L"Call-Stack argument Invalid\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ }
+
+ //
+ // Check CallStack Entry Count
+ //
+ if (DebuggerPrivate->CallStackEntryCount == 0) {
+ EDBPrint (L"No Call-Stack\n");
+ return EFI_DEBUG_CONTINUE;
+ } else if (DebuggerPrivate->CallStackEntryCount > EFI_DEBUGGER_CALLSTACK_MAX) {
+ EDBPrint (L"Call-Stack Crash, re-initialize!\n");
+ DebuggerPrivate->CallStackEntryCount = 0;
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Go through each CallStack entry and print
+ //
+ EDBPrint (L"Call-Stack (TOP):\n");
+ EDBPrint (L" Caller Callee Name\n");
+ EDBPrint (L" ================== ================== ========\n");
+//EDBPrint (L" 0x00000000FFFFFFFF 0xFFFFFFFF00000000 EfiMain\n");
+ for (Index = (INTN)(DebuggerPrivate->CallStackEntryCount - 1); Index >= 0; Index--) {
+ //
+ // Get CallStack and print
+ //
+ CallStackEntry = &DebuggerPrivate->CallStackEntry[Index];
+ EDBPrint (
+ L" 0x%016lx 0x%016lx",
+ CallStackEntry->SourceAddress,
+ CallStackEntry->DestAddress
+ );
+ FuncName = FindSymbolStr ((UINTN)CallStackEntry->DestAddress);
+ if (FuncName != NULL) {
+ EDBPrint (L" %a()", FuncName);
+ }
+ EDBPrint (L"\n");
+
+ if (ShowParameter) {
+ //
+ // Print parameter
+ //
+ if (sizeof(UINTN) == sizeof(UINT64)) {
+ EDBPrint (
+ L" Parameter Address (0x%016lx) (\n",
+ CallStackEntry->ParameterAddr
+ );
+ if (ParameterNumber == 0) {
+ EDBPrint (L" )\n");
+ continue;
+ }
+ //
+ // Print each parameter
+ //
+ for (SubIndex = 0; SubIndex < ParameterNumber - 1; SubIndex++) {
+ if (SubIndex % 2 == 0) {
+ EDBPrint (L" ");
+ }
+ EDBPrint (
+ L"0x%016lx, ",
+ CallStackEntry->Parameter[SubIndex]
+ );
+ if (SubIndex % 2 == 1) {
+ EDBPrint (L"\n");
+ }
+ }
+ if (SubIndex % 2 == 0) {
+ EDBPrint (L" ");
+ }
+ EDBPrint (
+ L"0x%016lx\n",
+ CallStackEntry->Parameter[SubIndex]
+ );
+ EDBPrint (L" )\n");
+ //
+ // break only for parameter
+ //
+ if ((((DebuggerPrivate->CallStackEntryCount - Index) % (16 / ParameterNumber)) == 0) &&
+ (Index != 0)) {
+ if (SetPageBreak ()) {
+ break;
+ }
+ }
+ } else {
+ EDBPrint (
+ L" Parameter Address (0x%08x) (\n",
+ CallStackEntry->ParameterAddr
+ );
+ if (ParameterNumber == 0) {
+ EDBPrint (L" )\n");
+ continue;
+ }
+ //
+ // Print each parameter
+ //
+ for (SubIndex = 0; SubIndex < ParameterNumber - 1; SubIndex++) {
+ if (SubIndex % 4 == 0) {
+ EDBPrint (L" ");
+ }
+ EDBPrint (
+ L"0x%08x, ",
+ CallStackEntry->Parameter[SubIndex]
+ );
+ if (SubIndex % 4 == 3) {
+ EDBPrint (L"\n");
+ }
+ }
+ if (SubIndex % 4 == 0) {
+ EDBPrint (L" ");
+ }
+ EDBPrint (
+ L"0x%08x\n",
+ CallStackEntry->Parameter[SubIndex]
+ );
+ EDBPrint (L" )\n");
+ //
+ // break only for parameter
+ //
+ if ((((DebuggerPrivate->CallStackEntryCount - Index) % (32 / ParameterNumber)) == 0) &&
+ (Index != 0)) {
+ if (SetPageBreak ()) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - InstructionBranch.
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerInstructionBranch (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN Index;
+
+ //
+ // Check argument
+ //
+ if (CommandArg != NULL) {
+ if (StriCmp (CommandArg, L"c") == 0) {
+ //
+ // Clear Trace
+ //
+ DebuggerPrivate->TraceEntryCount = 0;
+ ZeroMem (DebuggerPrivate->TraceEntry, sizeof(DebuggerPrivate->TraceEntry));
+ EDBPrint (L"Instruction Trace is cleared\n");
+ } else {
+ EDBPrint (L"Trace argument Invalid\n");
+ }
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Check Trace Entry Count
+ //
+ if (DebuggerPrivate->TraceEntryCount == 0) {
+ EDBPrint (L"No Instruction Trace\n");
+ return EFI_DEBUG_CONTINUE;
+ } else if (DebuggerPrivate->TraceEntryCount > EFI_DEBUGGER_TRACE_MAX) {
+ EDBPrint (L"Instruction Trace Crash, re-initialize!\n");
+ DebuggerPrivate->TraceEntryCount = 0;
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Go through each Trace entry and print
+ //
+ EDBPrint (L"Instruction Trace (->Latest):\n");
+ EDBPrint (L" Source Addr Destination Addr Type\n");
+ EDBPrint (L" ================== ================== ========\n");
+//EDBPrint (L" 0x00000000FFFFFFFF 0xFFFFFFFF00000000 (CALLEX)\n");
+ for (Index = 0; Index < DebuggerPrivate->TraceEntryCount; Index++) {
+ EDBPrint (
+ L" 0x%016lx 0x%016lx %s\n",
+ DebuggerPrivate->TraceEntry[Index].SourceAddress,
+ DebuggerPrivate->TraceEntry[Index].DestAddress,
+ EdbBranchTypeToStr (DebuggerPrivate->TraceEntry[Index].Type)
+ );
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreak.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreak.c
new file mode 100644
index 000000000..696703c4b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreak.c
@@ -0,0 +1,288 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+
+/**
+
+ DebuggerCommand - BreakOnCALL.
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakOnCALL (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ //
+ // Check argument
+ //
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOC) == EFI_DEBUG_FLAG_EBC_BOC) {
+ EDBPrint (L"BOC on\n");
+ } else {
+ EDBPrint (L"BOC off\n");
+ }
+ } else if (StriCmp (CommandArg, L"on") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOC;
+ EDBPrint (L"BOC on\n");
+ } else if (StriCmp (CommandArg, L"off") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOC;
+ EDBPrint (L"BOC off\n");
+ } else {
+ EDBPrint (L"BOC - argument error\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand BreakOnCALLEX.
+
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exceptiont type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakOnCALLEX (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ //
+ // Check argument
+ //
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOCX) == EFI_DEBUG_FLAG_EBC_BOCX) {
+ EDBPrint (L"BOCX on\n");
+ } else {
+ EDBPrint (L"BOCX off\n");
+ }
+ } else if (StriCmp (CommandArg, L"on") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOCX;
+ EDBPrint (L"BOCX on\n");
+ } else if (StriCmp (CommandArg, L"off") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOCX;
+ EDBPrint (L"BOCX off\n");
+ } else {
+ EDBPrint (L"BOCX - argument error\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - BreakOnRET.
+
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakOnRET (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ //
+ // Check argument
+ //
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOR) == EFI_DEBUG_FLAG_EBC_BOR) {
+ EDBPrint (L"BOR on\n");
+ } else {
+ EDBPrint (L"BOR off\n");
+ }
+ } else if (StriCmp (CommandArg, L"on") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOR;
+ EDBPrint (L"BOR on\n");
+ } else if (StriCmp (CommandArg, L"off") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOR;
+ EDBPrint (L"BOR off\n");
+ } else {
+ EDBPrint (L"BOR - argument error\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - BreakOnEntrypoint.
+
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakOnEntrypoint (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ //
+ // Check argument
+ //
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOE) == EFI_DEBUG_FLAG_EBC_BOE) {
+ EDBPrint (L"BOE on\n");
+ } else {
+ EDBPrint (L"BOE off\n");
+ }
+ } else if (StriCmp (CommandArg, L"on") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOE;
+ EDBPrint (L"BOE on\n");
+ } else if (StriCmp (CommandArg, L"off") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOE;
+ EDBPrint (L"BOE off\n");
+ } else {
+ EDBPrint (L"BOE - argument error\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+
+ DebuggerCommand - BreakOnThunk.
+
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakOnThunk (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ //
+ // Check argument
+ //
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOT) == EFI_DEBUG_FLAG_EBC_BOT) {
+ EDBPrint (L"BOT on\n");
+ } else {
+ EDBPrint (L"BOT off\n");
+ }
+ } else if (StriCmp (CommandArg, L"on") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOT;
+ EDBPrint (L"BOT on\n");
+ } else if (StriCmp (CommandArg, L"off") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOT;
+ EDBPrint (L"BOT off\n");
+ } else {
+ EDBPrint (L"BOT - argument error\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - BreakOnKey.
+
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakOnKey (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ //
+ // Check argument
+ //
+ if (CommandArg == NULL) {
+ if ((DebuggerPrivate->FeatureFlags & EFI_DEBUG_FLAG_EBC_BOK) == EFI_DEBUG_FLAG_EBC_BOK) {
+ EDBPrint (L"BOK on\n");
+ } else {
+ EDBPrint (L"BOK off\n");
+ }
+ } else if (StriCmp (CommandArg, L"on") == 0) {
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_BOK;
+ EDBPrint (L"BOK on\n");
+ } else if (StriCmp (CommandArg, L"off") == 0) {
+ DebuggerPrivate->FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOK;
+ EDBPrint (L"BOK off\n");
+ } else {
+ EDBPrint (L"BOK - argument error\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreakpoint.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreakpoint.c
new file mode 100644
index 000000000..e0c797be2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdBreakpoint.c
@@ -0,0 +1,542 @@
+/** @file
+
+Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ Check whether current IP is EBC BREAK3 instruction.
+
+ @param Address EBC IP address.
+
+ @retval TRUE Current IP is EBC BREAK3 instruction
+ @retval FALSE Current IP is not EBC BREAK3 instruction
+
+**/
+BOOLEAN
+IsEBCBREAK3 (
+ IN UINTN Address
+ )
+{
+ if (GET_OPCODE(Address) != OPCODE_BREAK) {
+ return FALSE;
+ }
+
+ if (GET_OPERANDS (Address) != 3) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/**
+
+ Check whether the Address is already set in breakpoint.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param Address Breakpoint Address
+
+ @retval TRUE breakpoint is found
+ @retval FALSE breakpoint is not found
+
+**/
+BOOLEAN
+DebuggerBreakpointIsDuplicated (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN UINTN Address
+ )
+{
+ UINTN Index;
+
+ //
+ // Go through each breakpoint context
+ //
+ for (Index = 0; Index < DebuggerPrivate->DebuggerBreakpointCount; Index++) {
+ if (DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress == Address) {
+ //
+ // Found it
+ //
+ return TRUE;
+ }
+ }
+
+ //
+ // Not found
+ //
+ return FALSE;
+}
+
+/**
+
+ Add this breakpoint.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param Address Breakpoint Address
+
+ @retval EFI_SUCCESS breakpoint added successfully
+ @retval EFI_ALREADY_STARTED breakpoint is already added
+ @retval EFI_OUT_OF_RESOURCES all the breakpoint entries are used
+
+**/
+EFI_STATUS
+DebuggerBreakpointAdd (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN UINTN Address
+ )
+{
+ //
+ // Check duplicated breakpoint
+ //
+ if (DebuggerBreakpointIsDuplicated (DebuggerPrivate, Address)) {
+ EDBPrint (L"Breakpoint duplicated!\n");
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Check whether the address is a breakpoint 3 instruction
+ //
+ if (IsEBCBREAK3 (Address)) {
+ EDBPrint (L"Breakpoint can not be set on BREAK 3 instruction!\n");
+ return EFI_ALREADY_STARTED;
+ }
+
+ if (DebuggerPrivate->DebuggerBreakpointCount >= EFI_DEBUGGER_BREAKPOINT_MAX) {
+ EDBPrint (L"Breakpoint out of resource!\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Set the breakpoint
+ //
+ DebuggerPrivate->DebuggerBreakpointContext[DebuggerPrivate->DebuggerBreakpointCount].BreakpointAddress = Address;
+ DebuggerPrivate->DebuggerBreakpointContext[DebuggerPrivate->DebuggerBreakpointCount].State = TRUE;
+ DebuggerPrivate->DebuggerBreakpointContext[DebuggerPrivate->DebuggerBreakpointCount].OldInstruction = 0;
+ CopyMem (
+ &DebuggerPrivate->DebuggerBreakpointContext[DebuggerPrivate->DebuggerBreakpointCount].OldInstruction,
+ (VOID *)Address,
+ sizeof(UINT16)
+ );
+
+ DebuggerPrivate->DebuggerBreakpointCount ++;
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Delete this breakpoint.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param Index Breakpoint Index
+
+ @retval EFI_SUCCESS breakpoint deleted successfully
+ @retval EFI_NOT_FOUND breakpoint not found
+
+**/
+EFI_STATUS
+DebuggerBreakpointDel (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN UINTN Index
+ )
+{
+ UINTN BpIndex;
+
+ if ((Index >= EFI_DEBUGGER_BREAKPOINT_MAX) ||
+ (Index >= DebuggerPrivate->DebuggerBreakpointCount)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Delete this breakpoint
+ //
+ for (BpIndex = Index; BpIndex < DebuggerPrivate->DebuggerBreakpointCount - 1; BpIndex++) {
+ DebuggerPrivate->DebuggerBreakpointContext[BpIndex] = DebuggerPrivate->DebuggerBreakpointContext[BpIndex + 1];
+ }
+ ZeroMem (
+ &DebuggerPrivate->DebuggerBreakpointContext[BpIndex],
+ sizeof(DebuggerPrivate->DebuggerBreakpointContext[BpIndex])
+ );
+
+ DebuggerPrivate->DebuggerBreakpointCount --;
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Disable this breakpoint.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param Index Breakpoint Index
+
+ @retval EFI_SUCCESS breakpoint disabled successfully
+ @retval EFI_NOT_FOUND breakpoint not found
+
+**/
+EFI_STATUS
+DebuggerBreakpointDis (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN UINTN Index
+ )
+{
+ if ((Index >= EFI_DEBUGGER_BREAKPOINT_MAX) ||
+ (Index >= DebuggerPrivate->DebuggerBreakpointCount)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Disable this breakpoint
+ //
+ DebuggerPrivate->DebuggerBreakpointContext[Index].State = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Enable this breakpoint.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param Index - Breakpoint Index
+
+ @retval EFI_SUCCESS - breakpoint enabled successfully
+ @retval EFI_NOT_FOUND - breakpoint not found
+
+**/
+EFI_STATUS
+DebuggerBreakpointEn (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN UINTN Index
+ )
+{
+ if ((Index >= EFI_DEBUGGER_BREAKPOINT_MAX) ||
+ (Index >= DebuggerPrivate->DebuggerBreakpointCount)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Enable this breakpoint
+ //
+ DebuggerPrivate->DebuggerBreakpointContext[Index].State = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ DebuggerCommand - BreakpointList.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakpointList (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN Index;
+
+ //
+ // Check breakpoint cound
+ //
+ if (DebuggerPrivate->DebuggerBreakpointCount == 0) {
+ EDBPrint (L"No Breakpoint\n");
+ return EFI_DEBUG_CONTINUE;
+ } else if (DebuggerPrivate->DebuggerBreakpointCount > EFI_DEBUGGER_BREAKPOINT_MAX) {
+ EDBPrint (L"Breakpoint too many!\n");
+ DebuggerPrivate->DebuggerBreakpointCount = 0;
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Go through each breakpoint
+ //
+ EDBPrint (L"Breakpoint :\n");
+ EDBPrint (L" Index Address Status\n");
+ EDBPrint (L"======= ================== ========\n");
+//EDBPrint (L" 1 0xFFFFFFFF00000000 *\n");
+//EDBPrint (L" 12 0x00000000FFFFFFFF\n");
+ for (Index = 0; Index < DebuggerPrivate->DebuggerBreakpointCount; Index++) {
+ //
+ // Print the breakpoint
+ //
+ EDBPrint (L" %2d 0x%016lx", Index, DebuggerPrivate->DebuggerBreakpointContext[Index].BreakpointAddress);
+ if (DebuggerPrivate->DebuggerBreakpointContext[Index].State) {
+ EDBPrint (L" *\n");
+ } else {
+ EDBPrint (L"\n");
+ }
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - BreakpointSet.
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakpointSet (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN Address;
+ EFI_STATUS Status;
+
+ if (CommandArg == NULL) {
+ EDBPrint (L"BreakpointSet Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Get breakpoint address
+ //
+ Status = Symboltoi (CommandArg, &Address);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND) {
+ Address = Xtoi(CommandArg);
+ } else {
+ //
+ // Something wrong, let Symboltoi print error info.
+ //
+ EDBPrint (L"Command Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ }
+
+ //
+ // Add breakpoint
+ //
+ Status = DebuggerBreakpointAdd (DebuggerPrivate, Address);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"BreakpointSet error!\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - BreakpointClear
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakpointClear (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+
+ if (CommandArg == NULL) {
+ EDBPrint (L"BreakpointClear Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ if (StriCmp (CommandArg, L"*") == 0) {
+ //
+ // delete all breakpoint
+ //
+ DebuggerPrivate->DebuggerBreakpointCount = 0;
+ ZeroMem (DebuggerPrivate->DebuggerBreakpointContext, sizeof(DebuggerPrivate->DebuggerBreakpointContext));
+ EDBPrint (L"All the Breakpoint is cleared\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Get breakpoint index
+ //
+ Index = Atoi(CommandArg);
+ if (Index == (UINTN) -1) {
+ EDBPrint (L"BreakpointClear Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ if ((Index >= EFI_DEBUGGER_BREAKPOINT_MAX) ||
+ (Index >= DebuggerPrivate->DebuggerBreakpointCount)) {
+ EDBPrint (L"BreakpointClear error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Delete breakpoint
+ //
+ Status = DebuggerBreakpointDel (DebuggerPrivate, Index);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"BreakpointClear error!\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - BreakpointDisable
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakpointDisable (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+
+ if (CommandArg == NULL) {
+ EDBPrint (L"BreakpointDisable Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ if (StriCmp (CommandArg, L"*") == 0) {
+ //
+ // disable all breakpoint
+ //
+ for (Index = 0; Index < DebuggerPrivate->DebuggerBreakpointCount; Index++) {
+ Status = DebuggerBreakpointDis (DebuggerPrivate, Index);
+ }
+ EDBPrint (L"All the Breakpoint is disabled\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Get breakpoint index
+ //
+ Index = Atoi(CommandArg);
+ if (Index == (UINTN) -1) {
+ EDBPrint (L"BreakpointDisable Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Disable breakpoint
+ //
+ Status = DebuggerBreakpointDis (DebuggerPrivate, Index);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"BreakpointDisable error!\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+ DebuggerCommand - BreakpointEnable.
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerBreakpointEnable (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+
+ if (CommandArg == NULL) {
+ EDBPrint (L"BreakpointEnable Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ if (StriCmp (CommandArg, L"*") == 0) {
+ //
+ // enable all breakpoint
+ //
+ for (Index = 0; Index < DebuggerPrivate->DebuggerBreakpointCount; Index++) {
+ Status = DebuggerBreakpointEn (DebuggerPrivate, Index);
+ }
+ EDBPrint (L"All the Breakpoint is enabled\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Get breakpoint index
+ //
+ Index = Atoi(CommandArg);
+ if (Index == (UINTN) -1) {
+ EDBPrint (L"BreakpointEnable Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Enable breakpoint
+ //
+ Status = DebuggerBreakpointEn (DebuggerPrivate, Index);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"BreakpointEnable error!\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdExtIo.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdExtIo.c
new file mode 100644
index 000000000..d5390d13a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdExtIo.c
@@ -0,0 +1,176 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ DebuggerCommand - IB.
+
+ @param CommandArg The argument for this command
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param ExceptionType Exception type.
+ @param SystemContext EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtIoIB (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+
+/**
+
+ DebuggerCommand - IW.
+
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtIoIW (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - ID.
+
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtIoID (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - OB.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtIoOB (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+
+/**
+
+ DebuggerCommand - OW.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtIoOW (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+
+/**
+
+ DebuggerCommand - OD.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtIoOD (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdExtPci.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdExtPci.c
new file mode 100644
index 000000000..93e8b503e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdExtPci.c
@@ -0,0 +1,145 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ DebuggerCommand - PCIL.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtPciPCIL (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - PCID.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtPciPCID (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - CFGB.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtPciCFGB (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+
+/**
+
+ DebuggerCommand - CFGW.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtPciCFGW (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - CFGD.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerExtPciCFGD (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EDBPrint (L"Unsupported\n");
+ //
+ // TBD
+ //
+ return EFI_DEBUG_CONTINUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdGo.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdGo.c
new file mode 100644
index 000000000..e5cf857a2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdGo.c
@@ -0,0 +1,76 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ DebuggerCommand - Go.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_BREAK - formal return value
+ @retval EFI_DEBUG_CONTINUE - something wrong
+
+**/
+EFI_DEBUG_STATUS
+DebuggerGo (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN Address;
+ CHAR16 *CommandStr;
+ EFI_STATUS Status;
+
+ //
+ // Check argument
+ //
+ if (CommandArg != NULL) {
+ if (StriCmp (CommandArg, L"til") == 0) {
+ CommandStr = StrGetNextTokenLine (L" ");
+ if (CommandStr != NULL) {
+ //
+ // Enable GoTil break now
+ // set BreakAddress, and set feature flag.
+ //
+ Status = Symboltoi (CommandStr, &Address);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND) {
+ Address = Xtoi(CommandStr);
+ } else {
+ //
+ // Something wrong, let Symboltoi print error info.
+ //
+ EDBPrint (L"Command Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ }
+ DebuggerPrivate->GoTilContext.BreakAddress = Address;
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_GT;
+ } else {
+ EDBPrint (L"Command Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ } else {
+ EDBPrint (L"Command Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_BREAK;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdHelp.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdHelp.c
new file mode 100644
index 000000000..74e1befee
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdHelp.c
@@ -0,0 +1,68 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ DebuggerCommand - Help.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerHelp (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN Index;
+
+ //
+ // if no argument, print all the command title
+ //
+ if (CommandArg == NULL) {
+ for (Index = 0; DebuggerPrivate->DebuggerCommandSet[Index].CommandName != NULL; Index++) {
+ EDBPrint (DebuggerPrivate->DebuggerCommandSet[Index].ClassName);
+ if (StrCmp (DebuggerPrivate->DebuggerCommandSet[Index].CommandTitle, L"") != 0) {
+ EDBPrint (L" ");
+ EDBPrint (DebuggerPrivate->DebuggerCommandSet[Index].CommandTitle);
+ }
+ }
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // If there is argument, the argument should be command name.
+ // Find the command and print the detail information.
+ //
+ for (Index = 0; DebuggerPrivate->DebuggerCommandSet[Index].CommandName != NULL; Index++) {
+ if (StriCmp (CommandArg, DebuggerPrivate->DebuggerCommandSet[Index].CommandName) == 0) {
+ EDBPrint (DebuggerPrivate->DebuggerCommandSet[Index].CommandHelp);
+ EDBPrint (DebuggerPrivate->DebuggerCommandSet[Index].CommandSyntax);
+ return EFI_DEBUG_CONTINUE;
+ }
+ }
+
+ //
+ // Command not found.
+ //
+ EDBPrint (L"No help info for this command\n");
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdMemory.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdMemory.c
new file mode 100644
index 000000000..42bd8093f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdMemory.c
@@ -0,0 +1,578 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+
+/**
+
+ Display memory unit.
+
+ @param Address - Memory Address
+ @param Width - Memory Width
+
+ @return Length of the memory unit
+
+**/
+UINTN
+EdbDisplayMemoryUnit (
+ IN UINTN Address,
+ IN EDB_DATA_WIDTH Width
+ )
+{
+ UINT8 Data8;
+ UINT16 Data16;
+ UINT32 Data32;
+ UINT64 Data64;
+
+ //
+ // Print according to width
+ //
+ switch (Width) {
+ case EdbWidthUint8:
+ CopyMem (&Data8, (VOID *)Address, sizeof(UINT8));
+ EDBPrint (L"%02x ", Data8);
+ return sizeof(UINT8);
+ case EdbWidthUint16:
+ CopyMem (&Data16, (VOID *)Address, sizeof(UINT16));
+ EDBPrint (L"%04x ", Data16);
+ return sizeof(UINT16);
+ case EdbWidthUint32:
+ CopyMem (&Data32, (VOID *)Address, sizeof(UINT32));
+ EDBPrint (L"%08x ", Data32);
+ return sizeof(UINT32);
+ case EdbWidthUint64:
+ CopyMem (&Data64, (VOID *)Address, sizeof(UINT64));
+ EDBPrint (L"%016lx ", Data64);
+ return sizeof(UINT64);
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ //
+ // something wrong
+ //
+ return 0;
+}
+
+/**
+
+ Display memory.
+
+ @param Address - Memory Address
+ @param Count - Memory Count
+ @param Width - Memory Width
+
+**/
+VOID
+EdbDisplayMemory (
+ IN UINTN Address,
+ IN UINTN Count,
+ IN EDB_DATA_WIDTH Width
+ )
+{
+ UINTN LineNumber;
+ UINTN ByteNumber;
+ UINTN LineIndex;
+ UINTN ByteIndex;
+ UINTN NumberInLine;
+
+ if (Count == 0) {
+ return ;
+ }
+
+ //
+ // Get line number and byte number
+ //
+ switch (Width) {
+ case EdbWidthUint8:
+ NumberInLine = 16;
+ break;
+ case EdbWidthUint16:
+ NumberInLine = 8;
+ break;
+ case EdbWidthUint32:
+ NumberInLine = 4;
+ break;
+ case EdbWidthUint64:
+ NumberInLine = 2;
+ break;
+ default:
+ return;
+ }
+
+ LineNumber = Count / NumberInLine;
+ ByteNumber = Count % NumberInLine;
+ if (ByteNumber == 0) {
+ LineNumber -= 1;
+ ByteNumber = NumberInLine;
+ }
+
+ //
+ // Print each line
+ //
+ for (LineIndex = 0; LineIndex < LineNumber; LineIndex++) {
+
+ //
+ // Break check
+ //
+ if (((LineIndex % EFI_DEBUGGER_LINE_NUMBER_IN_PAGE) == 0) &&
+ (LineIndex != 0)) {
+ if (SetPageBreak ()) {
+ break;
+ }
+ }
+
+ EDBPrint (EDB_PRINT_ADDRESS_FORMAT, (UINTN)Address);
+ for (ByteIndex = 0; ByteIndex < NumberInLine; ByteIndex++) {
+ Address += EdbDisplayMemoryUnit (Address, Width);
+ }
+ EDBPrint (L"\n");
+ }
+
+ //
+ // Break check
+ //
+ if (((LineIndex % EFI_DEBUGGER_LINE_NUMBER_IN_PAGE) == 0) &&
+ (LineIndex != 0)) {
+ if (SetPageBreak ()) {
+ return;
+ }
+ }
+
+ //
+ // Print last line
+ //
+ EDBPrint (EDB_PRINT_ADDRESS_FORMAT, (UINTN)Address);
+ for (ByteIndex = 0; ByteIndex < ByteNumber; ByteIndex++) {
+ Address += EdbDisplayMemoryUnit (Address, Width);
+ }
+
+ return ;
+}
+
+/**
+
+ Entry memory.
+
+ @param Address - Memory Address
+ @param Value - Memory Value
+ @param Width - Memory Width
+
+**/
+VOID
+EdbEnterMemory (
+ IN UINTN Address,
+ IN VOID *Value,
+ IN EDB_DATA_WIDTH Width
+ )
+{
+ switch (Width) {
+ case EdbWidthUint8:
+ CopyMem ((VOID *)Address, Value, sizeof(UINT8));
+ break;
+ case EdbWidthUint16:
+ CopyMem ((VOID *)Address, Value, sizeof(UINT16));
+ break;
+ case EdbWidthUint32:
+ CopyMem ((VOID *)Address, Value, sizeof(UINT32));
+ break;
+ case EdbWidthUint64:
+ CopyMem ((VOID *)Address, Value, sizeof(UINT64));
+ break;
+ default:
+ break;
+ }
+
+ return ;
+}
+
+/**
+
+ Get memory address and count.
+
+ @param CommandArg - The argument for this command
+ @param Address - Memory Address
+ @param Count - Memory Count
+
+ @retval EFI_SUCCESS - memory address and count are got
+ @retval EFI_INVALID_PARAMETER - something wrong
+
+**/
+EFI_STATUS
+EdbGetMemoryAddressCount (
+ IN CHAR16 *CommandArg,
+ IN UINTN *Address,
+ IN UINTN *Count
+ )
+{
+ CHAR16 *CommandStr;
+ UINTN MemAddress;
+ EFI_STATUS Status;
+
+ //
+ // Get Address
+ //
+ CommandStr = CommandArg;
+ if (CommandStr == NULL) {
+ EDBPrint (L"Memory: Address error!\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = Symboltoi (CommandStr, &MemAddress);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND) {
+ MemAddress = Xtoi(CommandStr);
+ } else {
+ //
+ // Something wrong, let Symboltoi print error info.
+ //
+ EDBPrint (L"Command Argument error!\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ *Address = MemAddress;
+
+ //
+ // Get Count
+ //
+ CommandStr = StrGetNextTokenLine (L" ");
+ if (CommandStr == NULL) {
+ *Count = 1;
+ } else {
+ *Count = Xtoi(CommandStr);
+ }
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get memory address and value.
+
+ @param CommandArg - The argument for this command
+ @param Address - Memory Address
+ @param Value - Memory Value
+
+ @retval EFI_SUCCESS - memory address and value are got
+ @retval EFI_INVALID_PARAMETER - something wrong
+
+**/
+EFI_STATUS
+EdbGetMemoryAddressValue (
+ IN CHAR16 *CommandArg,
+ IN UINTN *Address,
+ IN UINT64 *Value
+ )
+{
+ CHAR16 *CommandStr;
+ UINTN MemAddress;
+ EFI_STATUS Status;
+
+ //
+ // Get Address
+ //
+ CommandStr = CommandArg;
+ if (CommandStr == NULL) {
+ EDBPrint (L"Memory: Address error!\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = Symboltoi (CommandStr, &MemAddress);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND) {
+ MemAddress = Xtoi(CommandStr);
+ } else {
+ //
+ // Something wrong, let Symboltoi print error info.
+ //
+ EDBPrint (L"Command Argument error!\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ *Address = MemAddress;
+
+ //
+ // Get Value
+ //
+ CommandStr = StrGetNextTokenLine (L" ");
+ if (CommandStr == NULL) {
+ EDBPrint (L"Memory: Value error!\n");
+ return EFI_INVALID_PARAMETER;
+ }
+ *Value = LXtoi(CommandStr);
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Display memory.
+
+ @param CommandArg - The argument for this command
+ @param Width - Memory Width
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryDisplay (
+ IN CHAR16 *CommandArg,
+ IN EDB_DATA_WIDTH Width
+ )
+{
+ EFI_STATUS Status;
+ UINTN Address;
+ UINTN Count;
+
+ //
+ // Get memory address and count
+ //
+ Status = EdbGetMemoryAddressCount (CommandArg, &Address, &Count);
+ if (EFI_ERROR(Status)) {
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Display memory
+ //
+ EdbDisplayMemory (Address, Count, Width);
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ Enter memory.
+
+ @param CommandArg - The argument for this command
+ @param Width - Memory Width
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryEnter (
+ IN CHAR16 *CommandArg,
+ IN EDB_DATA_WIDTH Width
+ )
+{
+ EFI_STATUS Status;
+ UINTN Address;
+ UINT64 Value;
+
+ //
+ // Get memory address and value
+ //
+ Status = EdbGetMemoryAddressValue (CommandArg, &Address, &Value);
+ if (EFI_ERROR(Status)) {
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Enter memory
+ //
+ EdbEnterMemory (Address, &Value, Width);
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - DB.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryDB (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ return DebuggerMemoryDisplay (CommandArg, EdbWidthUint8);
+}
+
+/**
+
+ DebuggerCommand - DW.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryDW (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ return DebuggerMemoryDisplay (CommandArg, EdbWidthUint16);
+}
+
+/**
+
+ DebuggerCommand - DD.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryDD (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ return DebuggerMemoryDisplay (CommandArg, EdbWidthUint32);
+}
+
+/**
+
+ DebuggerCommand - DQ.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryDQ (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ return DebuggerMemoryDisplay (CommandArg, EdbWidthUint64);
+}
+
+/**
+
+ DebuggerCommand - EB.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryEB (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ return DebuggerMemoryEnter (CommandArg, EdbWidthUint8);
+}
+
+/**
+
+ DebuggerCommand - EW.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Interrupt type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryEW (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ return DebuggerMemoryEnter (CommandArg, EdbWidthUint16);
+}
+
+/**
+
+ DebuggerCommand - ED.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryED (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ return DebuggerMemoryEnter (CommandArg, EdbWidthUint32);
+}
+
+/**
+
+ DebuggerCommand - EQ.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerMemoryEQ (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ return DebuggerMemoryEnter (CommandArg, EdbWidthUint64);
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdQuit.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdQuit.c
new file mode 100644
index 000000000..76daf8540
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdQuit.c
@@ -0,0 +1,38 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+Module Name:
+
+ EdbCmdQuit.c
+
+Abstract:
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ DebuggerCommand - Quit
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_RETURN - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerQuit (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ return EFI_DEBUG_RETURN;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdRegister.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdRegister.c
new file mode 100644
index 000000000..2ced0e4dd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdRegister.c
@@ -0,0 +1,118 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ DebuggerCommand - Register.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerRegister (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ CHAR16 *RegName;
+ CHAR16 *RegValStr;
+ UINT64 RegVal;
+
+ //
+ // Check Argument, NULL means print all register
+ //
+ if (CommandArg == 0) {
+ EDBPrint (
+ L" R0 - 0x%016lx, R1 - 0x%016lx\n",
+ SystemContext.SystemContextEbc->R0,
+ SystemContext.SystemContextEbc->R1
+ );
+ EDBPrint (
+ L" R2 - 0x%016lx, R3 - 0x%016lx\n",
+ SystemContext.SystemContextEbc->R2,
+ SystemContext.SystemContextEbc->R3
+ );
+ EDBPrint (
+ L" R4 - 0x%016lx, R5 - 0x%016lx\n",
+ SystemContext.SystemContextEbc->R4,
+ SystemContext.SystemContextEbc->R5
+ );
+ EDBPrint (
+ L" R6 - 0x%016lx, R7 - 0x%016lx\n",
+ SystemContext.SystemContextEbc->R6,
+ SystemContext.SystemContextEbc->R7
+ );
+ EDBPrint (
+ L" Flags - 0x%016lx, ControlFlags - 0x%016lx\n",
+ SystemContext.SystemContextEbc->Flags,
+ SystemContext.SystemContextEbc->ControlFlags
+ );
+ EDBPrint (
+ L" Ip - 0x%016lx\n",
+ SystemContext.SystemContextEbc->Ip
+ );
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Get register name
+ //
+ RegName = CommandArg;
+ //
+ // Get register value
+ //
+ RegValStr = StrGetNextTokenLine (L" ");
+ if (RegValStr == NULL) {
+ EDBPrint (L"Invalid Register Value\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ RegVal = LXtoi (RegValStr);
+
+ //
+ // Assign register value
+ //
+ if (StriCmp (RegName, L"R0") == 0) {
+ SystemContext.SystemContextEbc->R0 = RegVal;
+ } else if (StriCmp (RegName, L"R1") == 0) {
+ SystemContext.SystemContextEbc->R1 = RegVal;
+ } else if (StriCmp (RegName, L"R2") == 0) {
+ SystemContext.SystemContextEbc->R2 = RegVal;
+ } else if (StriCmp (RegName, L"R3") == 0) {
+ SystemContext.SystemContextEbc->R3 = RegVal;
+ } else if (StriCmp (RegName, L"R4") == 0) {
+ SystemContext.SystemContextEbc->R4 = RegVal;
+ } else if (StriCmp (RegName, L"R5") == 0) {
+ SystemContext.SystemContextEbc->R5 = RegVal;
+ } else if (StriCmp (RegName, L"R6") == 0) {
+ SystemContext.SystemContextEbc->R6 = RegVal;
+ } else if (StriCmp (RegName, L"R7") == 0) {
+ SystemContext.SystemContextEbc->R7 = RegVal;
+ } else if (StriCmp (RegName, L"Flags") == 0) {
+ SystemContext.SystemContextEbc->Flags = RegVal;
+ } else if (StriCmp (RegName, L"ControlFlags") == 0) {
+ SystemContext.SystemContextEbc->ControlFlags = RegVal;
+ } else if (StriCmp (RegName, L"Ip") == 0) {
+ SystemContext.SystemContextEbc->Ip = RegVal;
+ } else {
+ EDBPrint (L"Invalid Register - %s\n", RegName);
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdScope.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdScope.c
new file mode 100644
index 000000000..8240ab624
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdScope.c
@@ -0,0 +1,99 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ DebuggerCommand - Scope.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerScope (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EFI_STATUS Status;
+ UINTN Address;
+
+ if (CommandArg == NULL) {
+ EDBPrint (L"Scope: invalid Address\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Load new scope
+ //
+ Status = Symboltoi (CommandArg, &Address);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND) {
+ Address = Xtoi(CommandArg);
+ } else {
+ //
+ // Something wrong, let Symboltoi print error info.
+ //
+ EDBPrint (L"Command Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ }
+ DebuggerPrivate->InstructionScope = Address;
+ EDBPrint (L"Scope: 0x%x\n", DebuggerPrivate->InstructionScope);
+ EdbShowDisasm (DebuggerPrivate, SystemContext);
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - List.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerList (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ if (CommandArg == NULL) {
+ EdbShowDisasm (DebuggerPrivate, SystemContext);
+ } else {
+ //
+ // Load new list number
+ //
+ DebuggerPrivate->InstructionNumber = Atoi(CommandArg);
+ EDBPrint (L"List Number: %d\n", DebuggerPrivate->InstructionNumber);
+ EdbShowDisasm (DebuggerPrivate, SystemContext);
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdStep.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdStep.c
new file mode 100644
index 000000000..441f53676
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdStep.c
@@ -0,0 +1,156 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ Check whether current IP is EBC CALL instruction (NOTE: CALLEX is exclusive)
+
+ @param Address - EBC IP address.
+
+ @retval TRUE - Current IP is EBC CALL instruction
+ @retval FALSE - Current IP is not EBC CALL instruction
+
+**/
+BOOLEAN
+IsEBCCALL (
+ IN UINTN Address
+ )
+{
+ if (GET_OPCODE(Address) != OPCODE_CALL) {
+ return FALSE;
+ }
+
+ if (GET_OPERANDS (Address) & OPERAND_M_NATIVE_CALL) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/**
+
+ Check whether current IP is EBC RET instruction.
+
+ @param Address - EBC IP address.
+
+ @retval TRUE - Current IP is EBC RET instruction
+ @retval FALSE - Current IP is not EBC RET instruction
+
+**/
+BOOLEAN
+IsEBCRET (
+ IN UINTN Address
+ )
+{
+ if (GET_OPCODE(Address) != OPCODE_RET) {
+ return FALSE;
+ }
+
+ if (GET_OPERANDS (Address) != 0) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/**
+
+ DebuggerCommand - StepInto.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerStepInto (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ SystemContext.SystemContextEbc->Flags |= VMFLAGS_STEP;
+
+ return EFI_DEBUG_BREAK;
+}
+
+/**
+
+ DebuggerCommand - StepOver.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerStepOver (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ if (IsEBCCALL((UINTN)SystemContext.SystemContextEbc->Ip)) {
+ //
+ // Check CALL (NOTE: CALLEX is exclusive)
+ //
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_STEPOVER;
+ } else {
+ //
+ // Other instruction including CALLEX
+ //
+ SystemContext.SystemContextEbc->Flags |= VMFLAGS_STEP;
+ }
+
+ return EFI_DEBUG_BREAK;
+}
+
+/**
+
+ DebuggerCommand - StepOut.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerStepOut (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ if (IsEBCRET((UINTN)SystemContext.SystemContextEbc->Ip)) {
+ //
+ // Check RET
+ //
+ SystemContext.SystemContextEbc->Flags |= VMFLAGS_STEP;
+ } else {
+ //
+ // Other instruction
+ //
+ DebuggerPrivate->FeatureFlags |= EFI_DEBUG_FLAG_EBC_STEPOUT;
+ }
+
+ return EFI_DEBUG_BREAK;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdSymbol.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdSymbol.c
new file mode 100644
index 000000000..7b453fa98
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCmdSymbol.c
@@ -0,0 +1,862 @@
+/** @file
+
+Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ Get file name from full path.
+
+ @param FullPath - full file path
+
+ @return file name
+
+**/
+CHAR16 *
+GetFileNameFromFullPath (
+ IN CHAR16 *FullPath
+ )
+{
+ CHAR16 *FileName;
+ CHAR16 *TempFileName;
+
+ FileName = FullPath;
+ TempFileName = StrGetNewTokenLine (FullPath, L"\\");
+
+ while (TempFileName != NULL) {
+ FileName = TempFileName;
+ TempFileName = StrGetNextTokenLine (L"\\");
+ PatchForStrTokenBefore (TempFileName, L'\\');
+ }
+
+ return FileName;
+}
+
+/**
+
+ Get dir name from full path.
+
+ @param FullPath - full file path
+
+ @return dir name
+
+**/
+CHAR16 *
+GetDirNameFromFullPath (
+ IN CHAR16 *FullPath
+ )
+{
+ CHAR16 *FileName;
+
+ FileName = GetFileNameFromFullPath (FullPath);
+ if (FileName != FullPath) {
+ *(FileName - 1) = 0;
+ return FullPath;
+ }
+
+ return L"";
+}
+
+/**
+
+ Construct full path according to dir and file path.
+
+ @param DirPath - dir path
+ @param FilePath - file path
+ @param Size - dir max size
+
+ @return Full file name
+
+**/
+CHAR16 *
+ConstructFullPath (
+ IN CHAR16 *DirPath,
+ IN CHAR16 *FilePath,
+ IN UINTN Size
+ )
+{
+ UINTN DirPathSize;
+
+ DirPathSize = StrLen(DirPath);
+ *(DirPath + DirPathSize) = L'\\';
+ StrnCatS (DirPath, DirPathSize + Size + 1, FilePath, Size);
+
+ *(DirPath + DirPathSize + Size + 1) = 0;
+
+ return DirPath;
+}
+
+CHAR16 *mSymbolTypeStr[] = {
+ L"( F)",
+ L"(SF)",
+ L"(GV)",
+ L"(SV)",
+};
+
+/**
+
+ Comvert Symbol Type to string.
+
+ @param Type - Symbol Type
+
+ @return String
+
+**/
+CHAR16 *
+EdbSymbolTypeToStr (
+ IN EFI_DEBUGGER_SYMBOL_TYPE Type
+ )
+{
+ if (Type < 0 || Type >= EfiDebuggerSymbolTypeMax) {
+ return L"(?)";
+ }
+
+ return mSymbolTypeStr [Type];
+}
+
+/**
+
+ Find the symbol according to address and display symbol.
+
+ @param Address - SymbolAddress
+ @param DebuggerPrivate - EBC Debugger private data structure
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerDisplaySymbolAccrodingToAddress (
+ IN UINTN Address,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate
+ )
+{
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
+ UINTN CandidateAddress;
+
+ //
+ // Find the nearest symbol address
+ //
+ CandidateAddress = EbdFindSymbolAddress (Address, EdbMatchSymbolTypeNearestAddress, &Object, &Entry);
+ if (CandidateAddress == 0 || CandidateAddress == (UINTN) -1 || Entry == NULL) {
+ EDBPrint (L"Symbole at Address not found!\n");
+ return EFI_DEBUG_CONTINUE;
+ } else if (Address != CandidateAddress) {
+ EDBPrint (L"Symbole at Address not found, print nearest one!\n");
+ }
+
+ //
+ // Display symbol
+ //
+ EDBPrint (L"Symbol File Name: %s\n", Object->Name);
+ if (sizeof(UINTN) == sizeof(UINT64)) {
+ EDBPrint (L" Address Type Symbol\n");
+ EDBPrint (L" ================== ==== ========\n");
+// EDBPrint (L" 0xFFFFFFFF00000000 ( F) TestMain\n");
+ EDBPrint (
+ L" 0x%016lx %s %a\n",
+ (UINT64)Entry->Rva + Object->BaseAddress,
+ EdbSymbolTypeToStr (Entry->Type),
+ Entry->Name
+ );
+ } else {
+ EDBPrint (L" Address Type Symbol\n");
+ EDBPrint (L" ========== ==== ========\n");
+// EDBPrint (L" 0xFFFF0000 ( F) TestMain\n");
+ EDBPrint (
+ L" 0x%08x %s %a\n",
+ Entry->Rva + Object->BaseAddress,
+ EdbSymbolTypeToStr (Entry->Type),
+ Entry->Name
+ );
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ Find the symbol according to name and display symbol.
+
+ @param SymbolFileName - The Symbol File Name, NULL means for all
+ @param SymbolName - The Symbol Name, NULL means for all
+ @param DebuggerPrivate - EBC Debugger private data structure
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerDisplaySymbolAccrodingToName (
+ IN CHAR16 *SymbolFileName,
+ IN CHAR16 *SymbolName,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate
+ )
+{
+ UINTN Index;
+ UINTN SubIndex;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
+
+ if (DebuggerPrivate->DebuggerSymbolContext.ObjectCount == 0) {
+ EDBPrint (L"No Symbol File!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Go throuth each symbol file
+ //
+ Object = DebuggerPrivate->DebuggerSymbolContext.Object;
+ for (Index = 0; Index < DebuggerPrivate->DebuggerSymbolContext.ObjectCount; Index++, Object++) {
+ if ((SymbolFileName != NULL) &&
+ (StriCmp (SymbolFileName, Object->Name) != 0)) {
+ continue;
+ }
+
+ //
+ // Break each symbol file
+ //
+ if (Index != 0) {
+ if (SetPageBreak ()) {
+ break;
+ }
+ }
+
+ EDBPrint (L"Symbol File Name: %s\n", Object->Name);
+ if (Object->EntryCount == 0) {
+ EDBPrint (L"No Symbol!\n");
+ continue;
+ }
+ Entry = Object->Entry;
+ if (sizeof(UINTN) == sizeof(UINT64)) {
+ EDBPrint (L" Address Type Symbol\n");
+ EDBPrint (L" ================== ==== ========\n");
+// EDBPrint (L" 0xFFFFFFFF00000000 ( F) TestMain (EbcTest.obj)\n");
+ } else {
+ EDBPrint (L" Address Type Symbol\n");
+ EDBPrint (L" ========== ==== ========\n");
+// EDBPrint (L" 0xFFFF0000 ( F) TestMain (EbcTest.obj)\n");
+ }
+
+ //
+ // Go through each symbol name
+ //
+ for (SubIndex = 0; SubIndex < Object->EntryCount; SubIndex++, Entry++) {
+ if ((SymbolName != NULL) &&
+ (StrCmpUnicodeAndAscii (SymbolName, Entry->Name) != 0)) {
+ continue;
+ }
+
+ //
+ // Break symbol
+ //
+ if (((SubIndex % EFI_DEBUGGER_LINE_NUMBER_IN_PAGE) == 0) &&
+ (SubIndex != 0)) {
+ if (SetPageBreak ()) {
+ break;
+ }
+ }
+
+ if (sizeof(UINTN) == sizeof(UINT64)) {
+ EDBPrint (
+ L" 0x%016lx %s %a (%a)\n",
+ (UINT64)Entry->Rva + Object->BaseAddress,
+ EdbSymbolTypeToStr (Entry->Type),
+ Entry->Name,
+ Entry->ObjName
+ );
+ } else {
+ EDBPrint (
+ L" 0x%08x %s %a (%a)\n",
+ Entry->Rva + Object->BaseAddress,
+ EdbSymbolTypeToStr (Entry->Type),
+ Entry->Name,
+ Entry->ObjName
+ );
+ }
+ }
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - ListSymbol.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerListSymbol (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ CHAR16 *SymbolFileName;
+ CHAR16 *SymbolName;
+ CHAR16 *CommandStr;
+ UINTN Address;
+
+ SymbolFileName = NULL;
+ SymbolName = NULL;
+ CommandStr = CommandArg;
+
+ //
+ // display symbol according to address
+ //
+ if (CommandStr != NULL) {
+ if ((StriCmp (CommandStr, L"F") != 0) &&
+ (StriCmp (CommandStr, L"S") != 0)) {
+ Address = Xtoi (CommandStr);
+ return DebuggerDisplaySymbolAccrodingToAddress (Address, DebuggerPrivate);
+ }
+ }
+
+ //
+ // Get SymbolFileName
+ //
+ if (CommandStr != NULL) {
+ if (StriCmp (CommandStr, L"F") == 0) {
+ CommandStr = StrGetNextTokenLine (L" ");
+ if (CommandStr == NULL) {
+ EDBPrint (L"Symbol File Name missing!\n");
+ return EFI_DEBUG_CONTINUE;
+ } else {
+ SymbolFileName = CommandStr;
+ CommandStr = StrGetNextTokenLine (L" ");
+ }
+ }
+ }
+ //
+ // Get SymbolName
+ //
+ if (CommandStr != NULL) {
+ if (StriCmp (CommandStr, L"S") == 0) {
+ CommandStr = StrGetNextTokenLine (L" ");
+ if (CommandStr == NULL) {
+ EDBPrint (L"Symbol Name missing!\n");
+ return EFI_DEBUG_CONTINUE;
+ } else {
+ SymbolName = CommandStr;
+ CommandStr = StrGetNextTokenLine (L" ");
+ }
+ }
+ }
+ if (CommandStr != NULL) {
+ EDBPrint (L"Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // display symbol according to name
+ //
+ return DebuggerDisplaySymbolAccrodingToName (SymbolFileName, SymbolName, DebuggerPrivate);
+}
+
+/**
+
+ DebuggerCommand - LoadSymbol.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerLoadSymbol (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN BufferSize;
+ VOID *Buffer;
+ EFI_STATUS Status;
+ CHAR16 *FileName;
+ CHAR16 *CommandArg2;
+ BOOLEAN IsLoadCode;
+ CHAR16 *DirName;
+ CHAR16 CodFile[EFI_DEBUGGER_SYMBOL_NAME_MAX];
+ CHAR16 *CodFileName;
+ UINTN Index;
+
+ //
+ // Check the argument
+ //
+ if (CommandArg == NULL) {
+ EDBPrint (L"SymbolFile not found!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ IsLoadCode = FALSE;
+ CommandArg2 = StrGetNextTokenLine (L" ");
+ if (CommandArg2 != NULL) {
+ if (StriCmp (CommandArg2, L"a") == 0) {
+ IsLoadCode = TRUE;
+ } else {
+ EDBPrint (L"Argument error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ }
+
+ if (StrLen (CommandArg) <= 4) {
+ EDBPrint (L"SymbolFile name error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ if (StriCmp (CommandArg + (StrLen (CommandArg) - 4), L".map") != 0) {
+ EDBPrint (L"SymbolFile name error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Read MAP file to memory
+ //
+ Status = ReadFileToBuffer (DebuggerPrivate, CommandArg, &BufferSize, &Buffer, TRUE);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"SymbolFile read error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ FileName = GetFileNameFromFullPath (CommandArg);
+ //
+ // Load Symbol
+ //
+ Status = EdbLoadSymbol (DebuggerPrivate, FileName, BufferSize, Buffer);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"LoadSymbol error!\n");
+ gBS->FreePool (Buffer);
+ return EFI_DEBUG_CONTINUE;
+ }
+ gBS->FreePool (Buffer);
+
+ //
+ // Patch Symbol for RVA
+ //
+ Status = EdbPatchSymbolRVA (DebuggerPrivate, FileName, EdbEbcImageRvaSearchTypeLast);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"PatchSymbol RVA - %r! Using the RVA in symbol file.\n", Status);
+ } else {
+ DEBUG ((DEBUG_ERROR, "PatchSymbol RVA successfully!\n"));
+ }
+
+ if (!IsLoadCode) {
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // load each cod file
+ //
+ DirName = GetDirNameFromFullPath (CommandArg);
+ ZeroMem (CodFile, sizeof(CodFile));
+ if (StrCmp (DirName, L"") != 0) {
+ StrCpyS (CodFile, sizeof(CodFile), DirName);
+ } else {
+ DirName = L"\\";
+ }
+
+ //
+ // Go throuth each file under this dir
+ //
+ Index = 0;
+ CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
+ while (CodFileName != NULL) {
+ ZeroMem (CodFile, sizeof(CodFile));
+ if (StrCmp (DirName, L"\\") != 0) {
+ StrCpyS (CodFile, sizeof(CodFile), DirName);
+ }
+
+ //
+ // read cod file to memory
+ //
+ Status = ReadFileToBuffer (DebuggerPrivate, ConstructFullPath (CodFile, CodFileName, EFI_DEBUGGER_SYMBOL_NAME_MAX - StrLen (CodFile) - 2), &BufferSize, &Buffer, FALSE);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"CodeFile read error!\n");
+ CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
+ continue;
+ }
+
+ //
+ // Load Code
+ //
+ Status = EdbLoadCode (DebuggerPrivate, FileName, CodFileName, BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ EDBPrint (L"LoadCode error!\n");
+ gBS->FreePool (Buffer);
+ CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
+ continue;
+ }
+
+ //
+ // Record the buffer
+ //
+ Status = EdbAddCodeBuffer (DebuggerPrivate, FileName, CodFileName, BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ EDBPrint (L"AddCodeBuffer error!\n");
+ gBS->FreePool (Buffer);
+ CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
+ continue;
+ }
+
+ //
+ // Get next file
+ //
+ CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - UnloadSymbol
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerUnloadSymbol (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *FileName;
+ CHAR16 *DirName;
+ CHAR16 CodFile[EFI_DEBUGGER_SYMBOL_NAME_MAX];
+ CHAR16 *CodFileName;
+ UINTN Index;
+ VOID *BufferPtr;
+
+ //
+ // Check the argument
+ //
+ if (CommandArg == NULL) {
+ EDBPrint (L"SymbolFile not found!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ FileName = GetFileNameFromFullPath (CommandArg);
+
+ //
+ // Unload Code
+ //
+ DirName = GetDirNameFromFullPath (CommandArg);
+ ZeroMem (CodFile, sizeof(CodFile));
+ if (StrCmp (DirName, L"") != 0) {
+ StrCpyS (CodFile, sizeof(CodFile), DirName);
+ } else {
+ DirName = L"\\";
+ }
+
+ //
+ // Go through each file under this dir
+ //
+ Index = 0;
+ CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
+ while (CodFileName != NULL) {
+ ZeroMem (CodFile, sizeof(CodFile));
+ if (StrCmp (DirName, L"\\") != 0) {
+ StrCpyS (CodFile, sizeof(CodFile), DirName);
+ }
+
+ //
+ // Unload Code
+ //
+ Status = EdbUnloadCode (DebuggerPrivate, FileName, CodFileName, &BufferPtr);
+ if (EFI_ERROR (Status)) {
+ EDBPrint (L"UnloadCode error!\n");
+ CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
+ continue;
+ }
+
+ //
+ // Delete the code buffer
+ //
+ Status = EdbDeleteCodeBuffer (DebuggerPrivate, FileName, CodFileName, BufferPtr);
+ if (EFI_ERROR (Status)) {
+ EDBPrint (L"DeleteCodeBuffer error!\n");
+ CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
+ continue;
+ }
+
+ //
+ // Get next file
+ //
+ CodFileName = GetFileNameUnderDir (DebuggerPrivate, DirName, L".cod", &Index);
+ }
+
+ //
+ // Unload Symbol
+ //
+ Status = EdbUnloadSymbol (DebuggerPrivate, FileName);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"UnloadSymbol error!\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - DisplaySymbol.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerDisplaySymbol (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ if (CommandArg == NULL) {
+ DebuggerPrivate->DebuggerSymbolContext.DisplaySymbol = !DebuggerPrivate->DebuggerSymbolContext.DisplaySymbol;
+ EdbShowDisasm (DebuggerPrivate, SystemContext);
+ } else if (StriCmp (CommandArg, L"on") == 0) {
+ DebuggerPrivate->DebuggerSymbolContext.DisplaySymbol = TRUE;
+ EdbShowDisasm (DebuggerPrivate, SystemContext);
+ } else if (StriCmp (CommandArg, L"off") == 0) {
+ DebuggerPrivate->DebuggerSymbolContext.DisplaySymbol = FALSE;
+ EdbShowDisasm (DebuggerPrivate, SystemContext);
+ } else {
+ EDBPrint (L"DisplaySymbol - argument error\n");
+ }
+
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - LoadCode.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerLoadCode (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ UINTN BufferSize;
+ VOID *Buffer;
+ EFI_STATUS Status;
+ CHAR16 *CommandArg2;
+ CHAR16 *FileName;
+ CHAR16 *MapFileName;
+
+ //
+ // Check the argument
+ //
+ if (CommandArg == NULL) {
+ EDBPrint (L"CodeFile not found!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ CommandArg2 = StrGetNextTokenLine (L" ");
+ if (CommandArg2 == NULL) {
+ EDBPrint (L"SymbolFile not found!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ if (StrLen (CommandArg) <= 4) {
+ EDBPrint (L"CodeFile name error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ if (StriCmp (CommandArg + (StrLen (CommandArg) - 4), L".cod") != 0) {
+ EDBPrint (L"CodeFile name error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ if (StrLen (CommandArg2) <= 4) {
+ EDBPrint (L"SymbolFile name error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ if (StriCmp (CommandArg2 + (StrLen (CommandArg2) - 4), L".map") != 0) {
+ EDBPrint (L"SymbolFile name error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // read cod file to memory
+ //
+ Status = ReadFileToBuffer (DebuggerPrivate, CommandArg, &BufferSize, &Buffer, TRUE);
+ if (EFI_ERROR(Status)) {
+ EDBPrint (L"CodeFile read error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ FileName = GetFileNameFromFullPath (CommandArg);
+ MapFileName = GetFileNameFromFullPath (CommandArg2);
+ //
+ // Load Code
+ //
+ Status = EdbLoadCode (DebuggerPrivate, MapFileName, FileName, BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ EDBPrint (L"LoadCode error!\n");
+ gBS->FreePool (Buffer);
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Record the buffer
+ //
+ Status = EdbAddCodeBuffer (DebuggerPrivate, MapFileName, FileName, BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ EDBPrint (L"AddCodeBuffer error!\n");
+ gBS->FreePool (Buffer);
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - UnloadCode.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerUnloadCode (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ CHAR16 *CommandArg2;
+ CHAR16 *FileName;
+ CHAR16 *MapFileName;
+ EFI_STATUS Status;
+ VOID *BufferPtr;
+
+ //
+ // Check the argument
+ //
+ if (CommandArg == NULL) {
+ EDBPrint (L"CodeFile not found!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+ CommandArg2 = StrGetNextTokenLine (L" ");
+ if (CommandArg2 == NULL) {
+ EDBPrint (L"SymbolFile not found!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ FileName = GetFileNameFromFullPath (CommandArg);
+ MapFileName = GetFileNameFromFullPath (CommandArg2);
+
+ //
+ // Unload Code
+ //
+ Status = EdbUnloadCode (DebuggerPrivate, MapFileName, FileName, &BufferPtr);
+ if (EFI_ERROR (Status)) {
+ EDBPrint (L"UnloadCode error!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Delete Code buffer
+ //
+ Status = EdbDeleteCodeBuffer (DebuggerPrivate, MapFileName, FileName, BufferPtr);
+ if (EFI_ERROR (Status)) {
+ EDBPrint (L"DeleteCodeBuffer error!\n");
+ }
+
+ //
+ // Done
+ //
+ return EFI_DEBUG_CONTINUE;
+}
+
+/**
+
+ DebuggerCommand - DisplayCode.
+
+ @param CommandArg - The argument for this command
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param ExceptionType - Exception type.
+ @param SystemContext - EBC system context.
+
+ @retval EFI_DEBUG_CONTINUE - formal return value
+
+**/
+EFI_DEBUG_STATUS
+DebuggerDisplayCode (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ if (CommandArg == NULL) {
+ DebuggerPrivate->DebuggerSymbolContext.DisplayCodeOnly = !DebuggerPrivate->DebuggerSymbolContext.DisplayCodeOnly;
+ EdbShowDisasm (DebuggerPrivate, SystemContext);
+ } else if (StriCmp (CommandArg, L"on") == 0) {
+ DebuggerPrivate->DebuggerSymbolContext.DisplayCodeOnly = TRUE;
+ EdbShowDisasm (DebuggerPrivate, SystemContext);
+ } else if (StriCmp (CommandArg, L"off") == 0) {
+ DebuggerPrivate->DebuggerSymbolContext.DisplayCodeOnly = FALSE;
+ EdbShowDisasm (DebuggerPrivate, SystemContext);
+ } else {
+ EDBPrint (L"DisplayCode - argument error\n");
+ }
+
+ return EFI_DEBUG_CONTINUE;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommand.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommand.c
new file mode 100644
index 000000000..5597a7e15
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommand.c
@@ -0,0 +1,656 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+//
+// Debugger Command Table
+//
+EFI_DEBUGGER_COMMAND_SET mDebuggerCommandSet[] = {
+ //
+ // Execution
+ //
+ {
+ L"G",
+ L"G/[F5] - continue to run the program\n",
+ L"The go command is used to cause the debugger to not interrupt execution of the EBC image. The debugger will only break execution of the interpreter if an exception is encountered (including an EBC breakpoint).\n\n",
+ L"G [til <Address|Symbol>]\n"
+ L" (No Argument) - It means continue run the program.\n"
+ L" til - It means continuing run the program till IP is the Address.\n"
+ L" <Address> - The hexical address user want to break at.\n"
+ L" <Symbol> - The symbol name for target address user want to break at. It has following format [MapFileName:]SymbolName\n",
+ L"Execution:\n",
+ {SCAN_F5, CHAR_NULL},
+ DebuggerGo
+ },
+ {
+ L"T",
+ L"T/[F8] - step into\n",
+ L"The step into command will cause the EBC debugger to step a single instruction. If the instruction is a call to internal code (CALL), then the debugger will break at the new function CALL.\n\n",
+ L"T\n"
+ L" (No Argument)\n",
+ L"",
+ {SCAN_F8, CHAR_NULL},
+ DebuggerStepInto
+ },
+ {
+ L"P",
+ L"P/[F10] - step over\n",
+ L"The step over command will cause the EBC debugger to step a single instruction. If the instruction is a call to internal code (CALL), then the external call will be made and the debugger will break at the instruction following the CALL.\n\n",
+ L"P\n"
+ L" (No Argument)\n",
+ L"",
+ {SCAN_F10, CHAR_NULL},
+ DebuggerStepOver
+ },
+ {
+ L"O",
+ L"O/[F11] - step out\n",
+ L"The step out command causes the EBC debugger to step out function calls. The function will be executed, but the debugger will stop after the called function returns.\n\n",
+ L"O\n"
+ L" (No Argument)\n",
+ L"",
+ {SCAN_F11, CHAR_NULL},
+ DebuggerStepOut
+ },
+ {
+ L"Q",
+ L"Q - reset the debugger to default value and go\n",
+ L"The quit command will reset the debugger to default value and go.\n\n",
+ L"Q\n"
+ L" (No Argument)\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerQuit
+ },
+ //
+ // Break
+ //
+ {
+ L"BOC",
+ L"BO[C|CX|R|E|T|K] - break on CALL/CALLEX/RET/Entrypoint/Native Thunk/Key\n",
+ L"Enabling break-on-call will cause the debugger to halt execution and display the debugger prompt prior to executing any EBC CALL (to EBC) instructions.\n\n",
+ L"BOC [on|off]\n"
+ L" (No Argument) - show current state\n"
+ L" on - enable break-on-call\n"
+ L" off - disable break-on-call\n",
+ L"Break:\n",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakOnCALL
+ },
+ {
+ L"BOCX",
+ L"",
+ L"Enabling break-on-callex will cause the debugger to halt execution and display the debugger prompt prior to executing EBC CALLEX (thunk out) instructions.\n\n",
+ L"BOCX [on|off]\n"
+ L" (No Argument) - show current state\n"
+ L" on - enable break-on-callex\n"
+ L" off - disable break-on-callex\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakOnCALLEX
+ },
+ {
+ L"BOR",
+ L"",
+ L"Enabling break-on-return will cause the debugger to halt execution and display the debugger prompt prior to executing EBC RET instructions.\n\n",
+ L"BOR [on|off]\n"
+ L" (No Argument) - show current state\n"
+ L" on - enable break-on-return\n"
+ L" off - disable break-on-return\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakOnRET
+ },
+ {
+ L"BOE",
+ L"",
+ L"Enabling break-on-entrypoint will cause the debugger to halt execution and display the debugger prompt prior to start a driver entry point. (Default is on)\n\n",
+ L"BOE [on|off]\n"
+ L" (No Argument) - show current state\n"
+ L" on - enable break-on-entrypoint\n"
+ L" off - disable break-on-entrypoint\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakOnEntrypoint
+ },
+ {
+ L"BOT",
+ L"",
+ L"Enabling break-on-thunk will cause the debugger to halt execution and display the debugger prompt prior to start native call EBC thunk. (Default is on)\n\n",
+ L"BOT [on|off]\n"
+ L" (No Argument) - show current state\n"
+ L" on - enable break-on-thunk\n"
+ L" off - disable break-on-thunk\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakOnThunk
+ },
+ {
+ L"BOK",
+ L"",
+ L"Enabling break-on-key will cause the debugger to halt execution and display the debugger prompt after press any key.\n\n",
+ L"BOK [on|off]\n"
+ L" (No Argument) - show current state\n"
+ L" on - enable break-on-key\n"
+ L" off - disable break-on-key\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakOnKey
+ },
+ {
+ L"BL",
+ L"B[L|P|C|D|E] - breakpoint list/set/clear/disable/enable\n",
+ L"List Breakpoint\n\n",
+ L"BL\n"
+ L" (No Argument) - show the state for current breakpoint\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakpointList
+ },
+ {
+ L"BP",
+ L"",
+ L"Set Breakpoint\n\n",
+ L"BP <Address|Symbol>\n"
+ L" <Address> - Hexical breakpoint address\n"
+ L" <Symbol> - Symbol name for breakpoint address. It has following format [MapFileName:]SymbolName.\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakpointSet
+ },
+ {
+ L"BC",
+ L"",
+ L"Clear Breakpoint\n\n",
+ L"BC <Index>|*\n"
+ L" <Index> - Decimal breakpoint index, which can be got from BL command\n"
+ L" * - For all the breakpoint\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakpointClear
+ },
+ {
+ L"BD",
+ L"",
+ L"Disable Breakpoint\n\n",
+ L"BD <Index>|*\n"
+ L" <Index> - Decimal breakpoint index, which can be got from BL command\n"
+ L" * - For all the breakpoint\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakpointDisable
+ },
+ {
+ L"BE",
+ L"",
+ L"Enable Breakpoint\n\n",
+ L"BE <Index>|*\n"
+ L" <Index> - Decimal breakpoint index, which can be got from BL command\n"
+ L" * - For all the breakpoint\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerBreakpointEnable
+ },
+ //
+ // Information
+ //
+ {
+ L"K",
+ L"K - show/clear call-stack\n",
+ L"The call-stack command will show or clear the current call-stack.\n\n",
+ L"K [p [<ParameterNum>]|c]\n"
+ L" (No Argument) - Show current call-stack\n"
+ L" p - Show current call-stack with parameters\n"
+ L" ParameterNum - Decimal call-stack parameters number, 8 by default, 16 as max\n"
+ L" c - Clear current call-stack\n",
+ L"Information:\n",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerCallStack
+ },
+ {
+ L"TRACE",
+ L"TRACE - show/clear trace instruction branch\n",
+ L"The trace command will show or clear the latest instruction branch.\n\n",
+ L"TRACE [c]\n"
+ L" (No Argument) - Show current instruction branch\n"
+ L" c - Clear current instruction branch\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerInstructionBranch
+ },
+ {
+ L"R",
+ L"R/[F2] - display/modify register\n",
+ L"The register command is used to display or modify the contents of EBC VM registers. (R0~R7, Flags, IP)\n\n",
+ L"R [<Register> <Value>]\n"
+ L" (No Argument) - Display all registers\n"
+ L" <Register> - EBC VM register name (R0~R7, Flags, ControlFlags, and IP\n"
+ L" <Value> - The Hexical value of register\n",
+ L"",
+ {SCAN_F2, CHAR_NULL},
+ DebuggerRegister
+ },
+ {
+ L"L",
+ L"L/[F4] - show/load instruction assembly count\n",
+ L"The list assembly command will disassemble instructions starting with the current EBC VM instruction pointer. (by default 5 instructions)\n\n",
+ L"L [<Count>]\n"
+ L" (No Argument) - List current assembly code\n"
+ L" Count - The decimal instruction assembly count\n",
+ L"",
+ {SCAN_F4, CHAR_NULL},
+ DebuggerList
+ },
+ {
+ L"SCOPE",
+ L"SCOPE - load scope address\n",
+ L"The scope command will disassemble instructions starting with the Scope. (by default current EBC VM IP)\n\n",
+ L"SCOPE <Address|Symbol>\n"
+ L" <Address> - The Hexical address where user wants to see the assembly code\n"
+ L" <Symbol> - Symbol name for scope address. It has following format [MapFileName:]SymbolName.\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerScope
+ },
+ {
+ L"DB",
+ L"[D|E][B|W|D|Q] - display/modify memory\n",
+ L"Display BYTES Memory\n\n",
+ L"DB <Address|Symbol> [<Count>]\n"
+ L" <Address> - The hexical memory address\n"
+ L" <Symbol> - Symbol name for memory address. It has following format [MapFileName:]SymbolName.\n"
+ L" <Count> - The hexical memory count (not set means 1)\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerMemoryDB
+ },
+ {
+ L"DW",
+ L"",
+ L"Display WORDS Memory\n\n",
+ L"DW <Address|Symbol> [<Count>]\n"
+ L" <Address> - The hexical memory address\n"
+ L" <Symbol> - Symbol name for memory address. It has following format [MapFileName:]SymbolName.\n"
+ L" <Count> - The hexical memory count (not set means 1)\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerMemoryDW
+ },
+ {
+ L"DD",
+ L"",
+ L"Display DWORDS Memory\n\n",
+ L"DD <Address|Symbol> [<Count>]\n"
+ L" <Address> - The hexical memory address\n"
+ L" <Symbol> - Symbol name for memory address. It has following format [MapFileName:]SymbolName.\n"
+ L" <Count> - The hexical memory count (not set means 1)\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerMemoryDD
+ },
+ {
+ L"DQ",
+ L"",
+ L"Display QWORDS Memory\n\n",
+ L"DQ <Address|Symbol> [<Count>]\n"
+ L" <Address> - The hexical memory address\n"
+ L" <Symbol> - Symbol name for memory address. It has following format [MapFileName:]SymbolName.\n"
+ L" <Count> - The hexical memory count (not set means 1)\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerMemoryDQ
+ },
+ {
+ L"EB",
+ L"",
+ L"Enter BYTES Memory\n\n",
+ L"EB <Address|Symbol> <Value>\n"
+ L" <Address> - The hexical memory address\n"
+ L" <Symbol> - Symbol name for memory address. It has following format [MapFileName:]SymbolName.\n"
+ L" <Value> - The hexical memory value\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerMemoryEB
+ },
+ {
+ L"EW",
+ L"",
+ L"Enter WORDS Memory\n\n",
+ L"EW <Address|Symbol> <Value>\n"
+ L" <Address> - The hexical memory address\n"
+ L" <Symbol> - Symbol name for memory address. It has following format [MapFileName:]SymbolName.\n"
+ L" <Value> - The hexical memory value\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerMemoryEW
+ },
+ {
+ L"ED",
+ L"",
+ L"Enter DWORDS Memory\n\n",
+ L"ED <Address|Symbol> <Value>\n"
+ L" <Address> - The hexical memory address\n"
+ L" <Symbol> - Symbol name for memory address. It has following format [MapFileName:]SymbolName.\n"
+ L" <Value> - The hexical memory value\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerMemoryED
+ },
+ {
+ L"EQ",
+ L"",
+ L"Enter QWORDS Memory\n\n",
+ L"EQ <Address|Symbol> <Value>\n"
+ L" <Address> - The hexical memory address\n"
+ L" <Symbol> - Symbol name for memory address. It has following format [MapFileName:]SymbolName.\n"
+ L" <Value> - The hexical memory value\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerMemoryEQ
+ },
+ //
+ // Symbol
+ //
+ {
+ L"LN",
+ L"LN - list the symbol\n",
+ L"The show symbol command will list all the current symbol. It can list the symbol in one symbol file, or list the same symbol in all the files. It can also list the symbol according to nearest address.\n\n",
+ L"LN [[F <SymbolFile>] [S <Symbol>]] | <Address>\n"
+ L" (No Argument) - List all the symbol\n"
+ L" F <SymbolFile> - List the symbol in this symbol file only\n"
+ L" S <Symbol> - List this symbol only\n"
+ L" <Address> - The hexical memory address, which user want to find the symbol for.\n",
+ L"Symbol:\n",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerListSymbol
+ },
+ {
+ L"LOADSYMBOL",
+ L"[UN]LOADSYMBOL - load/unload the symbol file\n",
+ L"The load symbol command will load the ebc map file. Then it parses the function name and global variable, and the print real name when do the disassembly. (Symbol file name should be XXX.MAP)\n\n",
+ L"LOADSYMBOL <SymbolFile> [a]\n"
+ L" SymbolFile - The EBC symbol file (Its name should be XXX.MAP)\n"
+ L" a - Automatically load code files in the same dir\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerLoadSymbol
+ },
+ {
+ L"UNLOADSYMBOL",
+ L"",
+ L"The unload symbol command will unload the ebc map and cod file. After that the name will not be print.\n\n",
+ L"UNLOADSYMBOL <SymbolFile>\n"
+ L" SymbolFile - The EBC symbol file (Its name should be XXX.MAP)\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerUnloadSymbol
+ },
+ {
+ L"LOADCODE",
+ L"[UN]LOADCODE - load/unload the code file\n",
+ L"The load code command will load the ebc cod file. Then it parses the cod file, and the print source code when do the disassembly. (Code file name should be XXX.COD)\n\n",
+ L"LOADCODE <CodeFile> <SymbolFile>\n"
+ L" CodeFile - The EBC code file (Its name should be XXX.COD)\n"
+ L" SymbolFile - The EBC symbol file (Its name should be XXX.MAP)\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerLoadCode
+ },
+ {
+ L"UNLOADCODE",
+ L"",
+ L"The unload code command will unload the ebc cod file. After that the source code will not be print.\n\n",
+ L"UNLOADCODE <CodeFile> <SymbolFile>\n"
+ L" CodeFile - The EBC code file (Its name should be XXX.COD)\n"
+ L" SymbolFile - The EBC symbol file (Its name should be XXX.MAP)\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerUnloadCode
+ },
+ {
+ L"DISPLAYSYMBOL",
+ L"DISPLAYSYMBOL/[F3] - disable/enable the symbol output\n",
+ L"",
+ L"The display symbol command will configure the symbol show or not-show when disassembly.\n\n"
+ L"DISPLAYSYMBOL [on|off]\n"
+ L" (No Argument) - swtich symbol output state to another one\n"
+ L" on - enable symbol output\n"
+ L" off - disable symbol output\n",
+ L"",
+ {SCAN_F3, CHAR_NULL},
+ DebuggerDisplaySymbol
+ },
+ {
+ L"DISPLAYCODE",
+ L"DISPLAYCODE/[F6] - disable/enable the source code only output\n",
+ L"",
+ L"The display code command will configure the source code only show or misc source code with assembly.\n\n"
+ L"DISPLAYCODE [on|off]\n"
+ L" (No Argument) - swtich source only output state to another one\n"
+ L" on - enable source only output\n"
+ L" off - disable source only output\n",
+ L"",
+ {SCAN_F6, CHAR_NULL},
+ DebuggerDisplayCode
+ },
+ //
+ // Other
+ //
+ {
+ L"H",
+ L"",
+ L"The help command will print help information for each command\n\n",
+ L"H [<Command>]\n",
+ L"",
+ {SCAN_F1, CHAR_NULL},
+ DebuggerHelp
+ },
+/*
+ //
+ // Extended
+ //
+ {
+ L"!IB",
+ L"![I|O][B|W|D] - display/modify IO\n",
+ L"",
+ L"!IB <Address>\n",
+ L"Extended:\n",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtIoIB
+ },
+ {
+ L"!IW",
+ L"",
+ L"",
+ L"!IW <Address>\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtIoIW
+ },
+ {
+ L"!ID",
+ L"",
+ L"",
+ L"!ID <Address>\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtIoID
+ },
+ {
+ L"!OB",
+ L"",
+ L"",
+ L"!OB <Address> <Value>\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtIoOB
+ },
+ {
+ L"!OW",
+ L"",
+ L"",
+ L"!OW <Address> <Value>\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtIoOW
+ },
+ {
+ L"!OD",
+ L"",
+ L"",
+ L"!OD <Address> <Value>\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtIoOD
+ },
+ {
+ L"!PCIL",
+ L"!PCIL - list PCI device, with BAR\n",
+ L"",
+ L"!PCIL [B]\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtPciPCIL
+ },
+ {
+ L"!PCID",
+ L"!PCID - show PCI space\n",
+ L"",
+ L"!PCID Bus Device Function [H|B|E]\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtPciPCID
+ },
+ {
+ L"!CFGB",
+ L"!CFG[B|W|D] - show/modify PCI space",
+ L"",
+ L"!CFGB <Address> [<Value>]\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtPciCFGB
+ },
+ {
+ L"!CFGW",
+ L"",
+ L"",
+ L"!CFGW <Address> [<Value>]\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtPciCFGW
+ },
+ {
+ L"!CFGD",
+ L"",
+ L"",
+ L"!CFGD <Address> [<Value>]\n",
+ L"",
+ {SCAN_NULL, CHAR_NULL},
+ DebuggerExtPciCFGD
+ },
+*/
+ {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ {SCAN_NULL, CHAR_NULL},
+ NULL
+ },
+};
+
+/**
+
+ Find the command according to name.
+
+ @param CommandName - Command Name
+ @param CommandArg - Command Argument
+
+ @return Not NULL - The DebuggerCommand is found successfully
+ @return NULL - not found
+
+**/
+EFI_DEBUGGER_COMMAND
+MatchDebuggerCommand (
+ IN CHAR16 *CommandName,
+ IN CHAR16 **CommandArg
+ )
+{
+ UINTN Index;
+ CHAR16 *Temp;
+
+ //
+ // Get Command Name
+ //
+ Temp = StrGetNewTokenLine (CommandName, L" ");
+ CommandName = Temp;
+ //
+ // Get Command Argument
+ //
+ Temp = StrGetNextTokenLine (L" ");
+ *CommandArg = Temp;
+
+ if (CommandName == NULL) {
+ return NULL;
+ }
+
+ //
+ // Go through each command, check the CommandName
+ //
+ for (Index = 0; mDebuggerCommandSet[Index].CommandName != NULL; Index++) {
+ if (StriCmp (CommandName, mDebuggerCommandSet[Index].CommandName) == 0) {
+ //
+ // Found
+ //
+ return mDebuggerCommandSet[Index].CommandFunc;
+ }
+ }
+
+ //
+ // Not found
+ //
+ return NULL;
+}
+
+/**
+
+ Find the command name according to the function key.
+
+ @param CommandKey - Command Function Key
+
+ @return Not NULL - The DebuggerName is found successfully
+ @return NULL - not found
+
+**/
+CHAR16 *
+GetCommandNameByKey (
+ IN EFI_INPUT_KEY CommandKey
+ )
+{
+ UINTN Index;
+
+ //
+ // Go through each command, check the CommandKey
+ //
+ for (Index = 0; mDebuggerCommandSet[Index].CommandName != NULL; Index++) {
+ if ((mDebuggerCommandSet[Index].CommandKey.UnicodeChar == CommandKey.UnicodeChar) &&
+ (mDebuggerCommandSet[Index].CommandKey.ScanCode == CommandKey.ScanCode)) {
+ //
+ // Found
+ //
+ return mDebuggerCommandSet[Index].CommandName;
+ }
+ }
+
+ //
+ // Not found
+ //
+ return NULL;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommand.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommand.h
new file mode 100644
index 000000000..ac8c23adf
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommand.h
@@ -0,0 +1,115 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#ifndef _EFI_EDB_COMMAND_H_
+#define _EFI_EDB_COMMAND_H_
+
+typedef enum {
+ EdbWidthUint8,
+ EdbWidthUint16,
+ EdbWidthUint32,
+ EdbWidthUint64,
+ EdbWidthMax
+} EDB_DATA_WIDTH;
+
+/**
+
+ Find the command according to name.
+
+ @param CommandName - Command Name
+ @param CommandArg - Command Argument
+
+ @return Not NULL - The DebuggerCommand is found successfully
+ @return NULL - not found
+
+**/
+EFI_DEBUGGER_COMMAND
+MatchDebuggerCommand (
+ IN CHAR16 *CommandName,
+ IN CHAR16 **CommandArg
+ );
+
+/**
+
+ Find the command name according to the function key.
+
+ @param CommandKey - Command Function Key
+
+ @return Not NULL - The DebuggerName is found successfully
+ @return NULL - not found
+
+**/
+CHAR16 *
+GetCommandNameByKey (
+ IN EFI_INPUT_KEY CommandKey
+ );
+
+//
+// Definition for Command Table
+//
+#define EDB_COMMAND_DEFINE(func) \
+EFI_DEBUG_STATUS \
+func ( \
+ IN CHAR16 *CommandArg, \
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate, \
+ IN EFI_EXCEPTION_TYPE ExceptionType, \
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext \
+ )
+
+EDB_COMMAND_DEFINE (DebuggerCallStack);
+EDB_COMMAND_DEFINE (DebuggerInstructionBranch);
+EDB_COMMAND_DEFINE (DebuggerBreakOnCALL);
+EDB_COMMAND_DEFINE (DebuggerBreakOnCALLEX);
+EDB_COMMAND_DEFINE (DebuggerBreakOnRET);
+EDB_COMMAND_DEFINE (DebuggerBreakOnEntrypoint);
+EDB_COMMAND_DEFINE (DebuggerBreakOnThunk);
+EDB_COMMAND_DEFINE (DebuggerBreakOnKey);
+EDB_COMMAND_DEFINE (DebuggerBreakpointList);
+EDB_COMMAND_DEFINE (DebuggerBreakpointSet);
+EDB_COMMAND_DEFINE (DebuggerBreakpointClear);
+EDB_COMMAND_DEFINE (DebuggerBreakpointDisable);
+EDB_COMMAND_DEFINE (DebuggerBreakpointEnable);
+EDB_COMMAND_DEFINE (DebuggerGo);
+EDB_COMMAND_DEFINE (DebuggerHelp);
+EDB_COMMAND_DEFINE (DebuggerMemoryDB);
+EDB_COMMAND_DEFINE (DebuggerMemoryDW);
+EDB_COMMAND_DEFINE (DebuggerMemoryDD);
+EDB_COMMAND_DEFINE (DebuggerMemoryDQ);
+EDB_COMMAND_DEFINE (DebuggerMemoryEB);
+EDB_COMMAND_DEFINE (DebuggerMemoryEW);
+EDB_COMMAND_DEFINE (DebuggerMemoryED);
+EDB_COMMAND_DEFINE (DebuggerMemoryEQ);
+EDB_COMMAND_DEFINE (DebuggerQuit);
+EDB_COMMAND_DEFINE (DebuggerRegister);
+EDB_COMMAND_DEFINE (DebuggerScope);
+EDB_COMMAND_DEFINE (DebuggerList);
+EDB_COMMAND_DEFINE (DebuggerStepInto);
+EDB_COMMAND_DEFINE (DebuggerStepOver);
+EDB_COMMAND_DEFINE (DebuggerStepOut);
+EDB_COMMAND_DEFINE (DebuggerListSymbol);
+EDB_COMMAND_DEFINE (DebuggerLoadSymbol);
+EDB_COMMAND_DEFINE (DebuggerUnloadSymbol);
+EDB_COMMAND_DEFINE (DebuggerDisplaySymbol);
+EDB_COMMAND_DEFINE (DebuggerLoadCode);
+EDB_COMMAND_DEFINE (DebuggerUnloadCode);
+EDB_COMMAND_DEFINE (DebuggerDisplayCode);
+EDB_COMMAND_DEFINE (DebuggerExtIoIB);
+EDB_COMMAND_DEFINE (DebuggerExtIoIW);
+EDB_COMMAND_DEFINE (DebuggerExtIoID);
+EDB_COMMAND_DEFINE (DebuggerExtIoOB);
+EDB_COMMAND_DEFINE (DebuggerExtIoOW);
+EDB_COMMAND_DEFINE (DebuggerExtIoOD);
+EDB_COMMAND_DEFINE (DebuggerExtPciPCIL);
+EDB_COMMAND_DEFINE (DebuggerExtPciPCID);
+EDB_COMMAND_DEFINE (DebuggerExtPciCFGB);
+EDB_COMMAND_DEFINE (DebuggerExtPciCFGW);
+EDB_COMMAND_DEFINE (DebuggerExtPciCFGD);
+
+extern EFI_DEBUGGER_COMMAND_SET mDebuggerCommandSet[];
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommon.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommon.h
new file mode 100644
index 000000000..924a2f755
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbCommon.h
@@ -0,0 +1,239 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_EDB_COMMON_H_
+#define _EFI_EDB_COMMON_H_
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PrintLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Protocol/Ebc.h>
+#include <Protocol/EbcVmTest.h>
+#include <Protocol/DebugSupport.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/DebuggerConfiguration.h>
+#include <Guid/FileInfo.h>
+#include <Guid/DebugImageInfoTable.h>
+
+typedef UINTN EFI_DEBUG_STATUS;
+
+typedef struct _EFI_DEBUGGER_PRIVATE_DATA EFI_DEBUGGER_PRIVATE_DATA;
+
+//
+// Definition for Debugger Command
+//
+typedef
+EFI_DEBUG_STATUS
+(* EFI_DEBUGGER_COMMAND) (
+ IN CHAR16 *CommandArg,
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+);
+
+typedef struct {
+ CHAR16 *CommandName;
+ CHAR16 *CommandTitle;
+ CHAR16 *CommandHelp;
+ CHAR16 *CommandSyntax;
+ CHAR16 *ClassName;
+ EFI_INPUT_KEY CommandKey;
+ EFI_DEBUGGER_COMMAND CommandFunc;
+} EFI_DEBUGGER_COMMAND_SET;
+
+//
+// Definition for Debugger Symbol
+//
+#define EFI_DEBUGGER_SYMBOL_NAME_MAX 256
+#define EFI_DEBUGGER_SYMBOL_ENTRY_MAX 512
+#define EFI_DEBUGGER_SYMBOL_OBJECT_MAX 32
+
+//
+// We have following SYMBOL data structure:
+//
+// SYMBOL_CONTEXT -> SYMBOL_OBJECT -> SYMBOL_ENTRY (FuncXXX, 0xXXX)
+// SYMBOL_ENTRY (VarYYY, 0xYYY)
+// SYMBOL_ENTRY
+//
+// SYMBOL_OBJECT -> SYMBOL_ENTRY
+// SYMBOL_ENTRY
+//
+// SYMBOL_OBJECT -> SYMBOL_ENTRY
+// SYMBOL_ENTRY
+//
+
+typedef enum {
+ EfiDebuggerSymbolFunction,
+ EfiDebuggerSymbolStaticFunction,
+ EfiDebuggerSymbolGlobalVariable,
+ EfiDebuggerSymbolStaticVariable,
+ EfiDebuggerSymbolTypeMax,
+} EFI_DEBUGGER_SYMBOL_TYPE;
+
+typedef struct {
+ CHAR8 Name[EFI_DEBUGGER_SYMBOL_NAME_MAX];
+ UINTN Rva;
+ EFI_DEBUGGER_SYMBOL_TYPE Type;
+ CHAR8 ObjName[EFI_DEBUGGER_SYMBOL_NAME_MAX];
+ CHAR8 *CodBuffer;
+ UINTN CodBufferSize;
+ UINTN FuncOffsetBase;
+ CHAR8 *SourceBuffer;
+} EFI_DEBUGGER_SYMBOL_ENTRY;
+
+typedef struct {
+ CHAR16 Name[EFI_DEBUGGER_SYMBOL_NAME_MAX];
+ UINTN EntryCount;
+ UINTN MaxEntryCount;
+ UINTN BaseAddress;
+ UINTN StartEntrypointRVA;
+ UINTN MainEntrypointRVA;
+ EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
+ VOID **SourceBuffer;
+} EFI_DEBUGGER_SYMBOL_OBJECT;
+
+typedef struct {
+ UINTN ObjectCount;
+ UINTN MaxObjectCount;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ BOOLEAN DisplaySymbol;
+ BOOLEAN DisplayCodeOnly;
+} EFI_DEBUGGER_SYMBOL_CONTEXT;
+
+//
+// Definition for Debugger Breakpoint
+//
+#define EFI_DEBUGGER_BREAKPOINT_MAX 0x10
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS BreakpointAddress;
+ UINT64 OldInstruction; // UINT64 is enough for an instruction
+ BOOLEAN State;
+} EFI_DEBUGGER_BREAKPOINT_CONTEXT;
+
+//
+// Definition for Debugger Call-Stack
+//
+#define EFI_DEBUGGER_CALLSTACK_MAX 0x10
+
+typedef enum {
+ EfiDebuggerBranchTypeEbcCall,
+ EfiDebuggerBranchTypeEbcCallEx,
+ EfiDebuggerBranchTypeEbcRet,
+ EfiDebuggerBranchTypeEbcJmp,
+ EfiDebuggerBranchTypeEbcJmp8,
+ EfiDebuggerBranchTypeEbcMax,
+} EFI_DEBUGGER_BRANCH_TYPE;
+
+#define EFI_DEBUGGER_CALL_MAX_PARAMETER 0x16
+#define EFI_DEBUGGER_CALL_DEFAULT_PARAMETER 0x8
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS SourceAddress;
+ EFI_PHYSICAL_ADDRESS DestAddress;
+ //
+ // We save all parameter here, because code may update the parameter as local variable.
+ //
+ UINTN ParameterAddr;
+ UINTN Parameter[EFI_DEBUGGER_CALL_MAX_PARAMETER];
+ EFI_DEBUGGER_BRANCH_TYPE Type;
+} EFI_DEBUGGER_CALLSTACK_CONTEXT;
+
+//
+// Definition for Debugger Trace
+//
+#define EFI_DEBUGGER_TRACE_MAX 0x10
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS SourceAddress;
+ EFI_PHYSICAL_ADDRESS DestAddress;
+ EFI_DEBUGGER_BRANCH_TYPE Type;
+} EFI_DEBUGGER_TRACE_CONTEXT;
+
+//
+// Definition for Debugger Step
+//
+typedef struct {
+ EFI_PHYSICAL_ADDRESS BreakAddress;
+ EFI_PHYSICAL_ADDRESS FramePointer;
+} EFI_DEBUGGER_STEP_CONTEXT;
+
+//
+// Definition for Debugger GoTil
+//
+typedef struct {
+ EFI_PHYSICAL_ADDRESS BreakAddress;
+} EFI_DEBUGGER_GOTIL_CONTEXT;
+
+//
+// Definition for Debugger private data structure
+//
+#define EFI_DEBUGGER_SIGNATURE SIGNATURE_32 ('e', 'd', 'b', '!')
+
+#define EFI_DEBUG_DEFAULT_INSTRUCTION_NUMBER 5
+
+#define EFI_DEBUG_BREAK_TIMER_INTERVAL 10000000 // 1 second
+
+#define EFI_DEBUG_FLAG_EBC 0x80000000
+#define EFI_DEBUG_FLAG_EBC_B_BOC 0x1
+#define EFI_DEBUG_FLAG_EBC_B_BOCX 0x2
+#define EFI_DEBUG_FLAG_EBC_B_BOR 0x4
+#define EFI_DEBUG_FLAG_EBC_B_BOE 0x8
+#define EFI_DEBUG_FLAG_EBC_B_BOT 0x10
+#define EFI_DEBUG_FLAG_EBC_B_STEPOVER 0x20
+#define EFI_DEBUG_FLAG_EBC_B_STEPOUT 0x40
+#define EFI_DEBUG_FLAG_EBC_B_BP 0x80
+#define EFI_DEBUG_FLAG_EBC_B_GT 0x100
+#define EFI_DEBUG_FLAG_EBC_B_BOK 0x200
+#define EFI_DEBUG_FLAG_EBC_BOC (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_BOC)
+#define EFI_DEBUG_FLAG_EBC_BOCX (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_BOCX)
+#define EFI_DEBUG_FLAG_EBC_BOR (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_BOR)
+#define EFI_DEBUG_FLAG_EBC_BOE (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_BOE)
+#define EFI_DEBUG_FLAG_EBC_BOT (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_BOT)
+#define EFI_DEBUG_FLAG_EBC_STEPOVER (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_STEPOVER)
+#define EFI_DEBUG_FLAG_EBC_STEPOUT (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_STEPOUT)
+#define EFI_DEBUG_FLAG_EBC_BP (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_BP)
+#define EFI_DEBUG_FLAG_EBC_GT (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_GT)
+#define EFI_DEBUG_FLAG_EBC_BOK (EFI_DEBUG_FLAG_EBC | EFI_DEBUG_FLAG_EBC_B_BOK)
+
+//
+// Debugger private data structure
+//
+typedef struct _EFI_DEBUGGER_PRIVATE_DATA {
+ UINT32 Signature;
+ EFI_INSTRUCTION_SET_ARCHITECTURE Isa;
+ UINT32 EfiDebuggerRevision;
+ UINT32 EbcVmRevision;
+ EFI_DEBUGGER_CONFIGURATION_PROTOCOL DebuggerConfiguration;
+ EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *DebugImageInfoTableHeader;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ EFI_DEBUGGER_COMMAND_SET *DebuggerCommandSet;
+ EFI_DEBUGGER_SYMBOL_CONTEXT DebuggerSymbolContext;
+ UINTN DebuggerBreakpointCount;
+ EFI_DEBUGGER_BREAKPOINT_CONTEXT DebuggerBreakpointContext[EFI_DEBUGGER_BREAKPOINT_MAX + 1];
+ UINTN CallStackEntryCount;
+ EFI_DEBUGGER_CALLSTACK_CONTEXT CallStackEntry[EFI_DEBUGGER_CALLSTACK_MAX + 1];
+ UINTN TraceEntryCount;
+ EFI_DEBUGGER_TRACE_CONTEXT TraceEntry[EFI_DEBUGGER_TRACE_MAX + 1];
+ EFI_DEBUGGER_STEP_CONTEXT StepContext;
+ EFI_DEBUGGER_GOTIL_CONTEXT GoTilContext;
+ EFI_PHYSICAL_ADDRESS InstructionScope;
+ UINTN InstructionNumber;
+ UINT32 FeatureFlags;
+ UINT32 StatusFlags;
+ BOOLEAN EnablePageBreak;
+ EFI_EVENT BreakEvent;
+} EFI_DEBUGGER_PRIVATE_DATA;
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasm.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasm.c
new file mode 100644
index 000000000..7d933cae7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasm.c
@@ -0,0 +1,1770 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+//
+// Debugger Disasm definition
+//
+#define EDB_DISASM_DEFINE(func) \
+UINTN \
+func ( \
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress, \
+ IN EFI_SYSTEM_CONTEXT SystemContext, \
+ OUT CHAR16 **DisasmString \
+ )
+
+EDB_DISASM_DEFINE (EdbDisasmBREAK);
+EDB_DISASM_DEFINE (EdbDisasmJMP);
+EDB_DISASM_DEFINE (EdbDisasmJMP8);
+EDB_DISASM_DEFINE (EdbDisasmCALL);
+EDB_DISASM_DEFINE (EdbDisasmRET);
+EDB_DISASM_DEFINE (EdbDisasmCMP);
+EDB_DISASM_DEFINE (EdbDisasmUnsignedDataManip);
+EDB_DISASM_DEFINE (EdbDisasmSignedDataManip);
+EDB_DISASM_DEFINE (EdbDisasmMOVxx);
+EDB_DISASM_DEFINE (EdbDisasmMOVsnw);
+EDB_DISASM_DEFINE (EdbDisasmMOVsnd);
+EDB_DISASM_DEFINE (EdbDisasmLOADSP);
+EDB_DISASM_DEFINE (EdbDisasmSTORESP);
+EDB_DISASM_DEFINE (EdbDisasmPUSH);
+EDB_DISASM_DEFINE (EdbDisasmPOP);
+EDB_DISASM_DEFINE (EdbDisasmCMPI);
+EDB_DISASM_DEFINE (EdbDisasmPUSHn);
+EDB_DISASM_DEFINE (EdbDisasmPOPn);
+EDB_DISASM_DEFINE (EdbDisasmMOVI);
+EDB_DISASM_DEFINE (EdbDisasmMOVIn);
+EDB_DISASM_DEFINE (EdbDisasmMOVREL);
+
+//
+// Debugger Disasm Table
+//
+EDB_DISASM_INSTRUCTION mEdbDisasmInstructionTable[] = {
+ EdbDisasmBREAK, // opcode 0x00 BREAK
+ EdbDisasmJMP, // opcode 0x01 JMP
+ EdbDisasmJMP8, // opcode 0x02 JMP8
+ EdbDisasmCALL, // opcode 0x03 CALL
+ EdbDisasmRET, // opcode 0x04 RET
+ EdbDisasmCMP, // opcode 0x05 CMPEQ
+ EdbDisasmCMP, // opcode 0x06 CMPLTE
+ EdbDisasmCMP, // opcode 0x07 CMPGTE
+ EdbDisasmCMP, // opcode 0x08 CMPULTE
+ EdbDisasmCMP, // opcode 0x09 CMPUGTE
+ EdbDisasmUnsignedDataManip, // opcode 0x0A NOT
+ EdbDisasmSignedDataManip, // opcode 0x0B NEG
+ EdbDisasmSignedDataManip, // opcode 0x0C ADD
+ EdbDisasmSignedDataManip, // opcode 0x0D SUB
+ EdbDisasmSignedDataManip, // opcode 0x0E MUL
+ EdbDisasmUnsignedDataManip, // opcode 0x0F MULU
+ EdbDisasmSignedDataManip, // opcode 0x10 DIV
+ EdbDisasmUnsignedDataManip, // opcode 0x11 DIVU
+ EdbDisasmSignedDataManip, // opcode 0x12 MOD
+ EdbDisasmUnsignedDataManip, // opcode 0x13 MODU
+ EdbDisasmUnsignedDataManip, // opcode 0x14 AND
+ EdbDisasmUnsignedDataManip, // opcode 0x15 OR
+ EdbDisasmUnsignedDataManip, // opcode 0x16 XOR
+ EdbDisasmUnsignedDataManip, // opcode 0x17 SHL
+ EdbDisasmUnsignedDataManip, // opcode 0x18 SHR
+ EdbDisasmSignedDataManip, // opcode 0x19 ASHR
+ EdbDisasmUnsignedDataManip, // opcode 0x1A EXTNDB
+ EdbDisasmUnsignedDataManip, // opcode 0x1B EXTNDW
+ EdbDisasmUnsignedDataManip, // opcode 0x1C EXTNDD
+ EdbDisasmMOVxx, // opcode 0x1D MOVBW
+ EdbDisasmMOVxx, // opcode 0x1E MOVWW
+ EdbDisasmMOVxx, // opcode 0x1F MOVDW
+ EdbDisasmMOVxx, // opcode 0x20 MOVQW
+ EdbDisasmMOVxx, // opcode 0x21 MOVBD
+ EdbDisasmMOVxx, // opcode 0x22 MOVWD
+ EdbDisasmMOVxx, // opcode 0x23 MOVDD
+ EdbDisasmMOVxx, // opcode 0x24 MOVQD
+ EdbDisasmMOVsnw, // opcode 0x25 MOVSNW
+ EdbDisasmMOVsnd, // opcode 0x26 MOVSND
+ NULL, // opcode 0x27
+ EdbDisasmMOVxx, // opcode 0x28 MOVQQ
+ EdbDisasmLOADSP, // opcode 0x29 LOADSP
+ EdbDisasmSTORESP, // opcode 0x2A STORESP
+ EdbDisasmPUSH, // opcode 0x2B PUSH
+ EdbDisasmPOP, // opcode 0x2C POP
+ EdbDisasmCMPI, // opcode 0x2D CMPIEQ
+ EdbDisasmCMPI, // opcode 0x2E CMPILTE
+ EdbDisasmCMPI, // opcode 0x2F CMPIGTE
+ EdbDisasmCMPI, // opcode 0x30 CMPIULTE
+ EdbDisasmCMPI, // opcode 0x31 CMPIUGTE
+ EdbDisasmMOVxx, // opcode 0x32 MOVNW
+ EdbDisasmMOVxx, // opcode 0x33 MOVND
+ NULL, // opcode 0x34
+ EdbDisasmPUSHn, // opcode 0x35 PUSHN
+ EdbDisasmPOPn, // opcode 0x36 POPN
+ EdbDisasmMOVI, // opcode 0x37 MOVI
+ EdbDisasmMOVIn, // opcode 0x38 MOVIN
+ EdbDisasmMOVREL, // opcode 0x39 MOVREL
+};
+
+/**
+
+ Disasm instruction - BREAK.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmBREAK (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_BREAK);
+
+ if (*(UINT8 *)(UINTN)(InstructionAddress + 1) > 6) {
+ return 0;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"BREAK");
+ EdbPrintDatan (*(UINT8 *)(UINTN)(InstructionAddress + 1));
+
+ EdbPostInstructionString ();
+ }
+
+ return 2;
+}
+
+extern CONST UINT8 mJMPLen[];
+
+/**
+
+ Disasm instruction - JMP.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmJMP (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT32 Data32;
+ UINT64 Data64;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_JMP);
+
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+ Size = (UINTN)mJMPLen[(Modifiers >> 6) & 0x03];
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"JMP");
+// if (Modifiers & OPCODE_M_IMMDATA64) {
+// EdbPrintInstructionName (L"64");
+// } else {
+// EdbPrintInstructionName (L"32");
+// }
+ if ((Modifiers & CONDITION_M_CONDITIONAL) != 0) {
+ if ((Modifiers & JMP_M_CS) != 0) {
+ EdbPrintInstructionName (L"cs");
+ } else {
+ EdbPrintInstructionName (L"cc");
+ }
+ }
+
+ InstructionAddress += 2;
+ if ((Modifiers & OPCODE_M_IMMDATA64) != 0) {
+ CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT64));
+ if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
+ EdbPrintData64 (Data64);
+ } else {
+ return 0;
+ }
+ } else {
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ EdbPrintRegister1 (Operands);
+
+ if ((Operands & OPERAND_M_INDIRECT1) == 0) {
+ if ((Modifiers & OPCODE_M_IMMDATA) == 0) {
+ Data32 = 0;
+ }
+ EdbPrintImmDatan (Data32);
+ } else {
+ EdbPrintRawIndexData32 (Data32);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - JMP8.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmJMP8 (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_JMP8);
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"JMP8");
+ if ((Modifiers & CONDITION_M_CONDITIONAL) != 0) {
+ if ((Modifiers & JMP_M_CS) != 0) {
+ EdbPrintInstructionName (L"cs");
+ } else {
+ EdbPrintInstructionName (L"cc");
+ }
+ }
+
+ EdbPrintData8 (*(UINT8 *)(UINTN)(InstructionAddress + 1));
+
+ EdbPostInstructionString ();
+ }
+
+ return 2;
+}
+
+/**
+
+ Disasm instruction - CALL.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmCALL (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT32 Data32;
+ UINT64 Data64;
+ UINT64 Ip;
+ UINTN Result;
+ EFI_PHYSICAL_ADDRESS SavedInstructionAddress;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_CALL);
+ SavedInstructionAddress = InstructionAddress;
+
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+ Size = (UINTN)mJMPLen[(Modifiers >> 6) & 0x03];
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"CALL");
+// if (Modifiers & OPCODE_M_IMMDATA64) {
+// EdbPrintInstructionName (L"64");
+// } else {
+// EdbPrintInstructionName (L"32");
+// }
+ if ((Operands & OPERAND_M_NATIVE_CALL) != 0) {
+ EdbPrintInstructionName (L"EX");
+ }
+// if ((Operands & OPERAND_M_RELATIVE_ADDR) == 0) {
+// EdbPrintInstructionName (L"a");
+// }
+
+ InstructionAddress += 2;
+ if ((Modifiers & OPCODE_M_IMMDATA64) != 0) {
+ CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT64));
+ Ip = Data64;
+ if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
+ Result = EdbFindAndPrintSymbol ((UINTN)Ip);
+ if (Result == 0) {
+ EdbPrintData64 (Data64);
+ }
+ } else {
+ return 0;
+ }
+ } else {
+ if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ } else {
+ Data32 = 0;
+ }
+
+ if ((Operands & OPERAND_M_OP1) == 0) {
+ Ip = (UINT64)Data32;
+ } else {
+ Ip = GetRegisterValue (SystemContext, (Operands & OPERAND_M_OP1));
+ }
+
+ if ((Operands & OPERAND_M_INDIRECT1) == 0) {
+ if ((Operands & OPERAND_M_RELATIVE_ADDR) != 0) {
+ Result = EdbFindAndPrintSymbol ((UINTN)(SavedInstructionAddress + Ip + Size));
+ } else {
+ Result = EdbFindAndPrintSymbol ((UINTN)Ip);
+ }
+ if (Result == 0) {
+ EdbPrintRegister1 (Operands);
+ if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
+ EdbPrintImmData32 (Data32);
+ }
+ }
+ } else {
+ EdbPrintRegister1 (Operands);
+ if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
+ EdbPrintRawIndexData32 (Data32);
+ }
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - RET.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmRET (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_RET);
+
+ if (*(UINT8 *)(UINTN)(InstructionAddress + 1) != 0) {
+ return 0;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"RET");
+
+ EdbPostInstructionString ();
+ }
+
+ return 2;
+}
+
+/**
+
+ Disasm instruction - CMP.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmCMP (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Opcode;
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINT16 Data16;
+ UINTN Size;
+
+ ASSERT (
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPEQ) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPLTE) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPGTE) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPULTE) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPUGTE)
+ );
+
+ Opcode = GET_OPCODE (InstructionAddress);
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+ if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"CMP");
+// if (Modifiers & OPCODE_M_64BIT) {
+// EdbPrintInstructionName (L"64");
+// } else {
+// EdbPrintInstructionName (L"32");
+// }
+ switch (Opcode) {
+ case OPCODE_CMPEQ:
+ EdbPrintInstructionName (L"eq");
+ break;
+ case OPCODE_CMPLTE:
+ EdbPrintInstructionName (L"lte");
+ break;
+ case OPCODE_CMPGTE:
+ EdbPrintInstructionName (L"gte");
+ break;
+ case OPCODE_CMPULTE:
+ EdbPrintInstructionName (L"ulte");
+ break;
+ case OPCODE_CMPUGTE:
+ EdbPrintInstructionName (L"ugte");
+ break;
+ }
+
+ EdbPrintRegister1 (Operands);
+ InstructionAddress += 2;
+
+ EdbPrintComma ();
+ EdbPrintRegister2 (Operands);
+
+ if ((Modifiers & OPCODE_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ if ((Operands & OPERAND_M_INDIRECT2) != 0) {
+ EdbPrintRawIndexData16 (Data16);
+ } else {
+ EdbPrintImmDatan (Data16);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - Unsigned Data Manipulate.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmUnsignedDataManip (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+
+ ASSERT (
+ (GET_OPCODE(InstructionAddress) == OPCODE_NOT) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MULU) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_DIVU) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MODU) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_AND) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_OR) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_XOR) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_SHL) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_SHR) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_EXTNDB) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_EXTNDW) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_EXTNDD)
+ );
+
+ Opcode = GET_OPCODE (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ if ((Modifiers & DATAMANIP_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ switch (Opcode) {
+ case OPCODE_NOT:
+ EdbPrintInstructionName (L"NOT");
+ break;
+ case OPCODE_MULU:
+ EdbPrintInstructionName (L"MULU");
+ break;
+ case OPCODE_DIVU:
+ EdbPrintInstructionName (L"DIVU");
+ break;
+ case OPCODE_MODU:
+ EdbPrintInstructionName (L"MODU");
+ break;
+ case OPCODE_AND:
+ EdbPrintInstructionName (L"AND");
+ break;
+ case OPCODE_OR:
+ EdbPrintInstructionName (L"OR");
+ break;
+ case OPCODE_XOR:
+ EdbPrintInstructionName (L"XOR");
+ break;
+ case OPCODE_SHL:
+ EdbPrintInstructionName (L"SHL");
+ break;
+ case OPCODE_SHR:
+ EdbPrintInstructionName (L"SHR");
+ break;
+ case OPCODE_EXTNDB:
+ EdbPrintInstructionName (L"EXTNDB");
+ break;
+ case OPCODE_EXTNDW:
+ EdbPrintInstructionName (L"EXTNDW");
+ break;
+ case OPCODE_EXTNDD:
+ EdbPrintInstructionName (L"EXTNDD");
+ break;
+ }
+// if (Modifiers & DATAMANIP_M_64) {
+// EdbPrintInstructionName (L"64");
+// } else {
+// EdbPrintInstructionName (L"32");
+// }
+
+ EdbPrintRegister1 (Operands);
+ EdbPrintComma ();
+ EdbPrintRegister2 (Operands);
+
+ InstructionAddress += 2;
+ if ((Modifiers & DATAMANIP_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ if ((Operands & OPERAND_M_INDIRECT2) != 0) {
+ EdbPrintRawIndexData16 (Data16);
+ } else {
+ EdbPrintImmDatan (Data16);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - Signed Data Manipulate,
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmSignedDataManip (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+
+ ASSERT (
+ (GET_OPCODE(InstructionAddress) == OPCODE_NEG) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_ADD) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_SUB) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MUL) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_DIV) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOD) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_ASHR)
+ );
+
+ Opcode = GET_OPCODE (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ if ((Modifiers & DATAMANIP_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ switch (Opcode) {
+ case OPCODE_NEG:
+ EdbPrintInstructionName (L"NEG");
+ break;
+ case OPCODE_ADD:
+ EdbPrintInstructionName (L"ADD");
+ break;
+ case OPCODE_SUB:
+ EdbPrintInstructionName (L"SUB");
+ break;
+ case OPCODE_MUL:
+ EdbPrintInstructionName (L"MUL");
+ break;
+ case OPCODE_DIV:
+ EdbPrintInstructionName (L"DIV");
+ break;
+ case OPCODE_MOD:
+ EdbPrintInstructionName (L"MOD");
+ break;
+ case OPCODE_ASHR:
+ EdbPrintInstructionName (L"ASHR");
+ break;
+ }
+// if (Modifiers & DATAMANIP_M_64) {
+// EdbPrintInstructionName (L"64");
+// } else {
+// EdbPrintInstructionName (L"32");
+// }
+
+ EdbPrintRegister1 (Operands);
+ EdbPrintComma ();
+ EdbPrintRegister2 (Operands);
+
+ InstructionAddress += 2;
+ if ((Modifiers & DATAMANIP_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ if ((Operands & OPERAND_M_INDIRECT2) != 0) {
+ EdbPrintRawIndexData16 (Data16);
+ } else {
+ EdbPrintImmDatan (Data16);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - MOVxx.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmMOVxx (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+ UINT32 Data32;
+ UINT64 Data64;
+
+ ASSERT (
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVBW) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVWW) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVDW) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVQW) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVBD) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVWD) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVDD) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVQD) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVQQ) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVNW) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_MOVND)
+ );
+
+ Opcode = GET_OPCODE (InstructionAddress);
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+ Size = 2;
+ if ((Modifiers & (OPCODE_M_IMMED_OP1 | OPCODE_M_IMMED_OP2)) != 0) {
+ if ((Opcode <= OPCODE_MOVQW) || (Opcode == OPCODE_MOVNW)) {
+ if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
+ Size += 2;
+ }
+ if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
+ Size += 2;
+ }
+ } else if (((Opcode <= OPCODE_MOVQD) || (Opcode == OPCODE_MOVND)) != 0) {
+ if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
+ Size += 4;
+ }
+ if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
+ Size += 4;
+ }
+ } else if (Opcode == OPCODE_MOVQQ) {
+ if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
+ Size += 8;
+ }
+ if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
+ Size += 8;
+ }
+ }
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"MOV");
+ switch (Opcode) {
+ case OPCODE_MOVBW:
+ EdbPrintInstructionName (L"bw");
+ break;
+ case OPCODE_MOVWW:
+ EdbPrintInstructionName (L"ww");
+ break;
+ case OPCODE_MOVDW:
+ EdbPrintInstructionName (L"dw");
+ break;
+ case OPCODE_MOVQW:
+ EdbPrintInstructionName (L"qw");
+ break;
+ case OPCODE_MOVBD:
+ EdbPrintInstructionName (L"bd");
+ break;
+ case OPCODE_MOVWD:
+ EdbPrintInstructionName (L"wd");
+ break;
+ case OPCODE_MOVDD:
+ EdbPrintInstructionName (L"dd");
+ break;
+ case OPCODE_MOVQD:
+ EdbPrintInstructionName (L"qd");
+ break;
+ case OPCODE_MOVQQ:
+ EdbPrintInstructionName (L"qq");
+ break;
+ case OPCODE_MOVNW:
+ EdbPrintInstructionName (L"nw");
+ break;
+ case OPCODE_MOVND:
+ EdbPrintInstructionName (L"nd");
+ break;
+ }
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
+ if ((Opcode <= OPCODE_MOVQW) || (Opcode == OPCODE_MOVNW)) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ InstructionAddress += 2;
+ EdbPrintRawIndexData16 (Data16);
+ } else if ((Opcode <= OPCODE_MOVQD) || (Opcode == OPCODE_MOVND)) {
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ InstructionAddress += 4;
+ EdbPrintRawIndexData32 (Data32);
+ } else if (Opcode == OPCODE_MOVQQ) {
+ CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT64));
+ InstructionAddress += 8;
+ EdbPrintRawIndexData64 (Data64);
+ }
+ }
+
+ EdbPrintComma ();
+ EdbPrintRegister2 (Operands);
+
+ if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
+ if ((Opcode <= OPCODE_MOVQW) || (Opcode == OPCODE_MOVNW)) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ EdbPrintRawIndexData16 (Data16);
+ } else if ((Opcode <= OPCODE_MOVQD) || (Opcode == OPCODE_MOVND)) {
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ EdbPrintRawIndexData32 (Data32);
+ } else if (Opcode == OPCODE_MOVQQ) {
+ CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT64));
+ EdbPrintRawIndexData64 (Data64);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - MOVsnw.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmMOVsnw (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_MOVSNW);
+
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+ Size = 2;
+ if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
+ Size += 2;
+ }
+ if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
+ Size += 2;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"MOVsnw");
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ InstructionAddress += 2;
+ EdbPrintRawIndexData16 (Data16);
+ }
+
+ EdbPrintComma ();
+ EdbPrintRegister2 (Operands);
+
+ if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ if ((Operands & OPERAND_M_INDIRECT2) != 0) {
+ EdbPrintRawIndexData16 (Data16);
+ } else {
+ EdbPrintImmDatan (Data16);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - MOVsnd.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmMOVsnd (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT32 Data32;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_MOVSND);
+
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+ Size = 2;
+ if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
+ Size += 4;
+ }
+ if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
+ Size += 4;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"MOVsnd");
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Modifiers & OPCODE_M_IMMED_OP1) != 0) {
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ InstructionAddress += 4;
+ EdbPrintRawIndexData32 (Data32);
+ }
+
+ EdbPrintComma ();
+ EdbPrintRegister2 (Operands);
+
+ if ((Modifiers & OPCODE_M_IMMED_OP2) != 0) {
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ if ((Operands & OPERAND_M_INDIRECT2) != 0) {
+ EdbPrintRawIndexData32 (Data32);
+ } else {
+ EdbPrintImmDatan (Data32);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - LOADSP.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmLOADSP (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Operands;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_LOADSP);
+
+ Operands = GET_OPERANDS (InstructionAddress);
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"LOADSP");
+
+ EdbPrintDedicatedRegister1 (Operands);
+
+ EdbPrintRegister2 (Operands);
+
+ EdbPostInstructionString ();
+ }
+
+ return 2;
+}
+
+/**
+
+ Disasm instruction - STORESP.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmSTORESP (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Operands;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_STORESP);
+
+ Operands = GET_OPERANDS (InstructionAddress);
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"STORESP");
+
+ EdbPrintRegister1 (Operands);
+
+ EdbPrintDedicatedRegister2 (Operands);
+
+ EdbPostInstructionString ();
+ }
+
+ return 2;
+}
+
+
+/**
+
+ Disasm instruction - PUSH.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmPUSH (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_PUSH);
+
+ Operands = GET_OPERANDS (InstructionAddress);
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"PUSH");
+// if (Modifiers & PUSHPOP_M_64) {
+// EdbPrintInstructionName (L"64");
+// } else {
+// EdbPrintInstructionName (L"32");
+// }
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ if ((Operands & OPERAND_M_INDIRECT1) != 0) {
+ EdbPrintRawIndexData16 (Data16);
+ } else {
+ EdbPrintImmDatan (Data16);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - POP.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmPOP (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_POP);
+
+ Operands = GET_OPERANDS (InstructionAddress);
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"POP");
+// if (Modifiers & PUSHPOP_M_64) {
+// EdbPrintInstructionName (L"64");
+// } else {
+// EdbPrintInstructionName (L"32");
+// }
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ if ((Operands & OPERAND_M_INDIRECT1) != 0) {
+ EdbPrintRawIndexData16 (Data16);
+ } else {
+ EdbPrintImmDatan (Data16);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - CMPI.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmCMPI (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINT16 Data16;
+ UINT32 Data32;
+ UINTN Size;
+
+ ASSERT (
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPIEQ) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPILTE) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPIGTE) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPIULTE) ||
+ (GET_OPCODE(InstructionAddress) == OPCODE_CMPIUGTE)
+ );
+
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Opcode = GET_OPCODE (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+
+ if ((Operands & 0xE0) != 0) {
+ return 0;
+ }
+
+ Size = 2;
+ if ((Operands & OPERAND_M_CMPI_INDEX) != 0) {
+ Size += 2;
+ }
+ if ((Modifiers & OPCODE_M_CMPI32_DATA) != 0) {
+ Size += 4;
+ } else {
+ Size += 2;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"CMPI");
+// if (Modifiers & OPCODE_M_CMPI64) {
+// EdbPrintInstructionName (L"64");
+// } else {
+// EdbPrintInstructionName (L"32");
+// }
+ if ((Modifiers & OPCODE_M_CMPI32_DATA) != 0) {
+ EdbPrintInstructionName (L"d");
+ } else {
+ EdbPrintInstructionName (L"w");
+ }
+ switch (Opcode) {
+ case OPCODE_CMPIEQ:
+ EdbPrintInstructionName (L"eq");
+ break;
+ case OPCODE_CMPILTE:
+ EdbPrintInstructionName (L"lte");
+ break;
+ case OPCODE_CMPIGTE:
+ EdbPrintInstructionName (L"gte");
+ break;
+ case OPCODE_CMPIULTE:
+ EdbPrintInstructionName (L"ulte");
+ break;
+ case OPCODE_CMPIUGTE:
+ EdbPrintInstructionName (L"ugte");
+ break;
+ }
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Operands & OPERAND_M_CMPI_INDEX) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ InstructionAddress += 2;
+ EdbPrintRawIndexData16 (Data16);
+ }
+
+ EdbPrintComma ();
+
+ if ((Modifiers & OPCODE_M_CMPI32_DATA) != 0) {
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ EdbPrintDatan (Data32);
+ } else {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ EdbPrintDatan (Data16);
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - PUSHn.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmPUSHn (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_PUSHN);
+
+ Operands = GET_OPERANDS (InstructionAddress);
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"PUSHn");
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ if ((Operands & OPERAND_M_INDIRECT1) != 0) {
+ EdbPrintRawIndexData16 (Data16);
+ } else {
+ EdbPrintImmDatan (Data16);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - POPn.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmPOPn (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_POPN);
+
+ Operands = GET_OPERANDS (InstructionAddress);
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"POPn");
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Modifiers & PUSHPOP_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ if ((Operands & OPERAND_M_INDIRECT1) != 0) {
+ EdbPrintRawIndexData16 (Data16);
+ } else {
+ EdbPrintImmDatan (Data16);
+ }
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - MOVI.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmMOVI (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+ UINT32 Data32;
+ UINT64 Data64;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_MOVI);
+
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+ if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
+ Size += 2;
+ } else if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
+ Size += 4;
+ } else if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
+ Size += 8;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"MOVI");
+ switch (Operands & MOVI_M_MOVEWIDTH) {
+ case MOVI_MOVEWIDTH8:
+ EdbPrintInstructionName (L"b");
+ break;
+ case MOVI_MOVEWIDTH16:
+ EdbPrintInstructionName (L"w");
+ break;
+ case MOVI_MOVEWIDTH32:
+ EdbPrintInstructionName (L"d");
+ break;
+ case MOVI_MOVEWIDTH64:
+ EdbPrintInstructionName (L"q");
+ break;
+ }
+ switch (Modifiers & MOVI_M_DATAWIDTH) {
+ case MOVI_DATAWIDTH16:
+ EdbPrintInstructionName (L"w");
+ break;
+ case MOVI_DATAWIDTH32:
+ EdbPrintInstructionName (L"d");
+ break;
+ case MOVI_DATAWIDTH64:
+ EdbPrintInstructionName (L"q");
+ break;
+ }
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ InstructionAddress += 2;
+ EdbPrintRawIndexData16 (Data16);
+ }
+
+ EdbPrintComma ();
+
+ switch (Modifiers & MOVI_M_DATAWIDTH) {
+ case MOVI_DATAWIDTH16:
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ EdbPrintDatan (Data16);
+ break;
+ case MOVI_DATAWIDTH32:
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ EdbPrintDatan (Data32);
+ break;
+ case MOVI_DATAWIDTH64:
+ CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT64));
+ EdbPrintData64n (Data64);
+ break;
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - MOVIn.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmMOVIn (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+ UINT32 Data32;
+ UINT64 Data64;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_MOVIN);
+
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+ if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
+ Size += 2;
+ } else if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
+ Size += 4;
+ } else if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
+ Size += 8;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"MOVIn");
+ switch (Modifiers & MOVI_M_DATAWIDTH) {
+ case MOVI_DATAWIDTH16:
+ EdbPrintInstructionName (L"w");
+ break;
+ case MOVI_DATAWIDTH32:
+ EdbPrintInstructionName (L"d");
+ break;
+ case MOVI_DATAWIDTH64:
+ EdbPrintInstructionName (L"q");
+ break;
+ }
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ InstructionAddress += 2;
+ EdbPrintRawIndexData16 (Data16);
+ }
+
+ EdbPrintComma ();
+
+ switch (Modifiers & MOVI_M_DATAWIDTH) {
+ case MOVI_DATAWIDTH16:
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ EdbPrintRawIndexData16 (Data16);
+ break;
+ case MOVI_DATAWIDTH32:
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ EdbPrintRawIndexData32 (Data32);
+ break;
+ case MOVI_DATAWIDTH64:
+ CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT64));
+ EdbPrintRawIndexData64 (Data64);
+ break;
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
+
+/**
+
+ Disasm instruction - MOVREL.
+
+ @param InstructionAddress - The instruction address
+ @param SystemContext - EBC system context.
+ @param DisasmString - The instruction string
+
+ @return Instruction length
+
+**/
+UINTN
+EdbDisasmMOVREL (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisasmString
+ )
+{
+ UINT8 Modifiers;
+ UINT8 Operands;
+ UINTN Size;
+ UINT16 Data16;
+ UINT32 Data32;
+ UINT64 Data64;
+ UINTN Result;
+ EFI_PHYSICAL_ADDRESS SavedInstructionAddress;
+
+ ASSERT (GET_OPCODE(InstructionAddress) == OPCODE_MOVREL);
+ SavedInstructionAddress = InstructionAddress;
+
+ Modifiers = GET_MODIFIERS (InstructionAddress);
+ Operands = GET_OPERANDS (InstructionAddress);
+
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ Size = 4;
+ } else {
+ Size = 2;
+ }
+ if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
+ Size += 2;
+ } else if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
+ Size += 4;
+ } else if ((Modifiers & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
+ Size += 8;
+ } else {
+ return 0;
+ }
+
+ //
+ // Construct Disasm String
+ //
+ if (DisasmString != NULL) {
+ *DisasmString = EdbPreInstructionString ();
+
+ EdbPrintInstructionName (L"MOVrel");
+ switch (Modifiers & MOVI_M_DATAWIDTH) {
+ case MOVI_DATAWIDTH16:
+ EdbPrintInstructionName (L"w");
+ break;
+ case MOVI_DATAWIDTH32:
+ EdbPrintInstructionName (L"d");
+ break;
+ case MOVI_DATAWIDTH64:
+ EdbPrintInstructionName (L"q");
+ break;
+ }
+
+ EdbPrintRegister1 (Operands);
+
+ InstructionAddress += 2;
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ InstructionAddress += 2;
+ EdbPrintRawIndexData16 (Data16);
+ }
+
+ EdbPrintComma ();
+
+ switch (Modifiers & MOVI_M_DATAWIDTH) {
+ case MOVI_DATAWIDTH16:
+ CopyMem (&Data16, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT16));
+ Result = EdbFindAndPrintSymbol ((UINTN)(SavedInstructionAddress + Size + (INT16)Data16));
+ if (Result == 0) {
+ EdbPrintData16 (Data16);
+ }
+ break;
+ case MOVI_DATAWIDTH32:
+ CopyMem (&Data32, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT32));
+ Result = EdbFindAndPrintSymbol ((UINTN)(SavedInstructionAddress + Size + (INT32)Data32));
+ if (Result == 0) {
+ EdbPrintData32 (Data32);
+ }
+ break;
+ case MOVI_DATAWIDTH64:
+ CopyMem (&Data64, (VOID *)(UINTN)(InstructionAddress), sizeof(UINT64));
+ if (sizeof(UINTN) == sizeof(UINT64)) {
+ Result = EdbFindAndPrintSymbol ((UINTN)(SavedInstructionAddress + Size + (INT64)Data64));
+ } else {
+ Result = 0;
+ }
+ if (Result == 0) {
+ EdbPrintData64 (Data64);
+ }
+ break;
+ }
+
+ EdbPostInstructionString ();
+ }
+
+ return Size;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasm.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasm.h
new file mode 100644
index 000000000..43fa5f4b8
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasm.h
@@ -0,0 +1,30 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#ifndef _EFI_EDB_DISASM_H_
+#define _EFI_EDB_DISASM_H_
+
+#include <Uefi.h>
+
+//
+// Definition for instruction OPCODE, MODIFIER, and OPERAND
+//
+#define GET_OPCODE(Addr) (UINT8)((*(UINT8 *)(UINTN)(Addr)) & 0x3F)
+#define GET_MODIFIERS(Addr) (UINT8)((*(UINT8 *)(UINTN)(Addr)) & 0xC0)
+#define GET_OPCODE_BYTE(Addr) (UINT8)(*(UINT8 *)(UINTN)(Addr))
+#define GET_OPERANDS(Addr) (UINT8)(*(UINT8 *)(UINTN)((Addr) + 1))
+
+typedef
+UINTN
+(* EDB_DISASM_INSTRUCTION) (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ OUT CHAR16 **DisAsmString
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasmSupport.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasmSupport.c
new file mode 100644
index 000000000..feb3fb121
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasmSupport.c
@@ -0,0 +1,1211 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+extern EDB_DISASM_INSTRUCTION mEdbDisasmInstructionTable[];
+
+typedef struct {
+ CHAR16 Name[EDB_INSTRUCTION_NAME_MAX_LENGTH];
+ CHAR16 Content[EDB_INSTRUCTION_CONTENT_MAX_LENGTH];
+ CHAR16 Tail;
+} EDB_INSTRUCTION_STRING;
+
+EDB_INSTRUCTION_STRING mInstructionString;
+UINTN mInstructionNameOffset;
+UINTN mInstructionContentOffset;
+
+/**
+
+ Set offset for Instruction name and content.
+
+ @param InstructionNameOffset - Instruction name offset
+ @param InstructionContentOffset - Instruction content offset
+
+**/
+VOID
+EdbSetOffset (
+ IN UINTN InstructionNameOffset,
+ IN UINTN InstructionContentOffset
+ )
+{
+ mInstructionNameOffset = InstructionNameOffset;
+ mInstructionContentOffset = InstructionContentOffset;
+
+ return ;
+}
+
+/**
+
+ Pre instruction string construction.
+
+ @return Instruction string
+
+**/
+CHAR16 *
+EdbPreInstructionString (
+ VOID
+ )
+{
+ ZeroMem (&mInstructionString, sizeof(mInstructionString));
+ mInstructionNameOffset = 0;
+ mInstructionContentOffset = 0;
+
+ return (CHAR16 *)&mInstructionString;
+}
+
+/**
+
+ Post instruction string construction.
+
+ @return Instruction string
+
+**/
+CHAR16 *
+EdbPostInstructionString (
+ VOID
+ )
+{
+ CHAR16 *Char;
+
+ for (Char = (CHAR16 *)&mInstructionString; Char < &mInstructionString.Tail; Char++) {
+ if (*Char == 0) {
+ *Char = L' ';
+ }
+ }
+ mInstructionString.Tail = 0;
+
+ mInstructionNameOffset = 0;
+ mInstructionContentOffset = 0;
+
+ return (CHAR16 *)&mInstructionString;
+}
+
+/**
+
+ Get Sign, NaturalUnits, and ConstantUnits of the WORD data.
+
+ @param Data16 - WORD data
+ @param NaturalUnits - Natural Units of the WORD
+ @param ConstantUnits - Constant Units of the WORD
+
+ @return Sign value of WORD
+
+**/
+BOOLEAN
+EdbGetNaturalIndex16 (
+ IN UINT16 Data16,
+ OUT UINTN *NaturalUnits,
+ OUT UINTN *ConstantUnits
+ )
+{
+ BOOLEAN Sign;
+ UINTN NaturalUnitBit;
+
+ Sign = (BOOLEAN)(Data16 >> 15);
+ NaturalUnitBit = (UINTN)((Data16 >> 12) & 0x7);
+ NaturalUnitBit *= 2;
+ Data16 = Data16 & 0xFFF;
+ *NaturalUnits = (UINTN)(Data16 & ((1 << NaturalUnitBit) - 1));
+ *ConstantUnits = (UINTN)((Data16 >> NaturalUnitBit) & ((1 << (12 - NaturalUnitBit)) - 1));
+
+ return Sign;
+}
+
+/**
+
+ Get Sign, NaturalUnits, and ConstantUnits of the DWORD data.
+
+ @param Data32 - DWORD data
+ @param NaturalUnits - Natural Units of the DWORD
+ @param ConstantUnits - Constant Units of the DWORD
+
+ @return Sign value of DWORD
+
+**/
+BOOLEAN
+EdbGetNaturalIndex32 (
+ IN UINT32 Data32,
+ OUT UINTN *NaturalUnits,
+ OUT UINTN *ConstantUnits
+ )
+{
+ BOOLEAN Sign;
+ UINTN NaturalUnitBit;
+
+ Sign = (BOOLEAN)(Data32 >> 31);
+ NaturalUnitBit = (UINTN)((Data32 >> 28) & 0x7);
+ NaturalUnitBit *= 4;
+ Data32 = Data32 & 0xFFFFFFF;
+ *NaturalUnits = (UINTN)(Data32 & ((1 << NaturalUnitBit) - 1));
+ *ConstantUnits = (UINTN)((Data32 >> NaturalUnitBit) & ((1 << (28 - NaturalUnitBit)) - 1));
+
+ return Sign;
+}
+
+/**
+
+ Get Sign, NaturalUnits, and ConstantUnits of the QWORD data.
+
+ @param Data64 - QWORD data
+ @param NaturalUnits - Natural Units of the QWORD
+ @param ConstantUnits - Constant Units of the QWORD
+
+ @return Sign value of QWORD
+
+**/
+BOOLEAN
+EdbGetNaturalIndex64 (
+ IN UINT64 Data64,
+ OUT UINT64 *NaturalUnits,
+ OUT UINT64 *ConstantUnits
+ )
+{
+ BOOLEAN Sign;
+ UINTN NaturalUnitBit;
+
+ Sign = (BOOLEAN)RShiftU64 (Data64, 63);
+ NaturalUnitBit = (UINTN)(RShiftU64 (Data64, 60) & 0x7);
+ NaturalUnitBit *= 8;
+ Data64 = RShiftU64 (LShiftU64 (Data64, 4), 4);
+ *NaturalUnits = (UINT64)(Data64 & (LShiftU64 (1, NaturalUnitBit) - 1));
+ *ConstantUnits = (UINT64)(RShiftU64 (Data64, NaturalUnitBit) & (LShiftU64 (1, (60 - NaturalUnitBit)) - 1));
+
+ return Sign;
+}
+
+/**
+
+ Get Bit Width of the value.
+
+ @param Value - data
+
+ @return Bit width
+
+**/
+UINT8
+EdbGetBitWidth (
+ IN UINT64 Value
+ )
+{
+ if (Value >= 10000000000000) {
+ return 14;
+ } else if (Value >= 1000000000000) {
+ return 13;
+ } else if (Value >= 100000000000) {
+ return 12;
+ } else if (Value >= 10000000000) {
+ return 11;
+ } else if (Value >= 1000000000) {
+ return 10;
+ } else if (Value >= 100000000) {
+ return 9;
+ } else if (Value >= 10000000) {
+ return 8;
+ } else if (Value >= 1000000) {
+ return 7;
+ } else if (Value >= 100000) {
+ return 6;
+ } else if (Value >= 10000) {
+ return 5;
+ } else if (Value >= 1000) {
+ return 4;
+ } else if (Value >= 100) {
+ return 3;
+ } else if (Value >= 10) {
+ return 2;
+ } else {
+ return 1;
+ }
+}
+
+/**
+
+ Print the instruction name.
+
+ @param Name - instruction name
+
+ @return Instruction name offset
+
+**/
+UINTN
+EdbPrintInstructionName (
+ IN CHAR16 *Name
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Name,
+ EDB_INSTRUCTION_NAME_MAX_SIZE,
+ mInstructionNameOffset,
+ L"%s",
+ Name
+ );
+ mInstructionNameOffset += StrLen (Name);
+
+ return mInstructionNameOffset;
+}
+
+/**
+
+ Print register 1 in operands.
+
+ @param Operands - instruction operands
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRegister1 (
+ IN UINT8 Operands
+ )
+{
+ if ((Operands & OPERAND_M_INDIRECT1) != 0) {
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"@"
+ );
+ mInstructionContentOffset += 1;
+ }
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"R%d",
+ (UINTN)(Operands & OPERAND_M_OP1)
+ );
+ mInstructionContentOffset += 2;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print register 2 in operands.
+
+ @param Operands - instruction operands
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRegister2 (
+ IN UINT8 Operands
+ )
+{
+ if ((Operands & OPERAND_M_INDIRECT2) != 0) {
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"@"
+ );
+ mInstructionContentOffset += 1;
+ }
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"R%d",
+ (UINTN)((Operands & OPERAND_M_OP2) >> 4)
+ );
+ mInstructionContentOffset += 2;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print dedicated register 1 in operands.
+
+ @param Operands - instruction operands
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintDedicatedRegister1 (
+ IN UINT8 Operands
+ )
+{
+ switch (Operands & OPERAND_M_OP1) {
+ case 0:
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"[FLAGS]"
+ );
+ mInstructionContentOffset += 7;
+ break;
+ case 1:
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"[IP]"
+ );
+ mInstructionContentOffset += 4;
+ break;
+ }
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print dedicated register 2 in operands.
+
+ @param Operands - instruction operands
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintDedicatedRegister2 (
+ IN UINT8 Operands
+ )
+{
+ switch ((Operands & OPERAND_M_OP2) >> 4) {
+ case 0:
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"[FLAGS]"
+ );
+ mInstructionContentOffset += 7;
+ break;
+ case 1:
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"[IP]"
+ );
+ mInstructionContentOffset += 4;
+ break;
+ }
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical UINTN index data to instruction content.
+
+ @param Sign - Signed bit of UINTN data
+ @param NaturalUnits - natural units of UINTN data
+ @param ConstantUnits - natural units of UINTN data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintIndexData (
+ IN BOOLEAN Sign,
+ IN UINTN NaturalUnits,
+ IN UINTN ConstantUnits
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"(%s%d,%s%d)",
+ Sign ? L"-" : L"+",
+ NaturalUnits,
+ Sign ? L"-" : L"+",
+ ConstantUnits
+ );
+ mInstructionContentOffset = mInstructionContentOffset + 5 + EdbGetBitWidth (NaturalUnits) + EdbGetBitWidth (ConstantUnits);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical QWORD index data to instruction content.
+
+ @param Sign - Signed bit of QWORD data
+ @param NaturalUnits - natural units of QWORD data
+ @param ConstantUnits - natural units of QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintIndexData64 (
+ IN BOOLEAN Sign,
+ IN UINT64 NaturalUnits,
+ IN UINT64 ConstantUnits
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"(%s%ld,%s%ld)",
+ Sign ? L"-" : L"+",
+ NaturalUnits,
+ Sign ? L"-" : L"+",
+ ConstantUnits
+ );
+ mInstructionContentOffset = mInstructionContentOffset + 5 + EdbGetBitWidth (NaturalUnits) + EdbGetBitWidth (ConstantUnits);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical WORD raw index data to instruction content.
+
+ @param Data16 - WORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRawIndexData16 (
+ IN UINT16 Data16
+ )
+{
+ BOOLEAN Sign;
+ UINTN NaturalUnits;
+ UINTN ConstantUnits;
+ UINTN Offset;
+
+ Sign = EdbGetNaturalIndex16 (Data16, &NaturalUnits, &ConstantUnits);
+ Offset = EdbPrintIndexData (Sign, NaturalUnits, ConstantUnits);
+
+ return Offset;
+}
+
+/**
+
+ Print the hexical DWORD raw index data to instruction content.
+
+ @param Data32 - DWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRawIndexData32 (
+ IN UINT32 Data32
+ )
+{
+ BOOLEAN Sign;
+ UINTN NaturalUnits;
+ UINTN ConstantUnits;
+ UINTN Offset;
+
+ Sign = EdbGetNaturalIndex32 (Data32, &NaturalUnits, &ConstantUnits);
+ Offset = EdbPrintIndexData (Sign, NaturalUnits, ConstantUnits);
+
+ return Offset;
+}
+
+/**
+
+ Print the hexical QWORD raw index data to instruction content.
+
+ @param Data64 - QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRawIndexData64 (
+ IN UINT64 Data64
+ )
+{
+ BOOLEAN Sign;
+ UINT64 NaturalUnits;
+ UINT64 ConstantUnits;
+ UINTN Offset;
+
+ Sign = EdbGetNaturalIndex64 (Data64, &NaturalUnits, &ConstantUnits);
+ Offset = EdbPrintIndexData64 (Sign, NaturalUnits, ConstantUnits);
+
+ return Offset;
+}
+
+/**
+
+ Print the hexical BYTE immediate data to instruction content.
+
+ @param Data - BYTE data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData8 (
+ IN UINT8 Data
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"(0x%02x)",
+ (UINTN)Data
+ );
+ mInstructionContentOffset += 6;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical WORD immediate data to instruction content.
+
+ @param Data - WORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData16 (
+ IN UINT16 Data
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"(0x%04x)",
+ (UINTN)Data
+ );
+ mInstructionContentOffset += 8;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical DWORD immediate data to instruction content.
+
+ @param Data - DWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData32 (
+ IN UINT32 Data
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"(0x%08x)",
+ (UINTN)Data
+ );
+ mInstructionContentOffset += 12;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical QWORD immediate data to instruction content.
+
+ @param Data - QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData64 (
+ IN UINT64 Data
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"(0x%016lx)",
+ Data
+ );
+ mInstructionContentOffset += 20;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the decimal UINTN immediate data to instruction content.
+
+ @param Data - UINTN data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmDatan (
+ IN UINTN Data
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"(%d)",
+ (UINTN)Data
+ );
+ mInstructionContentOffset = mInstructionContentOffset + 2 + EdbGetBitWidth (Data);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the decimal QWORD immediate data to instruction content.
+
+ @param Data64 - QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData64n (
+ IN UINT64 Data64
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"(%ld)",
+ Data64
+ );
+ mInstructionContentOffset = mInstructionContentOffset + 2 + EdbGetBitWidth (Data64);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical BYTE to instruction content.
+
+ @param Data8 - BYTE data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData8 (
+ IN UINT8 Data8
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"0x%02x",
+ (UINTN)Data8
+ );
+ mInstructionContentOffset += 4;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical WORD to instruction content.
+
+ @param Data16 - WORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData16 (
+ IN UINT16 Data16
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"0x%04x",
+ (UINTN)Data16
+ );
+ mInstructionContentOffset += 6;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical DWORD to instruction content.
+
+ @param Data32 - DWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData32 (
+ IN UINT32 Data32
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"0x%08x",
+ (UINTN)Data32
+ );
+ mInstructionContentOffset += 10;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the hexical QWORD to instruction content.
+
+ @param Data64 - QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData64 (
+ IN UINT64 Data64
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"0x%016lx",
+ (UINT64)Data64
+ );
+ mInstructionContentOffset += 18;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the decimal unsigned UINTN to instruction content.
+
+ @param Data - unsigned UINTN data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintDatan (
+ IN UINTN Data
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"%d",
+ (UINTN)Data
+ );
+ mInstructionContentOffset = mInstructionContentOffset + EdbGetBitWidth (Data);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the decimal unsigned QWORD to instruction content.
+
+ @param Data64 - unsigned QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData64n (
+ IN UINT64 Data64
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"%ld",
+ Data64
+ );
+ mInstructionContentOffset = mInstructionContentOffset + EdbGetBitWidth (Data64);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the decimal signed BYTE to instruction content.
+
+ @param Data8 - signed BYTE data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData8s (
+ IN UINT8 Data8
+ )
+{
+ BOOLEAN Sign;
+
+ Sign = (BOOLEAN)(Data8 >> 7);
+
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"%s%d",
+ Sign ? L"-" : L"+",
+ (UINTN)(Data8 & 0x7F)
+ );
+ mInstructionContentOffset = mInstructionContentOffset + 1 + EdbGetBitWidth (Data8 & 0x7F);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the decimal signed WORD to instruction content.
+
+ @param Data16 - signed WORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData16s (
+ IN UINT16 Data16
+ )
+{
+ BOOLEAN Sign;
+
+ Sign = (BOOLEAN)(Data16 >> 15);
+
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"%s%d",
+ Sign ? L"-" : L"+",
+ (UINTN)(Data16 & 0x7FFF)
+ );
+ mInstructionContentOffset = mInstructionContentOffset + 1 + EdbGetBitWidth (Data16 & 0x7FFF);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the decimal signed DWORD to instruction content.
+
+ @param Data32 - signed DWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData32s (
+ IN UINT32 Data32
+ )
+{
+ BOOLEAN Sign;
+
+ Sign = (BOOLEAN)(Data32 >> 31);
+
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"%s%d",
+ Sign ? L"-" : L"+",
+ (UINTN)(Data32 & 0x7FFFFFFF)
+ );
+ mInstructionContentOffset = mInstructionContentOffset + 1 + EdbGetBitWidth (Data32 & 0x7FFFFFFF);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the decimal signed QWORD to instruction content.
+
+ @param Data64 - signed QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData64s (
+ IN UINT64 Data64
+ )
+{
+ BOOLEAN Sign;
+ INT64 Data64s;
+
+ Sign = (BOOLEAN)RShiftU64 (Data64, 63);
+ Data64s = (INT64)RShiftU64 (LShiftU64 (Data64, 1), 1);
+
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"%s%ld",
+ Sign ? L"-" : L"+",
+ (UINT64)Data64s
+ );
+ mInstructionContentOffset = mInstructionContentOffset + 1 + EdbGetBitWidth (Data64s);
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Print the comma to instruction content.
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintComma (
+ VOID
+ )
+{
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L", "
+ );
+ mInstructionContentOffset += 2;
+
+ return mInstructionContentOffset;
+}
+
+/**
+
+ Find the symbol string according to address, then print it.
+
+ @param Address - instruction address
+
+ @retval 1 - symbol string is found and printed
+ @retval 0 - symbol string not found
+
+**/
+UINTN
+EdbFindAndPrintSymbol (
+ IN UINTN Address
+ )
+{
+ CHAR8 *SymbolStr;
+
+ SymbolStr = FindSymbolStr (Address);
+ if (SymbolStr != NULL) {
+ EDBSPrintWithOffset (
+ mInstructionString.Content,
+ EDB_INSTRUCTION_CONTENT_MAX_SIZE,
+ mInstructionContentOffset,
+ L"[%a]",
+ SymbolStr
+ );
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+
+ Print the EBC byte code.
+
+ @param InstructionAddress - instruction address
+ @param InstructionNumber - instruction number
+
+**/
+VOID
+EdbPrintRaw (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN UINTN InstructionNumber
+ )
+{
+ UINTN LineNumber;
+ UINTN ByteNumber;
+ UINTN LineIndex;
+ UINTN ByteIndex;
+ CHAR8 *SymbolStr;
+
+ if (InstructionNumber == 0) {
+ return ;
+ }
+
+ LineNumber = InstructionNumber / EDB_BYTECODE_NUMBER_IN_LINE;
+ ByteNumber = InstructionNumber % EDB_BYTECODE_NUMBER_IN_LINE;
+ if (ByteNumber == 0) {
+ LineNumber -= 1;
+ ByteNumber = EDB_BYTECODE_NUMBER_IN_LINE;
+ }
+
+ //
+ // Print Symbol
+ //
+ SymbolStr = FindSymbolStr ((UINTN)InstructionAddress);
+ if (SymbolStr != NULL) {
+ EDBPrint (L"[%a]:\n", SymbolStr);
+ }
+
+ for (LineIndex = 0; LineIndex < LineNumber; LineIndex++) {
+ EDBPrint (EDB_PRINT_ADDRESS_FORMAT, (UINTN)InstructionAddress);
+ for (ByteIndex = 0; ByteIndex < EDB_BYTECODE_NUMBER_IN_LINE; ByteIndex++) {
+ EDBPrint (L"%02x ", *(UINT8 *)(UINTN)InstructionAddress);
+ InstructionAddress += 1;
+ }
+ EDBPrint (L"\n");
+ }
+
+ EDBPrint (EDB_PRINT_ADDRESS_FORMAT, (UINTN)InstructionAddress);
+ for (ByteIndex = 0; ByteIndex < ByteNumber; ByteIndex++) {
+ EDBPrint (L"%02x ", *(UINT8 *)(UINTN)InstructionAddress);
+ InstructionAddress += 1;
+ }
+ for (ByteIndex = 0; ByteIndex < EDB_BYTECODE_NUMBER_IN_LINE - ByteNumber; ByteIndex++) {
+ EDBPrint (L" ");
+ }
+
+ return ;
+}
+
+/**
+
+ Print the EBC asm code.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param SystemContext - EBC system context.
+
+ @retval EFI_SUCCESS - show disasm successfully
+
+**/
+EFI_STATUS
+EdbShowDisasm (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EFI_PHYSICAL_ADDRESS InstructionAddress;
+ UINTN InstructionNumber;
+ UINTN InstructionLength;
+ UINT8 Opcode;
+ CHAR16 *InstructionString;
+// UINTN Result;
+
+ InstructionAddress = DebuggerPrivate->InstructionScope;
+ for (InstructionNumber = 0; InstructionNumber < DebuggerPrivate->InstructionNumber; InstructionNumber++) {
+
+ //
+ // Break each 0x10 instruction
+ //
+ if (((InstructionNumber % EFI_DEBUGGER_LINE_NUMBER_IN_PAGE) == 0) &&
+ (InstructionNumber != 0)) {
+ if (SetPageBreak ()) {
+ break;
+ }
+ }
+
+ Opcode = GET_OPCODE(InstructionAddress);
+ if ((Opcode < OPCODE_MAX) && (mEdbDisasmInstructionTable[Opcode] != NULL)) {
+ InstructionLength = mEdbDisasmInstructionTable [Opcode] (InstructionAddress, SystemContext, &InstructionString);
+ if (InstructionLength != 0) {
+
+ //
+ // Print Source
+ //
+// Result = EdbPrintSource ((UINTN)InstructionAddress, FALSE);
+
+ if (!DebuggerPrivate->DebuggerSymbolContext.DisplayCodeOnly) {
+
+ EdbPrintRaw (InstructionAddress, InstructionLength);
+ if (InstructionString != NULL) {
+ EDBPrint (L"%s\n", InstructionString);
+ } else {
+ EDBPrint (L"%s\n", L"<Unknown Instruction>");
+ }
+ }
+
+ EdbPrintSource ((UINTN)InstructionAddress, TRUE);
+
+ InstructionAddress += InstructionLength;
+ } else {
+ //
+ // Something wrong with OPCODE
+ //
+ EdbPrintRaw (InstructionAddress, EDB_BYTECODE_NUMBER_IN_LINE);
+ EDBPrint (L"%s\n", L"<Bad Instruction>");
+ break;
+ }
+ } else {
+ //
+ // Something wrong with OPCODE
+ //
+ EdbPrintRaw (InstructionAddress, EDB_BYTECODE_NUMBER_IN_LINE);
+ EDBPrint (L"%s\n", L"<Bad Instruction>");
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get register value according to the system context, and register index.
+
+ @param SystemContext - EBC system context.
+ @param Index - EBC register index
+
+ @return register value
+
+**/
+UINT64
+GetRegisterValue (
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ IN UINT8 Index
+ )
+{
+ switch (Index) {
+ case 0:
+ return SystemContext.SystemContextEbc->R0;
+ case 1:
+ return SystemContext.SystemContextEbc->R1;
+ case 2:
+ return SystemContext.SystemContextEbc->R2;
+ case 3:
+ return SystemContext.SystemContextEbc->R3;
+ case 4:
+ return SystemContext.SystemContextEbc->R4;
+ case 5:
+ return SystemContext.SystemContextEbc->R5;
+ case 6:
+ return SystemContext.SystemContextEbc->R6;
+ case 7:
+ return SystemContext.SystemContextEbc->R7;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ return 0;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasmSupport.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasmSupport.h
new file mode 100644
index 000000000..b1e7a468e
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbDisasmSupport.h
@@ -0,0 +1,567 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#ifndef _EFI_EDB_DISASM_SUPPORT_H_
+#define _EFI_EDB_DISASM_SUPPORT_H_
+
+#include <Uefi.h>
+
+#define EDB_BYTECODE_NUMBER_IN_LINE 5
+
+#ifdef EFI32
+#define EDB_PRINT_ADDRESS_FORMAT L"%08x: "
+#else
+// To use 012l instead of 016l because space is not enough
+#define EDB_PRINT_ADDRESS_FORMAT L"%012lx: "
+#endif
+
+#define OPCODE_MAX 0x40
+
+#define EDB_INSTRUCTION_NAME_MAX_LENGTH 10
+#define EDB_INSTRUCTION_NAME_MAX_SIZE (EDB_INSTRUCTION_NAME_MAX_LENGTH * sizeof(CHAR16))
+#define EDB_INSTRUCTION_CONTENT_MAX_LENGTH 30
+#define EDB_INSTRUCTION_CONTENT_MAX_SIZE (EDB_INSTRUCTION_CONTENT_MAX_LENGTH * sizeof(CHAR16))
+
+/**
+
+ Set offset for Instruction name and content.
+
+ @param InstructionNameOffset - Instruction name offset
+ @param InstructionContentOffset - Instruction content offset
+
+**/
+VOID
+EdbSetOffset (
+ IN UINTN InstructionNameOffset,
+ IN UINTN InstructionContentOffset
+ );
+
+/**
+
+ Pre instruction string construction.
+
+ @return Instruction string
+
+**/
+CHAR16 *
+EdbPreInstructionString (
+ VOID
+ );
+
+/**
+
+ Post instruction string construction.
+
+ @return Instruction string
+
+**/
+CHAR16 *
+EdbPostInstructionString (
+ VOID
+ );
+
+/**
+
+ Print the instruction name.
+
+ @param Name - instruction name
+
+ @return Instruction name offset
+
+**/
+UINTN
+EdbPrintInstructionName (
+ IN CHAR16 *Name
+ );
+
+/**
+
+ Get Sign, NaturalUnits, and ConstantUnits of the WORD data.
+
+ @param Data16 - WORD data
+ @param NaturalUnits - Natural Units of the WORD
+ @param ConstantUnits - Constant Units of the WORD
+
+ @return Sign value of WORD
+
+**/
+BOOLEAN
+EdbGetNaturalIndex16 (
+ IN UINT16 Data16,
+ OUT UINTN *NaturalUnits,
+ OUT UINTN *ConstantUnits
+ );
+
+/**
+
+ Get Sign, NaturalUnits, and ConstantUnits of the DWORD data.
+
+ @param Data32 - DWORD data
+ @param NaturalUnits - Natural Units of the DWORD
+ @param ConstantUnits - Constant Units of the DWORD
+
+ @return Sign value of DWORD
+
+**/
+BOOLEAN
+EdbGetNaturalIndex32 (
+ IN UINT32 Data32,
+ OUT UINTN *NaturalUnits,
+ OUT UINTN *ConstantUnits
+ );
+
+/**
+
+ Get Sign, NaturalUnits, and ConstantUnits of the QWORD data.
+
+ @param Data64 - QWORD data
+ @param NaturalUnits - Natural Units of the QWORD
+ @param ConstantUnits - Constant Units of the QWORD
+
+ @return Sign value of QWORD
+
+**/
+BOOLEAN
+EdbGetNaturalIndex64 (
+ IN UINT64 Data64,
+ OUT UINT64 *NaturalUnits,
+ OUT UINT64 *ConstantUnits
+ );
+
+/**
+
+ Print the hexical WORD raw index data to instruction content.
+
+ @param Data16 - WORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRawIndexData16 (
+ IN UINT16 Data16
+ );
+
+/**
+
+ Print the hexical DWORD raw index data to instruction content.
+
+ @param Data32 - DWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRawIndexData32 (
+ IN UINT32 Data32
+ );
+
+/**
+
+ Print the hexical QWORD raw index data to instruction content.
+
+ @param Data64 - QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRawIndexData64 (
+ IN UINT64 Data64
+ );
+
+/**
+
+ Print register 1 in operands.
+
+ @param Operands - instruction operands
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRegister1 (
+ IN UINT8 Operands
+ );
+
+/**
+
+ Print register 2 in operands.
+
+ @param Operands - instruction operands
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintRegister2 (
+ IN UINT8 Operands
+ );
+
+/**
+
+ Print dedicated register 1 in operands.
+
+ @param Operands - instruction operands
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintDedicatedRegister1 (
+ IN UINT8 Operands
+ );
+
+/**
+
+ Print dedicated register 2 in operands.
+
+ @param Operands - instruction operands
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintDedicatedRegister2 (
+ IN UINT8 Operands
+ );
+
+/**
+
+ Print the hexical UINTN index data to instruction content.
+
+ @param Sign - Signed bit of UINTN data
+ @param NaturalUnits - natural units of UINTN data
+ @param ConstantUnits - natural units of UINTN data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintIndexData (
+ IN BOOLEAN Sign,
+ IN UINTN NaturalUnits,
+ IN UINTN ConstantUnits
+ );
+
+/**
+
+ Print the hexical QWORD index data to instruction content.
+
+ @param Sign - Signed bit of QWORD data
+ @param NaturalUnits - natural units of QWORD data
+ @param ConstantUnits - natural units of QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintIndexData64 (
+ IN BOOLEAN Sign,
+ IN UINT64 NaturalUnits,
+ IN UINT64 ConstantUnits
+ );
+
+/**
+
+ Print the hexical BYTE immediate data to instruction content.
+
+ @param Data - BYTE data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData8 (
+ IN UINT8 Data
+ );
+
+/**
+
+ Print the hexical WORD immediate data to instruction content.
+
+ @param Data - WORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData16 (
+ IN UINT16 Data
+ );
+
+/**
+
+ Print the hexical DWORD immediate data to instruction content.
+
+ @param Data - DWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData32 (
+ IN UINT32 Data
+ );
+
+/**
+
+ Print the hexical QWORD immediate data to instruction content.
+
+ @param Data - QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData64 (
+ IN UINT64 Data
+ );
+
+/**
+
+ Print the decimal UINTN immediate data to instruction content.
+
+ @param Data - UINTN data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmDatan (
+ IN UINTN Data
+ );
+
+/**
+
+ Print the decimal QWORD immediate data to instruction content.
+
+ @param Data64 - QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintImmData64n (
+ IN UINT64 Data64
+ );
+
+/**
+
+ Print the hexical BYTE to instruction content.
+
+ @param Data8 - BYTE data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData8 (
+ IN UINT8 Data8
+ );
+
+/**
+
+ Print the hexical WORD to instruction content.
+
+ @param Data16 - WORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData16 (
+ IN UINT16 Data16
+ );
+
+/**
+
+ Print the hexical DWORD to instruction content.
+
+ @param Data32 - DWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData32 (
+ IN UINT32 Data32
+ );
+
+/**
+
+ Print the hexical QWORD to instruction content.
+
+ @param Data64 - QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData64 (
+ IN UINT64 Data64
+ );
+
+/**
+
+ Print the decimal unsigned UINTN to instruction content.
+
+ @param Data - unsigned UINTN data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintDatan (
+ IN UINTN Data
+ );
+
+/**
+
+ Print the decimal unsigned QWORD to instruction content.
+
+ @param Data64 - unsigned QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData64n (
+ IN UINT64 Data64
+ );
+
+/**
+
+ Print the decimal signed BYTE to instruction content.
+
+ @param Data8 - signed BYTE data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData8s (
+ IN UINT8 Data8
+ );
+
+/**
+
+ Print the decimal signed WORD to instruction content.
+
+ @param Data16 - signed WORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData16s (
+ IN UINT16 Data16
+ );
+
+/**
+
+ Print the decimal signed DWORD to instruction content.
+
+ @param Data32 - signed DWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData32s (
+ IN UINT32 Data32
+ );
+
+/**
+
+ Print the decimal signed QWORD to instruction content.
+
+ @param Data64 - signed QWORD data
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintData64s (
+ IN UINT64 Data64
+ );
+
+/**
+
+ Print the comma to instruction content.
+
+ @return Instruction content offset
+
+**/
+UINTN
+EdbPrintComma (
+ VOID
+ );
+
+/**
+
+ Find the symbol string according to address, then print it.
+
+ @param Address - instruction address
+
+ @retval 1 - symbol string is found and printed
+ @retval 0 - symbol string not found
+
+**/
+UINTN
+EdbFindAndPrintSymbol (
+ IN UINTN Address
+ );
+
+/**
+
+ Print the EBC byte code.
+
+ @param InstructionAddress - instruction address
+ @param InstructionNumber - instruction number
+
+**/
+VOID
+EdbPrintRaw (
+ IN EFI_PHYSICAL_ADDRESS InstructionAddress,
+ IN UINTN InstructionNumber
+ );
+
+/**
+
+ Print the EBC asm code.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param SystemContext - EBC system context.
+
+ @retval EFI_SUCCESS - show disasm successfully
+
+**/
+EFI_STATUS
+EdbShowDisasm (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+/**
+
+ Get register value according to the system context, and register index.
+
+ @param SystemContext - EBC system context.
+ @param Index - EBC register index
+
+ @return register value
+
+**/
+UINT64
+GetRegisterValue (
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ IN UINT8 Index
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.c
new file mode 100644
index 000000000..83257a2c2
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.c
@@ -0,0 +1,833 @@
+/** @file
+
+Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ Check the Hook flag, and trigger exception if match.
+
+ @param VmPtr - EbcDebuggerCheckHookFlag
+ @param Flag - Feature flag
+
+**/
+VOID
+EbcDebuggerCheckHookFlag (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Flag
+ )
+{
+ if ((mDebuggerPrivate.FeatureFlags & Flag) == Flag) {
+ mDebuggerPrivate.StatusFlags = Flag;
+ EbcDebugSignalException (
+ EXCEPT_EBC_BREAKPOINT,
+ EXCEPTION_FLAG_NONE,
+ VmPtr
+ );
+ }
+ return ;
+}
+
+/**
+
+ It will record soruce address for Callstack entry.
+
+ @param SourceEntry - Source address
+ @param Type - Branch type
+
+**/
+VOID
+EbcDebuggerPushCallstackSource (
+ IN UINT64 SourceEntry,
+ IN EFI_DEBUGGER_BRANCH_TYPE Type
+ )
+{
+ if (mDebuggerPrivate.CallStackEntryCount > EFI_DEBUGGER_CALLSTACK_MAX) {
+ ASSERT (FALSE);
+ mDebuggerPrivate.CallStackEntryCount = EFI_DEBUGGER_CALLSTACK_MAX;
+ }
+ //
+ // Record the new callstack entry
+ //
+ mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].SourceAddress = SourceEntry;
+ mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].Type = Type;
+
+ //
+ // Do not change CallStackEntryCount
+ //
+
+ return ;
+}
+
+/**
+
+ It will record parameter for Callstack entry.
+
+ @param ParameterAddress - The address for the parameter
+ @param Type - Branch type
+
+**/
+VOID
+EbcDebuggerPushCallstackParameter (
+ IN UINT64 ParameterAddress,
+ IN EFI_DEBUGGER_BRANCH_TYPE Type
+ )
+{
+ if (mDebuggerPrivate.CallStackEntryCount > EFI_DEBUGGER_CALLSTACK_MAX) {
+ ASSERT (FALSE);
+ mDebuggerPrivate.CallStackEntryCount = EFI_DEBUGGER_CALLSTACK_MAX;
+ }
+ //
+ // Record the new callstack parameter
+ //
+ mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].ParameterAddr = (UINTN)ParameterAddress;
+ CopyMem (
+ mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].Parameter,
+ (VOID *)(UINTN)ParameterAddress,
+ sizeof(mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].Parameter)
+ );
+
+ //
+ // Do not change CallStackEntryCount
+ //
+
+ return ;
+}
+
+/**
+
+ It will record source address for callstack entry.
+
+ @param DestEntry - Source address
+ @param Type - Branch type
+
+**/
+VOID
+EbcDebuggerPushCallstackDest (
+ IN UINT64 DestEntry,
+ IN EFI_DEBUGGER_BRANCH_TYPE Type
+ )
+{
+ UINTN Index;
+
+ if (mDebuggerPrivate.CallStackEntryCount < EFI_DEBUGGER_CALLSTACK_MAX) {
+ //
+ // If there is empty entry for callstack, add it
+ //
+ ASSERT (mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].Type == Type);
+ mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].DestAddress = DestEntry;
+ mDebuggerPrivate.CallStackEntryCount ++;
+ } else {
+ //
+ // If there is no empty entry for callstack, throw the oldest one
+ //
+ ASSERT (mDebuggerPrivate.CallStackEntry[EFI_DEBUGGER_TRACE_MAX].Type == Type);
+ for (Index = 0; Index < EFI_DEBUGGER_CALLSTACK_MAX; Index++) {
+ CopyMem (&mDebuggerPrivate.CallStackEntry[Index],
+ &mDebuggerPrivate.CallStackEntry[Index + 1],
+ sizeof (mDebuggerPrivate.CallStackEntry[Index])
+ );
+ }
+ mDebuggerPrivate.CallStackEntry[EFI_DEBUGGER_CALLSTACK_MAX - 1].DestAddress = DestEntry;
+ mDebuggerPrivate.CallStackEntryCount = EFI_DEBUGGER_CALLSTACK_MAX;
+ }
+
+ return ;
+}
+
+/**
+
+ It will throw the newest Callstack entry.
+
+**/
+VOID
+EbcDebuggerPopCallstack (
+ VOID
+ )
+{
+ if ((mDebuggerPrivate.CallStackEntryCount > 0) &&
+ (mDebuggerPrivate.CallStackEntryCount <= EFI_DEBUGGER_CALLSTACK_MAX)) {
+ //
+ // Throw the newest one
+ //
+ mDebuggerPrivate.CallStackEntryCount --;
+ mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].SourceAddress = 0;
+ mDebuggerPrivate.CallStackEntry[mDebuggerPrivate.CallStackEntryCount].DestAddress = 0;
+ } else if (mDebuggerPrivate.CallStackEntryCount == 0) {
+ //
+ // NOT assert here because it is reasonable, because when we start to build
+ // callstack, we do not know how many function already called.
+ //
+ } else {
+ ASSERT (FALSE);
+ }
+
+ return ;
+}
+
+/**
+
+ It will record source address for trace entry.
+
+ @param SourceEntry - Source address
+ @param Type - Branch type
+
+**/
+VOID
+EbcDebuggerPushTraceSourceEntry (
+ IN UINT64 SourceEntry,
+ IN EFI_DEBUGGER_BRANCH_TYPE Type
+ )
+{
+ if (mDebuggerPrivate.TraceEntryCount > EFI_DEBUGGER_TRACE_MAX) {
+ ASSERT (FALSE);
+ mDebuggerPrivate.TraceEntryCount = EFI_DEBUGGER_TRACE_MAX;
+ }
+ //
+ // Record the new trace entry
+ //
+ mDebuggerPrivate.TraceEntry[mDebuggerPrivate.TraceEntryCount].SourceAddress = SourceEntry;
+ mDebuggerPrivate.TraceEntry[mDebuggerPrivate.TraceEntryCount].Type = Type;
+
+ //
+ // Do not change TraceEntryCount
+ //
+
+ return ;
+}
+
+/**
+
+ It will record destination address for trace entry.
+
+ @param DestEntry - Destination address
+ @param Type - Branch type
+
+**/
+VOID
+EbcDebuggerPushTraceDestEntry (
+ IN UINT64 DestEntry,
+ IN EFI_DEBUGGER_BRANCH_TYPE Type
+ )
+{
+ UINTN Index;
+
+ if (mDebuggerPrivate.TraceEntryCount < EFI_DEBUGGER_TRACE_MAX) {
+ //
+ // If there is empty entry for trace, add it
+ //
+ ASSERT (mDebuggerPrivate.TraceEntry[mDebuggerPrivate.TraceEntryCount].Type == Type);
+ mDebuggerPrivate.TraceEntry[mDebuggerPrivate.TraceEntryCount].DestAddress = DestEntry;
+ mDebuggerPrivate.TraceEntryCount ++;
+ } else {
+ //
+ // If there is no empty entry for trace, throw the oldest one
+ //
+ ASSERT (mDebuggerPrivate.TraceEntry[EFI_DEBUGGER_TRACE_MAX].Type == Type);
+ for (Index = 0; Index < EFI_DEBUGGER_TRACE_MAX; Index++) {
+ mDebuggerPrivate.TraceEntry[Index] = mDebuggerPrivate.TraceEntry[Index + 1];
+ }
+ mDebuggerPrivate.TraceEntry[EFI_DEBUGGER_CALLSTACK_MAX - 1].DestAddress = DestEntry;
+ mDebuggerPrivate.TraceEntryCount = EFI_DEBUGGER_TRACE_MAX;
+ }
+
+ return ;
+}
+
+/**
+
+ It will record address for StepEntry, if STEPOVER or STEPOUT is enabled.
+
+ @param Entry - Break Address
+ @param FramePtr - Break Frame pointer
+ @param Flag - for STEPOVER or STEPOUT
+
+**/
+VOID
+EbcDebuggerPushStepEntry (
+ IN UINT64 Entry,
+ IN UINT64 FramePtr,
+ IN UINT32 Flag
+ )
+{
+ //
+ // Check StepOver
+ //
+ if ((Flag == EFI_DEBUG_FLAG_EBC_STEPOVER) &&
+ ((mDebuggerPrivate.FeatureFlags & EFI_DEBUG_FLAG_EBC_STEPOVER) == EFI_DEBUG_FLAG_EBC_STEPOVER)) {
+ mDebuggerPrivate.StepContext.BreakAddress = Entry;
+ mDebuggerPrivate.StepContext.FramePointer = FramePtr;
+ mDebuggerPrivate.FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_STEPOVER;
+ }
+ //
+ // Check StepOut
+ //
+ if ((Flag == EFI_DEBUG_FLAG_EBC_STEPOUT) &&
+ ((mDebuggerPrivate.FeatureFlags & EFI_DEBUG_FLAG_EBC_STEPOUT) == EFI_DEBUG_FLAG_EBC_STEPOUT)) {
+ mDebuggerPrivate.StepContext.BreakAddress = Entry;
+ mDebuggerPrivate.StepContext.FramePointer = FramePtr;
+ mDebuggerPrivate.FeatureFlags &= ~EFI_DEBUG_FLAG_EBC_B_STEPOUT;
+ }
+}
+
+
+/**
+ Notify the callback function when an event is triggered.
+
+ @param Event Indicates the event that invoke this function.
+ @param Context Indicates the calling context.
+
+**/
+VOID
+EFIAPI
+EbcDebuggerBreakEventFunc (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ if ((mDebuggerPrivate.FeatureFlags & EFI_DEBUG_FLAG_EBC_BOK) != EFI_DEBUG_FLAG_EBC_BOK) {
+ return ;
+ }
+
+ Status = gBS->CheckEvent (gST->ConIn->WaitForKey);
+ if (Status == EFI_SUCCESS) {
+ mDebuggerPrivate.StatusFlags = EFI_DEBUG_FLAG_EBC_BOK;
+ }
+}
+
+/**
+
+ The hook in InitializeEbcDriver.
+ It will init the EbcDebuggerPrivate data structure.
+
+ @param Handle - The EbcDebugProtocol handle.
+ @param EbcDebugProtocol - The EbcDebugProtocol interface.
+
+**/
+VOID
+EbcDebuggerHookInit (
+ IN EFI_HANDLE Handle,
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
+
+
+ //
+ // Register all exception handler
+ //
+ for (Index = EXCEPT_EBC_UNDEFINED; Index <= EXCEPT_EBC_STEP; Index++) {
+ EbcDebugProtocol->RegisterExceptionCallback (
+ EbcDebugProtocol,
+ 0,
+ NULL,
+ Index
+ );
+ EbcDebugProtocol->RegisterExceptionCallback (
+ EbcDebugProtocol,
+ 0,
+ EdbExceptionHandler,
+ Index
+ );
+ }
+
+ //
+ // Init Symbol
+ //
+ Object = AllocateZeroPool (sizeof(EFI_DEBUGGER_SYMBOL_OBJECT) * EFI_DEBUGGER_SYMBOL_OBJECT_MAX);
+ ASSERT (Object != NULL);
+ mDebuggerPrivate.DebuggerSymbolContext.Object = Object;
+ mDebuggerPrivate.DebuggerSymbolContext.ObjectCount = 0;
+ mDebuggerPrivate.DebuggerSymbolContext.MaxObjectCount = EFI_DEBUGGER_SYMBOL_OBJECT_MAX;
+ for (Index = 0; Index < EFI_DEBUGGER_SYMBOL_OBJECT_MAX; Index++) {
+ Entry = AllocateZeroPool (sizeof(EFI_DEBUGGER_SYMBOL_ENTRY) * EFI_DEBUGGER_SYMBOL_ENTRY_MAX);
+ ASSERT (Entry != NULL);
+ Object[Index].Entry = Entry;
+ Object[Index].MaxEntryCount = EFI_DEBUGGER_SYMBOL_ENTRY_MAX;
+ Object[Index].SourceBuffer = AllocateZeroPool (sizeof(VOID *) * (EFI_DEBUGGER_SYMBOL_ENTRY_MAX + 1));
+ ASSERT (Object[Index].SourceBuffer != NULL);
+ }
+
+ //
+ // locate PciRootBridgeIo
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiPciRootBridgeIoProtocolGuid,
+ NULL,
+ (VOID**) &mDebuggerPrivate.PciRootBridgeIo
+ );
+
+ //
+ // locate DebugImageInfoTable
+ //
+ Status = EfiGetSystemConfigurationTable (
+ &gEfiDebugImageInfoTableGuid,
+ (VOID**) &mDebuggerPrivate.DebugImageInfoTableHeader
+ );
+
+ //
+ // Register Debugger Configuration Protocol, for config in shell
+ //
+ Status = gBS->InstallProtocolInterface (
+ &Handle,
+ &gEfiDebuggerConfigurationProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mDebuggerPrivate.DebuggerConfiguration
+ );
+
+ //
+ //
+ // Create break event
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ EbcDebuggerBreakEventFunc,
+ NULL,
+ &mDebuggerPrivate.BreakEvent
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->SetTimer (
+ mDebuggerPrivate.BreakEvent,
+ TimerPeriodic,
+ EFI_DEBUG_BREAK_TIMER_INTERVAL
+ );
+ }
+
+ return ;
+}
+
+/**
+
+ The hook in UnloadImage for EBC Interpreter.
+ It clean up the environment.
+
+**/
+VOID
+EbcDebuggerHookUnload (
+ VOID
+ )
+{
+ UINTN Index;
+ UINTN SubIndex;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+
+ //
+ // Close the break event
+ //
+ if (mDebuggerPrivate.BreakEvent != NULL) {
+ gBS->CloseEvent (mDebuggerPrivate.BreakEvent);
+ }
+
+ //
+ // Clean up the symbol
+ //
+ Object = mDebuggerPrivate.DebuggerSymbolContext.Object;
+ for (Index = 0; Index < EFI_DEBUGGER_SYMBOL_OBJECT_MAX; Index++) {
+ //
+ // Clean up Entry
+ //
+ gBS->FreePool (Object[Index].Entry);
+ Object[Index].Entry = NULL;
+ Object[Index].EntryCount = 0;
+ //
+ // Clean up source buffer
+ //
+ for (SubIndex = 0; Object[Index].SourceBuffer[SubIndex] != NULL; SubIndex++) {
+ gBS->FreePool (Object[Index].SourceBuffer[SubIndex]);
+ Object[Index].SourceBuffer[SubIndex] = NULL;
+ }
+ gBS->FreePool (Object[Index].SourceBuffer);
+ Object[Index].SourceBuffer = NULL;
+ }
+
+ //
+ // Clean up Object
+ //
+ gBS->FreePool (Object);
+ mDebuggerPrivate.DebuggerSymbolContext.Object = NULL;
+ mDebuggerPrivate.DebuggerSymbolContext.ObjectCount = 0;
+
+ //
+ // Done
+ //
+ return ;
+}
+
+/**
+
+ The hook in EbcUnloadImage.
+ Currently do nothing here.
+
+ @param Handle - The EbcImage handle.
+
+**/
+VOID
+EbcDebuggerHookEbcUnloadImage (
+ IN EFI_HANDLE Handle
+ )
+{
+ return ;
+}
+
+/**
+
+ The hook in ExecuteEbcImageEntryPoint.
+ It will record the call-stack entry. (-1 means EbcImageEntryPoint call)
+ and trigger Exception if BOE enabled.
+
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookExecuteEbcImageEntryPoint (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerPushCallstackSource ((UINT64)(UINTN)-1, EfiDebuggerBranchTypeEbcCall);
+ EbcDebuggerPushCallstackParameter ((UINT64)(UINTN)VmPtr->Gpr[0], EfiDebuggerBranchTypeEbcCall);
+ EbcDebuggerPushCallstackDest ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
+ EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOE);
+ return ;
+}
+
+/**
+
+ The hook in ExecuteEbcImageEntryPoint.
+ It will record the call-stack entry. (-2 means EbcInterpret call)
+ and trigger Exception if BOT enabled.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookEbcInterpret (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerPushCallstackSource ((UINT64)(UINTN)-2, EfiDebuggerBranchTypeEbcCall);
+ EbcDebuggerPushCallstackParameter ((UINT64)(UINTN)VmPtr->Gpr[0], EfiDebuggerBranchTypeEbcCall);
+ EbcDebuggerPushCallstackDest ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
+ EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOT);
+ return ;
+}
+
+/**
+
+ The hook in EbcExecute, before ExecuteFunction.
+ It will trigger Exception if GoTil, StepOver, or StepOut hit.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookExecuteStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EFI_TPL CurrentTpl;
+
+ //
+ // Check Ip for GoTil
+ //
+ if (mDebuggerPrivate.GoTilContext.BreakAddress == (UINT64)(UINTN)VmPtr->Ip) {
+ mDebuggerPrivate.StatusFlags = EFI_DEBUG_FLAG_EBC_GT;
+ mDebuggerPrivate.GoTilContext.BreakAddress = 0;
+ EbcDebugSignalException (
+ EXCEPT_EBC_BREAKPOINT,
+ EXCEPTION_FLAG_NONE,
+ VmPtr
+ );
+ mDebuggerPrivate.StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_GT;
+ return ;
+ }
+ //
+ // Check ReturnAddress for StepOver
+ //
+ if ((mDebuggerPrivate.StepContext.BreakAddress == (UINT64)(UINTN)VmPtr->Ip) &&
+ (mDebuggerPrivate.StepContext.FramePointer == (UINT64)(UINTN)VmPtr->FramePtr)) {
+ mDebuggerPrivate.StatusFlags = EFI_DEBUG_FLAG_EBC_STEPOVER;
+ mDebuggerPrivate.StepContext.BreakAddress = 0;
+ mDebuggerPrivate.StepContext.FramePointer = 0;
+ EbcDebugSignalException (
+ EXCEPT_EBC_BREAKPOINT,
+ EXCEPTION_FLAG_NONE,
+ VmPtr
+ );
+ mDebuggerPrivate.StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_STEPOVER;
+ }
+ //
+ // Check FramePtr for StepOut
+ //
+ if (mDebuggerPrivate.StepContext.BreakAddress == (UINT64)(UINTN)VmPtr->FramePtr) {
+ mDebuggerPrivate.StatusFlags = EFI_DEBUG_FLAG_EBC_STEPOUT;
+ mDebuggerPrivate.StepContext.BreakAddress = 0;
+ mDebuggerPrivate.StepContext.FramePointer = 0;
+ EbcDebugSignalException (
+ EXCEPT_EBC_BREAKPOINT,
+ EXCEPTION_FLAG_NONE,
+ VmPtr
+ );
+ mDebuggerPrivate.StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_STEPOUT;
+ }
+ //
+ // Check Flags for BreakOnKey
+ //
+ if (mDebuggerPrivate.StatusFlags == EFI_DEBUG_FLAG_EBC_BOK) {
+ //
+ // Only break when the current TPL <= TPL_APPLICATION
+ //
+ CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+ gBS->RestoreTPL (CurrentTpl);
+ if (CurrentTpl <= TPL_APPLICATION) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_BREAKPOINT,
+ EXCEPTION_FLAG_NONE,
+ VmPtr
+ );
+ mDebuggerPrivate.StatusFlags &= ~EFI_DEBUG_FLAG_EBC_B_BOK;
+ }
+ }
+ return ;
+}
+
+/**
+
+ The hook in EbcExecute, after ExecuteFunction.
+ It will record StepOut Entry if need.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookExecuteEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINTN Address;
+
+ //
+ // Use FramePtr as checkpoint for StepOut
+ //
+ CopyMem (&Address, (VOID *)((UINTN)VmPtr->FramePtr), sizeof(Address));
+ EbcDebuggerPushStepEntry (Address, (UINT64)(UINTN)VmPtr->FramePtr, EFI_DEBUG_FLAG_EBC_STEPOUT);
+
+ return ;
+}
+
+/**
+
+ The hook in ExecuteCALL, before move IP.
+ It will trigger Exception if BOC enabled,
+ and record Callstack, and trace information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOC);
+ EbcDebuggerPushCallstackSource ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
+ EbcDebuggerPushCallstackParameter ((UINT64)(UINTN)VmPtr->Gpr[0], EfiDebuggerBranchTypeEbcCall);
+ EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
+ return ;
+}
+
+/**
+
+ The hook in ExecuteCALL, after move IP.
+ It will record Callstack, trace information
+ and record StepOver/StepOut Entry if need.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT64 Address;
+ UINTN FramePtr;
+
+ EbcDebuggerPushCallstackDest ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
+ EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCall);
+
+ //
+ // Get Old FramePtr
+ //
+ CopyMem (&FramePtr, (VOID *)((UINTN)VmPtr->FramePtr), sizeof(FramePtr));
+
+ //
+ // Use ReturnAddress as checkpoint for StepOver
+ //
+ CopyMem (&Address, (VOID *)(UINTN)VmPtr->Gpr[0], sizeof(Address));
+ EbcDebuggerPushStepEntry (Address, FramePtr, EFI_DEBUG_FLAG_EBC_STEPOVER);
+
+ //
+ // Use FramePtr as checkpoint for StepOut
+ //
+ Address = 0;
+ CopyMem (&Address, (VOID *)(FramePtr), sizeof(UINTN));
+ EbcDebuggerPushStepEntry (Address, FramePtr, EFI_DEBUG_FLAG_EBC_STEPOUT);
+
+ return ;
+}
+
+/**
+
+ The hook in ExecuteCALL, before call EbcLLCALLEX.
+ It will trigger Exception if BOCX enabled,
+ and record Callstack information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLEXStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOCX);
+// EbcDebuggerPushCallstackSource ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCallEx);
+// EbcDebuggerPushCallstackParameter ((UINT64)(UINTN)VmPtr->R[0], EfiDebuggerBranchTypeEbcCallEx);
+ EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCallEx);
+ return ;
+}
+
+/**
+
+ The hook in ExecuteCALL, after call EbcLLCALLEX.
+ It will record trace information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLEXEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+// EbcDebuggerPushCallstackDest ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCallEx);
+ EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcCallEx);
+ return ;
+}
+
+/**
+
+ The hook in ExecuteRET, before move IP.
+ It will trigger Exception if BOR enabled,
+ and record Callstack, and trace information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookRETStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerCheckHookFlag (VmPtr, EFI_DEBUG_FLAG_EBC_BOR);
+ EbcDebuggerPopCallstack ();
+ EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcRet);
+ return ;
+}
+
+/**
+
+ The hook in ExecuteRET, after move IP.
+ It will record trace information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookRETEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcRet);
+ return ;
+}
+
+/**
+
+ The hook in ExecuteJMP, before move IP.
+ It will record trace information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMPStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcJmp);
+ return ;
+}
+
+/**
+
+ The hook in ExecuteJMP, after move IP.
+ It will record trace information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMPEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcJmp);
+ return ;
+}
+
+/**
+
+ The hook in ExecuteJMP8, before move IP.
+ It will record trace information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMP8Start (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerPushTraceSourceEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcJmp8);
+ return ;
+}
+
+/**
+
+ The hook in ExecuteJMP8, after move IP.
+ It will record trace information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMP8End (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EbcDebuggerPushTraceDestEntry ((UINT64)(UINTN)VmPtr->Ip, EfiDebuggerBranchTypeEbcJmp8);
+ return ;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.h
new file mode 100644
index 000000000..6de50e0a7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbHook.h
@@ -0,0 +1,14 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_EDB_HOOKER_H_
+#define _EFI_EDB_HOOKER_H_
+
+#include <Uefi.h>
+#include "EbcDebuggerHook.h"
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupport.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupport.h
new file mode 100644
index 000000000..ba8b936b3
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupport.h
@@ -0,0 +1,477 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#ifndef _EFI_EDB_SUPPORT_H_
+#define _EFI_EDB_SUPPORT_H_
+
+#include <Uefi.h>
+
+#define EFI_DEBUG_PROMPT_STRING L"EDB > "
+#define EFI_DEBUG_PROMPT_COLUMN 5
+#define EFI_DEBUG_INPUS_BUFFER_SIZE 64
+
+#define EFI_DEBUGGER_LINE_NUMBER_IN_PAGE 0x10
+
+#define EFI_DEBUG_MAX_PRINT_BUFFER (80 * 4)
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINTN
+EFIAPI
+Xtoi (
+ CHAR16 *Str
+ );
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINT64
+EFIAPI
+LXtoi (
+ CHAR16 *Str
+ );
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINTN
+EFIAPI
+Atoi (
+ CHAR16 *Str
+ );
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINTN
+EFIAPI
+AsciiXtoi (
+ CHAR8 *Str
+ );
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINTN
+EFIAPI
+AsciiAtoi (
+ CHAR8 *Str
+ );
+
+/**
+ Compare the Unicode and Ascii string pointed by String to the string pointed by String2.
+
+ @param String - Unicode String to process
+
+ @param String2 - Ascii string to process
+
+ @return Return a positive integer if String is lexicall greater than String2; Zero if
+ the two strings are identical; and a negative interger if String is lexically
+ less than String2.
+
+**/
+INTN
+EFIAPI
+StrCmpUnicodeAndAscii (
+ IN CHAR16 *String,
+ IN CHAR8 *String2
+ );
+
+/**
+
+ Compare the Unicode string pointed by String to the string pointed by String2.
+
+ @param String - Unicode String to process
+ @param String2 - Unicode string to process
+
+ @return Return a positive integer if String is lexically greater than String2; Zero if
+ the two strings are identical; and a negative integer if String is lexically
+ less than String2.
+
+**/
+INTN
+EFIAPI
+StriCmp (
+ IN CHAR16 *String,
+ IN CHAR16 *String2
+ );
+
+/**
+
+ Compare the Unicode and Ascii string pointed by String to the string pointed by String2.
+
+ @param String - Unicode String to process
+ @param String2 - Ascii string to process
+
+ @return Return a positive integer if String is lexically greater than String2; Zero if
+ the two strings are identical; and a negative integer if String is lexically
+ less than String2.
+
+**/
+INTN
+EFIAPI
+StriCmpUnicodeAndAscii (
+ IN CHAR16 *String,
+ IN CHAR8 *String2
+ );
+
+/**
+
+ Verify if the string is end with the sub string.
+
+ @param Str - The string where to search the sub string
+ @param SubStr - The substring.
+
+**/
+BOOLEAN
+EFIAPI
+StrEndWith (
+ IN CHAR16 *Str,
+ IN CHAR16 *SubStr
+ );
+
+/**
+ Duplicate a string.
+
+ @param Src The string to be duplicated.
+
+**/
+CHAR16 *
+EFIAPI
+StrDuplicate (
+ IN CHAR16 *Src
+ );
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrGetNewTokenLine (
+ IN CHAR16 *String,
+ IN CHAR16 *CharSet
+ );
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrGetNextTokenLine (
+ IN CHAR16 *CharSet
+ );
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrGetNewTokenField (
+ IN CHAR16 *String,
+ IN CHAR16 *CharSet
+ );
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrGetNextTokenField (
+ IN CHAR16 *CharSet
+ );
+
+/**
+
+ Patch a character to the end of a string.
+
+ @param Buffer The string to be patched.
+ @param Patch The patch character.
+
+**/
+VOID
+EFIAPI
+PatchForStrTokenAfter (
+ IN CHAR16 *Buffer,
+ IN CHAR16 Patch
+ );
+
+/**
+ Patch a character at the beginning of a string.
+
+ @param Buffer The string to be patched.
+ @param Patch The patch character.
+
+**/
+VOID
+EFIAPI
+PatchForStrTokenBefore (
+ IN CHAR16 *Buffer,
+ IN CHAR16 Patch
+ );
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrGetNewTokenLine (
+ IN CHAR8 *String,
+ IN CHAR8 *CharSet
+ );
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrGetNextTokenLine (
+ IN CHAR8 *CharSet
+ );
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrGetNewTokenField (
+ IN CHAR8 *String,
+ IN CHAR8 *CharSet
+ );
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrGetNextTokenField (
+ IN CHAR8 *CharSet
+ );
+
+/**
+
+ Patch a character to the end of a string.
+
+ @param Buffer The string to be patched.
+ @param Patch The patch character.
+
+**/
+VOID
+EFIAPI
+PatchForAsciiStrTokenAfter (
+ IN CHAR8 *Buffer,
+ IN CHAR8 Patch
+ );
+
+/**
+ Patch a character at the beginning of a string.
+
+ @param Buffer The string to be patched.
+ @param Patch The patch character.
+
+**/
+VOID
+EFIAPI
+PatchForAsciiStrTokenBefore (
+ IN CHAR8 *Buffer,
+ IN CHAR8 Patch
+ );
+
+/**
+
+ Shell Library.
+ Get user input.
+
+ @param Prompt The prompt string.
+ @param InStr Point to the input string.
+ @param StrLen The max length of string user can input.
+
+**/
+VOID
+EFIAPI
+Input (
+ IN CHAR16 *Prompt OPTIONAL,
+ OUT CHAR16 *InStr,
+ IN UINTN StrLen
+ );
+
+/**
+
+ SetPageBreak.
+
+**/
+BOOLEAN
+EFIAPI
+SetPageBreak (
+ VOID
+ );
+
+/**
+ Print a Unicode string to the output device.
+
+ @param Format A Null-terminated Unicode format string.
+ @param ... The variable argument list that contains pointers to Null-
+ terminated Unicode strings to be printed
+
+**/
+UINTN
+EFIAPI
+EDBPrint (
+ IN CONST CHAR16 *Format,
+ ...
+ );
+
+/**
+ Print a Unicode string to the output buffer.
+
+ @param Buffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param Format A Null-terminated Unicode format string.
+ @param ... The variable argument list that contains pointers to Null-
+ terminated Unicode strings to be printed
+
+**/
+UINTN
+EFIAPI
+EDBSPrint (
+ OUT CHAR16 *Buffer,
+ IN INTN BufferSize,
+ IN CONST CHAR16 *Format,
+ ...
+ );
+
+/**
+ Print a Unicode string to the output buffer with specified offset..
+
+ @param Buffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param Offset The offset of the buffer.
+ @param Format A Null-terminated Unicode format string.
+ @param ... The variable argument list that contains pointers to Null-
+ terminated Unicode strings to be printed
+
+**/
+UINTN
+EFIAPI
+EDBSPrintWithOffset (
+ OUT CHAR16 *Buffer,
+ IN INTN BufferSize,
+ IN UINTN Offset,
+ IN CONST CHAR16 *Format,
+ ...
+ );
+
+/**
+
+ Read a file.
+ If ScanFs is FLASE, it will use DebuggerPrivate->Vol as default Fs.
+ If ScanFs is TRUE, it will scan all FS and check the file.
+ If there is only one file match the name, it will be read.
+ If there is more than one file match the name, it will return Error.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param FileName - The file to be read.
+ @param BufferSize - The file buffer size
+ @param Buffer - The file buffer
+ @param ScanFs - Need Scan all FS
+
+ @retval EFI_SUCCESS - read file successfully
+ @retval EFI_NOT_FOUND - file not found
+ @retval EFI_NO_MAPPING - there is duplicated files found
+
+**/
+EFI_STATUS
+EFIAPI
+ReadFileToBuffer (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *FileName,
+ OUT UINTN *BufferSize,
+ OUT VOID **Buffer,
+ IN BOOLEAN ScanFs
+ );
+
+/**
+
+ Get file name under this dir with index
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param DirName - The dir to be read.
+ @param FileName - The file name pattern under this dir
+ @param Index - The file index under this dir
+
+ @return File Name which match the pattern and index.
+
+**/
+CHAR16 *
+EFIAPI
+GetFileNameUnderDir (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *DirName,
+ IN CHAR16 *FileName,
+ IN OUT UINTN *Index
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportFile.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportFile.c
new file mode 100644
index 000000000..ee2f8fc2f
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportFile.c
@@ -0,0 +1,384 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+ Read a file.
+
+ @param Vol - File System Volume
+ @param FileName - The file to be read.
+ @param BufferSize - The file buffer size
+ @param Buffer - The file buffer
+
+ @retval EFI_SUCCESS - read file successfully
+ @retval EFI_NOT_FOUND - file not found
+
+**/
+EFI_STATUS
+EFIAPI
+ReadFileFromVol (
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol,
+ IN CHAR16 *FileName,
+ OUT UINTN *BufferSize,
+ OUT VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE_HANDLE RootDir;
+ EFI_FILE_HANDLE Handle;
+ UINTN FileInfoSize;
+ EFI_FILE_INFO *FileInfo;
+ UINTN TempBufferSize;
+ VOID *TempBuffer;
+
+ //
+ // Open the root directory
+ //
+ Status = Vol->OpenVolume (Vol, &RootDir);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Open the file
+ //
+ Status = RootDir->Open (
+ RootDir,
+ &Handle,
+ FileName,
+ EFI_FILE_MODE_READ,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ RootDir->Close (RootDir);
+ return Status;
+ }
+
+ RootDir->Close (RootDir);
+
+ //
+ // Get the file information
+ //
+ FileInfoSize = sizeof(EFI_FILE_INFO) + 1024;
+
+ FileInfo = AllocateZeroPool (FileInfoSize);
+ if (FileInfo == NULL) {
+ Handle->Close (Handle);
+ return Status;
+ }
+
+ Status = Handle->GetInfo (
+ Handle,
+ &gEfiFileInfoGuid,
+ &FileInfoSize,
+ FileInfo
+ );
+ if (EFI_ERROR (Status)) {
+ Handle->Close (Handle);
+ gBS->FreePool (FileInfo);
+ return Status;
+ }
+
+ //
+ // Allocate buffer for the file data. The last CHAR16 is for L'\0'
+ //
+ TempBufferSize = (UINTN) FileInfo->FileSize + sizeof(CHAR16);
+ TempBuffer = AllocateZeroPool (TempBufferSize);
+ if (TempBuffer == NULL) {
+ Handle->Close (Handle);
+ gBS->FreePool (FileInfo);
+ return Status;
+ }
+
+ gBS->FreePool (FileInfo);
+
+ //
+ // Read the file data to the buffer
+ //
+ Status = Handle->Read (
+ Handle,
+ &TempBufferSize,
+ TempBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ Handle->Close (Handle);
+ gBS->FreePool (TempBuffer);
+ return Status;
+ }
+
+ Handle->Close (Handle);
+
+ *BufferSize = TempBufferSize;
+ *Buffer = TempBuffer;
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Read a file.
+ If ScanFs is FLASE, it will use DebuggerPrivate->Vol as default Fs.
+ If ScanFs is TRUE, it will scan all FS and check the file.
+ If there is only one file match the name, it will be read.
+ If there is more than one file match the name, it will return Error.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param FileName - The file to be read.
+ @param BufferSize - The file buffer size
+ @param Buffer - The file buffer
+ @param ScanFs - Need Scan all FS
+
+ @retval EFI_SUCCESS - read file successfully
+ @retval EFI_NOT_FOUND - file not found
+ @retval EFI_NO_MAPPING - there is duplicated files found
+
+**/
+EFI_STATUS
+EFIAPI
+ReadFileToBuffer (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *FileName,
+ OUT UINTN *BufferSize,
+ OUT VOID **Buffer,
+ IN BOOLEAN ScanFs
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol;
+ UINTN TempBufferSize;
+ VOID *TempBuffer;
+ UINTN NoHandles;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+
+ //
+ // Check parameters
+ //
+ if ((FileName == NULL) || (Buffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // not scan fs
+ //
+ if (!ScanFs) {
+ if (DebuggerPrivate->Vol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Read file directly from Vol
+ //
+ return ReadFileFromVol (DebuggerPrivate->Vol, FileName, BufferSize, Buffer);
+ }
+
+ //
+ // need scan fs
+ //
+
+ //
+ // Get all Vol handle
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &NoHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status) && (NoHandles == 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Walk through each Vol
+ //
+ DebuggerPrivate->Vol = NULL;
+ *BufferSize = 0;
+ *Buffer = NULL;
+ for (Index = 0; Index < NoHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID**) &Vol
+ );
+ if (EFI_ERROR(Status)) {
+ continue;
+ }
+
+ Status = ReadFileFromVol (Vol, FileName, &TempBufferSize, &TempBuffer);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Read file OK, check duplication
+ //
+ if (DebuggerPrivate->Vol != NULL) {
+ //
+ // Find the duplicated file
+ //
+ gBS->FreePool (TempBuffer);
+ gBS->FreePool (*Buffer);
+ EDBPrint (L"Duplicated FileName found!\n");
+ return EFI_NO_MAPPING;
+ } else {
+ //
+ // Record value
+ //
+ DebuggerPrivate->Vol = Vol;
+ *BufferSize = TempBufferSize;
+ *Buffer = TempBuffer;
+ }
+ }
+ }
+
+ //
+ // Scan Fs done
+ //
+ if (DebuggerPrivate->Vol == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get file name under this dir with index
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param DirName - The dir to be read.
+ @param FileName - The file name pattern under this dir
+ @param Index - The file index under this dir
+
+ @return File Name which match the pattern and index.
+
+**/
+CHAR16 *
+EFIAPI
+GetFileNameUnderDir (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *DirName,
+ IN CHAR16 *FileName,
+ IN OUT UINTN *Index
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE_HANDLE RootDir;
+ EFI_FILE_HANDLE Handle;
+ UINTN FileInfoSize;
+ EFI_FILE_INFO *FileInfo;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol;
+ VOID *TempName;
+ UINTN FileIndex;
+
+ if (DebuggerPrivate->Vol == NULL) {
+ Status = gBS->LocateProtocol (
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ (VOID**) &DebuggerPrivate->Vol
+ );
+ if (EFI_ERROR(Status)) {
+ return NULL;
+ }
+ }
+ Vol = DebuggerPrivate->Vol;
+
+ //
+ // Open the root directory
+ //
+ Status = Vol->OpenVolume (Vol, &RootDir);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ //
+ // Open the file
+ //
+ Status = RootDir->Open (
+ RootDir,
+ &Handle,
+ DirName,
+ EFI_FILE_MODE_READ,
+ EFI_FILE_DIRECTORY
+ );
+ if (EFI_ERROR (Status)) {
+ RootDir->Close (RootDir);
+ return NULL;
+ }
+ RootDir->Close (RootDir);
+
+ //
+ // Set Dir Position
+ //
+ Status = Handle->SetPosition (Handle, 0);
+ if (EFI_ERROR (Status)) {
+ Handle->Close (Handle);
+ return NULL;
+ }
+
+ //
+ // Get the file information
+ //
+ FileInfoSize = sizeof(EFI_FILE_INFO) + 1024;
+
+ FileInfo = AllocateZeroPool (FileInfoSize);
+ if (FileInfo == NULL) {
+ Handle->Close (Handle);
+ return NULL;
+ }
+
+ //
+ // Walk through each file in the directory
+ //
+ FileIndex = 0;
+ TempName = NULL;
+ while (TRUE) {
+ //
+ // Read a file entry
+ //
+ FileInfoSize = sizeof(EFI_FILE_INFO) + 1024;
+
+ Status = Handle->Read (
+ Handle,
+ &FileInfoSize,
+ FileInfo
+ );
+ if (EFI_ERROR (Status) || (FileInfoSize == 0)) {
+ break;
+ }
+
+ if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {
+ //
+ // This is a file
+ //
+
+ //
+ // Only deal with the EFI key file
+ //
+ if (!StrEndWith (FileInfo->FileName, FileName)) {
+ continue;
+ }
+
+ if (FileIndex == *Index) {
+ TempName = StrDuplicate (FileInfo->FileName);
+ *Index = *Index + 1;
+ break;
+ }
+ FileIndex ++;
+ }
+ }
+
+ //
+ // Free resources
+ //
+ gBS->FreePool (FileInfo);
+ Handle->Close (Handle);
+
+ return TempName;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportString.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportString.c
new file mode 100644
index 000000000..9679a2300
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportString.c
@@ -0,0 +1,1020 @@
+/** @file
+
+Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINTN
+EFIAPI
+Xtoi (
+ CHAR16 *Str
+ )
+{
+ UINTN RetVal;
+ CHAR16 TempChar;
+ UINTN MaxVal;
+
+ ASSERT (Str != NULL);
+
+ MaxVal = (UINTN) -1 >> 4;
+ //
+ // skip preceeding white space
+ //
+ while (*Str != '\0' && *Str == ' ') {
+ Str += 1;
+ }
+ //
+ // skip preceeding zeros
+ //
+ while (*Str != '\0' && *Str == '0') {
+ Str += 1;
+ }
+ //
+ // skip preceeding white space
+ //
+ if (*Str != '\0' && (*Str == 'x' || *Str == 'X')) {
+ Str += 1;
+ }
+ //
+ // convert hex digits
+ //
+ RetVal = 0;
+ TempChar = *(Str++);
+ while (TempChar != '\0') {
+ if (TempChar >= 'a' && TempChar <= 'f') {
+ TempChar -= 'a' - 'A';
+ }
+
+ if ((TempChar >= '0' && TempChar <= '9') || (TempChar >= 'A' && TempChar <= 'F')) {
+ if (RetVal > MaxVal) {
+ return (UINTN) -1;
+ }
+
+ RetVal = (RetVal << 4) | (TempChar - (TempChar >= 'A' ? 'A' - 10 : '0'));
+ } else {
+ break;
+ }
+
+ TempChar = *(Str++);
+ }
+
+ return RetVal;
+}
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINT64
+EFIAPI
+LXtoi (
+ CHAR16 *Str
+ )
+{
+ UINT64 RetVal;
+ CHAR16 TempChar;
+ UINT64 MaxVal;
+
+ ASSERT (Str != NULL);
+
+ MaxVal = RShiftU64 ((UINT64) -1, 4);
+ //
+ // skip preceeding white space
+ //
+ while (*Str != '\0' && *Str == ' ') {
+ Str += 1;
+ }
+ //
+ // skip preceeding zeros
+ //
+ while (*Str != '\0' && *Str == '0') {
+ Str += 1;
+ }
+ //
+ // skip preceeding white space
+ //
+ if (*Str != '\0' && (*Str == 'x' || *Str == 'X')) {
+ Str += 1;
+ }
+ //
+ // convert hex digits
+ //
+ RetVal = 0;
+ TempChar = *(Str++);
+ while (TempChar != '\0') {
+ if (TempChar >= 'a' && TempChar <= 'f') {
+ TempChar -= 'a' - 'A';
+ }
+
+ if ((TempChar >= '0' && TempChar <= '9') || (TempChar >= 'A' && TempChar <= 'F')) {
+ if (RetVal > MaxVal) {
+ return (UINT64) -1;
+ }
+
+ RetVal = LShiftU64 (RetVal, 4);
+ RetVal = RetVal + (TempChar - (TempChar >= 'A' ? 'A' - 10 : '0'));
+ } else {
+ break;
+ }
+
+ TempChar = *(Str++);
+ }
+
+ return RetVal;
+}
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINTN
+EFIAPI
+Atoi (
+ CHAR16 *Str
+ )
+{
+ UINTN RetVal;
+ CHAR16 TempChar;
+ UINTN MaxVal;
+ UINTN ResteVal;
+
+ ASSERT (Str != NULL);
+
+ MaxVal = (UINTN) -1 / 10;
+ ResteVal = (UINTN) -1 % 10;
+ //
+ // skip preceeding white space
+ //
+ while (*Str != '\0' && *Str == ' ') {
+ Str += 1;
+ }
+ //
+ // convert digits
+ //
+ RetVal = 0;
+ TempChar = *(Str++);
+ while (TempChar != '\0') {
+ if (TempChar >= '0' && TempChar <= '9') {
+ if (RetVal > MaxVal || (RetVal == MaxVal && TempChar - '0' > (INTN) ResteVal)) {
+ return (UINTN) -1;
+ }
+
+ RetVal = (RetVal * 10) + TempChar - '0';
+ } else {
+ break;
+ }
+
+ TempChar = *(Str++);
+ }
+
+ return RetVal;
+}
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINTN
+EFIAPI
+AsciiXtoi (
+ CHAR8 *Str
+ )
+{
+ UINTN RetVal;
+ CHAR8 TempChar;
+ UINTN MaxVal;
+
+ ASSERT (Str != NULL);
+
+ MaxVal = (UINTN) -1 >> 4;
+ //
+ // skip preceeding white space
+ //
+ while (*Str != '\0' && *Str == ' ') {
+ Str += 1;
+ }
+ //
+ // skip preceeding zeros
+ //
+ while (*Str != '\0' && *Str == '0') {
+ Str += 1;
+ }
+ //
+ // skip preceeding white space
+ //
+ if (*Str != '\0' && (*Str == 'x' || *Str == 'X')) {
+ Str += 1;
+ }
+ //
+ // convert hex digits
+ //
+ RetVal = 0;
+ TempChar = *(Str++);
+ while (TempChar != '\0') {
+ if (TempChar >= 'a' && TempChar <= 'f') {
+ TempChar -= 'a' - 'A';
+ }
+
+ if ((TempChar >= '0' && TempChar <= '9') || (TempChar >= 'A' && TempChar <= 'F')) {
+ if (RetVal > MaxVal) {
+ return (UINTN) -1;
+ }
+
+ RetVal = (RetVal << 4) | (TempChar - (TempChar >= 'A' ? 'A' - 10 : '0'));
+ } else {
+ break;
+ }
+
+ TempChar = *(Str++);
+ }
+
+ return RetVal;
+}
+
+/**
+
+ Convert hex string to uint.
+
+ @param Str - The string
+
+**/
+UINTN
+EFIAPI
+AsciiAtoi (
+ CHAR8 *Str
+ )
+{
+ UINTN RetVal;
+ CHAR8 TempChar;
+ UINTN MaxVal;
+ UINTN ResteVal;
+
+ ASSERT (Str != NULL);
+
+ MaxVal = (UINTN) -1 / 10;
+ ResteVal = (UINTN) -1 % 10;
+ //
+ // skip preceeding white space
+ //
+ while (*Str != '\0' && *Str == ' ') {
+ Str += 1;
+ }
+ //
+ // convert digits
+ //
+ RetVal = 0;
+ TempChar = *(Str++);
+ while (TempChar != '\0') {
+ if (TempChar >= '0' && TempChar <= '9') {
+ if (RetVal > MaxVal || (RetVal == MaxVal && TempChar - '0' > (INTN) ResteVal)) {
+ return (UINTN) -1;
+ }
+
+ RetVal = (RetVal * 10) + TempChar - '0';
+ } else {
+ break;
+ }
+
+ TempChar = *(Str++);
+ }
+
+ return RetVal;
+}
+
+
+/**
+ Compare the Unicode and Ascii string pointed by String to the string pointed by String2.
+
+ @param String - Unicode String to process
+
+ @param String2 - Ascii string to process
+
+ @return Return a positive integer if String is lexicall greater than String2; Zero if
+ the two strings are identical; and a negative interger if String is lexically
+ less than String2.
+
+**/
+INTN
+EFIAPI
+StrCmpUnicodeAndAscii (
+ IN CHAR16 *String,
+ IN CHAR8 *String2
+ )
+{
+ while (*String != '\0') {
+ if (*String != (CHAR16)*String2) {
+ break;
+ }
+
+ String += 1;
+ String2 += 1;
+ }
+
+ return (*String - (CHAR16)*String2);
+}
+
+/**
+
+ Compare the Unicode string pointed by String to the string pointed by String2.
+
+ @param String - Unicode String to process
+ @param String2 - Unicode string to process
+
+ @return Return a positive integer if String is lexically greater than String2; Zero if
+ the two strings are identical; and a negative integer if String is lexically
+ less than String2.
+
+**/
+INTN
+EFIAPI
+StriCmp (
+ IN CHAR16 *String,
+ IN CHAR16 *String2
+ )
+{
+ while ((*String != L'\0') &&
+ (CharToUpper (*String) == CharToUpper (*String2))) {
+ String++;
+ String2++;
+ }
+
+ return CharToUpper (*String) - CharToUpper (*String2);
+}
+
+/**
+
+ Compare the Unicode and Ascii string pointed by String to the string pointed by String2.
+
+ @param String - Unicode String to process
+ @param String2 - Ascii string to process
+
+ @return Return a positive integer if String is lexically greater than String2; Zero if
+ the two strings are identical; and a negative integer if String is lexically
+ less than String2.
+
+**/
+INTN
+EFIAPI
+StriCmpUnicodeAndAscii (
+ IN CHAR16 *String,
+ IN CHAR8 *String2
+ )
+{
+ while ((*String != L'\0') &&
+ (CharToUpper (*String) == (CHAR16)AsciiCharToUpper (*String2))) {
+ String++;
+ String2++;
+ }
+
+ return CharToUpper (*String) - (CHAR16)AsciiCharToUpper (*String2);
+}
+
+/**
+
+ Verify if the string is end with the sub string.
+
+ @param Str - The string where to search the sub string
+ @param SubStr - The substring.
+
+**/
+BOOLEAN
+EFIAPI
+StrEndWith (
+ IN CHAR16 *Str,
+ IN CHAR16 *SubStr
+ )
+{
+ CHAR16 *Temp;
+
+ if ((Str == NULL) || (SubStr == NULL) || (StrLen(Str) < StrLen(SubStr))) {
+ return FALSE;
+ }
+
+ Temp = Str + StrLen(Str) - StrLen(SubStr);
+
+ //
+ // Compare
+ //
+ if (StriCmp (Temp, SubStr) == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Duplicate a string.
+
+ @param Src The string to be duplicated.
+
+**/
+CHAR16 *
+EFIAPI
+StrDuplicate (
+ IN CHAR16 *Src
+ )
+{
+ CHAR16 *Dest;
+ UINTN Size;
+
+ Size = (StrLen(Src) + 1) * sizeof(CHAR16);
+ Dest = AllocateZeroPool (Size);
+ if (Dest != NULL) {
+ CopyMem (Dest, Src, Size);
+ }
+ return Dest;
+}
+
+
+CHAR16 *mLineBuffer = NULL;
+CHAR16 *mFieldBuffer = NULL;
+
+/**
+
+ Find the first substring.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+UINTN
+EFIAPI
+StrSpn (
+ IN CHAR16 *String,
+ IN CHAR16 *CharSet
+ )
+{
+ UINTN Count;
+ CHAR16 *Str1;
+ CHAR16 *Str2;
+
+ Count = 0;
+
+ for (Str1 = String; *Str1 != L'\0'; Str1 ++) {
+ for (Str2 = CharSet; *Str2 != L'\0'; Str2 ++) {
+ if (*Str1 == *Str2) {
+ break;
+ }
+ }
+
+ if (*Str2 == L'\0') {
+ return Count;
+ }
+
+ Count ++;
+ }
+
+ return Count;
+}
+
+/**
+
+ Searches a string for the first occurrence of a character contained in a
+ specified buffer.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrBrk (
+ IN CHAR16 *String,
+ IN CHAR16 *CharSet
+ )
+{
+ CHAR16 *Str1;
+ CHAR16 *Str2;
+
+ for (Str1 = String; *Str1 != L'\0'; Str1 ++) {
+ for (Str2 = CharSet; *Str2 != L'\0'; Str2 ++) {
+ if (*Str1 == *Str2) {
+ return (CHAR16 *) Str1;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrTokenLine (
+ IN CHAR16 *String OPTIONAL,
+ IN CHAR16 *CharSet
+ )
+{
+ CHAR16 *Begin;
+ CHAR16 *End;
+
+ Begin = (String == NULL) ? mLineBuffer : String;
+ if (Begin == NULL) {
+ return NULL;
+ }
+
+ Begin += StrSpn (Begin, CharSet);
+ if (*Begin == L'\0') {
+ mLineBuffer = NULL;
+ return NULL;
+ }
+
+ End = StrBrk (Begin, CharSet);
+ if ((End != NULL) && (*End != L'\0')) {
+ *End = L'\0';
+ End ++;
+ }
+
+ mLineBuffer = End;
+ return Begin;
+}
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrTokenField (
+ IN CHAR16 *String OPTIONAL,
+ IN CHAR16 *CharSet
+ )
+{
+ CHAR16 *Begin;
+ CHAR16 *End;
+
+
+ Begin = (String == NULL) ? mFieldBuffer : String;
+ if (Begin == NULL) {
+ return NULL;
+ }
+
+ if (*Begin == L'\0') {
+ mFieldBuffer = NULL;
+ return NULL;
+ }
+
+ End = StrBrk (Begin, CharSet);
+ if ((End != NULL) && (*End != L'\0')) {
+ *End = L'\0';
+ End ++;
+ }
+
+ mFieldBuffer = End;
+ return Begin;
+}
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrGetNewTokenLine (
+ IN CHAR16 *String,
+ IN CHAR16 *CharSet
+ )
+{
+ return StrTokenLine (String, CharSet);
+}
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrGetNextTokenLine (
+ IN CHAR16 *CharSet
+ )
+{
+ return StrTokenLine (NULL, CharSet);
+}
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrGetNewTokenField (
+ IN CHAR16 *String,
+ IN CHAR16 *CharSet
+ )
+{
+ return StrTokenField (String, CharSet);
+}
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR16 *
+EFIAPI
+StrGetNextTokenField (
+ IN CHAR16 *CharSet
+ )
+{
+ return StrTokenField (NULL, CharSet);
+}
+
+/**
+
+ Patch a character to the end of a string.
+
+ @param Buffer The string to be patched.
+ @param Patch The patch character.
+
+**/
+VOID
+EFIAPI
+PatchForStrTokenAfter (
+ IN CHAR16 *Buffer,
+ IN CHAR16 Patch
+ )
+{
+ CHAR16 *Str;
+
+ if (Buffer == NULL) {
+ return ;
+ }
+
+ Str = Buffer;
+ while (*Str != 0) {
+ Str ++;
+ }
+ *Str = Patch;
+
+ while (*(Str ++) != '\0') {
+ if (*Str == 0) {
+ *Str = Patch;
+ } else {
+ break;
+ }
+ }
+
+ return ;
+}
+
+/**
+ Patch a character at the beginning of a string.
+
+ @param Buffer The string to be patched.
+ @param Patch The patch character.
+
+**/
+VOID
+EFIAPI
+PatchForStrTokenBefore (
+ IN CHAR16 *Buffer,
+ IN CHAR16 Patch
+ )
+{
+ CHAR16 *Str;
+
+ if (Buffer == NULL) {
+ return ;
+ }
+
+ Str = Buffer;
+ while (*(Str --) != '\0') {
+ if ((*Str == 0) || (*Str == Patch)) {
+ *Str = Patch;
+ } else {
+ break;
+ }
+ }
+
+ return ;
+}
+
+CHAR8 *mAsciiLineBuffer = NULL;
+CHAR8 *mAsciiFieldBuffer = NULL;
+
+/**
+
+ Find the first substring.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+UINTN
+EFIAPI
+AsciiStrSpn (
+ IN CHAR8 *String,
+ IN CHAR8 *CharSet
+ )
+{
+ UINTN Count;
+ CHAR8 *Str1;
+ CHAR8 *Str2;
+
+ Count = 0;
+
+ for (Str1 = String; *Str1 != '\0'; Str1 ++) {
+ for (Str2 = CharSet; *Str2 != '\0'; Str2 ++) {
+ if (*Str1 == *Str2) {
+ break;
+ }
+ }
+
+ if (*Str2 == '\0') {
+ return Count;
+ }
+
+ Count ++;
+ }
+
+ return Count;
+}
+
+/**
+ Searches a string for the first occurrence of a character contained in a
+ specified buffer.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrBrk (
+ IN CHAR8 *String,
+ IN CHAR8 *CharSet
+ )
+{
+ CHAR8 *Str1;
+ CHAR8 *Str2;
+
+ for (Str1 = String; *Str1 != '\0'; Str1 ++) {
+ for (Str2 = CharSet; *Str2 != '\0'; Str2 ++) {
+ if (*Str1 == *Str2) {
+ return (CHAR8 *) Str1;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrTokenLine (
+ IN CHAR8 *String OPTIONAL,
+ IN CHAR8 *CharSet
+ )
+{
+ CHAR8 *Begin;
+ CHAR8 *End;
+
+ Begin = (String == NULL) ? mAsciiLineBuffer : String;
+ if (Begin == NULL) {
+ return NULL;
+ }
+
+ Begin += AsciiStrSpn (Begin, CharSet);
+ if (*Begin == '\0') {
+ mAsciiLineBuffer = NULL;
+ return NULL;
+ }
+
+ End = AsciiStrBrk (Begin, CharSet);
+ if ((End != NULL) && (*End != '\0')) {
+ *End = '\0';
+ End ++;
+ }
+
+ mAsciiLineBuffer = End;
+ return Begin;
+}
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrTokenField (
+ IN CHAR8 *String OPTIONAL,
+ IN CHAR8 *CharSet
+ )
+{
+ CHAR8 *Begin;
+ CHAR8 *End;
+
+
+ Begin = (String == NULL) ? mAsciiFieldBuffer : String;
+ if (Begin == NULL) {
+ return NULL;
+ }
+
+ if (*Begin == '\0') {
+ mAsciiFieldBuffer = NULL;
+ return NULL;
+ }
+
+ End = AsciiStrBrk (Begin, CharSet);
+ if ((End != NULL) && (*End != '\0')) {
+ *End = '\0';
+ End ++;
+ }
+
+ mAsciiFieldBuffer = End;
+ return Begin;
+}
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrGetNewTokenLine (
+ IN CHAR8 *String,
+ IN CHAR8 *CharSet
+ )
+{
+ return AsciiStrTokenLine (String, CharSet);
+}
+
+/**
+
+ Find the next token after one or more specified characters.
+
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrGetNextTokenLine (
+ IN CHAR8 *CharSet
+ )
+{
+ return AsciiStrTokenLine (NULL, CharSet);
+}
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param String Point to the string where to find the substring.
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrGetNewTokenField (
+ IN CHAR8 *String,
+ IN CHAR8 *CharSet
+ )
+{
+ return AsciiStrTokenField (String, CharSet);
+}
+
+/**
+
+ Find the next token after one specificed characters.
+
+ @param CharSet Point to the string to be found.
+
+**/
+CHAR8 *
+EFIAPI
+AsciiStrGetNextTokenField (
+ IN CHAR8 *CharSet
+ )
+{
+ return AsciiStrTokenField (NULL, CharSet);
+}
+
+/**
+
+ Patch a character to the end of a string.
+
+ @param Buffer The string to be patched.
+ @param Patch The patch character.
+
+**/
+VOID
+EFIAPI
+PatchForAsciiStrTokenAfter (
+ IN CHAR8 *Buffer,
+ IN CHAR8 Patch
+ )
+{
+ CHAR8 *Str;
+
+ if (Buffer == NULL) {
+ return ;
+ }
+
+ Str = Buffer;
+ while (*Str != 0) {
+ Str ++;
+ }
+ *Str = Patch;
+
+ while (*(Str ++) != '\0') {
+ if (*Str == 0) {
+ *Str = Patch;
+ } else {
+ break;
+ }
+ }
+
+ return ;
+}
+
+/**
+ Patch a character at the beginning of a string.
+
+ @param Buffer The string to be patched.
+ @param Patch The patch character.
+
+**/
+VOID
+EFIAPI
+PatchForAsciiStrTokenBefore (
+ IN CHAR8 *Buffer,
+ IN CHAR8 Patch
+ )
+{
+ CHAR8 *Str;
+
+ if (Buffer == NULL) {
+ return ;
+ }
+
+ Str = Buffer;
+ while (*(Str --) != '\0') {
+ if ((*Str == 0) || (*Str == Patch)) {
+ *Str = Patch;
+ } else {
+ break;
+ }
+ }
+
+ return ;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportUI.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportUI.c
new file mode 100644
index 000000000..dd881a021
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSupportUI.c
@@ -0,0 +1,754 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+ Set the current coordinates of the cursor position.
+
+ @param ConOut Point to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.
+ @param Column The position to set the cursor to.
+ @param Row The position to set the cursor to.
+ @param LineLength Length of a line.
+ @param TotalRow Total row of a screen.
+ @param Str Point to the string.
+ @param StrPos The position of the string.
+ @param Len The length of the string.
+
+**/
+VOID
+EFIAPI
+SetCursorPosition (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,
+ IN UINTN Column,
+ IN INTN Row,
+ IN UINTN LineLength,
+ IN UINTN TotalRow,
+ IN CHAR16 *Str,
+ IN UINTN StrPos,
+ IN UINTN Len
+ );
+
+/**
+
+ Function waits for a given event to fire, or for an optional timeout to expire.
+
+ @param Event - The event to wait for
+ @param Timeout - An optional timeout value in 100 ns units.
+
+ @retval EFI_SUCCESS - Event fired before Timeout expired.
+ @retval EFI_TIME_OUT - Timout expired before Event fired..
+
+**/
+EFI_STATUS
+EFIAPI
+WaitForSingleEvent (
+ IN EFI_EVENT Event,
+ IN UINT64 Timeout OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_EVENT TimerEvent;
+ EFI_EVENT WaitList[2];
+
+ if (Timeout != 0) {
+ //
+ // Create a timer event
+ //
+ Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Set the timer event
+ //
+ gBS->SetTimer (
+ TimerEvent,
+ TimerRelative,
+ Timeout
+ );
+
+ //
+ // Wait for the original event or the timer
+ //
+ WaitList[0] = Event;
+ WaitList[1] = TimerEvent;
+ Status = gBS->WaitForEvent (2, WaitList, &Index);
+ gBS->CloseEvent (TimerEvent);
+
+ //
+ // If the timer expired, change the return to timed out
+ //
+ if (!EFI_ERROR (Status) && Index == 1) {
+ Status = EFI_TIMEOUT;
+ }
+ }
+ } else {
+ //
+ // No timeout... just wait on the event
+ //
+ Status = gBS->WaitForEvent (1, &Event, &Index);
+ ASSERT (!EFI_ERROR (Status));
+ ASSERT (Index == 0);
+ }
+
+ return Status;
+}
+
+/**
+
+ Move the cursor position one character backward.
+
+ @param LineLength Length of a line. Get it by calling QueryMode
+ @param Column Current column of the cursor position
+ @param Row Current row of the cursor position
+
+**/
+VOID
+EFIAPI
+ConMoveCursorBackward (
+ IN UINTN LineLength,
+ IN OUT UINTN *Column,
+ IN OUT UINTN *Row
+ )
+{
+ ASSERT (Column != NULL);
+ ASSERT (Row != NULL);
+ //
+ // If current column is 0, move to the last column of the previous line,
+ // otherwise, just decrement column.
+ //
+ if (*Column == 0) {
+ (*Column) = LineLength - 1;
+ //
+ // if (*Row > 0) {
+ //
+ (*Row)--;
+ //
+ // }
+ //
+ } else {
+ (*Column)--;
+ }
+}
+
+/**
+
+ Move the cursor position one character backward.
+
+ @param LineLength Length of a line. Get it by calling QueryMode
+ @param TotalRow Total row of a screen, get by calling QueryMode
+ @param Column Current column of the cursor position
+ @param Row Current row of the cursor position
+
+**/
+VOID
+EFIAPI
+ConMoveCursorForward (
+ IN UINTN LineLength,
+ IN UINTN TotalRow,
+ IN OUT UINTN *Column,
+ IN OUT UINTN *Row
+ )
+{
+ ASSERT (Column != NULL);
+ ASSERT (Row != NULL);
+ //
+ // If current column is at line end, move to the first column of the nest
+ // line, otherwise, just increment column.
+ //
+ (*Column)++;
+ if (*Column >= LineLength) {
+ (*Column) = 0;
+ if ((*Row) < TotalRow - 1) {
+ (*Row)++;
+ }
+ }
+}
+
+CHAR16 mBackupSpace[EFI_DEBUG_INPUS_BUFFER_SIZE];
+CHAR16 mInputBufferHistory[EFI_DEBUG_INPUS_BUFFER_SIZE];
+
+/**
+
+ Get user input.
+
+ @param Prompt The prompt string.
+ @param InStr Point to the input string.
+ @param StrLength The max length of string user can input.
+
+**/
+VOID
+EFIAPI
+Input (
+ IN CHAR16 *Prompt OPTIONAL,
+ OUT CHAR16 *InStr,
+ IN UINTN StrLength
+ )
+{
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
+ BOOLEAN Done;
+ UINTN Column;
+ UINTN Row;
+ UINTN StartColumn;
+ UINTN Update;
+ UINTN Delete;
+ UINTN Len;
+ UINTN StrPos;
+ UINTN Index;
+ UINTN LineLength;
+ UINTN TotalRow;
+ UINTN SkipLength;
+ UINTN OutputLength;
+ UINTN TailRow;
+ UINTN TailColumn;
+ EFI_INPUT_KEY Key;
+ BOOLEAN InsertMode;
+ BOOLEAN NeedAdjust;
+ UINTN SubIndex;
+ CHAR16 *CommandStr;
+
+ ConOut = gST->ConOut;
+ ConIn = gST->ConIn;
+
+ ASSERT (ConOut != NULL);
+ ASSERT (ConIn != NULL);
+ ASSERT (InStr != NULL);
+
+ if (Prompt != NULL) {
+ ConOut->OutputString (ConOut, Prompt);
+ }
+ //
+ // Read a line from the console
+ //
+ Len = 0;
+ StrPos = 0;
+ OutputLength = 0;
+ Update = 0;
+ Delete = 0;
+ InsertMode = TRUE;
+ NeedAdjust = FALSE;
+
+ //
+ // If buffer is not large enough to hold a CHAR16, do nothing.
+ //
+ if (StrLength < 1) {
+ return ;
+ }
+ //
+ // Get the screen setting and the current cursor location
+ //
+ StartColumn = ConOut->Mode->CursorColumn;
+ Column = StartColumn;
+ Row = ConOut->Mode->CursorRow;
+ ConOut->QueryMode (ConOut, ConOut->Mode->Mode, &LineLength, &TotalRow);
+ if (LineLength == 0) {
+ return ;
+ }
+
+ SetMem (InStr, StrLength * sizeof (CHAR16), 0);
+ Done = FALSE;
+ do {
+ //
+ // Read a key
+ //
+ WaitForSingleEvent (ConIn->WaitForKey, 0);
+ ConIn->ReadKeyStroke (ConIn, &Key);
+
+ switch (Key.UnicodeChar) {
+ case CHAR_CARRIAGE_RETURN:
+ //
+ // All done, print a newline at the end of the string
+ //
+ TailRow = Row + (Len - StrPos + Column) / LineLength;
+ TailColumn = (Len - StrPos + Column) % LineLength;
+ Done = TRUE;
+ break;
+
+ case CHAR_BACKSPACE:
+ if (StrPos != 0) {
+ //
+ // If not move back beyond string beginning, move all characters behind
+ // the current position one character forward
+ //
+ StrPos -= 1;
+ Update = StrPos;
+ Delete = 1;
+ CopyMem (InStr + StrPos, InStr + StrPos + 1, sizeof (CHAR16) * (Len - StrPos));
+
+ //
+ // Adjust the current column and row
+ //
+ ConMoveCursorBackward (LineLength, &Column, &Row);
+
+ NeedAdjust = TRUE;
+ }
+ break;
+
+ default:
+ if (Key.UnicodeChar >= ' ') {
+ //
+ // If we are at the buffer's end, drop the key
+ //
+ if (Len == StrLength - 1 && (InsertMode || StrPos == Len)) {
+ break;
+ }
+ //
+ // If in insert mode, move all characters behind the current position
+ // one character backward to make space for this character. Then store
+ // the character.
+ //
+ if (InsertMode) {
+ for (Index = Len; Index > StrPos; Index -= 1) {
+ InStr[Index] = InStr[Index - 1];
+ }
+ }
+
+ InStr[StrPos] = Key.UnicodeChar;
+ Update = StrPos;
+
+ StrPos += 1;
+ OutputLength = 1;
+ }
+ break;
+
+ case 0:
+ switch (Key.ScanCode) {
+ case SCAN_DELETE:
+ //
+ // Move characters behind current position one character forward
+ //
+ if (Len != 0) {
+ Update = StrPos;
+ Delete = 1;
+ CopyMem (InStr + StrPos, InStr + StrPos + 1, sizeof (CHAR16) * (Len - StrPos));
+
+ NeedAdjust = TRUE;
+ }
+ break;
+
+ case SCAN_LEFT:
+ //
+ // Adjust current cursor position
+ //
+ if (StrPos != 0) {
+ StrPos -= 1;
+ ConMoveCursorBackward (LineLength, &Column, &Row);
+ }
+ break;
+
+ case SCAN_RIGHT:
+ //
+ // Adjust current cursor position
+ //
+ if (StrPos < Len) {
+ StrPos += 1;
+ ConMoveCursorForward (LineLength, TotalRow, &Column, &Row);
+ }
+ break;
+
+ case SCAN_HOME:
+ //
+ // Move current cursor position to the beginning of the command line
+ //
+ Row -= (StrPos + StartColumn) / LineLength;
+ Column = StartColumn;
+ StrPos = 0;
+ break;
+
+ case SCAN_END:
+ //
+ // Move current cursor position to the end of the command line
+ //
+ TailRow = Row + (Len - StrPos + Column) / LineLength;
+ TailColumn = (Len - StrPos + Column) % LineLength;
+ Row = TailRow;
+ Column = TailColumn;
+ StrPos = Len;
+ break;
+
+ case SCAN_ESC:
+ //
+ // Prepare to clear the current command line
+ //
+ InStr[0] = 0;
+ Update = 0;
+ Delete = Len;
+ Row -= (StrPos + StartColumn) / LineLength;
+ Column = StartColumn;
+ OutputLength = 0;
+
+ NeedAdjust = TRUE;
+ break;
+
+ case SCAN_INSERT:
+ //
+ // Toggle the SEnvInsertMode flag
+ //
+ InsertMode = (BOOLEAN)!InsertMode;
+ break;
+
+ case SCAN_UP:
+ case SCAN_DOWN:
+ //
+ // show history
+ //
+ CopyMem (InStr, mInputBufferHistory, StrLength * sizeof(CHAR16));
+ StrPos = StrLen (mInputBufferHistory);
+ Update = 0;
+ Delete = 0;
+ OutputLength = 0;
+
+ TailRow = Row + (StrPos + StartColumn) / LineLength;
+ TailColumn = (StrPos + StartColumn) % LineLength;
+ Row = TailRow;
+ Column = TailColumn;
+ NeedAdjust = FALSE;
+
+ ConOut->SetCursorPosition (ConOut, StartColumn, Row);
+ for (SubIndex = 0; SubIndex < EFI_DEBUG_INPUS_BUFFER_SIZE - (StartColumn - EFI_DEBUG_PROMPT_COLUMN); SubIndex++) {
+ mBackupSpace[SubIndex] = L' ';
+ }
+ EDBPrint (mBackupSpace);
+ SetMem (mBackupSpace, (EFI_DEBUG_INPUS_BUFFER_SIZE - (StartColumn - EFI_DEBUG_PROMPT_COLUMN)) * sizeof(CHAR16), 0);
+
+ ConOut->SetCursorPosition (ConOut, StartColumn, Row);
+ Len = StrPos;
+
+ break;
+
+ case SCAN_F1:
+ case SCAN_F2:
+ case SCAN_F3:
+ case SCAN_F4:
+ case SCAN_F5:
+ case SCAN_F6:
+ case SCAN_F7:
+ case SCAN_F8:
+ case SCAN_F9:
+ case SCAN_F10:
+ case SCAN_F11:
+ case SCAN_F12:
+ CommandStr = GetCommandNameByKey (Key);
+ if (CommandStr != NULL) {
+ StrnCpyS (InStr, StrLength, CommandStr, StrLength - 1);
+ return ;
+ }
+ break;
+ }
+ }
+
+ if (Done) {
+ break;
+ }
+ //
+ // If we need to update the output do so now
+ //
+ if (Update != -1) {
+ if (NeedAdjust) {
+ ConOut->SetCursorPosition (ConOut, Column, Row);
+ for (SubIndex = 0; SubIndex < EFI_DEBUG_INPUS_BUFFER_SIZE - (Column - EFI_DEBUG_PROMPT_COLUMN); SubIndex++) {
+ mBackupSpace[SubIndex] = L' ';
+ }
+ EDBPrint (mBackupSpace);
+ SetMem (mBackupSpace, (EFI_DEBUG_INPUS_BUFFER_SIZE - (Column - EFI_DEBUG_PROMPT_COLUMN)) * sizeof(CHAR16), 0);
+ ConOut->SetCursorPosition (ConOut, Column, Row);
+ NeedAdjust = FALSE;
+ }
+ EDBPrint (InStr + Update);
+ Len = StrLen (InStr);
+
+ if (Delete != 0) {
+ SetMem (InStr + Len, Delete * sizeof (CHAR16), 0x00);
+ }
+
+ if (StrPos > Len) {
+ StrPos = Len;
+ }
+
+ Update = (UINTN) -1;
+
+ //
+ // After using print to reflect newly updates, if we're not using
+ // BACKSPACE and DELETE, we need to move the cursor position forward,
+ // so adjust row and column here.
+ //
+ if (Key.UnicodeChar != CHAR_BACKSPACE && !(Key.UnicodeChar == 0 && Key.ScanCode == SCAN_DELETE)) {
+ //
+ // Calulate row and column of the tail of current string
+ //
+ TailRow = Row + (Len - StrPos + Column + OutputLength) / LineLength;
+ TailColumn = (Len - StrPos + Column + OutputLength) % LineLength;
+
+ //
+ // If the tail of string reaches screen end, screen rolls up, so if
+ // Row does not equal TailRow, Row should be decremented
+ //
+ // (if we are recalling commands using UPPER and DOWN key, and if the
+ // old command is too long to fit the screen, TailColumn must be 79.
+ //
+ if (TailColumn == 0 && TailRow >= TotalRow && (UINTN) Row != TailRow) {
+ Row--;
+ }
+ //
+ // Calculate the cursor position after current operation. If cursor
+ // reaches line end, update both row and column, otherwise, only
+ // column will be changed.
+ //
+ if (Column + OutputLength >= LineLength) {
+ SkipLength = OutputLength - (LineLength - Column);
+
+ Row += SkipLength / LineLength + 1;
+ if ((UINTN) Row > TotalRow - 1) {
+ Row = TotalRow - 1;
+ }
+
+ Column = SkipLength % LineLength;
+ } else {
+ Column += OutputLength;
+ }
+ }
+
+ Delete = 0;
+ }
+ //
+ // Set the cursor position for this key
+ //
+ SetCursorPosition (ConOut, Column, Row, LineLength, TotalRow, InStr, StrPos, Len);
+ } while (!Done);
+
+ CopyMem (mInputBufferHistory, InStr, StrLength * sizeof(CHAR16));
+
+ //
+ // Return the data to the caller
+ //
+ return ;
+}
+
+/**
+ Set the current coordinates of the cursor position.
+
+ @param ConOut Point to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.
+ @param Column The position to set the cursor to.
+ @param Row The position to set the cursor to.
+ @param LineLength Length of a line.
+ @param TotalRow Total row of a screen.
+ @param Str Point to the string.
+ @param StrPos The position of the string.
+ @param Len The length of the string.
+
+**/
+VOID
+EFIAPI
+SetCursorPosition (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,
+ IN UINTN Column,
+ IN INTN Row,
+ IN UINTN LineLength,
+ IN UINTN TotalRow,
+ IN CHAR16 *Str,
+ IN UINTN StrPos,
+ IN UINTN Len
+ )
+{
+ CHAR16 Backup;
+
+ ASSERT (ConOut != NULL);
+ ASSERT (Str != NULL);
+
+ Backup = 0;
+ if (Row >= 0) {
+ ConOut->SetCursorPosition (ConOut, Column, Row);
+ return ;
+ }
+
+ if (Len - StrPos > Column * Row) {
+ Backup = *(Str + StrPos + Column * Row);
+ *(Str + StrPos + Column * Row) = 0;
+ }
+
+ EDBPrint (L"%s", Str + StrPos);
+ if (Len - StrPos > Column * Row) {
+ *(Str + StrPos + Column * Row) = Backup;
+ }
+
+ ConOut->SetCursorPosition (ConOut, 0, 0);
+}
+
+/**
+
+ SetPageBreak.
+
+**/
+BOOLEAN
+EFIAPI
+SetPageBreak (
+ VOID
+ )
+{
+ EFI_INPUT_KEY Key;
+ CHAR16 Str[3];
+ BOOLEAN OmitPrint;
+
+ //
+ // Check
+ //
+ if (!mDebuggerPrivate.EnablePageBreak) {
+ return FALSE;
+ }
+
+ gST->ConOut->OutputString (gST->ConOut, L"Press ENTER to continue, 'q' to exit:");
+
+ OmitPrint = FALSE;
+ //
+ // Wait for user input
+ //
+ Str[0] = ' ';
+ Str[1] = 0;
+ Str[2] = 0;
+ for (;;) {
+ WaitForSingleEvent (gST->ConIn->WaitForKey, 0);
+ gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+
+ //
+ // handle control keys
+ //
+ if (Key.UnicodeChar == CHAR_NULL) {
+ if (Key.ScanCode == SCAN_ESC) {
+ gST->ConOut->OutputString (gST->ConOut, L"\r\n");
+ OmitPrint = TRUE;
+ break;
+ }
+
+ continue;
+ }
+
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
+ gST->ConOut->OutputString (gST->ConOut, L"\r\n");
+ break;
+ }
+ //
+ // Echo input
+ //
+ Str[1] = Key.UnicodeChar;
+ if (Str[1] == CHAR_BACKSPACE) {
+ continue;
+ }
+
+ gST->ConOut->OutputString (gST->ConOut, Str);
+
+ if ((Str[1] == L'q') || (Str[1] == L'Q')) {
+ OmitPrint = TRUE;
+ } else {
+ OmitPrint = FALSE;
+ }
+
+ Str[0] = CHAR_BACKSPACE;
+ }
+
+ return OmitPrint;
+}
+
+/**
+ Print a Unicode string to the output device.
+
+ @param Format A Null-terminated Unicode format string.
+ @param ... The variable argument list that contains pointers to Null-
+ terminated Unicode strings to be printed
+
+**/
+UINTN
+EFIAPI
+EDBPrint (
+ IN CONST CHAR16 *Format,
+ ...
+ )
+{
+ UINTN Return;
+ VA_LIST Marker;
+ CHAR16 Buffer[EFI_DEBUG_MAX_PRINT_BUFFER];
+
+ VA_START (Marker, Format);
+ Return = UnicodeVSPrint (Buffer, sizeof (Buffer), Format, Marker);
+ VA_END (Marker);
+
+ if (gST->ConOut != NULL) {
+ //
+ // To be extra safe make sure ConOut has been initialized
+ //
+ gST->ConOut->OutputString (gST->ConOut, Buffer);
+ }
+
+ return Return;
+}
+
+/**
+ Print a Unicode string to the output buffer.
+
+ @param Buffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param Format A Null-terminated Unicode format string.
+ @param ... The variable argument list that contains pointers to Null-
+ terminated Unicode strings to be printed
+
+**/
+UINTN
+EFIAPI
+EDBSPrint (
+ OUT CHAR16 *Buffer,
+ IN INTN BufferSize,
+ IN CONST CHAR16 *Format,
+ ...
+ )
+{
+ UINTN Return;
+ VA_LIST Marker;
+
+ ASSERT (BufferSize > 0);
+
+ VA_START (Marker, Format);
+ Return = UnicodeVSPrint (Buffer, (UINTN)BufferSize, Format, Marker);
+ VA_END (Marker);
+
+ return Return;
+}
+
+/**
+ Print a Unicode string to the output buffer with specified offset..
+
+ @param Buffer A pointer to the output buffer for the produced Null-terminated
+ Unicode string.
+ @param BufferSize The size, in bytes, of the output buffer specified by StartOfBuffer.
+ @param Offset The offset of the buffer.
+ @param Format A Null-terminated Unicode format string.
+ @param ... The variable argument list that contains pointers to Null-
+ terminated Unicode strings to be printed
+
+**/
+UINTN
+EFIAPI
+EDBSPrintWithOffset (
+ OUT CHAR16 *Buffer,
+ IN INTN BufferSize,
+ IN UINTN Offset,
+ IN CONST CHAR16 *Format,
+ ...
+ )
+{
+ UINTN Return;
+ VA_LIST Marker;
+
+ ASSERT (BufferSize - (Offset * sizeof(CHAR16)) > 0);
+
+ VA_START (Marker, Format);
+ Return = UnicodeVSPrint (Buffer + Offset, (UINTN)(BufferSize - (Offset * sizeof(CHAR16))), Format, Marker);
+ VA_END (Marker);
+
+ return Return;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c
new file mode 100644
index 000000000..90a9b9fbd
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.c
@@ -0,0 +1,2230 @@
+/** @file
+
+Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#include "Edb.h"
+
+/**
+
+ Load single symbol entry.
+
+ @param Object - Symbol file object
+ @param Name - Symbol name
+ @param ObjName - Object name
+ @param Address - Symbol address
+ @param Type - Symbol type
+
+ @retval EFI_SUCCESS - add single symbol entry successfully
+
+**/
+EFI_STATUS
+EdbLoadSymbolSingleEntry (
+ IN EFI_DEBUGGER_SYMBOL_OBJECT *Object,
+ IN CHAR8 *Name,
+ IN CHAR8 *ObjName,
+ IN UINTN Address,
+ IN EFI_DEBUGGER_SYMBOL_TYPE Type
+ )
+{
+ EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
+
+ //
+ // Check Count VS MaxCount
+ //
+ if (Object->EntryCount >= Object->MaxEntryCount) {
+ //
+ // reallocate (for codebuffer too)
+ // TBD
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Entry = &Object->Entry[Object->EntryCount];
+
+ //
+ // Print Debug info
+ //
+ if (sizeof (UINTN) == sizeof(UINT64)) {
+ DEBUG ((DEBUG_ERROR, " Symbol: %a, Address: 0x%016lx (%d)\n", Name, (UINT64)Address, (UINTN)Type));
+ } else {
+ DEBUG ((DEBUG_ERROR, " Symbol: %a, Address: 0x%08x (%d)\n", Name, Address, (UINTN)Type));
+ }
+
+ //
+ // Fill the entry - name, RVA, type
+ //
+ AsciiStrnCpyS (Entry->Name, sizeof(Entry->Name), Name, sizeof(Entry->Name) - 1);
+ if (ObjName != NULL) {
+ AsciiStrnCpyS (Entry->ObjName, sizeof(Entry->ObjName), ObjName, sizeof(Entry->ObjName) - 1);
+ }
+ Entry->Rva = Address % EFI_DEBUGGER_DEFAULT_LINK_IMAGEBASE;
+ Entry->Type = Type;
+
+ //
+ // Increase Count
+ //
+ Object->EntryCount++;
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+typedef enum {
+ EdbEbcMapParseStateUninitialized,
+ EdbEbcMapParseStateSymbolStart,
+ EdbEbcMapParseStateSeHandlerSymbol,
+ EdbEbcMapParseStateFunctionSymbol,
+ EdbEbcMapParseStateVarbssInitSymbol,
+ EdbEbcMapParseStateCrtSymbol,
+ EdbEbcMapParseStateVariableSymbol,
+ EdbEbcMapParseStateStaticFunctionSymbol,
+ EdbEbcMapParseStateMax,
+} EDB_EBC_MAP_PARSE_STATE;
+
+typedef enum {
+ EdbEbcSymbolParseStateUninitialized,
+ EdbEbcSymbolParseStateReadyForName,
+ EdbEbcSymbolParseStateReadyForRVA,
+ EdbEbcSymbolParseStateReadyForType,
+ EdbEbcSymbolParseStateReadyForObject,
+ EdbEbcSymbolParseStateMax,
+} EDB_EBC_SYMBOL_PARSE_STATE;
+
+/**
+
+ The following code depends on the MAP file generated by IEC compiler (actually Microsoft linker).
+
+ Sample as follows: EbcTest.map
+===============================================================================
+ EbcTest
+
+ Timestamp is 45b02718 (Fri Jan 19 10:04:08 2007)
+
+ Preferred load address is 10000000
+
+ Start Length Name Class
+ 0001:00000000 00000370H .text CODE
+ 0002:00000000 00000030H _VARBSS_INIT CODE
+ 0003:00000000 00000004H .CRT$TSA DATA
+ 0003:00000004 00000004H .CRT$TSC DATA
+ 0003:00000008 00000004H .CRT$X DATA
+ 0003:0000000c 00000008H .CRT$XCU DATA
+ 0003:00000014 00000004H .CRT$Z DATA
+ 0003:00000020 0000001cH .rdata DATA
+ 0003:0000003c 00000000H .edata DATA
+ 0003:0000003c 00000056H .rdata$debug DATA
+ 0004:00000000 00000070H .data DATA
+ 0004:00000070 00000020H .bss DATA
+
+ Address Publics by Value Rva+Base Lib:Object
+
+ 0000:00000000 ___safe_se_handler_table 00000000 <absolute>
+ 0000:00000000 ___safe_se_handler_count 00000000 <absolute>
+ 0001:00000042 TestSubRoutine 10000442 f EbcTest.obj
+ 0001:0000011a EfiMain 1000051a f EbcTest.obj
+ 0001:00000200 TestSubRoutineSub 10000600 f EbcTestSub.obj
+ 0001:00000220 EfiStart 10000620 f EbcLib:EbcLib.obj
+ 0002:00000000 varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTest$c45b02717 10000800 f EbcTest.obj
+ 0002:00000020 varbss_init_C:\efi_src\TIANO\Edk\Sample\Universal\Ebc\Dxe\EbcTest\EbcTestSub$c45af77f3 10000820 f EbcTestSub.obj
+ 0003:00000000 CrtThunkBegin 10000a00 EbcLib:EbcLib.obj
+ 0003:00000004 CrtThunkEnd 10000a04 EbcLib:EbcLib.obj
+ 0003:00000008 CrtBegin 10000a08 EbcLib:EbcLib.obj
+ 0003:00000014 CrtEnd 10000a14 EbcLib:EbcLib.obj
+ 0004:00000070 TestStr 10000c70 EbcTest.obj
+ 0004:00000078 TestVariable1 10000c78 EbcTest.obj
+ 0004:00000080 TestSubVariableSub 10000c80 EbcTestSub.obj
+
+ entry point at 0001:00000220
+
+ Static symbols
+
+ 0001:00000000 TestSubRoutine2 10000400 f EbcTest.obj
+===============================================================================
+
+**/
+
+/**
+
+ Load symbol entry by Iec.
+
+ @param Object - Symbol file object
+ @param BufferSize - Symbol file buffer size
+ @param Buffer - Symbol file buffer
+
+ @retval EFI_SUCCESS - add symbol entry successfully
+
+**/
+EFI_STATUS
+EdbLoadSymbolEntryByIec (
+ IN EFI_DEBUGGER_SYMBOL_OBJECT *Object,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ CHAR8 *LineBuffer;
+ CHAR8 *FieldBuffer;
+ EDB_EBC_MAP_PARSE_STATE MapParseState;
+ EDB_EBC_SYMBOL_PARSE_STATE SymbolParseState;
+ CHAR8 *Name;
+ CHAR8 *ObjName;
+ UINTN Address;
+ EFI_DEBUGGER_SYMBOL_TYPE Type;
+
+
+ //
+ // Begin to parse the Buffer
+ //
+ LineBuffer = AsciiStrGetNewTokenLine (Buffer, "\n\r");
+ MapParseState = EdbEbcMapParseStateUninitialized;
+ //
+ // Check each line
+ //
+ while (LineBuffer != NULL) {
+ FieldBuffer = AsciiStrGetNewTokenField (LineBuffer, " ");
+ SymbolParseState = EdbEbcSymbolParseStateUninitialized;
+ //
+ // Init entry value
+ //
+ Name = NULL;
+ ObjName = NULL;
+ Address = 0;
+ Type = EfiDebuggerSymbolTypeMax;
+ //
+ // Check each field
+ //
+ while (FieldBuffer != NULL) {
+ if (AsciiStrCmp (FieldBuffer, "") == 0) {
+ FieldBuffer = AsciiStrGetNextTokenField (" ");
+ continue;
+ }
+ //
+ // check "Address"
+ //
+ if (AsciiStrCmp (FieldBuffer, "Address") == 0) {
+ MapParseState = EdbEbcMapParseStateSymbolStart;
+ break;
+ }
+ //
+ // check "Static"
+ //
+ if (AsciiStrCmp (FieldBuffer, "Static") == 0) {
+ MapParseState = EdbEbcMapParseStateStaticFunctionSymbol;
+ break;
+ }
+
+ if (MapParseState == EdbEbcMapParseStateUninitialized) {
+ //
+ // Do not parse anything until get "Address" or "Static"
+ //
+ break;
+ }
+ if (AsciiStrCmp (FieldBuffer, "entry") == 0) {
+ //
+ // Skip entry point
+ //
+ break;
+ }
+
+ //
+ // Now we start to parse this line for Name, Address, and Object
+ //
+ switch (SymbolParseState) {
+ case EdbEbcSymbolParseStateUninitialized:
+ //
+ // Get the Address
+ //
+ SymbolParseState = EdbEbcSymbolParseStateReadyForName;
+ break;
+ case EdbEbcSymbolParseStateReadyForName:
+ //
+ // Get the Name
+ //
+ if (AsciiStrnCmp (FieldBuffer, "___safe_se_handler", AsciiStrLen ("___safe_se_handler")) == 0) {
+ //
+ // skip SeHandler
+ //
+ MapParseState = EdbEbcMapParseStateSeHandlerSymbol;
+ goto ExitFieldParse;
+ } else if (AsciiStrnCmp (FieldBuffer, "varbss_init", AsciiStrLen ("varbss_init")) == 0) {
+ //
+ // check VarbssInit
+ //
+ MapParseState = EdbEbcMapParseStateVarbssInitSymbol;
+// goto ExitFieldParse;
+ Name = FieldBuffer;
+ SymbolParseState = EdbEbcSymbolParseStateReadyForRVA;
+ } else if (AsciiStrnCmp (FieldBuffer, "Crt", AsciiStrLen ("Crt")) == 0) {
+ //
+ // check Crt
+ //
+ MapParseState = EdbEbcMapParseStateCrtSymbol;
+// goto ExitFieldParse;
+ Name = FieldBuffer;
+ SymbolParseState = EdbEbcSymbolParseStateReadyForRVA;
+ } else {
+ //
+ // Now, it is normal function
+ //
+ switch (MapParseState) {
+ case EdbEbcMapParseStateSeHandlerSymbol:
+ MapParseState = EdbEbcMapParseStateFunctionSymbol;
+ break;
+ case EdbEbcMapParseStateCrtSymbol:
+ MapParseState = EdbEbcMapParseStateVariableSymbol;
+ break;
+ case EdbEbcMapParseStateFunctionSymbol:
+ case EdbEbcMapParseStateVariableSymbol:
+ case EdbEbcMapParseStateStaticFunctionSymbol:
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ Name = FieldBuffer;
+ SymbolParseState = EdbEbcSymbolParseStateReadyForRVA;
+ }
+ break;
+ case EdbEbcSymbolParseStateReadyForRVA:
+ //
+ // Get the RVA
+ //
+ Address = AsciiXtoi (FieldBuffer);
+ SymbolParseState = EdbEbcSymbolParseStateReadyForType;
+ break;
+ case EdbEbcSymbolParseStateReadyForType:
+ //
+ // Get the Type. This is optional, only for "f".
+ //
+ if (AsciiStrCmp (FieldBuffer, "f") == 0) {
+ SymbolParseState = EdbEbcSymbolParseStateReadyForObject;
+ switch (MapParseState) {
+ case EdbEbcMapParseStateFunctionSymbol:
+ case EdbEbcMapParseStateVarbssInitSymbol:
+ Type = EfiDebuggerSymbolFunction;
+ break;
+ case EdbEbcMapParseStateStaticFunctionSymbol:
+ Type = EfiDebuggerSymbolStaticFunction;
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ break;
+ }
+ //
+ // Else it should be Object.
+ // let it bypass here
+ //
+ case EdbEbcSymbolParseStateReadyForObject:
+ switch (Type) {
+ case EfiDebuggerSymbolTypeMax:
+ switch (MapParseState) {
+ case EdbEbcMapParseStateVariableSymbol:
+ case EdbEbcMapParseStateCrtSymbol:
+ Type = EfiDebuggerSymbolGlobalVariable;
+ break;
+ case EdbEbcMapParseStateSeHandlerSymbol:
+ //
+ // do nothing here
+ //
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ break;
+ case EfiDebuggerSymbolFunction:
+ case EfiDebuggerSymbolStaticFunction:
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ //
+ // Get the Object
+ //
+ ObjName = FieldBuffer;
+ SymbolParseState = EdbEbcSymbolParseStateUninitialized;
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ //
+ // Get the next field
+ //
+ FieldBuffer = AsciiStrGetNextTokenField (" ");
+ }
+
+ //
+ // Add the entry if we get everything.
+ //
+ if ((Name != NULL) && (Type != EfiDebuggerSymbolTypeMax)) {
+ EdbLoadSymbolSingleEntry (Object, Name, ObjName, Address, Type);
+ }
+
+ExitFieldParse:
+ //
+ // Get the next line
+ //
+ LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
+ }
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Load symbol entry.
+
+ @param Object - Symbol file object
+ @param BufferSize - Symbol file buffer size
+ @param Buffer - Symbol file buffer
+
+ @retval EFI_SUCCESS - add symbol entry successfully
+
+**/
+EFI_STATUS
+EdbLoadSymbolEntry (
+ IN EFI_DEBUGGER_SYMBOL_OBJECT *Object,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ //
+ // MAP file format depends on the compiler (actually linker).
+ //
+ // It is possible to check the different MAP file format in this routine.
+ // Now only IEC is supported.
+ //
+ return EdbLoadSymbolEntryByIec (Object, BufferSize, Buffer);
+}
+
+/**
+
+ Find symbol file by name.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param FileName - Symbol file name
+ @param Index - Symbol file index
+
+ @return Object
+
+**/
+EFI_DEBUGGER_SYMBOL_OBJECT *
+EdbFindSymbolFile (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *FileName,
+ IN OUT UINTN *Index OPTIONAL
+ )
+{
+ UINTN ObjectIndex;
+
+ //
+ // Check each Object
+ //
+ for (ObjectIndex = 0; ObjectIndex < DebuggerPrivate->DebuggerSymbolContext.ObjectCount; ObjectIndex++) {
+ if (StrCmp (FileName, DebuggerPrivate->DebuggerSymbolContext.Object[ObjectIndex].Name) == 0) {
+ //
+ // Name match, found it
+ //
+ if (Index != NULL) {
+ *Index = ObjectIndex;
+ }
+ return &DebuggerPrivate->DebuggerSymbolContext.Object[ObjectIndex];
+ }
+ }
+
+ //
+ // Not found
+ //
+ return NULL;
+}
+
+/**
+
+ Find symbol by address.
+
+ @param Address - Symbol address
+ @param Type - Search type
+ @param RetObject - Symbol object
+ @param RetEntry - Symbol entry
+
+ @return Nearest symbol address
+
+**/
+UINTN
+EbdFindSymbolAddress (
+ IN UINTN Address,
+ IN EDB_MATCH_SYMBOL_TYPE Type,
+ OUT EFI_DEBUGGER_SYMBOL_OBJECT **RetObject,
+ OUT EFI_DEBUGGER_SYMBOL_ENTRY **RetEntry
+ )
+{
+ UINTN Index;
+ UINTN SubIndex;
+ UINTN CandidateLowerAddress;
+ UINTN CandidateUpperAddress;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
+ EFI_DEBUGGER_SYMBOL_ENTRY *LowEntry;
+ EFI_DEBUGGER_SYMBOL_ENTRY *UpperEntry;
+ EFI_DEBUGGER_SYMBOL_OBJECT *LowObject;
+ EFI_DEBUGGER_SYMBOL_OBJECT *UpperObject;
+
+ if ((Type < 0) || (Type >= EdbMatchSymbolTypeMax)) {
+ return 0;
+ }
+
+ //
+ // Init
+ //
+ CandidateLowerAddress = 0;
+ CandidateUpperAddress = (UINTN)-1;
+ LowEntry = NULL;
+ UpperEntry = NULL;
+ LowObject = NULL;
+ UpperObject = NULL;
+
+ //
+ // Go through each object
+ //
+ Object = mDebuggerPrivate.DebuggerSymbolContext.Object;
+ for (Index = 0; Index < mDebuggerPrivate.DebuggerSymbolContext.ObjectCount; Index++, Object++) {
+ if (Object->EntryCount == 0) {
+ continue;
+ }
+ //
+ // Go through each entry
+ //
+ Entry = Object->Entry;
+ for (SubIndex = 0; SubIndex < Object->EntryCount; SubIndex++, Entry++) {
+ if (Address != Entry->Rva + Object->BaseAddress) {
+ //
+ // Check for nearest address
+ //
+ if (Address > Entry->Rva + Object->BaseAddress) {
+ //
+ // Record it if Current RVA < Address
+ //
+ if (CandidateLowerAddress < Entry->Rva + Object->BaseAddress) {
+ CandidateLowerAddress = Entry->Rva + Object->BaseAddress;
+ LowEntry = Entry;
+ LowObject = Object;
+ }
+ } else {
+ //
+ // Record it if Current RVA > Address
+ //
+ if (CandidateUpperAddress > Entry->Rva + Object->BaseAddress) {
+ CandidateUpperAddress = Entry->Rva + Object->BaseAddress;
+ UpperEntry = Entry;
+ UpperObject = Object;
+ }
+ }
+ continue;
+ }
+ //
+ // address match, return directly
+ //
+ *RetEntry = Entry;
+ *RetObject = Object;
+ return Address;
+ }
+ }
+
+ //
+ // No Match, provide latest symbol
+ //
+
+ if ((Address - CandidateLowerAddress) < EFI_DEBUGGER_MAX_SYMBOL_ADDRESS_DELTA_VALUE) {
+ //
+ // Check for lower address
+ //
+ if (((Type == EdbMatchSymbolTypeNearestAddress) &&
+ ((CandidateUpperAddress - Address) > (Address - CandidateLowerAddress))) ||
+ (Type == EdbMatchSymbolTypeLowerAddress)) {
+ //
+ // return nearest lower address
+ //
+ *RetEntry = LowEntry;
+ *RetObject = LowObject;
+ return CandidateLowerAddress;
+ }
+ }
+
+ if ((CandidateUpperAddress - Address) < EFI_DEBUGGER_MAX_SYMBOL_ADDRESS_DELTA_VALUE) {
+ //
+ // Check for upper address
+ //
+ if (((Type == EdbMatchSymbolTypeNearestAddress) &&
+ ((CandidateUpperAddress - Address) < (Address - CandidateLowerAddress))) ||
+ (Type == EdbMatchSymbolTypeUpperAddress)) {
+ //
+ // return nearest upper address
+ //
+ *RetEntry = UpperEntry;
+ *RetObject = UpperObject;
+ return CandidateUpperAddress;
+ }
+ }
+
+ //
+ // No match and nearest one, return NULL
+ //
+ return 0;
+}
+
+/**
+
+ Unload symbol file by name.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param FileName - Symbol file name
+
+ @retval EFI_SUCCESS - unload symbol successfully
+
+**/
+EFI_STATUS
+EdbUnloadSymbol (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *FileName
+ )
+{
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ UINTN ObjectIndex;
+ UINTN Index;
+ EFI_DEBUGGER_SYMBOL_ENTRY *OldEntry;
+ UINTN OldEntryCount;
+ UINTN MaxEntryCount;
+ VOID **OldSourceBuffer;
+
+ //
+ // Find Symbol
+ //
+ Object = EdbFindSymbolFile (DebuggerPrivate, FileName, &ObjectIndex);
+ if (Object == NULL) {
+ EDBPrint (L"SymbolFile is not loaded!\n");
+ return EFI_DEBUG_CONTINUE;
+ }
+
+ //
+ // Record old data
+ //
+ Object = DebuggerPrivate->DebuggerSymbolContext.Object;
+ OldEntry = Object->Entry;
+ OldSourceBuffer = Object->SourceBuffer;
+ MaxEntryCount = Object->MaxEntryCount;
+ OldEntryCount = Object->EntryCount;
+
+ //
+ // Remove the matched Object
+ //
+ for (Index = ObjectIndex; Index < DebuggerPrivate->DebuggerSymbolContext.ObjectCount - 1; Index++) {
+ CopyMem (&Object[Index], &Object[Index + 1], sizeof(EFI_DEBUGGER_SYMBOL_OBJECT));
+ }
+ ZeroMem (&Object[Index], sizeof(Object[Index]));
+
+ //
+ // Move old data to new place
+ //
+ Object[Index].Entry = OldEntry;
+ Object[Index].SourceBuffer = OldSourceBuffer;
+ Object[Index].MaxEntryCount = MaxEntryCount;
+ DebuggerPrivate->DebuggerSymbolContext.ObjectCount --;
+
+ //
+ // Clean old entry data
+ //
+ for (Index = 0; Index < OldEntryCount; Index++) {
+ ZeroMem (&OldEntry[Index], sizeof(OldEntry[Index]));
+ }
+
+ //
+ // Free OldSourceBuffer
+ //
+ for (Index = 0; OldSourceBuffer[Index] != NULL; Index++) {
+ gBS->FreePool (OldSourceBuffer[Index]);
+ OldSourceBuffer[Index] = NULL;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Load symbol file by name.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param FileName - Symbol file name
+ @param BufferSize - Symbol file buffer size
+ @param Buffer - Symbol file buffer
+
+ @retval EFI_SUCCESS - load symbol successfully
+
+**/
+EFI_STATUS
+EdbLoadSymbol (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *FileName,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ EFI_STATUS Status;
+
+ //
+ // Check duplicated File
+ //
+ Object = EdbFindSymbolFile (DebuggerPrivate, FileName, NULL);
+ if (Object != NULL) {
+ Status = EdbUnloadSymbol (DebuggerPrivate, FileName);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "Unload Duplicated Symbol File Error!\n"));
+ return Status;
+ }
+ }
+
+ //
+ // Check Count VS MaxCount
+ //
+ if (DebuggerPrivate->DebuggerSymbolContext.ObjectCount >= DebuggerPrivate->DebuggerSymbolContext.MaxObjectCount) {
+ //
+ // reallocate
+ // TBD
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Object = &DebuggerPrivate->DebuggerSymbolContext.Object[DebuggerPrivate->DebuggerSymbolContext.ObjectCount];
+
+ //
+ // Init Object
+ //
+ Object->EntryCount = 0;
+ Object->MaxEntryCount = EFI_DEBUGGER_SYMBOL_ENTRY_MAX;
+
+ //
+ // Load SymbolEntry
+ //
+ DEBUG ((DEBUG_ERROR, "Symbol File: %s\n", FileName));
+ Status = EdbLoadSymbolEntry (Object, BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Fill Object value
+ //
+ StrnCpyS (Object->Name, sizeof(Object->Name) / sizeof(CHAR16),
+ FileName, (sizeof(Object->Name) / sizeof(CHAR16)) - 1);
+ Object->BaseAddress = 0;
+
+ //
+ // Increase the object count
+ //
+ DebuggerPrivate->DebuggerSymbolContext.ObjectCount ++;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Located PDB path name in PE image.
+
+ @param ImageBase - base of PE to search
+
+ @return Pointer into image at offset of PDB file name if PDB file name is found,
+ Otherwise a pointer to an empty string.
+
+**/
+CHAR8 *
+GetPdbPath (
+ VOID *ImageBase
+ )
+{
+ CHAR8 *PdbPath;
+ UINT32 DirCount;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
+ EFI_IMAGE_OPTIONAL_HEADER32 *OptionalHdr32;
+ EFI_IMAGE_OPTIONAL_HEADER64 *OptionalHdr64;
+ EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
+ EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
+ VOID *CodeViewEntryPointer;
+
+ //
+ // Init value
+ //
+ CodeViewEntryPointer = NULL;
+ PdbPath = NULL;
+ DosHdr = ImageBase;
+
+ //
+ // Check magic
+ //
+ if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
+ return NULL;
+ }
+ NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) DosHdr + DosHdr->e_lfanew);
+ //
+ // Check Machine, filter for EBC
+ //
+ if (NtHdr->Pe32.FileHeader.Machine != EFI_IMAGE_MACHINE_EBC) {
+ //
+ // If not EBC, return NULL
+ //
+ return NULL;
+ }
+
+ //
+ // Get DirectoryEntry
+ // EBC spec says PE32+, but implementation uses PE32. So check dynamically here.
+ //
+ if (NtHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ OptionalHdr32 = (VOID *) &NtHdr->Pe32.OptionalHeader;
+ DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionalHdr32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
+ } else if (NtHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ OptionalHdr64 = (VOID *) &NtHdr->Pe32Plus.OptionalHeader;
+ DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionalHdr64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
+ } else {
+ return NULL;
+ }
+ if (DirectoryEntry->VirtualAddress == 0) {
+ return NULL;
+ }
+ //
+ // Go through DirectoryEntry
+ //
+ for (DirCount = 0;
+ (DirCount < DirectoryEntry->Size / sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) && CodeViewEntryPointer == NULL;
+ DirCount++
+ ) {
+ DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (DirectoryEntry->VirtualAddress + (UINTN) ImageBase + DirCount * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));
+ if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
+ //
+ // Match DebugEntry, only CODEVIEW_SIGNATURE_NB10 and CODEVIEW_SIGNATURE_RSDS are supported.
+ //
+ CodeViewEntryPointer = (VOID *) ((UINTN) DebugEntry->RVA + (UINTN) ImageBase);
+ switch (*(UINT32 *) CodeViewEntryPointer) {
+ case CODEVIEW_SIGNATURE_NB10:
+ PdbPath = (CHAR8 *) CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
+ break;
+ case CODEVIEW_SIGNATURE_RSDS:
+ PdbPath = (CHAR8 *) CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ //
+ // Done successfully
+ //
+ return PdbPath;
+}
+
+/**
+
+ Check whether PDB file and MAP file have same name.
+
+ @param PdbFileName - PDB file name
+ @param MapFileName - MAP file name
+
+ @retval TRUE - PDB and MAP file name match
+ @retval FALSE - PDB and MAP file name not match
+
+**/
+BOOLEAN
+MatchPdbAndMap (
+ IN CHAR8 *PdbFileName,
+ IN CHAR16 *MapFileName
+ )
+{
+ UINTN PdbNameSize;
+ UINTN MapNameSize;
+ CHAR8 *PurePdbFileName;
+ UINTN Index;
+
+ //
+ // remove dir name
+ //
+ PurePdbFileName = PdbFileName;
+ for (Index = 0; PdbFileName[Index] != 0; Index++) {
+ if (PdbFileName[Index] == '\\') {
+ PurePdbFileName = &PdbFileName[Index + 1];
+ }
+ }
+ PdbFileName = PurePdbFileName;
+
+ //
+ // get size
+ //
+ PdbNameSize = AsciiStrLen (PdbFileName);
+ MapNameSize = StrLen (MapFileName);
+
+ if (PdbNameSize != MapNameSize) {
+ return FALSE;
+ }
+
+ //
+ // check the name
+ //
+ for (Index = 0; Index < MapNameSize - 4; Index++) {
+ if ((PdbFileName[Index] | 0x20) != (MapFileName[Index] | 0x20)) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+//
+// BUGBUG: work-around start
+//
+typedef struct {
+ EFI_DEBUG_IMAGE_INFO *EfiDebugImageInfoTable;
+ volatile UINT32 UpdateStatus;
+ UINT32 TableSize;
+} EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD;
+
+EFI_DEBUG_IMAGE_INFO_TABLE_HEADER mDebugImageInfoTableHeader;
+
+/**
+For compatibility consideration, we handle 2 cases:
+
+1) IA32:
+ Old: New:
+ +------------------------+ +------------------------+
+ | EfiDebugImageInfoTable | | UpdateStatus |
+ +------------------------+ +------------------------+
+ | UpdateStatus | | TableSize |
+ +------------------------+ +------------------------+
+ | TableSize | | EfiDebugImageInfoTable |
+ +------------------------+ +------------------------+
+
+2) X64 and IPF:
+ Old: New:
+ +------------------------+ +------------------------+
+ | EfiDebugImageInfoTable | | UpdateStatus |
+ | | +------------------------+
+ | | | TableSize |
+ +------------------------+ +------------------------+
+ | UpdateStatus | | EfiDebugImageInfoTable |
+ +------------------------+ | |
+ | TableSize | | |
+ +------------------------+ +------------------------+
+
+ @param DebugImageInfoTableHeader Point to the EFI_DEBUG_IMAGE_INFO_TABLE_HEADER structure.
+
+**/
+VOID
+EdbFixDebugImageInfoTable (
+ IN OUT EFI_DEBUG_IMAGE_INFO_TABLE_HEADER **DebugImageInfoTableHeader
+ )
+{
+ mDebugImageInfoTableHeader.EfiDebugImageInfoTable = ((EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD *)(*DebugImageInfoTableHeader))->EfiDebugImageInfoTable;
+ mDebugImageInfoTableHeader.UpdateStatus = ((EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD *)(*DebugImageInfoTableHeader))->UpdateStatus;
+ mDebugImageInfoTableHeader.TableSize = ((EFI_DEBUG_IMAGE_INFO_TABLE_HEADER_OLD *)(*DebugImageInfoTableHeader))->TableSize;
+
+ if ((*DebugImageInfoTableHeader)->UpdateStatus > 3) {
+ *DebugImageInfoTableHeader = &mDebugImageInfoTableHeader;
+ return ;
+ }
+
+ if ((*DebugImageInfoTableHeader)->TableSize % (EFI_PAGE_SIZE / (sizeof (VOID *))) != 0) {
+ *DebugImageInfoTableHeader = &mDebugImageInfoTableHeader;
+ return ;
+ }
+
+ return ;
+}
+//
+// BUGBUG: work-around end
+//
+
+/**
+
+ Patch symbol RVA.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param FileName - Symbol file name
+ @param SearchType - Search type for Object
+
+ @retval EFI_SUCCESS - Patch symbol RVA successfully
+ @retval EFI_NOT_FOUND - Symbol RVA base not found
+
+**/
+EFI_STATUS
+EdbPatchSymbolRVA (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *FileName,
+ IN EDB_EBC_IMAGE_RVA_SEARCH_TYPE SearchType
+ )
+{
+ EFI_STATUS Status;
+ UINTN ImageNumber;
+ EFI_DEBUG_IMAGE_INFO *ImageTable;
+ CHAR8 *PdbPath;
+ VOID *ImageBase;
+ VOID *CandidateImageBase;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+
+ if (SearchType < 0 || SearchType >= EdbEbcImageRvaSearchTypeMax) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the related object
+ //
+ Object = EdbFindSymbolFile (DebuggerPrivate, FileName, NULL);
+ if (Object == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Try again to get DebugImageInfoTable
+ //
+ if (mDebuggerPrivate.DebugImageInfoTableHeader == NULL) {
+ Status = EfiGetSystemConfigurationTable (
+ &gEfiDebugImageInfoTableGuid,
+ (VOID **) &mDebuggerPrivate.DebugImageInfoTableHeader
+ );
+ if (EFI_ERROR (Status)) {
+ EDBPrint (L"DebugImageInfoTable not found!\n");
+ return Status;
+ }
+ }
+ DEBUG ((DEBUG_ERROR, "DebugImageInfoTableHeader: %x\n", mDebuggerPrivate.DebugImageInfoTableHeader));
+
+ //
+ // BUGBUG: work-around start
+ //
+ EdbFixDebugImageInfoTable (&mDebuggerPrivate.DebugImageInfoTableHeader);
+ //
+ // BUGBUG: work-around end
+ //
+
+ //
+ // Go through DebugImageInfoTable for each Image
+ //
+ CandidateImageBase = NULL;
+ ImageTable = mDebuggerPrivate.DebugImageInfoTableHeader->EfiDebugImageInfoTable;
+ for (ImageNumber = 0; ImageNumber < mDebuggerPrivate.DebugImageInfoTableHeader->TableSize; ImageNumber++) {
+ if (ImageTable[ImageNumber].NormalImage == NULL) {
+ continue;
+ }
+ ImageBase = ImageTable[ImageNumber].NormalImage->LoadedImageProtocolInstance->ImageBase;
+ //
+ // Get PDB path
+ //
+ PdbPath = GetPdbPath (ImageBase);
+ if (PdbPath == NULL) {
+ continue;
+ }
+ //
+ // Check PDB name
+ //
+ if (!MatchPdbAndMap (PdbPath, FileName)) {
+ continue;
+ }
+ DEBUG ((DEBUG_ERROR, "ImageBase: %x\n", ImageBase));
+
+ //
+ // Check SearchType
+ //
+ if (SearchType == EdbEbcImageRvaSearchTypeAny || SearchType == EdbEbcImageRvaSearchTypeFirst) {
+ //
+ // Assign base address and return
+ //
+ Object->BaseAddress = (UINTN)ImageBase;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get CandidateImageBase for EdbEbcImageRvaSearchTypeLast
+ //
+ CandidateImageBase = ImageBase;
+ }
+
+ //
+ // Check EdbEbcImageRvaSearchTypeLast
+ //
+ if (SearchType == EdbEbcImageRvaSearchTypeLast) {
+ if (CandidateImageBase == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Assign base address and return
+ //
+ Object->BaseAddress = (UINTN)CandidateImageBase;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // No match
+ //
+ return EFI_NOT_FOUND;
+}
+
+/**
+
+ Check whether OBJ file and COD file have same name.
+
+ @param ObjFileName - OBJ file name
+ @param CodFileName - COD file name
+
+ @retval TRUE - OBJ and COD file name match
+ @retval FALSE - OBJ and COD file name not match
+
+**/
+BOOLEAN
+MatchObjAndCod (
+ IN CHAR8 *ObjFileName,
+ IN CHAR16 *CodFileName
+ )
+{
+ UINTN ObjNameSize;
+ UINTN CodNameSize;
+ CHAR8 *PureObjFileName;
+ UINTN Index;
+
+ //
+ // remove library name
+ //
+ PureObjFileName = ObjFileName;
+ for (Index = 0; ObjFileName[Index] != 0; Index++) {
+ if (ObjFileName[Index] == ':') {
+ PureObjFileName = &ObjFileName[Index + 1];
+ break;
+ }
+ }
+ ObjFileName = PureObjFileName;
+
+ //
+ // get size
+ //
+ ObjNameSize = AsciiStrLen (ObjFileName);
+ CodNameSize = StrLen (CodFileName);
+
+ if (ObjNameSize != CodNameSize) {
+ return FALSE;
+ }
+
+ //
+ // check the name
+ //
+ for (Index = 0; Index < CodNameSize - 4; Index++) {
+ if ((ObjFileName[Index] | 0x20) != (CodFileName[Index] | 0x20)) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+typedef enum {
+ EdbEbcCodParseStateUninitialized,
+ EdbEbcCodParseStateSymbolInitialized,
+ EdbEbcCodParseStateSymbolStart,
+ EdbEbcCodParseStateSymbolEnd,
+ EdbEbcCodParseStateMax,
+} EDB_EBC_COD_PARSE_STATE;
+
+/**
+
+ The following code depends on the COD file generated by IEC compiler.
+
+**/
+
+/**
+
+ Load code by symbol by Iec.
+
+ @param Name - Symbol file name
+ @param Buffer - Symbol file buffer
+ @param BufferSize - Symbol file buffer size
+ @param CodeBufferSize - Code buffer size
+ @param FuncOffset - Code funcion offset
+
+ @return CodeBuffer
+
+**/
+CHAR8 *
+EdbLoadCodBySymbolByIec (
+ IN CHAR8 *Name,
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ OUT UINTN *CodeBufferSize,
+ OUT UINTN *FuncOffset
+ )
+{
+ CHAR8 *LineBuffer;
+ CHAR8 *FieldBuffer;
+ VOID *BufferStart;
+ VOID *BufferEnd;
+ UINTN Offset;
+ EDB_EBC_COD_PARSE_STATE CodParseState;
+ CHAR8 Char[2];
+
+ //
+ // Init
+ //
+ Char[0] = 9;
+ Char[1] = 0;
+ LineBuffer = AsciiStrGetNewTokenLine (Buffer, "\n\r");
+ Offset = (UINTN)-1;
+ BufferStart = NULL;
+ BufferEnd = NULL;
+ CodParseState = EdbEbcCodParseStateUninitialized;
+
+ //
+ // Check each line
+ //
+ while (LineBuffer != NULL) {
+ switch (CodParseState) {
+ case EdbEbcCodParseStateUninitialized:
+ //
+ // check mark_begin, begin to check line after this match
+ //
+ if (AsciiStrCmp (LineBuffer, "; mark_begin;") == 0) {
+ CodParseState = EdbEbcCodParseStateSymbolInitialized;
+ }
+ LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ break;
+
+ case EdbEbcCodParseStateSymbolInitialized:
+ //
+ // check mark_end, not check line after this match
+ //
+ if (AsciiStrCmp (LineBuffer, "; mark_end;") == 0) {
+ CodParseState = EdbEbcCodParseStateUninitialized;
+ LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ break;
+ }
+
+ //
+ // not check this line if the first char is as follows
+ //
+ if ((*LineBuffer == 0) ||
+ (*LineBuffer == '$') ||
+ (*LineBuffer == ';') ||
+ (*LineBuffer == '_') ||
+ (*LineBuffer == ' ')) {
+ LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ break;
+ }
+
+ //
+ // get function name, function name is followed by char 0x09.
+ //
+ FieldBuffer = AsciiStrGetNewTokenField (LineBuffer, Char);
+ ASSERT (FieldBuffer != NULL);
+ if (AsciiStriCmp (FieldBuffer, Name) == 0) {
+ BufferStart = FieldBuffer;
+ CodParseState = EdbEbcCodParseStateSymbolStart;
+ }
+ PatchForAsciiStrTokenAfter (FieldBuffer, 0x9);
+
+ //
+ // Get next line
+ //
+ LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ break;
+
+ case EdbEbcCodParseStateSymbolStart:
+ //
+ // check mark_end, if this match, means the function is found successfully.
+ //
+ if (AsciiStrCmp (LineBuffer, "; mark_end;") == 0) {
+ CodParseState = EdbEbcCodParseStateSymbolEnd;
+ //
+ // prepare CodeBufferSize, FuncOffset, and FuncStart to return
+ //
+ BufferEnd = LineBuffer + sizeof("; mark_end;") - 1;
+ *CodeBufferSize = (UINTN)BufferEnd - (UINTN)BufferStart;
+ *FuncOffset = Offset;
+ PatchForAsciiStrTokenAfter (LineBuffer, '\n');
+ return BufferStart;
+ }
+
+ //
+ // Get function offset
+ //
+ if ((Offset == (UINTN)-1) &&
+ (*LineBuffer == ' ')) {
+ FieldBuffer = AsciiStrGetNewTokenField (LineBuffer + 2, " ");
+ Offset = AsciiXtoi (FieldBuffer);
+ PatchForAsciiStrTokenAfter (FieldBuffer, ' ');
+ }
+
+ //
+ // Get next line
+ //
+ LineBuffer = AsciiStrGetNextTokenLine ("\n\r");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ break;
+
+ case EdbEbcCodParseStateSymbolEnd:
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ //
+ // no function found
+ //
+ return NULL;
+}
+
+/**
+
+ Load code by symbol.
+
+ @param Name - Symbol file name
+ @param Buffer - Symbol file buffer
+ @param BufferSize - Symbol file buffer size
+ @param CodeBufferSize - Code buffer size
+ @param FuncOffset - Code funcion offset
+
+ @return CodeBuffer
+
+**/
+CHAR8 *
+EdbLoadCodBySymbol (
+ IN CHAR8 *Name,
+ IN VOID *Buffer,
+ IN UINTN BufferSize,
+ OUT UINTN *CodeBufferSize,
+ OUT UINTN *FuncOffset
+ )
+{
+ //
+ // COD file format depends on the compiler.
+ //
+ // It is possible to check the different COD file format in this routine.
+ // Now only IEC is supported.
+ //
+ return EdbLoadCodBySymbolByIec (Name, Buffer, BufferSize, CodeBufferSize, FuncOffset);
+}
+
+/**
+
+ Find code from object.
+
+ @param DebuggerPrivate EBC Debugger private data structure
+ @param Object - Symbol object
+ @param FileName - File name
+
+**/
+VOID *
+EdbFindCodeFromObject (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN EFI_DEBUGGER_SYMBOL_OBJECT *Object,
+ IN CHAR16 *FileName
+ )
+{
+ UINTN EntryIndex;
+
+ //
+ // Go througn each Entry in this Object
+ //
+ for (EntryIndex = 0; EntryIndex < Object->EntryCount; EntryIndex++) {
+ //
+ // This check is for Function only
+ //
+ if ((Object->Entry[EntryIndex].Type != EfiDebuggerSymbolFunction) &&
+ (Object->Entry[EntryIndex].Type != EfiDebuggerSymbolStaticFunction)) {
+ continue;
+ }
+ //
+ // Skip match varbss_init function, because they has no source code
+ //
+ if (AsciiStrnCmp (Object->Entry[EntryIndex].Name, "varbss_init", sizeof("varbss_init") - 1) == 0) {
+ continue;
+ }
+ //
+ // check the name
+ //
+ if (!MatchObjAndCod (Object->Entry[EntryIndex].ObjName, FileName)) {
+ continue;
+ }
+ //
+ // found it, return source buffer
+ //
+ if (Object->Entry[EntryIndex].CodBuffer != NULL) {
+ return Object->Entry[EntryIndex].SourceBuffer;
+ }
+ }
+
+ //
+ // not found
+ //
+ return NULL;
+}
+
+/**
+
+ Load code.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param MapFileName - Symbol file name
+ @param FileName - Code file name
+ @param BufferSize - Code file buffer size
+ @param Buffer - Code file buffer
+
+ @retval EFI_SUCCESS - Code loaded successfully
+
+**/
+EFI_STATUS
+EdbLoadCode (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *MapFileName,
+ IN CHAR16 *FileName,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ UINTN ObjectIndex;
+ UINTN EntryIndex;
+ VOID *SourceBuffer;
+ EFI_STATUS Status;
+
+ //
+ // Find Symbol
+ //
+ Object = EdbFindSymbolFile (DebuggerPrivate, MapFileName, &ObjectIndex);
+ if (Object == NULL) {
+ EDBPrint (L"SymbolFile is not loaded!\n");
+ return EFI_NOT_FOUND;
+ } else {
+ //
+ // Check duplicated File
+ //
+ SourceBuffer = EdbFindCodeFromObject (DebuggerPrivate, Object, FileName);
+ if (SourceBuffer != NULL) {
+ //
+ // unnload duplicated code
+ //
+ Status = EdbUnloadCode (DebuggerPrivate, MapFileName, FileName, &SourceBuffer);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "Unload Duplicated Code File Error!\n"));
+ return Status;
+ }
+ Status = EdbDeleteCodeBuffer (DebuggerPrivate, MapFileName, FileName, SourceBuffer);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "Delete Duplicated Code File Error!\n"));
+ return Status;
+ }
+ }
+ }
+
+ //
+ // Go through each SymbolEntry
+ //
+ for (EntryIndex = 0; EntryIndex < Object->EntryCount; EntryIndex++) {
+ //
+ // load symbol for function only
+ //
+ if ((Object->Entry[EntryIndex].Type != EfiDebuggerSymbolFunction) &&
+ (Object->Entry[EntryIndex].Type != EfiDebuggerSymbolStaticFunction)) {
+ continue;
+ }
+ //
+ // skip varbss_init
+ //
+ if (AsciiStrnCmp (Object->Entry[EntryIndex].Name, "varbss_init", sizeof("varbss_init") - 1) == 0) {
+ continue;
+ }
+ //
+ // Check the name
+ //
+ if (!MatchObjAndCod (Object->Entry[EntryIndex].ObjName, FileName)) {
+ continue;
+ }
+ //
+ // load code for this symbol
+ //
+ Object->Entry[EntryIndex].CodBuffer = EdbLoadCodBySymbol (
+ Object->Entry[EntryIndex].Name,
+ Buffer,
+ BufferSize,
+ &Object->Entry[EntryIndex].CodBufferSize,
+ &Object->Entry[EntryIndex].FuncOffsetBase
+ );
+ if (Object->Entry[EntryIndex].CodBuffer != NULL) {
+ Object->Entry[EntryIndex].SourceBuffer = Buffer;
+ }
+ }
+
+ //
+ // patch end '\0' for each code buffer
+ //
+ for (EntryIndex = 0; EntryIndex < Object->EntryCount; EntryIndex++) {
+ if (Object->Entry[EntryIndex].CodBuffer != NULL) {
+ *((UINT8 *)Object->Entry[EntryIndex].CodBuffer + Object->Entry[EntryIndex].CodBufferSize) = 0;
+ DEBUG ((DEBUG_ERROR, " CodeSymbol: %a, FuncOffset: 0x05%x\n", Object->Entry[EntryIndex].Name, Object->Entry[EntryIndex].FuncOffsetBase));
+// DEBUG ((DEBUG_ERROR, " [CODE]:\n%a\n", Object->Entry[EntryIndex].CodBuffer));
+ }
+ }
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Unload code.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param MapFileName - Symbol file name
+ @param FileName - Code file name
+ @param Buffer - Code file buffer
+
+ @retval EFI_SUCCESS - Code unloaded successfully
+
+**/
+EFI_STATUS
+EdbUnloadCode (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *MapFileName,
+ IN CHAR16 *FileName,
+ OUT VOID **Buffer
+ )
+{
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ UINTN ObjectIndex;
+ UINTN EntryIndex;
+
+ //
+ // Find Symbol
+ //
+ Object = EdbFindSymbolFile (DebuggerPrivate, MapFileName, &ObjectIndex);
+ if (Object == NULL) {
+ EDBPrint (L"SymbolFile is not loaded!\n");
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Find code
+ //
+ *Buffer = EdbFindCodeFromObject (DebuggerPrivate, Object, FileName);
+ if (*Buffer == NULL) {
+ EDBPrint (L"CodeFile is not loaded!\n");
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // go through each entry
+ //
+ for (EntryIndex = 0; EntryIndex < Object->EntryCount; EntryIndex++) {
+ if ((Object->Entry[EntryIndex].Type != EfiDebuggerSymbolFunction) &&
+ (Object->Entry[EntryIndex].Type != EfiDebuggerSymbolStaticFunction)) {
+ continue;
+ }
+ if (AsciiStrnCmp (Object->Entry[EntryIndex].Name, "varbss_init", sizeof("varbss_init") - 1) == 0) {
+ continue;
+ }
+ if (!MatchObjAndCod (Object->Entry[EntryIndex].ObjName, FileName)) {
+ continue;
+ }
+ //
+ // clean up the buffer
+ //
+ Object->Entry[EntryIndex].CodBuffer = NULL;
+ Object->Entry[EntryIndex].CodBufferSize = 0;
+ Object->Entry[EntryIndex].FuncOffsetBase = 0;
+ Object->Entry[EntryIndex].SourceBuffer = NULL;
+ }
+
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Add code buffer.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param MapFileName - Symbol file name
+ @param CodeFileName - Code file name
+ @param SourceBufferSize- Code buffer size
+ @param SourceBuffer - Code buffer
+
+ @retval EFI_SUCCESS - CodeBuffer added successfully
+
+**/
+EFI_STATUS
+EdbAddCodeBuffer (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *MapFileName,
+ IN CHAR16 *CodeFileName,
+ IN UINTN SourceBufferSize,
+ IN VOID *SourceBuffer
+ )
+{
+ UINTN Index;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+
+ //
+ // Find Symbol
+ //
+ Object = EdbFindSymbolFile (DebuggerPrivate, MapFileName, NULL);
+ if (Object == NULL) {
+ EDBPrint (L"SymbolFile is not loaded!\n");
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Add it to last entry
+ //
+ for (Index = 0; Object->SourceBuffer[Index] != NULL; Index++) {
+ ;
+ }
+ Object->SourceBuffer[Index] = SourceBuffer;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Delete code buffer.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param MapFileName - Symbol file name
+ @param CodeFileName - Code file name
+ @param SourceBuffer - Code buffer
+
+ @retval EFI_SUCCESS - CodeBuffer deleted successfully
+
+**/
+EFI_STATUS
+EdbDeleteCodeBuffer (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *MapFileName,
+ IN CHAR16 *CodeFileName,
+ IN VOID *SourceBuffer
+ )
+{
+ UINTN Index;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+
+ //
+ // Find Symbol
+ //
+ Object = EdbFindSymbolFile (DebuggerPrivate, MapFileName, NULL);
+ if (Object == NULL) {
+ EDBPrint (L"SymbolFile is not loaded!\n");
+ return EFI_NOT_FOUND;
+ }
+
+ for (Index = 0; Object->SourceBuffer[Index] != NULL; Index++) {
+ //
+ // free the buffer if match
+ //
+ if (Object->SourceBuffer[Index] == SourceBuffer) {
+ gBS->FreePool (SourceBuffer);
+ break;
+ }
+ }
+
+ if (Object->SourceBuffer[Index] == NULL) {
+ //
+ // not return NOT_FOUND
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // remove the entry
+ //
+ Object->SourceBuffer[Index] = NULL;
+ for (Index = Index + 1; Object->SourceBuffer[Index] != NULL; Index++) {
+ Object->SourceBuffer[Index - 1] = Object->SourceBuffer[Index];
+ }
+ Object->SourceBuffer[Index - 1] = NULL;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Find the symbol string according to address.
+
+ @param Address - Symbol address
+
+ @return Symbol string
+
+**/
+CHAR8 *
+FindSymbolStr (
+ IN UINTN Address
+ )
+{
+ UINTN ObjectIndex;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ UINTN EntryIndex;
+ EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
+
+ //
+ // need we display symbol
+ //
+ if (!mDebuggerPrivate.DebuggerSymbolContext.DisplaySymbol) {
+ return NULL;
+ }
+
+ //
+ // Go through each object and entry
+ //
+ Object = mDebuggerPrivate.DebuggerSymbolContext.Object;
+ for (ObjectIndex = 0; ObjectIndex < mDebuggerPrivate.DebuggerSymbolContext.ObjectCount; ObjectIndex++) {
+ Entry = Object[ObjectIndex].Entry;
+ for (EntryIndex = 0; EntryIndex < Object[ObjectIndex].EntryCount; EntryIndex++) {
+ //
+ // if Address match, return Name
+ //
+ if (Address == (Entry[EntryIndex].Rva + Object[ObjectIndex].BaseAddress)) {
+ return Entry[EntryIndex].Name;
+ }
+ }
+ }
+
+ //
+ // not found
+ //
+ return NULL;
+}
+
+/**
+
+ Get line number and offset from this line in code file.
+
+ @param Line - Line buffer in code file
+ @param Offset - Offset to functin entry
+
+ @return Line number
+
+**/
+UINTN
+EdbGetLineNumberAndOffsetFromThisLine (
+ IN VOID *Line,
+ OUT UINTN *Offset
+ )
+{
+ UINTN LineNumber;
+ CHAR8 *LineBuffer;
+ CHAR8 *FieldBuffer;
+
+ LineNumber = (UINTN)-1;
+ LineBuffer = Line;
+ *Offset = (UINTN)-1;
+
+ while (LineBuffer != NULL) {
+ //
+ // Check candidate
+ //
+ if (*LineBuffer != ' ') {
+ return (UINTN)-1;
+ }
+
+ //
+ // Get Offset
+ //
+ if (*(LineBuffer + 2) != ' ') {
+ if (*Offset == (UINTN)-1) {
+ FieldBuffer = AsciiStrGetNewTokenField (LineBuffer + 2, " ");
+ *Offset = AsciiXtoi (FieldBuffer);
+ PatchForAsciiStrTokenAfter (FieldBuffer, ' ');
+ }
+ }
+
+ //
+ // 1. assembly instruction
+ //
+ FieldBuffer = AsciiStrGetNewTokenField (LineBuffer, ":");
+ //
+ // 2. file path
+ //
+ FieldBuffer = AsciiStrGetNextTokenField (":");
+ PatchForAsciiStrTokenBefore (FieldBuffer, ':');
+ if (FieldBuffer == NULL) {
+ //
+ // candidate found
+ //
+ LineNumber = 0;
+ LineBuffer = AsciiStrGetNextTokenLine ("\n");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ continue;
+ }
+ //
+ // 3. line number
+ //
+ FieldBuffer = AsciiStrGetNextTokenField (":");
+ PatchForAsciiStrTokenBefore (FieldBuffer, ':');
+ if (FieldBuffer == NULL) {
+ //
+ // impossible, TBD?
+ //
+ LineBuffer = AsciiStrGetNextTokenLine ("\n");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ continue;
+ }
+
+ LineNumber = AsciiAtoi (FieldBuffer);
+ //
+ // Not patch after
+ //
+
+ return LineNumber;
+ }
+
+ return (UINTN)-1;
+}
+
+typedef enum {
+ EdbEbcLineSearchTypeAny,
+ EdbEbcLineSearchTypeFirst,
+ EdbEbcLineSearchTypeLast,
+ EdbEbcLineSearchTypeMax,
+} EDB_EBC_LINE_SEARCH_TYPE;
+
+/**
+
+ Get line number from this code file.
+
+ @param Entry - Symbol entry
+ @param FuncOffset - Offset to functin entry
+ @param SearchType - Search type for the code
+
+ @return Line number
+
+**/
+UINTN
+EdbGetLineNumberFromCode (
+ IN EFI_DEBUGGER_SYMBOL_ENTRY *Entry,
+ IN UINTN FuncOffset,
+ IN EDB_EBC_LINE_SEARCH_TYPE SearchType
+ )
+{
+ CHAR8 *LineBuffer;
+ UINTN LineNumber;
+ UINTN Offset;
+ UINTN CandidateLineNumber;
+ UINTN CandidateOffset;
+
+ if (SearchType < 0 || SearchType >= EdbEbcLineSearchTypeMax) {
+ return (UINTN)-1;
+ }
+
+ LineNumber = (UINTN)-1;
+ CandidateLineNumber = (UINTN)-1;
+ CandidateOffset = (UINTN)-1;
+ LineBuffer = AsciiStrGetNewTokenLine (Entry->CodBuffer, "\n");
+ while (LineBuffer != NULL) {
+ if (*LineBuffer != ' ') {
+ LineBuffer = AsciiStrGetNextTokenLine ("\n");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ continue;
+ }
+
+ //
+ // Get Info
+ //
+ LineNumber = EdbGetLineNumberAndOffsetFromThisLine (LineBuffer, &Offset);
+
+ //
+ // Check offset
+ //
+ if (Offset != FuncOffset) {
+ //
+ // Check last offset match
+ //
+ if (CandidateOffset == FuncOffset) {
+ if (SearchType == EdbEbcLineSearchTypeLast) {
+ PatchForAsciiStrTokenAfter (LineBuffer, '\n');
+ if (CandidateLineNumber != LineNumber) {
+ return CandidateLineNumber;
+ } else {
+ return (UINTN)-1;
+ }
+ } else {
+ //
+ // impossible, TBD?
+ //
+ }
+ }
+
+ LineBuffer = AsciiStrGetNextTokenLine ("\n");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ CandidateLineNumber = LineNumber;
+ continue;
+ }
+
+ //
+ // Offset match, more check
+ //
+ if (SearchType == EdbEbcLineSearchTypeAny) {
+ PatchForAsciiStrTokenAfter (LineBuffer, '\n');
+ return LineNumber;
+ }
+
+ if (SearchType == EdbEbcLineSearchTypeFirst) {
+ //
+ // Check last line
+ //
+ PatchForAsciiStrTokenAfter (LineBuffer, '\n');
+ if (CandidateLineNumber != LineNumber) {
+ return LineNumber;
+ } else {
+ return (UINTN)-1;
+ }
+ }
+
+ CandidateLineNumber = LineNumber;
+ CandidateOffset = Offset;
+
+ LineBuffer = AsciiStrGetNextTokenLine ("\n");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ }
+
+ //
+ // Check last offset match
+ //
+ if (CandidateOffset == FuncOffset) {
+ if (SearchType == EdbEbcLineSearchTypeLast) {
+ return CandidateLineNumber;
+ }
+ }
+
+ return (UINTN)-1;
+}
+
+/**
+
+ Get the source string from this code file by line.
+
+ @param Entry - Symbol entry
+ @param LineNumber - line number
+ @param FuncEnd - Function end
+
+ @return Funtion start
+
+**/
+VOID *
+EdbGetSourceStrFromCodeByLine (
+ IN EFI_DEBUGGER_SYMBOL_ENTRY *Entry,
+ IN UINTN LineNumber,
+ IN VOID **FuncEnd
+ )
+{
+ CHAR8 *LineBuffer;
+ CHAR8 *FieldBuffer;
+ VOID *FuncStart;
+ UINTN Number;
+
+ FuncStart = NULL;
+ LineBuffer = AsciiStrGetNewTokenLine (Entry->CodBuffer, "\n");
+ while (LineBuffer != NULL) {
+ if (*LineBuffer != ';') {
+ if (FuncStart != NULL) {
+ //
+ // Over
+ //
+ *FuncEnd = LineBuffer - 1;
+ PatchForAsciiStrTokenAfter (LineBuffer, '\n');
+ return FuncStart;
+ }
+ LineBuffer = AsciiStrGetNextTokenLine ("\n");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ continue;
+ }
+
+ //
+ // Check LineNumber
+ //
+ FieldBuffer = AsciiStrGetNewTokenField (LineBuffer + 1, " ");
+ Number = AsciiAtoi (FieldBuffer);
+ PatchForAsciiStrTokenAfter (FieldBuffer, ' ');
+ if (Number != LineNumber) {
+ LineBuffer = AsciiStrGetNextTokenLine ("\n");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ continue;
+ }
+
+ //
+ // Line match, get line number
+ //
+ if (FuncStart == NULL) {
+ FuncStart = LineBuffer;
+ }
+
+ LineBuffer = AsciiStrGetNextTokenLine ("\n");
+ PatchForAsciiStrTokenBefore (LineBuffer, '\n');
+ }
+
+ return NULL;
+}
+
+/**
+
+ Get source string from this code file.
+
+ @param Entry - Symbol entry
+ @param FuncOffset - Offset to functin entry
+ @param FuncEnd - Function end
+
+ @retval Funtion start
+
+**/
+VOID *
+EdbGetSourceStrFromCode (
+ IN EFI_DEBUGGER_SYMBOL_ENTRY *Entry,
+ IN UINTN FuncOffset,
+ IN VOID **FuncEnd
+ )
+{
+ UINTN LineNumber;
+
+ //
+ // Only search the last line, then display
+ //
+ LineNumber = EdbGetLineNumberFromCode (Entry, FuncOffset, EdbEbcLineSearchTypeLast);
+ if (LineNumber == (UINTN)-1) {
+ return NULL;
+ }
+
+ return EdbGetSourceStrFromCodeByLine (Entry, LineNumber, FuncEnd);
+}
+
+/**
+
+ Print source.
+
+ @param Address - Instruction address
+ @param IsPrint - Whether need to print
+
+ @retval 1 - find the source
+ @retval 0 - not find the source
+
+**/
+UINTN
+EdbPrintSource (
+ IN UINTN Address,
+ IN BOOLEAN IsPrint
+ )
+{
+ UINTN SymbolAddress;
+ EFI_DEBUGGER_SYMBOL_OBJECT *RetObject;
+ EFI_DEBUGGER_SYMBOL_ENTRY *RetEntry;
+ UINTN FuncOffset;
+ UINT8 *FuncStart;
+ UINT8 *FuncEnd;
+ UINT8 *FuncIndex;
+ CHAR8 Buffer[EFI_DEBUG_MAX_PRINT_BUFFER];
+ UINTN BufferSize;
+
+ //
+ // need we display symbol
+ //
+ if (!mDebuggerPrivate.DebuggerSymbolContext.DisplaySymbol) {
+ return 0 ;
+ }
+
+ //
+ // find the symbol address
+ //
+ SymbolAddress = EbdFindSymbolAddress (
+ Address,
+ EdbMatchSymbolTypeLowerAddress,
+ &RetObject,
+ &RetEntry
+ );
+ if (SymbolAddress == 0 || RetEntry == NULL) {
+ return 0 ;
+ }
+
+ FuncOffset = Address - SymbolAddress + RetEntry->FuncOffsetBase;
+
+ //
+ // Get Func String
+ //
+ FuncStart = EdbGetSourceStrFromCode (RetEntry, FuncOffset, (VOID**) &FuncEnd);
+ if (FuncStart == NULL) {
+ return 0 ;
+ }
+
+ //
+ // check whether need to real print
+ //
+ if (!IsPrint) {
+ return 1;
+ }
+
+ *(UINT8 *)FuncEnd = 0;
+
+ //
+ // seperate buffer by \n, so that \r can be added.
+ //
+ FuncIndex = FuncStart;
+ while (*FuncIndex != 0) {
+ if (*FuncIndex == '\n') {
+ if ((FuncIndex - FuncStart) < (EFI_DEBUG_MAX_PRINT_BUFFER - 3)) {
+ BufferSize = FuncIndex - FuncStart;
+ } else {
+ BufferSize = EFI_DEBUG_MAX_PRINT_BUFFER - 3;
+ }
+ if (BufferSize != 0) {
+ CopyMem (Buffer, FuncStart, BufferSize);
+ }
+ Buffer[BufferSize] = 0;
+ EDBPrint (L"%a\n", Buffer);
+ FuncStart = FuncIndex + 1;
+ FuncIndex = FuncStart;
+ } else {
+ FuncIndex ++;
+ }
+ }
+
+ //
+ // Patch the end
+ //
+ *(UINT8 *)FuncEnd = '\n';
+
+ return 1 ;
+}
+
+/**
+
+ Get Mapfile and SymbolName from one symbol format: [MapFileName:]SymbolName.
+
+ @param Symbol - whole Symbol name
+ @param MapfileName - the mapfile name in the symbol
+ @param SymbolName - the symbol name in the symbol
+
+**/
+VOID
+GetMapfileAndSymbol (
+ IN CHAR16 *Symbol,
+ OUT CHAR16 **MapfileName,
+ OUT CHAR16 **SymbolName
+ )
+{
+ CHAR16 *Ch;
+
+ *MapfileName = NULL;
+ *SymbolName = Symbol;
+
+ for (Ch = Symbol; *Ch != 0; Ch++) {
+ //
+ // Find split char
+ //
+ if (*Ch == L':') {
+ *MapfileName = Symbol;
+ *Ch = 0;
+ *SymbolName = Ch + 1;
+ break;
+ }
+ }
+
+ return ;
+}
+
+/**
+
+ Convert a symbol to an address.
+
+ @param Symbol - Symbol name
+ @param Address - Symbol address
+
+ @retval EFI_SUCCESS - symbol found and address returned.
+ @retval EFI_NOT_FOUND - symbol not found
+ @retval EFI_NO_MAPPING - duplicated symbol not found
+
+**/
+EFI_STATUS
+Symboltoi (
+ IN CHAR16 *Symbol,
+ OUT UINTN *Address
+ )
+{
+ UINTN ObjectIndex;
+ EFI_DEBUGGER_SYMBOL_OBJECT *Object;
+ UINTN EntryIndex;
+ EFI_DEBUGGER_SYMBOL_ENTRY *Entry;
+ CHAR16 *SymbolName;
+ CHAR16 *MapfileName;
+
+ //
+ // Split one symbol to mapfile name and symbol name
+ //
+ GetMapfileAndSymbol (Symbol, &MapfileName, &SymbolName);
+
+ *Address = 0;
+ //
+ // Go through each object
+ //
+ Object = mDebuggerPrivate.DebuggerSymbolContext.Object;
+ for (ObjectIndex = 0; ObjectIndex < mDebuggerPrivate.DebuggerSymbolContext.ObjectCount; ObjectIndex++) {
+ //
+ // Check MapfileName
+ //
+ if ((MapfileName != NULL) && (StriCmp (Object[ObjectIndex].Name, MapfileName) != 0)) {
+ continue;
+ }
+ //
+ // Go through each entry
+ //
+ Entry = Object[ObjectIndex].Entry;
+ for (EntryIndex = 0; EntryIndex < Object[ObjectIndex].EntryCount; EntryIndex++) {
+ //
+ // Check SymbolName (case sensitive)
+ //
+ if (StrCmpUnicodeAndAscii (SymbolName, Entry[EntryIndex].Name) == 0) {
+ if ((*Address != 0) && (MapfileName == NULL)) {
+ //
+ // Find the duplicated symbol
+ //
+ EDBPrint (L"Duplicated Symbol found!\n");
+ return EFI_NO_MAPPING;
+ } else {
+ //
+ // record Address
+ //
+ *Address = (Entry[EntryIndex].Rva + Object[ObjectIndex].BaseAddress);
+ }
+ }
+ }
+ }
+
+ if (*Address == 0) {
+ //
+ // Not found
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.h
new file mode 100644
index 000000000..f82e5b76c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebugger/EdbSymbol.h
@@ -0,0 +1,244 @@
+/** @file
+
+Copyright (c) 2007, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+#ifndef _EFI_EDB_SYMBOL_H_
+#define _EFI_EDB_SYMBOL_H_
+
+#include <Uefi.h>
+
+//
+// The default base address is 0x10000000
+//
+#define EFI_DEBUGGER_DEFAULT_LINK_IMAGEBASE 0x10000000
+
+#define EFI_DEBUGGER_MAX_SYMBOL_ADDRESS_DELTA_VALUE 0x100000 // 1 M delta
+
+typedef enum {
+ EdbMatchSymbolTypeSameAdderss,
+ EdbMatchSymbolTypeNearestAddress,
+ EdbMatchSymbolTypeLowerAddress,
+ EdbMatchSymbolTypeUpperAddress,
+ EdbMatchSymbolTypeMax,
+} EDB_MATCH_SYMBOL_TYPE;
+
+typedef enum {
+ EdbEbcImageRvaSearchTypeAny,
+ EdbEbcImageRvaSearchTypeFirst,
+ EdbEbcImageRvaSearchTypeLast,
+ EdbEbcImageRvaSearchTypeMax,
+} EDB_EBC_IMAGE_RVA_SEARCH_TYPE;
+
+/**
+
+ Find symbol by address.
+
+ @param Address - Symbol address
+ @param Type - Search type
+ @param RetObject - Symbol object
+ @param RetEntry - Symbol entry
+
+ @return Nearest symbol address
+
+**/
+UINTN
+EbdFindSymbolAddress (
+ IN UINTN Address,
+ IN EDB_MATCH_SYMBOL_TYPE Type,
+ OUT EFI_DEBUGGER_SYMBOL_OBJECT **Object,
+ OUT EFI_DEBUGGER_SYMBOL_ENTRY **Entry
+ );
+
+/**
+
+ Load symbol file by name.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param FileName - Symbol file name
+ @param BufferSize - Symbol file buffer size
+ @param Buffer - Symbol file buffer
+
+ @retval EFI_SUCCESS - load symbol successfully
+
+**/
+EFI_STATUS
+EdbLoadSymbol (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *FileName,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+
+ Unload symbol file by name.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param FileName - Symbol file name
+
+ @retval EFI_SUCCESS - unload symbol successfully
+
+**/
+EFI_STATUS
+EdbUnloadSymbol (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *FileName
+ );
+
+/**
+
+ Patch symbol RVA.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param FileName - Symbol file name
+ @param SearchType - Search type for Object
+
+ @retval EFI_SUCCESS - Patch symbol RVA successfully
+ @retval EFI_NOT_FOUND - Symbol RVA base not found
+
+**/
+EFI_STATUS
+EdbPatchSymbolRVA (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *FileName,
+ IN EDB_EBC_IMAGE_RVA_SEARCH_TYPE SearchType
+ );
+
+/**
+
+ Load code.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param MapFileName - Symbol file name
+ @param FileName - Code file name
+ @param BufferSize - Code file buffer size
+ @param Buffer - Code file buffer
+
+ @retval EFI_SUCCESS - Code loaded successfully
+
+**/
+EFI_STATUS
+EdbLoadCode (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *MapFileName,
+ IN CHAR16 *FileName,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+
+ Unload code.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param MapFileName - Symbol file name
+ @param FileName - Code file name
+ @param Buffer - Code file buffer
+
+ @retval EFI_SUCCESS - Code unloaded successfully
+
+**/
+EFI_STATUS
+EdbUnloadCode (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *MapFileName,
+ IN CHAR16 *FileName,
+ OUT VOID **Buffer
+ );
+
+/**
+
+ Add code buffer.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param MapFileName - Symbol file name
+ @param CodeFileName - Code file name
+ @param SourceBufferSize- Code buffer size
+ @param SourceBuffer - Code buffer
+
+ @retval EFI_SUCCESS - CodeBuffer added successfully
+
+**/
+EFI_STATUS
+EdbAddCodeBuffer (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *MapFileName,
+ IN CHAR16 *CodeFileName,
+ IN UINTN SourceBufferSize,
+ IN VOID *SourceBuffer
+ );
+
+/**
+
+ Delete code buffer.
+
+ @param DebuggerPrivate - EBC Debugger private data structure
+ @param MapFileName - Symbol file name
+ @param CodeFileName - Code file name
+ @param SourceBuffer - Code buffer
+
+ @retval EFI_SUCCESS - CodeBuffer deleted successfully
+
+**/
+EFI_STATUS
+EdbDeleteCodeBuffer (
+ IN EFI_DEBUGGER_PRIVATE_DATA *DebuggerPrivate,
+ IN CHAR16 *MapFileName,
+ IN CHAR16 *CodeFileName,
+ IN VOID *SourceBuffer
+ );
+
+/**
+
+ Find the symbol string according to address.
+
+ @param Address - Symbol address
+
+ @return Symbol string
+
+**/
+CHAR8 *
+FindSymbolStr (
+ IN UINTN Address
+ );
+
+/**
+
+ Print source.
+
+ @param Address - Instruction address
+ @param IsPrint - Whether need to print
+
+ @retval 1 - find the source
+ @retval 0 - not find the source
+
+**/
+UINTN
+EdbPrintSource (
+ IN UINTN Address,
+ IN BOOLEAN IsPrint
+ );
+
+/**
+
+ Convert a symbol to an address.
+
+ @param Symbol - Symbol name
+ @param Address - Symbol address
+
+ @retval EFI_SUCCESS - symbol found and address returned.
+ @retval EFI_NOT_FOUND - symbol not found
+ @retval EFI_NO_MAPPING - duplicated symbol not found
+
+**/
+EFI_STATUS
+Symboltoi (
+ IN CHAR16 *Symbol,
+ OUT UINTN *Address
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfig.inf b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfig.inf
new file mode 100644
index 000000000..22cf64d95
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfig.inf
@@ -0,0 +1,57 @@
+## @file
+# EBC Debugger configuration application.
+#
+# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EdbCfg
+ MODULE_UNI_FILE = EbcDebuggerConfig.uni
+ FILE_GUID = 8CFC5233-23C6-49e3-8A2D-7E581AB305BA
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeEbcDebuggerConfig
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 AARCH64
+#
+
+[Sources]
+ EbcDebugger/EbcDebuggerConfig.c
+ EbcDebugger/EdbCommon.h
+ EbcDebugger/EdbSupportString.c
+ EbcDebugger/EdbSupport.h
+ EbcDebugger/EdbCommand.h
+ EbcDebugger/EdbHook.h
+ EbcDebugger/Edb.h
+ EbcDebugger/EdbDisasmSupport.h
+ EbcDebugger/EdbDisasm.h
+ EbcDebugger/EdbSymbol.h
+ EbcDebuggerHook.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiLib
+ BaseLib
+ DebugLib
+ UefiApplicationEntryPoint
+
+[Protocols]
+ gEfiDebuggerConfigurationProtocolGuid ## CONSUMES
+ gEfiShellParametersProtocolGuid ## CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ EbcDebuggerConfigExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfig.uni b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfig.uni
new file mode 100644
index 000000000..c8592407c
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfig.uni
@@ -0,0 +1,13 @@
+// /** @file
+// EBC Debugger configuration application.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "EBC Debugger configuration application"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This application allows configuring the EBC Debugger."
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfigExtra.uni b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfigExtra.uni
new file mode 100644
index 000000000..1d532c86a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerConfigExtra.uni
@@ -0,0 +1,12 @@
+// /** @file
+// EBC Debugger configuration application.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"EBC Debugger Config"
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerExtra.uni b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerExtra.uni
new file mode 100644
index 000000000..944abae21
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerExtra.uni
@@ -0,0 +1,12 @@
+// /** @file
+// EFI Byte Code (EBC) Debugger
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"EFI Byte Code (EBC) Debugger"
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerHook.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerHook.c
new file mode 100644
index 000000000..b516147ff
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerHook.c
@@ -0,0 +1,267 @@
+/** @file
+ Contains the empty version of the EBC Debugger hooks, to be used when
+ compiling the regular EBC VM module.
+ As debugging is not needed for the standard EBC VM, all calls are left empty.
+
+ The EBC Debugger defines its own version for these calls in EbdHooks.c.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EbcDebuggerHook.h"
+
+/**
+
+ The hook in InitializeEbcDriver.
+
+ @param Handle - The EbcDebugProtocol handle.
+ @param EbcDebugProtocol - The EbcDebugProtocol interface.
+
+**/
+VOID
+EbcDebuggerHookInit (
+ IN EFI_HANDLE Handle,
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol
+ )
+{
+ return;
+}
+
+/**
+
+The hook in UnloadImage for EBC Interpreter.
+
+**/
+VOID
+EbcDebuggerHookUnload (
+ VOID
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in EbcUnloadImage.
+ Currently do nothing here.
+
+ @param Handle The EbcImage handle.
+
+**/
+VOID
+EbcDebuggerHookEbcUnloadImage (
+ IN EFI_HANDLE Handle
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteEbcImageEntryPoint.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookExecuteEbcImageEntryPoint (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteEbcImageEntryPoint.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookEbcInterpret (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+ The hook in EbcExecute, before ExecuteFunction.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookExecuteStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+ The hook in EbcExecute, after ExecuteFunction.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookExecuteEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteCALL, before move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteCALL, after move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteCALL, before call EbcLLCALLEX.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLEXStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteCALL, after call EbcLLCALLEX.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLEXEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteRET, before move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookRETStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteRET, after move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookRETEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteJMP, before move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMPStart (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteJMP, after move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMPEnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteJMP8, before move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMP8Start (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
+
+/**
+
+ The hook in ExecuteJMP8, after move IP..
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMP8End (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ return;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerHook.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerHook.h
new file mode 100644
index 000000000..b166e505a
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDebuggerHook.h
@@ -0,0 +1,241 @@
+/** @file
+ Prototypes for the EBC Debugger hooks.
+
+ Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EFI_EBC_DEBUGGER_HOOK_H_
+#define _EFI_EBC_DEBUGGER_HOOK_H_
+
+#include <Uefi.h>
+
+#include <Protocol/DebugSupport.h>
+#include <Protocol/EbcVmTest.h>
+
+/**
+ The VM interpreter calls this function when an exception is detected.
+
+ @param ExceptionType Specifies the processor exception detected.
+ @param ExceptionFlags Specifies the exception context.
+ @param VmPtr Pointer to a VM context for passing info to the
+ EFI debugger.
+
+ @retval EFI_SUCCESS This function completed successfully.
+
+**/
+EFI_STATUS
+EbcDebugSignalException (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EXCEPTION_FLAGS ExceptionFlags,
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in InitializeEbcDriver.
+
+ @param Handle - The EbcDebugProtocol handle.
+ @param EbcDebugProtocol - The EbcDebugProtocol interface.
+
+**/
+VOID
+EbcDebuggerHookInit (
+ IN EFI_HANDLE Handle,
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol
+ );
+
+/**
+
+The hook in UnloadImage for EBC Interpreter.
+
+**/
+VOID
+EbcDebuggerHookUnload (
+ VOID
+ );
+
+/**
+
+ The hook in EbcUnloadImage.
+ Currently do nothing here.
+
+ @param Handle The EbcImage handle.
+
+**/
+VOID
+EbcDebuggerHookEbcUnloadImage (
+ IN EFI_HANDLE Handle
+ );
+
+
+/**
+
+ Hooks in EbcSupport.c
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookExecuteEbcImageEntryPoint (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in ExecuteEbcImageEntryPoint.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookEbcInterpret (
+ IN VM_CONTEXT *VmPtr
+ );
+
+
+/**
+ The hook in EbcExecute, before ExecuteFunction.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookExecuteStart (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ The hook in EbcExecute, after ExecuteFunction.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookExecuteEnd (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ The hook in ExecuteCALL, before move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLStart (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in ExecuteCALL, after move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLEnd (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in ExecuteCALL, before call EbcLLCALLEX.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLEXStart (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in ExecuteCALL, after call EbcLLCALLEX.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookCALLEXEnd (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in ExecuteRET, before move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookRETStart (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in ExecuteRET, after move IP.
+ It will record trace information.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookRETEnd (
+ IN VM_CONTEXT *VmPtr
+ );
+
+
+/**
+
+ The hook in ExecuteJMP, before move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMPStart (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in ExecuteJMP, after move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMPEnd (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in ExecuteJMP8, before move IP.
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMP8Start (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+
+ The hook in ExecuteJMP8, after move IP..
+
+ @param VmPtr - pointer to VM context.
+
+**/
+VOID
+EbcDebuggerHookJMP8End (
+ IN VM_CONTEXT *VmPtr
+ );
+
+#endif
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxe.inf b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
new file mode 100644
index 000000000..a38700df5
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxe.inf
@@ -0,0 +1,81 @@
+## @file
+# Module that produces EBC Interprete and EBC Debug Support protocols.
+#
+# This module implements EFI Byte Code (EBC) Virtual Machine that can provide
+# platform and processor-independent mechanisms for loading and executing EFI
+# device drivers.
+#
+# Copyright (c) 2015, The Linux Foundation. All rights reserved.
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EbcDxe
+ MODULE_UNI_FILE = EbcDxe.uni
+ FILE_GUID = 13AC6DD0-73D0-11D4-B06B-00AA00BD6DE7
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeEbcDriver
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 AARCH64
+#
+
+[Sources]
+ EbcDebuggerHook.h
+ EbcDebuggerHook.c
+ EbcExecute.h
+ EbcExecute.c
+ EbcInt.h
+ EbcInt.c
+
+[Sources.Ia32]
+ Ia32/EbcSupport.c
+ Ia32/EbcLowLevel.nasm
+
+[Sources.X64]
+ X64/EbcSupport.c
+ X64/EbcLowLevel.nasm
+
+[Sources.AARCH64]
+ AArch64/EbcSupport.c
+ AArch64/EbcLowLevel.S
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ CacheMaintenanceLib
+ MemoryAllocationLib
+ PeCoffLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ UefiDriverEntryPoint
+ DebugLib
+ BaseLib
+
+
+[Protocols]
+ gEfiDebugSupportProtocolGuid ## PRODUCES
+ gEfiEbcProtocolGuid ## PRODUCES
+ gEdkiiPeCoffImageEmulatorProtocolGuid ## PRODUCES
+ gEfiEbcVmTestProtocolGuid ## SOMETIMES_PRODUCES
+ gEfiEbcSimpleDebuggerProtocolGuid ## SOMETIMES_CONSUMES
+
+[Depex]
+ TRUE
+
+# [Event]
+#
+# Periodic timer event to support EFI debug support protocol for EBC image.
+#
+# EVENT_TYPE_PERIODIC_TIMER ## CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ EbcDxeExtra.uni
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxe.uni b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxe.uni
new file mode 100644
index 000000000..746d8b911
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxe.uni
@@ -0,0 +1,18 @@
+// /** @file
+// Module that produces EBC Interprete and EBC Debug Support protocols.
+//
+// This module implements EFI Byte Code (EBC) Virtual Machine that can provide
+// platform and processor-independent mechanisms for loading and executing EFI
+// device drivers.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces EBC Interpreter and EBC Debug Support protocols"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module implements EFI Byte Code (EBC) Virtual Machine that can provide platform and processor-independent mechanisms for loading and executing UEFI device drivers."
+
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxeExtra.uni b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxeExtra.uni
new file mode 100644
index 000000000..7b47f15a7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcDxeExtra.uni
@@ -0,0 +1,14 @@
+// /** @file
+// EbcDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"EFI Byte Code DXE Interpreter"
+
+
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcExecute.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcExecute.c
new file mode 100644
index 000000000..1c4a4f515
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcExecute.c
@@ -0,0 +1,5383 @@
+/** @file
+ Contains code that implements the virtual machine.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EbcInt.h"
+#include "EbcExecute.h"
+#include "EbcDebuggerHook.h"
+
+
+//
+// Define some useful data size constants to allow switch statements based on
+// size of operands or data.
+//
+#define DATA_SIZE_INVALID 0
+#define DATA_SIZE_8 1
+#define DATA_SIZE_16 2
+#define DATA_SIZE_32 4
+#define DATA_SIZE_64 8
+#define DATA_SIZE_N 48 // 4 or 8
+//
+// Structure we'll use to dispatch opcodes to execute functions.
+//
+typedef struct {
+ EFI_STATUS (*ExecuteFunction) (IN VM_CONTEXT * VmPtr);
+}
+VM_TABLE_ENTRY;
+
+typedef
+UINT64
+(*DATA_MANIP_EXEC_FUNCTION) (
+ IN VM_CONTEXT * VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Decode a 16-bit index to determine the offset. Given an index value:
+
+ b15 - sign bit
+ b14:12 - number of bits in this index assigned to natural units (=a)
+ ba:11 - constant units = ConstUnits
+ b0:a - natural units = NaturalUnits
+
+ Given this info, the offset can be computed by:
+ offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
+
+ Max offset is achieved with index = 0x7FFF giving an offset of
+ 0x27B (32-bit machine) or 0x477 (64-bit machine).
+ Min offset is achieved with index =
+
+ @param VmPtr A pointer to VM context.
+ @param CodeOffset Offset from IP of the location of the 16-bit index
+ to decode.
+
+ @return The decoded offset.
+
+**/
+INT16
+VmReadIndex16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 CodeOffset
+ );
+
+/**
+ Decode a 32-bit index to determine the offset.
+
+ @param VmPtr A pointer to VM context.
+ @param CodeOffset Offset from IP of the location of the 32-bit index
+ to decode.
+
+ @return Converted index per EBC VM specification.
+
+**/
+INT32
+VmReadIndex32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 CodeOffset
+ );
+
+/**
+ Decode a 64-bit index to determine the offset.
+
+ @param VmPtr A pointer to VM context.s
+ @param CodeOffset Offset from IP of the location of the 64-bit index
+ to decode.
+
+ @return Converted index per EBC VM specification
+
+**/
+INT64
+VmReadIndex64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 CodeOffset
+ );
+
+/**
+ Reads 8-bit data form the memory address.
+
+ @param VmPtr A pointer to VM context.
+ @param Addr The memory address.
+
+ @return The 8-bit value from the memory address.
+
+**/
+UINT8
+VmReadMem8 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ );
+
+/**
+ Reads 16-bit data form the memory address.
+
+ @param VmPtr A pointer to VM context.
+ @param Addr The memory address.
+
+ @return The 16-bit value from the memory address.
+
+**/
+UINT16
+VmReadMem16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ );
+
+/**
+ Reads 32-bit data form the memory address.
+
+ @param VmPtr A pointer to VM context.
+ @param Addr The memory address.
+
+ @return The 32-bit value from the memory address.
+
+**/
+UINT32
+VmReadMem32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ );
+
+/**
+ Reads 64-bit data form the memory address.
+
+ @param VmPtr A pointer to VM context.
+ @param Addr The memory address.
+
+ @return The 64-bit value from the memory address.
+
+**/
+UINT64
+VmReadMem64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ );
+
+/**
+ Read a natural value from memory. May or may not be aligned.
+
+ @param VmPtr current VM context
+ @param Addr the address to read from
+
+ @return The natural value at address Addr.
+
+**/
+UINTN
+VmReadMemN (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ );
+
+/**
+ Writes 8-bit data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMem8 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINT8 Data
+ );
+
+/**
+ Writes 16-bit data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMem16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINT16 Data
+ );
+
+/**
+ Writes 32-bit data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMem32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINT32 Data
+ );
+
+/**
+ Reads 16-bit unsigned data from the code stream.
+
+ This routine provides the ability to read raw unsigned data from the code
+ stream.
+
+ @param VmPtr A pointer to VM context
+ @param Offset Offset from current IP to the raw data to read.
+
+ @return The raw unsigned 16-bit value from the code stream.
+
+**/
+UINT16
+VmReadCode16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ );
+
+/**
+ Reads 32-bit unsigned data from the code stream.
+
+ This routine provides the ability to read raw unsigned data from the code
+ stream.
+
+ @param VmPtr A pointer to VM context
+ @param Offset Offset from current IP to the raw data to read.
+
+ @return The raw unsigned 32-bit value from the code stream.
+
+**/
+UINT32
+VmReadCode32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ );
+
+/**
+ Reads 64-bit unsigned data from the code stream.
+
+ This routine provides the ability to read raw unsigned data from the code
+ stream.
+
+ @param VmPtr A pointer to VM context
+ @param Offset Offset from current IP to the raw data to read.
+
+ @return The raw unsigned 64-bit value from the code stream.
+
+**/
+UINT64
+VmReadCode64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ );
+
+/**
+ Reads 8-bit immediate value at the offset.
+
+ This routine is called by the EBC execute
+ functions to read EBC immediate values from the code stream.
+ Since we can't assume alignment, each tries to read in the biggest
+ chunks size available, but will revert to smaller reads if necessary.
+
+ @param VmPtr A pointer to a VM context.
+ @param Offset offset from IP of the code bytes to read.
+
+ @return Signed data of the requested size from the specified address.
+
+**/
+INT8
+VmReadImmed8 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ );
+
+/**
+ Reads 16-bit immediate value at the offset.
+
+ This routine is called by the EBC execute
+ functions to read EBC immediate values from the code stream.
+ Since we can't assume alignment, each tries to read in the biggest
+ chunks size available, but will revert to smaller reads if necessary.
+
+ @param VmPtr A pointer to a VM context.
+ @param Offset offset from IP of the code bytes to read.
+
+ @return Signed data of the requested size from the specified address.
+
+**/
+INT16
+VmReadImmed16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ );
+
+/**
+ Reads 32-bit immediate value at the offset.
+
+ This routine is called by the EBC execute
+ functions to read EBC immediate values from the code stream.
+ Since we can't assume alignment, each tries to read in the biggest
+ chunks size available, but will revert to smaller reads if necessary.
+
+ @param VmPtr A pointer to a VM context.
+ @param Offset offset from IP of the code bytes to read.
+
+ @return Signed data of the requested size from the specified address.
+
+**/
+INT32
+VmReadImmed32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ );
+
+/**
+ Reads 64-bit immediate value at the offset.
+
+ This routine is called by the EBC execute
+ functions to read EBC immediate values from the code stream.
+ Since we can't assume alignment, each tries to read in the biggest
+ chunks size available, but will revert to smaller reads if necessary.
+
+ @param VmPtr A pointer to a VM context.
+ @param Offset offset from IP of the code bytes to read.
+
+ @return Signed data of the requested size from the specified address.
+
+**/
+INT64
+VmReadImmed64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ );
+
+/**
+ Given an address that EBC is going to read from or write to, return
+ an appropriate address that accounts for a gap in the stack.
+ The stack for this application looks like this (high addr on top)
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+ The EBC assumes that its arguments are at the top of its stack, which
+ is where the VM stack is really. Therefore if the EBC does memory
+ accesses into the VM stack area, then we need to convert the address
+ to point to the EBC entry point arguments area. Do this here.
+
+ @param VmPtr A Pointer to VM context.
+ @param Addr Address of interest
+
+ @return The unchanged address if it's not in the VM stack region. Otherwise,
+ adjust for the stack gap and return the modified address.
+
+**/
+UINTN
+ConvertStackAddr (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ );
+
+/**
+ Execute all the EBC data manipulation instructions.
+ Since the EBC data manipulation instructions all have the same basic form,
+ they can share the code that does the fetch of operands and the write-back
+ of the result. This function performs the fetch of the operands (even if
+ both are not needed to be fetched, like NOT instruction), dispatches to the
+ appropriate subfunction, then writes back the returned result.
+
+ Format:
+ INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
+
+ @param VmPtr A pointer to VM context.
+ @param IsSignedOp Indicates whether the operand is signed or not.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteDataManip (
+ IN VM_CONTEXT *VmPtr,
+ IN BOOLEAN IsSignedOp
+ );
+
+//
+// Functions that execute VM opcodes
+//
+/**
+ Execute the EBC BREAK instruction.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteBREAK (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the JMP instruction.
+
+ Instruction syntax:
+ JMP64{cs|cc} Immed64
+ JMP32{cs|cc} {@}R1 {Immed32|Index32}
+
+ Encoding:
+ b0.7 - immediate data present
+ b0.6 - 1 = 64 bit immediate data
+ 0 = 32 bit immediate data
+ b1.7 - 1 = conditional
+ b1.6 1 = CS (condition set)
+ 0 = CC (condition clear)
+ b1.4 1 = relative address
+ 0 = absolute address
+ b1.3 1 = operand1 indirect
+ b1.2-0 operand 1
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteJMP (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC JMP8 instruction.
+
+ Instruction syntax:
+ JMP8{cs|cc} Offset/2
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteJMP8 (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Implements the EBC CALL instruction.
+
+ Instruction format:
+ CALL64 Immed64
+ CALL32 {@}R1 {Immed32|Index32}
+ CALLEX64 Immed64
+ CALLEX16 {@}R1 {Immed32}
+
+ If Rx == R0, then it's a PC relative call to PC = PC + imm32.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteCALL (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC RET instruction.
+
+ Instruction syntax:
+ RET
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteRET (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC CMP instruction.
+
+ Instruction syntax:
+ CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteCMP (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC CMPI instruction
+
+ Instruction syntax:
+ CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteCMPI (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the MOVxx instructions.
+
+ Instruction format:
+
+ MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
+ MOVqq {@}R1 {Index64}, {@}R2 {Index64}
+
+ Copies contents of [R2] -> [R1], zero extending where required.
+
+ First character indicates the size of the move.
+ Second character indicates the size of the index(s).
+
+ Invalid to have R1 direct with index.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVxx (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC MOVI.
+
+ Instruction syntax:
+
+ MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
+
+ First variable character specifies the move size
+ Second variable character specifies size of the immediate data
+
+ Sign-extend the immediate data to the size of the operation, and zero-extend
+ if storing to a register.
+
+ Operand1 direct with index/immed is invalid.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVI (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC MOV immediate natural. This instruction moves an immediate
+ index value into a register or memory location.
+
+ Instruction syntax:
+
+ MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVIn (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC MOVREL instruction.
+ Dest <- Ip + ImmData
+
+ Instruction syntax:
+
+ MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVREL (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC PUSHn instruction
+
+ Instruction syntax:
+ PUSHn {@}R1 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecutePUSHn (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC PUSH instruction.
+
+ Instruction syntax:
+ PUSH[32|64] {@}R1 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecutePUSH (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC POPn instruction.
+
+ Instruction syntax:
+ POPn {@}R1 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecutePOPn (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC POP instruction.
+
+ Instruction syntax:
+ POPn {@}R1 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecutePOP (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute all the EBC signed data manipulation instructions.
+ Since the EBC data manipulation instructions all have the same basic form,
+ they can share the code that does the fetch of operands and the write-back
+ of the result. This function performs the fetch of the operands (even if
+ both are not needed to be fetched, like NOT instruction), dispatches to the
+ appropriate subfunction, then writes back the returned result.
+
+ Format:
+ INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
+
+ @param VmPtr A pointer to VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteSignedDataManip (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute all the EBC unsigned data manipulation instructions.
+ Since the EBC data manipulation instructions all have the same basic form,
+ they can share the code that does the fetch of operands and the write-back
+ of the result. This function performs the fetch of the operands (even if
+ both are not needed to be fetched, like NOT instruction), dispatches to the
+ appropriate subfunction, then writes back the returned result.
+
+ Format:
+ INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
+
+ @param VmPtr A pointer to VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteUnsignedDataManip (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC LOADSP instruction.
+
+ Instruction syntax:
+ LOADSP SP1, R2
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteLOADSP (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC STORESP instruction.
+
+ Instruction syntax:
+ STORESP Rx, FLAGS|IP
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteSTORESP (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC MOVsnw instruction. This instruction loads a signed
+ natural value from memory or register to another memory or register. On
+ 32-bit machines, the value gets sign-extended to 64 bits if the destination
+ is a register.
+
+ Instruction syntax:
+
+ MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
+
+ 0:7 1=>operand1 index present
+ 0:6 1=>operand2 index present
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVsnd (
+ IN VM_CONTEXT *VmPtr
+ );
+
+/**
+ Execute the EBC MOVsnw instruction. This instruction loads a signed
+ natural value from memory or register to another memory or register. On
+ 32-bit machines, the value gets sign-extended to 64 bits if the destination
+ is a register.
+
+ Instruction syntax:
+
+ MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
+
+ 0:7 1=>operand1 index present
+ 0:6 1=>operand2 index present
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVsnw (
+ IN VM_CONTEXT *VmPtr
+ );
+
+//
+// Data manipulation subfunctions
+//
+/**
+ Execute the EBC NOT instruction.s
+
+ Instruction syntax:
+ NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return ~Op2
+
+**/
+UINT64
+ExecuteNOT (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC NEG instruction.
+
+ Instruction syntax:
+ NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op2 * -1
+
+**/
+UINT64
+ExecuteNEG (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC ADD instruction.
+
+ Instruction syntax:
+ ADD[32|64] {@}R1, {@}R2 {Index16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 + Op2
+
+**/
+UINT64
+ExecuteADD (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC SUB instruction.
+
+ Instruction syntax:
+ SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 - Op2
+
+**/
+UINT64
+ExecuteSUB (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC MUL instruction.
+
+ Instruction syntax:
+ SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 * Op2
+
+**/
+UINT64
+ExecuteMUL (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC MULU instruction
+
+ Instruction syntax:
+ MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (unsigned)Op1 * (unsigned)Op2
+
+**/
+UINT64
+ExecuteMULU (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC DIV instruction.
+
+ Instruction syntax:
+ DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 / Op2
+
+**/
+UINT64
+ExecuteDIV (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC DIVU instruction
+
+ Instruction syntax:
+ DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (unsigned)Op1 / (unsigned)Op2
+
+**/
+UINT64
+ExecuteDIVU (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC MOD instruction.
+
+ Instruction syntax:
+ MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 MODULUS Op2
+
+**/
+UINT64
+ExecuteMOD (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC MODU instruction.
+
+ Instruction syntax:
+ MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 UNSIGNED_MODULUS Op2
+
+**/
+UINT64
+ExecuteMODU (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC AND instruction.
+
+ Instruction syntax:
+ AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 AND Op2
+
+**/
+UINT64
+ExecuteAND (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC OR instruction.
+
+ Instruction syntax:
+ OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 OR Op2
+
+**/
+UINT64
+ExecuteOR (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC XOR instruction.
+
+ Instruction syntax:
+ XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 XOR Op2
+
+**/
+UINT64
+ExecuteXOR (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC SHL shift left instruction.
+
+ Instruction syntax:
+ SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 << Op2
+
+**/
+UINT64
+ExecuteSHL (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC SHR instruction.
+
+ Instruction syntax:
+ SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 >> Op2 (unsigned operands)
+
+**/
+UINT64
+ExecuteSHR (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC ASHR instruction.
+
+ Instruction syntax:
+ ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 >> Op2 (signed)
+
+**/
+UINT64
+ExecuteASHR (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC EXTNDB instruction to sign-extend a byte value.
+
+ Instruction syntax:
+ EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (INT64)(INT8)Op2
+
+**/
+UINT64
+ExecuteEXTNDB (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
+
+ Instruction syntax:
+ EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (INT64)(INT16)Op2
+
+**/
+UINT64
+ExecuteEXTNDW (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+/**
+ Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
+
+ Instruction syntax:
+ EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (INT64)(INT32)Op2
+
+**/
+UINT64
+ExecuteEXTNDD (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ );
+
+//
+// Once we retrieve the operands for the data manipulation instructions,
+// call these functions to perform the operation.
+//
+CONST DATA_MANIP_EXEC_FUNCTION mDataManipDispatchTable[] = {
+ ExecuteNOT,
+ ExecuteNEG,
+ ExecuteADD,
+ ExecuteSUB,
+ ExecuteMUL,
+ ExecuteMULU,
+ ExecuteDIV,
+ ExecuteDIVU,
+ ExecuteMOD,
+ ExecuteMODU,
+ ExecuteAND,
+ ExecuteOR,
+ ExecuteXOR,
+ ExecuteSHL,
+ ExecuteSHR,
+ ExecuteASHR,
+ ExecuteEXTNDB,
+ ExecuteEXTNDW,
+ ExecuteEXTNDD,
+};
+
+CONST VM_TABLE_ENTRY mVmOpcodeTable[] = {
+ { ExecuteBREAK }, // opcode 0x00
+ { ExecuteJMP }, // opcode 0x01
+ { ExecuteJMP8 }, // opcode 0x02
+ { ExecuteCALL }, // opcode 0x03
+ { ExecuteRET }, // opcode 0x04
+ { ExecuteCMP }, // opcode 0x05 CMPeq
+ { ExecuteCMP }, // opcode 0x06 CMPlte
+ { ExecuteCMP }, // opcode 0x07 CMPgte
+ { ExecuteCMP }, // opcode 0x08 CMPulte
+ { ExecuteCMP }, // opcode 0x09 CMPugte
+ { ExecuteUnsignedDataManip }, // opcode 0x0A NOT
+ { ExecuteSignedDataManip }, // opcode 0x0B NEG
+ { ExecuteSignedDataManip }, // opcode 0x0C ADD
+ { ExecuteSignedDataManip }, // opcode 0x0D SUB
+ { ExecuteSignedDataManip }, // opcode 0x0E MUL
+ { ExecuteUnsignedDataManip }, // opcode 0x0F MULU
+ { ExecuteSignedDataManip }, // opcode 0x10 DIV
+ { ExecuteUnsignedDataManip }, // opcode 0x11 DIVU
+ { ExecuteSignedDataManip }, // opcode 0x12 MOD
+ { ExecuteUnsignedDataManip }, // opcode 0x13 MODU
+ { ExecuteUnsignedDataManip }, // opcode 0x14 AND
+ { ExecuteUnsignedDataManip }, // opcode 0x15 OR
+ { ExecuteUnsignedDataManip }, // opcode 0x16 XOR
+ { ExecuteUnsignedDataManip }, // opcode 0x17 SHL
+ { ExecuteUnsignedDataManip }, // opcode 0x18 SHR
+ { ExecuteSignedDataManip }, // opcode 0x19 ASHR
+ { ExecuteUnsignedDataManip }, // opcode 0x1A EXTNDB
+ { ExecuteUnsignedDataManip }, // opcode 0x1B EXTNDW
+ { ExecuteUnsignedDataManip }, // opcode 0x1C EXTNDD
+ { ExecuteMOVxx }, // opcode 0x1D MOVBW
+ { ExecuteMOVxx }, // opcode 0x1E MOVWW
+ { ExecuteMOVxx }, // opcode 0x1F MOVDW
+ { ExecuteMOVxx }, // opcode 0x20 MOVQW
+ { ExecuteMOVxx }, // opcode 0x21 MOVBD
+ { ExecuteMOVxx }, // opcode 0x22 MOVWD
+ { ExecuteMOVxx }, // opcode 0x23 MOVDD
+ { ExecuteMOVxx }, // opcode 0x24 MOVQD
+ { ExecuteMOVsnw }, // opcode 0x25 MOVsnw
+ { ExecuteMOVsnd }, // opcode 0x26 MOVsnd
+ { NULL }, // opcode 0x27
+ { ExecuteMOVxx }, // opcode 0x28 MOVqq
+ { ExecuteLOADSP }, // opcode 0x29 LOADSP SP1, R2
+ { ExecuteSTORESP }, // opcode 0x2A STORESP R1, SP2
+ { ExecutePUSH }, // opcode 0x2B PUSH {@}R1 [imm16]
+ { ExecutePOP }, // opcode 0x2C POP {@}R1 [imm16]
+ { ExecuteCMPI }, // opcode 0x2D CMPIEQ
+ { ExecuteCMPI }, // opcode 0x2E CMPILTE
+ { ExecuteCMPI }, // opcode 0x2F CMPIGTE
+ { ExecuteCMPI }, // opcode 0x30 CMPIULTE
+ { ExecuteCMPI }, // opcode 0x31 CMPIUGTE
+ { ExecuteMOVxx }, // opcode 0x32 MOVN
+ { ExecuteMOVxx }, // opcode 0x33 MOVND
+ { NULL }, // opcode 0x34
+ { ExecutePUSHn }, // opcode 0x35
+ { ExecutePOPn }, // opcode 0x36
+ { ExecuteMOVI }, // opcode 0x37 - mov immediate data
+ { ExecuteMOVIn }, // opcode 0x38 - mov immediate natural
+ { ExecuteMOVREL }, // opcode 0x39 - move data relative to PC
+ { NULL }, // opcode 0x3a
+ { NULL }, // opcode 0x3b
+ { NULL }, // opcode 0x3c
+ { NULL }, // opcode 0x3d
+ { NULL }, // opcode 0x3e
+ { NULL } // opcode 0x3f
+};
+
+//
+// Length of JMP instructions, depending on upper two bits of opcode.
+//
+CONST UINT8 mJMPLen[] = { 2, 2, 6, 10 };
+
+/**
+ Given a pointer to a new VM context, execute one or more instructions. This
+ function is only used for test purposes via the EBC VM test protocol.
+
+ @param This A pointer to the EFI_EBC_VM_TEST_PROTOCOL structure.
+ @param VmPtr A pointer to a VM context.
+ @param InstructionCount A pointer to a UINTN value holding the number of
+ instructions to execute. If it holds value of 0,
+ then the instruction to be executed is 1.
+
+ @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
+ @retval EFI_SUCCESS All of the instructions are executed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcExecuteInstructions (
+ IN EFI_EBC_VM_TEST_PROTOCOL *This,
+ IN VM_CONTEXT *VmPtr,
+ IN OUT UINTN *InstructionCount
+ )
+{
+ UINTN ExecFunc;
+ EFI_STATUS Status;
+ UINTN InstructionsLeft;
+ UINTN SavedInstructionCount;
+
+ Status = EFI_SUCCESS;
+
+ if (*InstructionCount == 0) {
+ InstructionsLeft = 1;
+ } else {
+ InstructionsLeft = *InstructionCount;
+ }
+
+ SavedInstructionCount = *InstructionCount;
+ *InstructionCount = 0;
+
+ //
+ // Index into the opcode table using the opcode byte for this instruction.
+ // This gives you the execute function, which we first test for null, then
+ // call it if it's not null.
+ //
+ while (InstructionsLeft != 0) {
+ ExecFunc = (UINTN) mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction;
+ if (ExecFunc == (UINTN) NULL) {
+ EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE, EXCEPTION_FLAG_FATAL, VmPtr);
+ return EFI_UNSUPPORTED;
+ } else {
+ mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction (VmPtr);
+ *InstructionCount = *InstructionCount + 1;
+ }
+
+ //
+ // Decrement counter if applicable
+ //
+ if (SavedInstructionCount != 0) {
+ InstructionsLeft--;
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Execute an EBC image from an entry point or from a published protocol.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
+ @retval EFI_SUCCESS All of the instructions are executed successfully.
+
+**/
+EFI_STATUS
+EbcExecute (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINTN ExecFunc;
+ UINT8 StackCorrupted;
+ EFI_STATUS Status;
+ EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL *EbcSimpleDebugger;
+
+ mVmPtr = VmPtr;
+ EbcSimpleDebugger = NULL;
+ Status = EFI_SUCCESS;
+ StackCorrupted = 0;
+
+ //
+ // Make sure the magic value has been put on the stack before we got here.
+ //
+ if (*VmPtr->StackMagicPtr != (UINTN) VM_STACK_KEY_VALUE) {
+ StackCorrupted = 1;
+ }
+
+ VmPtr->FramePtr = (VOID *) ((UINT8 *) (UINTN) VmPtr->Gpr[0] + 8);
+
+ //
+ // Try to get the debug support for EBC
+ //
+ DEBUG_CODE_BEGIN ();
+ Status = gBS->LocateProtocol (
+ &gEfiEbcSimpleDebuggerProtocolGuid,
+ NULL,
+ (VOID **) &EbcSimpleDebugger
+ );
+ if (EFI_ERROR (Status)) {
+ EbcSimpleDebugger = NULL;
+ }
+ DEBUG_CODE_END ();
+
+ //
+ // Save the start IP for debug. For example, if we take an exception we
+ // can print out the location of the exception relative to the entry point,
+ // which could then be used in a disassembly listing to find the problem.
+ //
+ VmPtr->EntryPoint = (VOID *) VmPtr->Ip;
+
+ //
+ // We'll wait for this flag to know when we're done. The RET
+ // instruction sets it if it runs out of stack.
+ //
+ VmPtr->StopFlags = 0;
+ while ((VmPtr->StopFlags & STOPFLAG_APP_DONE) == 0) {
+ //
+ // If we've found a simple debugger protocol, call it
+ //
+ DEBUG_CODE_BEGIN ();
+ if (EbcSimpleDebugger != NULL) {
+ EbcSimpleDebugger->Debugger (EbcSimpleDebugger, VmPtr);
+ }
+ DEBUG_CODE_END ();
+
+ //
+ // Use the opcode bits to index into the opcode dispatch table. If the
+ // function pointer is null then generate an exception.
+ //
+ ExecFunc = (UINTN) mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction;
+ if (ExecFunc == (UINTN) NULL) {
+ EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE, EXCEPTION_FLAG_FATAL, VmPtr);
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ EbcDebuggerHookExecuteStart (VmPtr);
+
+ //
+ // The EBC VM is a strongly ordered processor, so perform a fence operation before
+ // and after each instruction is executed.
+ //
+ MemoryFence ();
+
+ mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction (VmPtr);
+
+ MemoryFence ();
+
+ EbcDebuggerHookExecuteEnd (VmPtr);
+
+ //
+ // If the step flag is set, signal an exception and continue. We don't
+ // clear it here. Assuming the debugger is responsible for clearing it.
+ //
+ if (VMFLAG_ISSET (VmPtr, VMFLAGS_STEP)) {
+ EbcDebugSignalException (EXCEPT_EBC_STEP, EXCEPTION_FLAG_NONE, VmPtr);
+ }
+ //
+ // Make sure stack has not been corrupted. Only report it once though.
+ //
+ if ((StackCorrupted == 0) && (*VmPtr->StackMagicPtr != (UINTN) VM_STACK_KEY_VALUE)) {
+ EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT, EXCEPTION_FLAG_FATAL, VmPtr);
+ StackCorrupted = 1;
+ }
+ if ((StackCorrupted == 0) && ((UINT64)VmPtr->Gpr[0] <= (UINT64)(UINTN) VmPtr->StackTop)) {
+ EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT, EXCEPTION_FLAG_FATAL, VmPtr);
+ StackCorrupted = 1;
+ }
+ }
+
+Done:
+ mVmPtr = NULL;
+
+ return Status;
+}
+
+
+/**
+ Execute the MOVxx instructions.
+
+ Instruction format:
+
+ MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
+ MOVqq {@}R1 {Index64}, {@}R2 {Index64}
+
+ Copies contents of [R2] -> [R1], zero extending where required.
+
+ First character indicates the size of the move.
+ Second character indicates the size of the index(s).
+
+ Invalid to have R1 direct with index.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVxx (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 OpcMasked;
+ UINT8 Operands;
+ UINT8 Size;
+ UINT8 MoveSize;
+ INT16 Index16;
+ INT32 Index32;
+ INT64 Index64Op1;
+ INT64 Index64Op2;
+ UINT64 Data64;
+ UINT64 DataMask;
+ UINTN Source;
+
+ Opcode = GETOPCODE (VmPtr);
+ OpcMasked = (UINT8) (Opcode & OPCODE_M_OPCODE);
+
+ //
+ // Get the operands byte so we can get R1 and R2
+ //
+ Operands = GETOPERANDS (VmPtr);
+
+ //
+ // Assume no indexes
+ //
+ Index64Op1 = 0;
+ Index64Op2 = 0;
+ Data64 = 0;
+
+ //
+ // Determine if we have an index/immediate data. Base instruction size
+ // is 2 (opcode + operands). Add to this size each index specified.
+ //
+ Size = 2;
+ if ((Opcode & (OPCODE_M_IMMED_OP1 | OPCODE_M_IMMED_OP2)) != 0) {
+ //
+ // Determine size of the index from the opcode. Then get it.
+ //
+ if ((OpcMasked <= OPCODE_MOVQW) || (OpcMasked == OPCODE_MOVNW)) {
+ //
+ // MOVBW, MOVWW, MOVDW, MOVQW, and MOVNW have 16-bit immediate index.
+ // Get one or both index values.
+ //
+ if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ Index64Op1 = (INT64) Index16;
+ Size += sizeof (UINT16);
+ }
+
+ if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
+ Index16 = VmReadIndex16 (VmPtr, Size);
+ Index64Op2 = (INT64) Index16;
+ Size += sizeof (UINT16);
+ }
+ } else if ((OpcMasked <= OPCODE_MOVQD) || (OpcMasked == OPCODE_MOVND)) {
+ //
+ // MOVBD, MOVWD, MOVDD, MOVQD, and MOVND have 32-bit immediate index
+ //
+ if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
+ Index32 = VmReadIndex32 (VmPtr, 2);
+ Index64Op1 = (INT64) Index32;
+ Size += sizeof (UINT32);
+ }
+
+ if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
+ Index32 = VmReadIndex32 (VmPtr, Size);
+ Index64Op2 = (INT64) Index32;
+ Size += sizeof (UINT32);
+ }
+ } else if (OpcMasked == OPCODE_MOVQQ) {
+ //
+ // MOVqq -- only form with a 64-bit index
+ //
+ if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
+ Index64Op1 = VmReadIndex64 (VmPtr, 2);
+ Size += sizeof (UINT64);
+ }
+
+ if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
+ Index64Op2 = VmReadIndex64 (VmPtr, Size);
+ Size += sizeof (UINT64);
+ }
+ } else {
+ //
+ // Obsolete MOVBQ, MOVWQ, MOVDQ, and MOVNQ have 64-bit immediate index
+ //
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+ }
+ //
+ // Determine the size of the move, and create a mask for it so we can
+ // clear unused bits.
+ //
+ if ((OpcMasked == OPCODE_MOVBW) || (OpcMasked == OPCODE_MOVBD)) {
+ MoveSize = DATA_SIZE_8;
+ DataMask = 0xFF;
+ } else if ((OpcMasked == OPCODE_MOVWW) || (OpcMasked == OPCODE_MOVWD)) {
+ MoveSize = DATA_SIZE_16;
+ DataMask = 0xFFFF;
+ } else if ((OpcMasked == OPCODE_MOVDW) || (OpcMasked == OPCODE_MOVDD)) {
+ MoveSize = DATA_SIZE_32;
+ DataMask = 0xFFFFFFFF;
+ } else if ((OpcMasked == OPCODE_MOVQW) || (OpcMasked == OPCODE_MOVQD) || (OpcMasked == OPCODE_MOVQQ)) {
+ MoveSize = DATA_SIZE_64;
+ DataMask = (UINT64)~0;
+ } else if ((OpcMasked == OPCODE_MOVNW) || (OpcMasked == OPCODE_MOVND)) {
+ MoveSize = DATA_SIZE_N;
+ DataMask = (UINT64)~0 >> (64 - 8 * sizeof (UINTN));
+ } else {
+ //
+ // We were dispatched to this function and we don't recognize the opcode
+ //
+ EbcDebugSignalException (EXCEPT_EBC_UNDEFINED, EXCEPTION_FLAG_FATAL, VmPtr);
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Now get the source address
+ //
+ if (OPERAND2_INDIRECT (Operands)) {
+ //
+ // Indirect form @R2. Compute address of operand2
+ //
+ Source = (UINTN) (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index64Op2);
+ //
+ // Now get the data from the source. Always 0-extend and let the compiler
+ // sign-extend where required.
+ //
+ switch (MoveSize) {
+ case DATA_SIZE_8:
+ Data64 = (UINT64) (UINT8) VmReadMem8 (VmPtr, Source);
+ break;
+
+ case DATA_SIZE_16:
+ Data64 = (UINT64) (UINT16) VmReadMem16 (VmPtr, Source);
+ break;
+
+ case DATA_SIZE_32:
+ Data64 = (UINT64) (UINT32) VmReadMem32 (VmPtr, Source);
+ break;
+
+ case DATA_SIZE_64:
+ Data64 = (UINT64) VmReadMem64 (VmPtr, Source);
+ break;
+
+ case DATA_SIZE_N:
+ Data64 = (UINT64) (UINTN) VmReadMemN (VmPtr, Source);
+ break;
+
+ default:
+ //
+ // not reached
+ //
+ break;
+ }
+ } else {
+ //
+ // Not indirect source: MOVxx {@}Rx, Ry [Index]
+ //
+ Data64 = (UINT64) (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index64Op2);
+ //
+ // Did Operand2 have an index? If so, treat as two signed values since
+ // indexes are signed values.
+ //
+ if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
+ //
+ // NOTE: need to find a way to fix this, most likely by changing the VM
+ // implementation to remove the stack gap. To do that, we'd need to
+ // allocate stack space for the VM and actually set the system
+ // stack pointer to the allocated buffer when the VM starts.
+ //
+ // Special case -- if someone took the address of a function parameter
+ // then we need to make sure it's not in the stack gap. We can identify
+ // this situation if (Operand2 register == 0) && (Operand2 is direct)
+ // && (Index applies to Operand2) && (Index > 0) && (Operand1 register != 0)
+ // Situations that to be aware of:
+ // * stack adjustments at beginning and end of functions R0 = R0 += stacksize
+ //
+ if ((OPERAND2_REGNUM (Operands) == 0) &&
+ (!OPERAND2_INDIRECT (Operands)) &&
+ (Index64Op2 > 0) &&
+ (OPERAND1_REGNUM (Operands) == 0) &&
+ (OPERAND1_INDIRECT (Operands))
+ ) {
+ Data64 = (UINT64) ConvertStackAddr (VmPtr, (UINTN) (INT64) Data64);
+ }
+ }
+ }
+ //
+ // Now write it back
+ //
+ if (OPERAND1_INDIRECT (Operands)) {
+ //
+ // Reuse the Source variable to now be dest.
+ //
+ Source = (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index64Op1);
+ //
+ // Do the write based on the size
+ //
+ switch (MoveSize) {
+ case DATA_SIZE_8:
+ VmWriteMem8 (VmPtr, Source, (UINT8) Data64);
+ break;
+
+ case DATA_SIZE_16:
+ VmWriteMem16 (VmPtr, Source, (UINT16) Data64);
+ break;
+
+ case DATA_SIZE_32:
+ VmWriteMem32 (VmPtr, Source, (UINT32) Data64);
+ break;
+
+ case DATA_SIZE_64:
+ VmWriteMem64 (VmPtr, Source, Data64);
+ break;
+
+ case DATA_SIZE_N:
+ VmWriteMemN (VmPtr, Source, (UINTN) Data64);
+ break;
+
+ default:
+ //
+ // not reached
+ //
+ break;
+ }
+ } else {
+ //
+ // Operand1 direct.
+ // Make sure we didn't have an index on operand1.
+ //
+ if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Direct storage in register. Clear unused bits and store back to
+ // register.
+ //
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Data64 & DataMask;
+ }
+ //
+ // Advance the instruction pointer
+ //
+ VmPtr->Ip += Size;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC BREAK instruction.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteBREAK (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Operands;
+ VOID *EbcEntryPoint;
+ VOID *Thunk;
+ UINT64 U64EbcEntryPoint;
+ INT32 Offset;
+
+ Thunk = NULL;
+ Operands = GETOPERANDS (VmPtr);
+ switch (Operands) {
+ //
+ // Runaway program break. Generate an exception and terminate
+ //
+ case 0:
+ EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK, EXCEPTION_FLAG_FATAL, VmPtr);
+ break;
+
+ //
+ // Get VM version -- return VM revision number in R7
+ //
+ case 1:
+ //
+ // Bits:
+ // 63-17 = 0
+ // 16-8 = Major version
+ // 7-0 = Minor version
+ //
+ VmPtr->Gpr[7] = GetVmVersion ();
+ break;
+
+ //
+ // Debugger breakpoint
+ //
+ case 3:
+ VmPtr->StopFlags |= STOPFLAG_BREAKPOINT;
+ //
+ // See if someone has registered a handler
+ //
+ EbcDebugSignalException (
+ EXCEPT_EBC_BREAKPOINT,
+ EXCEPTION_FLAG_NONE,
+ VmPtr
+ );
+ break;
+
+ //
+ // System call, which there are none, so NOP it.
+ //
+ case 4:
+ break;
+
+ //
+ // Create a thunk for EBC code. R7 points to a 32-bit (in a 64-bit slot)
+ // "offset from self" pointer to the EBC entry point.
+ // After we're done, *(UINT64 *)R7 will be the address of the new thunk.
+ //
+ case 5:
+ Offset = (INT32) VmReadMem32 (VmPtr, (UINTN) VmPtr->Gpr[7]);
+ U64EbcEntryPoint = (UINT64) (VmPtr->Gpr[7] + Offset + 4);
+ EbcEntryPoint = (VOID *) (UINTN) U64EbcEntryPoint;
+
+ //
+ // Now create a new thunk
+ //
+ Status = EbcCreateThunks (VmPtr->ImageHandle, EbcEntryPoint, &Thunk, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Finally replace the EBC entry point memory with the thunk address
+ //
+ VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[7], (UINT64) (UINTN) Thunk);
+ break;
+
+ //
+ // Compiler setting version per value in R7
+ //
+ case 6:
+ VmPtr->CompilerVersion = (UINT32) VmPtr->Gpr[7];
+ //
+ // Check compiler version against VM version?
+ //
+ break;
+
+ //
+ // Unhandled break code. Signal exception.
+ //
+ default:
+ EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK, EXCEPTION_FLAG_FATAL, VmPtr);
+ break;
+ }
+ //
+ // Advance IP
+ //
+ VmPtr->Ip += 2;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the JMP instruction.
+
+ Instruction syntax:
+ JMP64{cs|cc} Immed64
+ JMP32{cs|cc} {@}R1 {Immed32|Index32}
+
+ Encoding:
+ b0.7 - immediate data present
+ b0.6 - 1 = 64 bit immediate data
+ 0 = 32 bit immediate data
+ b1.7 - 1 = conditional
+ b1.6 1 = CS (condition set)
+ 0 = CC (condition clear)
+ b1.4 1 = relative address
+ 0 = absolute address
+ b1.3 1 = operand1 indirect
+ b1.2-0 operand 1
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteJMP (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 CompareSet;
+ UINT8 ConditionFlag;
+ UINT8 Size;
+ UINT8 Operand;
+ UINT64 Data64;
+ INT32 Index32;
+ UINTN Addr;
+
+ Operand = GETOPERANDS (VmPtr);
+ Opcode = GETOPCODE (VmPtr);
+
+ //
+ // Get instruction length from the opcode. The upper two bits are used here
+ // to index into the length array.
+ //
+ Size = mJMPLen[(Opcode >> 6) & 0x03];
+
+ //
+ // Decode instruction conditions
+ // If we haven't met the condition, then simply advance the IP and return.
+ //
+ CompareSet = (UINT8) (((Operand & JMP_M_CS) != 0) ? 1 : 0);
+ ConditionFlag = (UINT8) VMFLAG_ISSET (VmPtr, VMFLAGS_CC);
+ if ((Operand & CONDITION_M_CONDITIONAL) != 0) {
+ if (CompareSet != ConditionFlag) {
+ EbcDebuggerHookJMPStart (VmPtr);
+ VmPtr->Ip += Size;
+ EbcDebuggerHookJMPEnd (VmPtr);
+ return EFI_SUCCESS;
+ }
+ }
+ //
+ // Check for 64-bit form and do it right away since it's the most
+ // straight-forward form.
+ //
+ if ((Opcode & OPCODE_M_IMMDATA64) != 0) {
+ //
+ // Double check for immediate-data, which is required. If not there,
+ // then signal an exception
+ //
+ if ((Opcode & OPCODE_M_IMMDATA) == 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_ERROR,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // 64-bit immediate data is full address. Read the immediate data,
+ // check for alignment, and jump absolute.
+ //
+ Data64 = (UINT64) VmReadImmed64 (VmPtr, 2);
+ if (!IS_ALIGNED ((UINTN) Data64, sizeof (UINT16))) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_ALIGNMENT_CHECK,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Take jump -- relative or absolute
+ //
+ EbcDebuggerHookJMPStart (VmPtr);
+ if ((Operand & JMP_M_RELATIVE) != 0) {
+ VmPtr->Ip += (UINTN) Data64 + Size;
+ } else {
+ VmPtr->Ip = (VMIP) (UINTN) Data64;
+ }
+ EbcDebuggerHookJMPEnd (VmPtr);
+
+ return EFI_SUCCESS;
+ }
+ //
+ // 32-bit forms:
+ // Get the index if there is one. May be either an index, or an immediate
+ // offset depending on indirect operand.
+ // JMP32 @R1 Index32 -- immediate data is an index
+ // JMP32 R1 Immed32 -- immedate data is an offset
+ //
+ if ((Opcode & OPCODE_M_IMMDATA) != 0) {
+ if (OPERAND1_INDIRECT (Operand)) {
+ Index32 = VmReadIndex32 (VmPtr, 2);
+ } else {
+ Index32 = VmReadImmed32 (VmPtr, 2);
+ }
+ } else {
+ Index32 = 0;
+ }
+ //
+ // Get the register data. If R == 0, then special case where it's ignored.
+ //
+ if (OPERAND1_REGNUM (Operand) == 0) {
+ Data64 = 0;
+ } else {
+ Data64 = (UINT64) OPERAND1_REGDATA (VmPtr, Operand);
+ }
+ //
+ // Decode the forms
+ //
+ if (OPERAND1_INDIRECT (Operand)) {
+ //
+ // Form: JMP32 @Rx {Index32}
+ //
+ Addr = VmReadMemN (VmPtr, (UINTN) Data64 + Index32);
+ if (!IS_ALIGNED ((UINTN) Addr, sizeof (UINT16))) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_ALIGNMENT_CHECK,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+
+ return EFI_UNSUPPORTED;
+ }
+
+ EbcDebuggerHookJMPStart (VmPtr);
+ if ((Operand & JMP_M_RELATIVE) != 0) {
+ VmPtr->Ip += (UINTN) Addr + Size;
+ } else {
+ VmPtr->Ip = (VMIP) Addr;
+ }
+ EbcDebuggerHookJMPEnd (VmPtr);
+
+ } else {
+ //
+ // Form: JMP32 Rx {Immed32}
+ //
+ Addr = (UINTN) (Data64 + Index32);
+ if (!IS_ALIGNED ((UINTN) Addr, sizeof (UINT16))) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_ALIGNMENT_CHECK,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+
+ return EFI_UNSUPPORTED;
+ }
+
+ EbcDebuggerHookJMPStart (VmPtr);
+ if ((Operand & JMP_M_RELATIVE) != 0) {
+ VmPtr->Ip += (UINTN) Addr + Size;
+ } else {
+ VmPtr->Ip = (VMIP) Addr;
+ }
+ EbcDebuggerHookJMPEnd (VmPtr);
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC JMP8 instruction.
+
+ Instruction syntax:
+ JMP8{cs|cc} Offset/2
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteJMP8 (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 ConditionFlag;
+ UINT8 CompareSet;
+ INT8 Offset;
+
+ //
+ // Decode instruction.
+ //
+ Opcode = GETOPCODE (VmPtr);
+ CompareSet = (UINT8) (((Opcode & JMP_M_CS) != 0) ? 1 : 0);
+ ConditionFlag = (UINT8) VMFLAG_ISSET (VmPtr, VMFLAGS_CC);
+
+ //
+ // If we haven't met the condition, then simply advance the IP and return
+ //
+ if ((Opcode & CONDITION_M_CONDITIONAL) != 0) {
+ if (CompareSet != ConditionFlag) {
+ EbcDebuggerHookJMP8Start (VmPtr);
+ VmPtr->Ip += 2;
+ EbcDebuggerHookJMP8End (VmPtr);
+ return EFI_SUCCESS;
+ }
+ }
+ //
+ // Get the offset from the instruction stream. It's relative to the
+ // following instruction, and divided by 2.
+ //
+ Offset = VmReadImmed8 (VmPtr, 1);
+ //
+ // Want to check for offset == -2 and then raise an exception?
+ //
+ EbcDebuggerHookJMP8Start (VmPtr);
+ VmPtr->Ip += (Offset * 2) + 2;
+ EbcDebuggerHookJMP8End (VmPtr);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC MOVI.
+
+ Instruction syntax:
+
+ MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
+
+ First variable character specifies the move size
+ Second variable character specifies size of the immediate data
+
+ Sign-extend the immediate data to the size of the operation, and zero-extend
+ if storing to a register.
+
+ Operand1 direct with index/immed is invalid.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVI (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINT8 Size;
+ INT16 Index16;
+ INT64 ImmData64;
+ UINT64 Op1;
+ UINT64 Mask64;
+
+ //
+ // Get the opcode and operands byte so we can get R1 and R2
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+
+ //
+ // Get the index (16-bit) if present
+ //
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ Size = 4;
+ } else {
+ Index16 = 0;
+ Size = 2;
+ }
+ //
+ // Extract the immediate data. Sign-extend always.
+ //
+ if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
+ ImmData64 = (INT64) (INT16) VmReadImmed16 (VmPtr, Size);
+ Size += 2;
+ } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
+ ImmData64 = (INT64) (INT32) VmReadImmed32 (VmPtr, Size);
+ Size += 4;
+ } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
+ ImmData64 = (INT64) VmReadImmed64 (VmPtr, Size);
+ Size += 8;
+ } else {
+ //
+ // Invalid encoding
+ //
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Now write back the result
+ //
+ if (!OPERAND1_INDIRECT (Operands)) {
+ //
+ // Operand1 direct. Make sure it didn't have an index.
+ //
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Writing directly to a register. Clear unused bits.
+ //
+ if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH8) {
+ Mask64 = 0x000000FF;
+ } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH16) {
+ Mask64 = 0x0000FFFF;
+ } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH32) {
+ Mask64 = 0x00000000FFFFFFFF;
+ } else {
+ Mask64 = (UINT64)~0;
+ }
+
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = ImmData64 & Mask64;
+ } else {
+ //
+ // Get the address then write back based on size of the move
+ //
+ Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;
+ if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH8) {
+ VmWriteMem8 (VmPtr, (UINTN) Op1, (UINT8) ImmData64);
+ } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH16) {
+ VmWriteMem16 (VmPtr, (UINTN) Op1, (UINT16) ImmData64);
+ } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH32) {
+ VmWriteMem32 (VmPtr, (UINTN) Op1, (UINT32) ImmData64);
+ } else {
+ VmWriteMem64 (VmPtr, (UINTN) Op1, (UINT64) ImmData64);
+ }
+ }
+ //
+ // Advance the instruction pointer
+ //
+ VmPtr->Ip += Size;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC MOV immediate natural. This instruction moves an immediate
+ index value into a register or memory location.
+
+ Instruction syntax:
+
+ MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVIn (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINT8 Size;
+ INT16 Index16;
+ INT16 ImmedIndex16;
+ INT32 ImmedIndex32;
+ INT64 ImmedIndex64;
+ UINT64 Op1;
+
+ //
+ // Get the opcode and operands byte so we can get R1 and R2
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+
+ //
+ // Get the operand1 index (16-bit) if present
+ //
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ Size = 4;
+ } else {
+ Index16 = 0;
+ Size = 2;
+ }
+ //
+ // Extract the immediate data and convert to a 64-bit index.
+ //
+ if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
+ ImmedIndex16 = VmReadIndex16 (VmPtr, Size);
+ ImmedIndex64 = (INT64) ImmedIndex16;
+ Size += 2;
+ } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
+ ImmedIndex32 = VmReadIndex32 (VmPtr, Size);
+ ImmedIndex64 = (INT64) ImmedIndex32;
+ Size += 4;
+ } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
+ ImmedIndex64 = VmReadIndex64 (VmPtr, Size);
+ Size += 8;
+ } else {
+ //
+ // Invalid encoding
+ //
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Now write back the result
+ //
+ if (!OPERAND1_INDIRECT (Operands)) {
+ //
+ // Check for MOVIn R1 Index16, Immed (not indirect, with index), which
+ // is illegal
+ //
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = ImmedIndex64;
+ } else {
+ //
+ // Get the address
+ //
+ Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;
+ VmWriteMemN (VmPtr, (UINTN) Op1, (UINTN)(INTN) ImmedIndex64);
+ }
+ //
+ // Advance the instruction pointer
+ //
+ VmPtr->Ip += Size;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC MOVREL instruction.
+ Dest <- Ip + ImmData
+
+ Instruction syntax:
+
+ MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVREL (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINT8 Size;
+ INT16 Index16;
+ INT64 ImmData64;
+ UINT64 Op1;
+ UINT64 Op2;
+
+ //
+ // Get the opcode and operands byte so we can get R1 and R2
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+
+ //
+ // Get the Operand 1 index (16-bit) if present
+ //
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ Size = 4;
+ } else {
+ Index16 = 0;
+ Size = 2;
+ }
+ //
+ // Get the immediate data.
+ //
+ if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
+ ImmData64 = (INT64) VmReadImmed16 (VmPtr, Size);
+ Size += 2;
+ } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
+ ImmData64 = (INT64) VmReadImmed32 (VmPtr, Size);
+ Size += 4;
+ } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
+ ImmData64 = VmReadImmed64 (VmPtr, Size);
+ Size += 8;
+ } else {
+ //
+ // Invalid encoding
+ //
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Compute the value and write back the result
+ //
+ Op2 = (UINT64) ((INT64) ((UINT64) (UINTN) VmPtr->Ip) + (INT64) ImmData64 + Size);
+ if (!OPERAND1_INDIRECT (Operands)) {
+ //
+ // Check for illegal combination of operand1 direct with immediate data
+ //
+ if ((Operands & MOVI_M_IMMDATA) != 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (VM_REGISTER) Op2;
+ } else {
+ //
+ // Get the address = [Rx] + Index16
+ // Write back the result. Always a natural size write, since
+ // we're talking addresses here.
+ //
+ Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;
+ VmWriteMemN (VmPtr, (UINTN) Op1, (UINTN) Op2);
+ }
+ //
+ // Advance the instruction pointer
+ //
+ VmPtr->Ip += Size;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC MOVsnw instruction. This instruction loads a signed
+ natural value from memory or register to another memory or register. On
+ 32-bit machines, the value gets sign-extended to 64 bits if the destination
+ is a register.
+
+ Instruction syntax:
+
+ MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
+
+ 0:7 1=>operand1 index present
+ 0:6 1=>operand2 index present
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVsnw (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINT8 Size;
+ INT16 Op1Index;
+ INT16 Op2Index;
+ UINT64 Op2;
+
+ //
+ // Get the opcode and operand bytes
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+
+ Op1Index = Op2Index = 0;
+
+ //
+ // Get the indexes if present.
+ //
+ Size = 2;
+ if ((Opcode & OPCODE_M_IMMED_OP1) !=0) {
+ if (OPERAND1_INDIRECT (Operands)) {
+ Op1Index = VmReadIndex16 (VmPtr, 2);
+ } else {
+ //
+ // Illegal form operand1 direct with index: MOVsnw R1 Index16, {@}R2
+ //
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+
+ Size += sizeof (UINT16);
+ }
+
+ if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
+ if (OPERAND2_INDIRECT (Operands)) {
+ Op2Index = VmReadIndex16 (VmPtr, Size);
+ } else {
+ Op2Index = VmReadImmed16 (VmPtr, Size);
+ }
+
+ Size += sizeof (UINT16);
+ }
+ //
+ // Get the data from the source.
+ //
+ Op2 = (UINT64)(INT64)(INTN)(VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Op2Index);
+ if (OPERAND2_INDIRECT (Operands)) {
+ Op2 = (UINT64)(INT64)(INTN)VmReadMemN (VmPtr, (UINTN) Op2);
+ }
+ //
+ // Now write back the result.
+ //
+ if (!OPERAND1_INDIRECT (Operands)) {
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Op2;
+ } else {
+ VmWriteMemN (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Op1Index), (UINTN) Op2);
+ }
+ //
+ // Advance the instruction pointer
+ //
+ VmPtr->Ip += Size;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC MOVsnw instruction. This instruction loads a signed
+ natural value from memory or register to another memory or register. On
+ 32-bit machines, the value gets sign-extended to 64 bits if the destination
+ is a register.
+
+ Instruction syntax:
+
+ MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
+
+ 0:7 1=>operand1 index present
+ 0:6 1=>operand2 index present
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteMOVsnd (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINT8 Size;
+ INT32 Op1Index;
+ INT32 Op2Index;
+ UINT64 Op2;
+
+ //
+ // Get the opcode and operand bytes
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+
+ Op1Index = Op2Index = 0;
+
+ //
+ // Get the indexes if present.
+ //
+ Size = 2;
+ if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
+ if (OPERAND1_INDIRECT (Operands)) {
+ Op1Index = VmReadIndex32 (VmPtr, 2);
+ } else {
+ //
+ // Illegal form operand1 direct with index: MOVsnd R1 Index16,..
+ //
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return EFI_UNSUPPORTED;
+ }
+
+ Size += sizeof (UINT32);
+ }
+
+ if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
+ if (OPERAND2_INDIRECT (Operands)) {
+ Op2Index = VmReadIndex32 (VmPtr, Size);
+ } else {
+ Op2Index = VmReadImmed32 (VmPtr, Size);
+ }
+
+ Size += sizeof (UINT32);
+ }
+ //
+ // Get the data from the source.
+ //
+ Op2 = (UINT64)(INT64)(INTN)(INT64)(VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Op2Index);
+ if (OPERAND2_INDIRECT (Operands)) {
+ Op2 = (UINT64)(INT64)(INTN)(INT64)VmReadMemN (VmPtr, (UINTN) Op2);
+ }
+ //
+ // Now write back the result.
+ //
+ if (!OPERAND1_INDIRECT (Operands)) {
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Op2;
+ } else {
+ VmWriteMemN (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Op1Index), (UINTN) Op2);
+ }
+ //
+ // Advance the instruction pointer
+ //
+ VmPtr->Ip += Size;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC PUSHn instruction
+
+ Instruction syntax:
+ PUSHn {@}R1 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecutePUSHn (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ INT16 Index16;
+ UINTN DataN;
+
+ //
+ // Get opcode and operands
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+
+ //
+ // Get index if present
+ //
+ if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {
+ if (OPERAND1_INDIRECT (Operands)) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ } else {
+ Index16 = VmReadImmed16 (VmPtr, 2);
+ }
+
+ VmPtr->Ip += 4;
+ } else {
+ Index16 = 0;
+ VmPtr->Ip += 2;
+ }
+ //
+ // Get the data to push
+ //
+ if (OPERAND1_INDIRECT (Operands)) {
+ DataN = VmReadMemN (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16));
+ } else {
+ DataN = (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16);
+ }
+ //
+ // Adjust the stack down.
+ //
+ VmPtr->Gpr[0] -= sizeof (UINTN);
+ VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], DataN);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC PUSH instruction.
+
+ Instruction syntax:
+ PUSH[32|64] {@}R1 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecutePUSH (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINT32 Data32;
+ UINT64 Data64;
+ INT16 Index16;
+
+ //
+ // Get opcode and operands
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+ //
+ // Get immediate index if present, then advance the IP.
+ //
+ if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {
+ if (OPERAND1_INDIRECT (Operands)) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ } else {
+ Index16 = VmReadImmed16 (VmPtr, 2);
+ }
+
+ VmPtr->Ip += 4;
+ } else {
+ Index16 = 0;
+ VmPtr->Ip += 2;
+ }
+ //
+ // Get the data to push
+ //
+ if ((Opcode & PUSHPOP_M_64) != 0) {
+ if (OPERAND1_INDIRECT (Operands)) {
+ Data64 = VmReadMem64 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16));
+ } else {
+ Data64 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;
+ }
+ //
+ // Adjust the stack down, then write back the data
+ //
+ VmPtr->Gpr[0] -= sizeof (UINT64);
+ VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], Data64);
+ } else {
+ //
+ // 32-bit data
+ //
+ if (OPERAND1_INDIRECT (Operands)) {
+ Data32 = VmReadMem32 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16));
+ } else {
+ Data32 = (UINT32) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;
+ }
+ //
+ // Adjust the stack down and write the data
+ //
+ VmPtr->Gpr[0] -= sizeof (UINT32);
+ VmWriteMem32 (VmPtr, (UINTN) VmPtr->Gpr[0], Data32);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC POPn instruction.
+
+ Instruction syntax:
+ POPn {@}R1 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecutePOPn (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ INT16 Index16;
+ UINTN DataN;
+
+ //
+ // Get opcode and operands
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+ //
+ // Get immediate data if present, and advance the IP
+ //
+ if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {
+ if (OPERAND1_INDIRECT (Operands)) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ } else {
+ Index16 = VmReadImmed16 (VmPtr, 2);
+ }
+
+ VmPtr->Ip += 4;
+ } else {
+ Index16 = 0;
+ VmPtr->Ip += 2;
+ }
+ //
+ // Read the data off the stack, then adjust the stack pointer
+ //
+ DataN = VmReadMemN (VmPtr, (UINTN) VmPtr->Gpr[0]);
+ VmPtr->Gpr[0] += sizeof (UINTN);
+ //
+ // Do the write-back
+ //
+ if (OPERAND1_INDIRECT (Operands)) {
+ VmWriteMemN (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16), DataN);
+ } else {
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (INT64) (UINT64) (UINTN) (DataN + Index16);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC POP instruction.
+
+ Instruction syntax:
+ POPn {@}R1 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecutePOP (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ INT16 Index16;
+ INT32 Data32;
+ UINT64 Data64;
+
+ //
+ // Get opcode and operands
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+ //
+ // Get immediate data if present, and advance the IP.
+ //
+ if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {
+ if (OPERAND1_INDIRECT (Operands)) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ } else {
+ Index16 = VmReadImmed16 (VmPtr, 2);
+ }
+
+ VmPtr->Ip += 4;
+ } else {
+ Index16 = 0;
+ VmPtr->Ip += 2;
+ }
+ //
+ // Get the data off the stack, then write it to the appropriate location
+ //
+ if ((Opcode & PUSHPOP_M_64) != 0) {
+ //
+ // Read the data off the stack, then adjust the stack pointer
+ //
+ Data64 = VmReadMem64 (VmPtr, (UINTN) VmPtr->Gpr[0]);
+ VmPtr->Gpr[0] += sizeof (UINT64);
+ //
+ // Do the write-back
+ //
+ if (OPERAND1_INDIRECT (Operands)) {
+ VmWriteMem64 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16), Data64);
+ } else {
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Data64 + Index16;
+ }
+ } else {
+ //
+ // 32-bit pop. Read it off the stack and adjust the stack pointer
+ //
+ Data32 = (INT32) VmReadMem32 (VmPtr, (UINTN) VmPtr->Gpr[0]);
+ VmPtr->Gpr[0] += sizeof (UINT32);
+ //
+ // Do the write-back
+ //
+ if (OPERAND1_INDIRECT (Operands)) {
+ VmWriteMem32 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16), Data32);
+ } else {
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (INT64) Data32 + Index16;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Implements the EBC CALL instruction.
+
+ Instruction format:
+ CALL64 Immed64
+ CALL32 {@}R1 {Immed32|Index32}
+ CALLEX64 Immed64
+ CALLEX16 {@}R1 {Immed32}
+
+ If Rx == R0, then it's a PC relative call to PC = PC + imm32.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteCALL (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ INT32 Immed32;
+ UINT8 Size;
+ INT64 Immed64;
+ VOID *FramePtr;
+
+ //
+ // Get opcode and operands
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+
+ if ((Operands & OPERAND_M_NATIVE_CALL) != 0) {
+ EbcDebuggerHookCALLEXStart (VmPtr);
+ } else {
+ EbcDebuggerHookCALLStart (VmPtr);
+ }
+
+ //
+ // Assign these as well to avoid compiler warnings
+ //
+ Immed64 = 0;
+ Immed32 = 0;
+
+ FramePtr = VmPtr->FramePtr;
+ //
+ // Determine the instruction size, and get immediate data if present
+ //
+ if ((Opcode & OPCODE_M_IMMDATA) != 0) {
+ if ((Opcode & OPCODE_M_IMMDATA64) != 0) {
+ Immed64 = VmReadImmed64 (VmPtr, 2);
+ Size = 10;
+ } else {
+ //
+ // If register operand is indirect, then the immediate data is an index
+ //
+ if (OPERAND1_INDIRECT (Operands)) {
+ Immed32 = VmReadIndex32 (VmPtr, 2);
+ } else {
+ Immed32 = VmReadImmed32 (VmPtr, 2);
+ }
+
+ Size = 6;
+ }
+ } else {
+ Size = 2;
+ }
+ //
+ // If it's a call to EBC, adjust the stack pointer down 16 bytes and
+ // put our return address and frame pointer on the VM stack.
+ //
+ if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {
+ VmPtr->Gpr[0] -= 8;
+ VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], (UINTN) FramePtr);
+ VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0];
+ VmPtr->Gpr[0] -= 8;
+ VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (VmPtr->Ip + Size));
+ }
+ //
+ // If 64-bit data, then absolute jump only
+ //
+ if ((Opcode & OPCODE_M_IMMDATA64) != 0) {
+ //
+ // Native or EBC call?
+ //
+ if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {
+ VmPtr->Ip = (VMIP) (UINTN) Immed64;
+ } else {
+ //
+ // Call external function, get the return value, and advance the IP
+ //
+ EbcLLCALLEX (VmPtr, (UINTN) Immed64, (UINTN) VmPtr->Gpr[0], FramePtr, Size);
+ }
+ } else {
+ //
+ // Get the register data. If operand1 == 0, then ignore register and
+ // take immediate data as relative or absolute address.
+ // Compiler should take care of upper bits if 32-bit machine.
+ //
+ if (OPERAND1_REGNUM (Operands) != 0) {
+ Immed64 = (UINT64) (UINTN) VmPtr->Gpr[OPERAND1_REGNUM (Operands)];
+ }
+ //
+ // Get final address
+ //
+ if (OPERAND1_INDIRECT (Operands)) {
+ Immed64 = (INT64) (UINT64) (UINTN) VmReadMemN (VmPtr, (UINTN) (Immed64 + Immed32));
+ } else {
+ Immed64 += Immed32;
+ }
+ //
+ // Now determine if external call, and then if relative or absolute
+ //
+ if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {
+ //
+ // EBC call. Relative or absolute? If relative, then it's relative to the
+ // start of the next instruction.
+ //
+ if ((Operands & OPERAND_M_RELATIVE_ADDR) != 0) {
+ VmPtr->Ip += Immed64 + Size;
+ } else {
+ VmPtr->Ip = (VMIP) (UINTN) Immed64;
+ }
+ } else {
+ //
+ // Native call. Relative or absolute?
+ //
+ if ((Operands & OPERAND_M_RELATIVE_ADDR) != 0) {
+ EbcLLCALLEX (VmPtr, (UINTN) (Immed64 + VmPtr->Ip + Size), (UINTN) VmPtr->Gpr[0], FramePtr, Size);
+ } else {
+ if ((VmPtr->StopFlags & STOPFLAG_BREAK_ON_CALLEX) != 0) {
+ CpuBreakpoint ();
+ }
+
+ EbcLLCALLEX (VmPtr, (UINTN) Immed64, (UINTN) VmPtr->Gpr[0], FramePtr, Size);
+ }
+ }
+ }
+
+ if ((Operands & OPERAND_M_NATIVE_CALL) != 0) {
+ EbcDebuggerHookCALLEXEnd (VmPtr);
+ } else {
+ EbcDebuggerHookCALLEnd (VmPtr);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC RET instruction.
+
+ Instruction syntax:
+ RET
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteRET (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+
+ EbcDebuggerHookRETStart (VmPtr);
+
+ //
+ // If we're at the top of the stack, then simply set the done
+ // flag and return
+ //
+ if (VmPtr->StackRetAddr == (UINT64) VmPtr->Gpr[0]) {
+ VmPtr->StopFlags |= STOPFLAG_APP_DONE;
+ } else {
+ //
+ // Pull the return address off the VM app's stack and set the IP
+ // to it
+ //
+ if (!IS_ALIGNED ((UINTN) VmPtr->Gpr[0], sizeof (UINT16))) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_ALIGNMENT_CHECK,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ }
+ //
+ // Restore the IP and frame pointer from the stack
+ //
+ VmPtr->Ip = (VMIP) (UINTN) VmReadMem64 (VmPtr, (UINTN) VmPtr->Gpr[0]);
+ VmPtr->Gpr[0] += 8;
+ VmPtr->FramePtr = (VOID *) VmReadMemN (VmPtr, (UINTN) VmPtr->Gpr[0]);
+ VmPtr->Gpr[0] += 8;
+ }
+
+
+ EbcDebuggerHookRETEnd (VmPtr);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC CMP instruction.
+
+ Instruction syntax:
+ CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteCMP (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINT8 Size;
+ INT16 Index16;
+ UINT32 Flag;
+ INT64 Op2;
+ INT64 Op1;
+
+ //
+ // Get opcode and operands
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+ //
+ // Get the register data we're going to compare to
+ //
+ Op1 = VmPtr->Gpr[OPERAND1_REGNUM (Operands)];
+ //
+ // Get immediate data
+ //
+ if ((Opcode & OPCODE_M_IMMDATA) != 0) {
+ if (OPERAND2_INDIRECT (Operands)) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ } else {
+ Index16 = VmReadImmed16 (VmPtr, 2);
+ }
+
+ Size = 4;
+ } else {
+ Index16 = 0;
+ Size = 2;
+ }
+ //
+ // Now get Op2
+ //
+ if (OPERAND2_INDIRECT (Operands)) {
+ if ((Opcode & OPCODE_M_64BIT) != 0) {
+ Op2 = (INT64) VmReadMem64 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index16));
+ } else {
+ //
+ // 32-bit operations. 0-extend the values for all cases.
+ //
+ Op2 = (INT64) (UINT64) ((UINT32) VmReadMem32 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index16)));
+ }
+ } else {
+ Op2 = VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index16;
+ }
+ //
+ // Now do the compare
+ //
+ Flag = 0;
+ if ((Opcode & OPCODE_M_64BIT) != 0) {
+ //
+ // 64-bit compares
+ //
+ switch (Opcode & OPCODE_M_OPCODE) {
+ case OPCODE_CMPEQ:
+ if (Op1 == Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPLTE:
+ if (Op1 <= Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPGTE:
+ if (Op1 >= Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPULTE:
+ if ((UINT64) Op1 <= (UINT64) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPUGTE:
+ if ((UINT64) Op1 >= (UINT64) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ default:
+ ASSERT (0);
+ }
+ } else {
+ //
+ // 32-bit compares
+ //
+ switch (Opcode & OPCODE_M_OPCODE) {
+ case OPCODE_CMPEQ:
+ if ((INT32) Op1 == (INT32) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPLTE:
+ if ((INT32) Op1 <= (INT32) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPGTE:
+ if ((INT32) Op1 >= (INT32) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPULTE:
+ if ((UINT32) Op1 <= (UINT32) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPUGTE:
+ if ((UINT32) Op1 >= (UINT32) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ default:
+ ASSERT (0);
+ }
+ }
+ //
+ // Now set the flag accordingly for the comparison
+ //
+ if (Flag != 0) {
+ VMFLAG_SET (VmPtr, VMFLAGS_CC);
+ } else {
+ VMFLAG_CLEAR (VmPtr, (UINT64)VMFLAGS_CC);
+ }
+ //
+ // Advance the IP
+ //
+ VmPtr->Ip += Size;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC CMPI instruction
+
+ Instruction syntax:
+ CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteCMPI (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Opcode;
+ UINT8 Operands;
+ UINT8 Size;
+ INT64 Op1;
+ INT64 Op2;
+ INT16 Index16;
+ UINT32 Flag;
+
+ //
+ // Get opcode and operands
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+
+ //
+ // Get operand1 index if present
+ //
+ Size = 2;
+ if ((Operands & OPERAND_M_CMPI_INDEX) != 0) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ Size += 2;
+ } else {
+ Index16 = 0;
+ }
+ //
+ // Get operand1 data we're going to compare to
+ //
+ Op1 = (INT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)];
+ if (OPERAND1_INDIRECT (Operands)) {
+ //
+ // Indirect operand1. Fetch 32 or 64-bit value based on compare size.
+ //
+ if ((Opcode & OPCODE_M_CMPI64) != 0) {
+ Op1 = (INT64) VmReadMem64 (VmPtr, (UINTN) Op1 + Index16);
+ } else {
+ Op1 = (INT64) VmReadMem32 (VmPtr, (UINTN) Op1 + Index16);
+ }
+ } else {
+ //
+ // Better not have been an index with direct. That is, CMPI R1 Index,...
+ // is illegal.
+ //
+ if ((Operands & OPERAND_M_CMPI_INDEX) != 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_ERROR,
+ VmPtr
+ );
+ VmPtr->Ip += Size;
+ return EFI_UNSUPPORTED;
+ }
+ }
+ //
+ // Get immediate data -- 16- or 32-bit sign extended
+ //
+ if ((Opcode & OPCODE_M_CMPI32_DATA) != 0) {
+ Op2 = (INT64) VmReadImmed32 (VmPtr, Size);
+ Size += 4;
+ } else {
+ //
+ // 16-bit immediate data. Sign extend always.
+ //
+ Op2 = (INT64) ((INT16) VmReadImmed16 (VmPtr, Size));
+ Size += 2;
+ }
+ //
+ // Now do the compare
+ //
+ Flag = 0;
+ if ((Opcode & OPCODE_M_CMPI64) != 0) {
+ //
+ // 64 bit comparison
+ //
+ switch (Opcode & OPCODE_M_OPCODE) {
+ case OPCODE_CMPIEQ:
+ if (Op1 == (INT64) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPILTE:
+ if (Op1 <= (INT64) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPIGTE:
+ if (Op1 >= (INT64) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPIULTE:
+ if ((UINT64) Op1 <= (UINT64) ((UINT32) Op2)) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPIUGTE:
+ if ((UINT64) Op1 >= (UINT64) ((UINT32) Op2)) {
+ Flag = 1;
+ }
+ break;
+
+ default:
+ ASSERT (0);
+ }
+ } else {
+ //
+ // 32-bit comparisons
+ //
+ switch (Opcode & OPCODE_M_OPCODE) {
+ case OPCODE_CMPIEQ:
+ if ((INT32) Op1 == Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPILTE:
+ if ((INT32) Op1 <= Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPIGTE:
+ if ((INT32) Op1 >= Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPIULTE:
+ if ((UINT32) Op1 <= (UINT32) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ case OPCODE_CMPIUGTE:
+ if ((UINT32) Op1 >= (UINT32) Op2) {
+ Flag = 1;
+ }
+ break;
+
+ default:
+ ASSERT (0);
+ }
+ }
+ //
+ // Now set the flag accordingly for the comparison
+ //
+ if (Flag != 0) {
+ VMFLAG_SET (VmPtr, VMFLAGS_CC);
+ } else {
+ VMFLAG_CLEAR (VmPtr, (UINT64)VMFLAGS_CC);
+ }
+ //
+ // Advance the IP
+ //
+ VmPtr->Ip += Size;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC NOT instruction.s
+
+ Instruction syntax:
+ NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return ~Op2
+
+**/
+UINT64
+ExecuteNOT (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ return ~Op2;
+}
+
+
+/**
+ Execute the EBC NEG instruction.
+
+ Instruction syntax:
+ NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op2 * -1
+
+**/
+UINT64
+ExecuteNEG (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ return ~Op2 + 1;
+}
+
+
+/**
+ Execute the EBC ADD instruction.
+
+ Instruction syntax:
+ ADD[32|64] {@}R1, {@}R2 {Index16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 + Op2
+
+**/
+UINT64
+ExecuteADD (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ return Op1 + Op2;
+}
+
+
+/**
+ Execute the EBC SUB instruction.
+
+ Instruction syntax:
+ SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 - Op2
+
+**/
+UINT64
+ExecuteSUB (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
+ return (UINT64) ((INT64) ((INT64) Op1 - (INT64) Op2));
+ } else {
+ return (UINT64) ((INT64) ((INT32) ((INT32) Op1 - (INT32) Op2)));
+ }
+}
+
+
+/**
+ Execute the EBC MUL instruction.
+
+ Instruction syntax:
+ SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 * Op2
+
+**/
+UINT64
+ExecuteMUL (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
+ return MultS64x64 ((INT64)Op1, (INT64)Op2);
+ } else {
+ return (UINT64) ((INT64) ((INT32) ((INT32) Op1 * (INT32) Op2)));
+ }
+}
+
+
+/**
+ Execute the EBC MULU instruction
+
+ Instruction syntax:
+ MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (unsigned)Op1 * (unsigned)Op2
+
+**/
+UINT64
+ExecuteMULU (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
+ return MultU64x64 (Op1, Op2);
+ } else {
+ return (UINT64) ((UINT32) ((UINT32) Op1 * (UINT32) Op2));
+ }
+}
+
+
+/**
+ Execute the EBC DIV instruction.
+
+ Instruction syntax:
+ DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 / Op2
+
+**/
+UINT64
+ExecuteDIV (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ INT64 Remainder;
+
+ //
+ // Check for divide-by-0
+ //
+ if (Op2 == 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_DIVIDE_ERROR,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+
+ return 0;
+ } else {
+ if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
+ return (UINT64) (DivS64x64Remainder (Op1, Op2, &Remainder));
+ } else {
+ return (UINT64) ((INT64) ((INT32) Op1 / (INT32) Op2));
+ }
+ }
+}
+
+
+/**
+ Execute the EBC DIVU instruction
+
+ Instruction syntax:
+ DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (unsigned)Op1 / (unsigned)Op2
+
+**/
+UINT64
+ExecuteDIVU (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ UINT64 Remainder;
+
+ //
+ // Check for divide-by-0
+ //
+ if (Op2 == 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_DIVIDE_ERROR,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return 0;
+ } else {
+ //
+ // Get the destination register
+ //
+ if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
+ return (UINT64) (DivU64x64Remainder (Op1, Op2, &Remainder));
+ } else {
+ return (UINT64) ((UINT32) Op1 / (UINT32) Op2);
+ }
+ }
+}
+
+
+/**
+ Execute the EBC MOD instruction.
+
+ Instruction syntax:
+ MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 MODULUS Op2
+
+**/
+UINT64
+ExecuteMOD (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ INT64 Remainder;
+
+ //
+ // Check for divide-by-0
+ //
+ if (Op2 == 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_DIVIDE_ERROR,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return 0;
+ } else {
+ DivS64x64Remainder ((INT64)Op1, (INT64)Op2, &Remainder);
+ return Remainder;
+ }
+}
+
+
+/**
+ Execute the EBC MODU instruction.
+
+ Instruction syntax:
+ MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 UNSIGNED_MODULUS Op2
+
+**/
+UINT64
+ExecuteMODU (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ UINT64 Remainder;
+
+ //
+ // Check for divide-by-0
+ //
+ if (Op2 == 0) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_DIVIDE_ERROR,
+ EXCEPTION_FLAG_FATAL,
+ VmPtr
+ );
+ return 0;
+ } else {
+ DivU64x64Remainder (Op1, Op2, &Remainder);
+ return Remainder;
+ }
+}
+
+
+/**
+ Execute the EBC AND instruction.
+
+ Instruction syntax:
+ AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 AND Op2
+
+**/
+UINT64
+ExecuteAND (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ return Op1 & Op2;
+}
+
+
+/**
+ Execute the EBC OR instruction.
+
+ Instruction syntax:
+ OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 OR Op2
+
+**/
+UINT64
+ExecuteOR (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ return Op1 | Op2;
+}
+
+
+/**
+ Execute the EBC XOR instruction.
+
+ Instruction syntax:
+ XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 XOR Op2
+
+**/
+UINT64
+ExecuteXOR (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ return Op1 ^ Op2;
+}
+
+
+/**
+ Execute the EBC SHL shift left instruction.
+
+ Instruction syntax:
+ SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 << Op2
+
+**/
+UINT64
+ExecuteSHL (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
+ return LShiftU64 (Op1, (UINTN)Op2);
+ } else {
+ return (UINT64) ((UINT32) ((UINT32) Op1 << (UINT32) Op2));
+ }
+}
+
+
+/**
+ Execute the EBC SHR instruction.
+
+ Instruction syntax:
+ SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 >> Op2 (unsigned operands)
+
+**/
+UINT64
+ExecuteSHR (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
+ return RShiftU64 (Op1, (UINTN)Op2);
+ } else {
+ return (UINT64) ((UINT32) Op1 >> (UINT32) Op2);
+ }
+}
+
+
+/**
+ Execute the EBC ASHR instruction.
+
+ Instruction syntax:
+ ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return Op1 >> Op2 (signed)
+
+**/
+UINT64
+ExecuteASHR (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
+ return ARShiftU64 (Op1, (UINTN)Op2);
+ } else {
+ return (UINT64) ((INT64) ((INT32) Op1 >> (UINT32) Op2));
+ }
+}
+
+
+/**
+ Execute the EBC EXTNDB instruction to sign-extend a byte value.
+
+ Instruction syntax:
+ EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (INT64)(INT8)Op2
+
+**/
+UINT64
+ExecuteEXTNDB (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ INT8 Data8;
+ INT64 Data64;
+ //
+ // Convert to byte, then return as 64-bit signed value to let compiler
+ // sign-extend the value
+ //
+ Data8 = (INT8) Op2;
+ Data64 = (INT64) Data8;
+
+ return (UINT64) Data64;
+}
+
+
+/**
+ Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
+
+ Instruction syntax:
+ EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (INT64)(INT16)Op2
+
+**/
+UINT64
+ExecuteEXTNDW (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ INT16 Data16;
+ INT64 Data64;
+ //
+ // Convert to word, then return as 64-bit signed value to let compiler
+ // sign-extend the value
+ //
+ Data16 = (INT16) Op2;
+ Data64 = (INT64) Data16;
+
+ return (UINT64) Data64;
+}
+//
+// Execute the EBC EXTNDD instruction.
+//
+// Format: EXTNDD {@}Rx, {@}Ry [Index16|Immed16]
+// EXTNDD Dest, Source
+//
+// Operation: Dest <- SignExtended((DWORD)Source))
+//
+
+/**
+ Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
+
+ Instruction syntax:
+ EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
+
+ @param VmPtr A pointer to a VM context.
+ @param Op1 Operand 1 from the instruction
+ @param Op2 Operand 2 from the instruction
+
+ @return (INT64)(INT32)Op2
+
+**/
+UINT64
+ExecuteEXTNDD (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Op1,
+ IN UINT64 Op2
+ )
+{
+ INT32 Data32;
+ INT64 Data64;
+ //
+ // Convert to 32-bit value, then return as 64-bit signed value to let compiler
+ // sign-extend the value
+ //
+ Data32 = (INT32) Op2;
+ Data64 = (INT64) Data32;
+
+ return (UINT64) Data64;
+}
+
+
+/**
+ Execute all the EBC signed data manipulation instructions.
+ Since the EBC data manipulation instructions all have the same basic form,
+ they can share the code that does the fetch of operands and the write-back
+ of the result. This function performs the fetch of the operands (even if
+ both are not needed to be fetched, like NOT instruction), dispatches to the
+ appropriate subfunction, then writes back the returned result.
+
+ Format:
+ INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
+
+ @param VmPtr A pointer to VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteSignedDataManip (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ //
+ // Just call the data manipulation function with a flag indicating this
+ // is a signed operation.
+ //
+ return ExecuteDataManip (VmPtr, TRUE);
+}
+
+
+/**
+ Execute all the EBC unsigned data manipulation instructions.
+ Since the EBC data manipulation instructions all have the same basic form,
+ they can share the code that does the fetch of operands and the write-back
+ of the result. This function performs the fetch of the operands (even if
+ both are not needed to be fetched, like NOT instruction), dispatches to the
+ appropriate subfunction, then writes back the returned result.
+
+ Format:
+ INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
+
+ @param VmPtr A pointer to VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteUnsignedDataManip (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ //
+ // Just call the data manipulation function with a flag indicating this
+ // is not a signed operation.
+ //
+ return ExecuteDataManip (VmPtr, FALSE);
+}
+
+
+/**
+ Execute all the EBC data manipulation instructions.
+ Since the EBC data manipulation instructions all have the same basic form,
+ they can share the code that does the fetch of operands and the write-back
+ of the result. This function performs the fetch of the operands (even if
+ both are not needed to be fetched, like NOT instruction), dispatches to the
+ appropriate subfunction, then writes back the returned result.
+
+ Format:
+ INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
+
+ @param VmPtr A pointer to VM context.
+ @param IsSignedOp Indicates whether the operand is signed or not.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteDataManip (
+ IN VM_CONTEXT *VmPtr,
+ IN BOOLEAN IsSignedOp
+ )
+{
+ UINT8 Opcode;
+ INT16 Index16;
+ UINT8 Operands;
+ UINT8 Size;
+ UINT64 Op1;
+ UINT64 Op2;
+ INTN DataManipDispatchTableIndex;
+
+ //
+ // Get opcode and operands
+ //
+ Opcode = GETOPCODE (VmPtr);
+ Operands = GETOPERANDS (VmPtr);
+
+ //
+ // Determine if we have immediate data by the opcode
+ //
+ if ((Opcode & DATAMANIP_M_IMMDATA) != 0) {
+ //
+ // Index16 if Ry is indirect, or Immed16 if Ry direct.
+ //
+ if (OPERAND2_INDIRECT (Operands)) {
+ Index16 = VmReadIndex16 (VmPtr, 2);
+ } else {
+ Index16 = VmReadImmed16 (VmPtr, 2);
+ }
+
+ Size = 4;
+ } else {
+ Index16 = 0;
+ Size = 2;
+ }
+ //
+ // Now get operand2 (source). It's of format {@}R2 {Index16|Immed16}
+ //
+ Op2 = (UINT64) VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index16;
+ if (OPERAND2_INDIRECT (Operands)) {
+ //
+ // Indirect form: @R2 Index16. Fetch as 32- or 64-bit data
+ //
+ if ((Opcode & DATAMANIP_M_64) != 0) {
+ Op2 = VmReadMem64 (VmPtr, (UINTN) Op2);
+ } else {
+ //
+ // Read as signed value where appropriate.
+ //
+ if (IsSignedOp) {
+ Op2 = (UINT64) (INT64) ((INT32) VmReadMem32 (VmPtr, (UINTN) Op2));
+ } else {
+ Op2 = (UINT64) VmReadMem32 (VmPtr, (UINTN) Op2);
+ }
+ }
+ } else {
+ if ((Opcode & DATAMANIP_M_64) == 0) {
+ if (IsSignedOp) {
+ Op2 = (UINT64) (INT64) ((INT32) Op2);
+ } else {
+ Op2 = (UINT64) ((UINT32) Op2);
+ }
+ }
+ }
+ //
+ // Get operand1 (destination and sometimes also an actual operand)
+ // of form {@}R1
+ //
+ Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)];
+ if (OPERAND1_INDIRECT (Operands)) {
+ if ((Opcode & DATAMANIP_M_64) != 0) {
+ Op1 = VmReadMem64 (VmPtr, (UINTN) Op1);
+ } else {
+ if (IsSignedOp) {
+ Op1 = (UINT64) (INT64) ((INT32) VmReadMem32 (VmPtr, (UINTN) Op1));
+ } else {
+ Op1 = (UINT64) VmReadMem32 (VmPtr, (UINTN) Op1);
+ }
+ }
+ } else {
+ if ((Opcode & DATAMANIP_M_64) == 0) {
+ if (IsSignedOp) {
+ Op1 = (UINT64) (INT64) ((INT32) Op1);
+ } else {
+ Op1 = (UINT64) ((UINT32) Op1);
+ }
+ }
+ }
+ //
+ // Dispatch to the computation function
+ //
+ DataManipDispatchTableIndex = (Opcode & OPCODE_M_OPCODE) - OPCODE_NOT;
+ if ((DataManipDispatchTableIndex < 0) ||
+ (DataManipDispatchTableIndex >= ARRAY_SIZE (mDataManipDispatchTable))) {
+ EbcDebugSignalException (
+ EXCEPT_EBC_INVALID_OPCODE,
+ EXCEPTION_FLAG_ERROR,
+ VmPtr
+ );
+ //
+ // Advance and return
+ //
+ VmPtr->Ip += Size;
+ return EFI_UNSUPPORTED;
+ } else {
+ Op2 = mDataManipDispatchTable[DataManipDispatchTableIndex](VmPtr, Op1, Op2);
+ }
+ //
+ // Write back the result.
+ //
+ if (OPERAND1_INDIRECT (Operands)) {
+ Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)];
+ if ((Opcode & DATAMANIP_M_64) != 0) {
+ VmWriteMem64 (VmPtr, (UINTN) Op1, Op2);
+ } else {
+ VmWriteMem32 (VmPtr, (UINTN) Op1, (UINT32) Op2);
+ }
+ } else {
+ //
+ // Storage back to a register. Write back, clearing upper bits (as per
+ // the specification) if 32-bit operation.
+ //
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Op2;
+ if ((Opcode & DATAMANIP_M_64) == 0) {
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] &= 0xFFFFFFFF;
+ }
+ }
+ //
+ // Advance the instruction pointer
+ //
+ VmPtr->Ip += Size;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC LOADSP instruction.
+
+ Instruction syntax:
+ LOADSP SP1, R2
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteLOADSP (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Operands;
+
+ //
+ // Get the operands
+ //
+ Operands = GETOPERANDS (VmPtr);
+
+ //
+ // Do the operation
+ //
+ switch (OPERAND1_REGNUM (Operands)) {
+ //
+ // Set flags
+ //
+ case 0:
+ //
+ // Spec states that this instruction will not modify reserved bits in
+ // the flags register.
+ //
+ VmPtr->Flags = (VmPtr->Flags &~VMFLAGS_ALL_VALID) | (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] & VMFLAGS_ALL_VALID);
+ break;
+
+ default:
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_WARNING,
+ VmPtr
+ );
+ VmPtr->Ip += 2;
+ return EFI_UNSUPPORTED;
+ }
+
+ VmPtr->Ip += 2;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Execute the EBC STORESP instruction.
+
+ Instruction syntax:
+ STORESP Rx, FLAGS|IP
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
+ @retval EFI_SUCCESS The instruction is executed successfully.
+
+**/
+EFI_STATUS
+ExecuteSTORESP (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ UINT8 Operands;
+
+ //
+ // Get the operands
+ //
+ Operands = GETOPERANDS (VmPtr);
+
+ //
+ // Do the operation
+ //
+ switch (OPERAND2_REGNUM (Operands)) {
+ //
+ // Get flags
+ //
+ case 0:
+ //
+ // Retrieve the value in the flags register, then clear reserved bits
+ //
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (UINT64) (VmPtr->Flags & VMFLAGS_ALL_VALID);
+ break;
+
+ //
+ // Get IP -- address of following instruction
+ //
+ case 1:
+ VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (UINT64) (UINTN) VmPtr->Ip + 2;
+ break;
+
+ default:
+ EbcDebugSignalException (
+ EXCEPT_EBC_INSTRUCTION_ENCODING,
+ EXCEPTION_FLAG_WARNING,
+ VmPtr
+ );
+ VmPtr->Ip += 2;
+ return EFI_UNSUPPORTED;
+ break;
+ }
+
+ VmPtr->Ip += 2;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Decode a 16-bit index to determine the offset. Given an index value:
+
+ b15 - sign bit
+ b14:12 - number of bits in this index assigned to natural units (=a)
+ ba:11 - constant units = ConstUnits
+ b0:a - natural units = NaturalUnits
+
+ Given this info, the offset can be computed by:
+ offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
+
+ Max offset is achieved with index = 0x7FFF giving an offset of
+ 0x27B (32-bit machine) or 0x477 (64-bit machine).
+ Min offset is achieved with index =
+
+ @param VmPtr A pointer to VM context.
+ @param CodeOffset Offset from IP of the location of the 16-bit index
+ to decode.
+
+ @return The decoded offset.
+
+**/
+INT16
+VmReadIndex16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 CodeOffset
+ )
+{
+ UINT16 Index;
+ INT16 Offset;
+ INT16 ConstUnits;
+ INT16 NaturalUnits;
+ INT16 NBits;
+ INT16 Mask;
+
+ //
+ // First read the index from the code stream
+ //
+ Index = VmReadCode16 (VmPtr, CodeOffset);
+
+ //
+ // Get the mask for NaturalUnits. First get the number of bits from the index.
+ //
+ NBits = (INT16) ((Index & 0x7000) >> 12);
+
+ //
+ // Scale it for 16-bit indexes
+ //
+ NBits *= 2;
+
+ //
+ // Now using the number of bits, create a mask.
+ //
+ Mask = (INT16) ((INT16)~0 << NBits);
+
+ //
+ // Now using the mask, extract NaturalUnits from the lower bits of the index.
+ //
+ NaturalUnits = (INT16) (Index &~Mask);
+
+ //
+ // Now compute ConstUnits
+ //
+ ConstUnits = (INT16) (((Index &~0xF000) & Mask) >> NBits);
+
+ Offset = (INT16) (NaturalUnits * sizeof (UINTN) + ConstUnits);
+
+ //
+ // Now set the sign
+ //
+ if ((Index & 0x8000) != 0) {
+ //
+ // Do it the hard way to work around a bogus compiler warning
+ //
+ // Offset = -1 * Offset;
+ //
+ Offset = (INT16) ((INT32) Offset * -1);
+ }
+
+ return Offset;
+}
+
+
+/**
+ Decode a 32-bit index to determine the offset.
+
+ @param VmPtr A pointer to VM context.
+ @param CodeOffset Offset from IP of the location of the 32-bit index
+ to decode.
+
+ @return Converted index per EBC VM specification.
+
+**/
+INT32
+VmReadIndex32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 CodeOffset
+ )
+{
+ UINT32 Index;
+ INT32 Offset;
+ INT32 ConstUnits;
+ INT32 NaturalUnits;
+ INT32 NBits;
+ INT32 Mask;
+
+ Index = VmReadImmed32 (VmPtr, CodeOffset);
+
+ //
+ // Get the mask for NaturalUnits. First get the number of bits from the index.
+ //
+ NBits = (Index & 0x70000000) >> 28;
+
+ //
+ // Scale it for 32-bit indexes
+ //
+ NBits *= 4;
+
+ //
+ // Now using the number of bits, create a mask.
+ //
+ Mask = (INT32)~0 << NBits;
+
+ //
+ // Now using the mask, extract NaturalUnits from the lower bits of the index.
+ //
+ NaturalUnits = Index &~Mask;
+
+ //
+ // Now compute ConstUnits
+ //
+ ConstUnits = ((Index &~0xF0000000) & Mask) >> NBits;
+
+ Offset = NaturalUnits * sizeof (UINTN) + ConstUnits;
+
+ //
+ // Now set the sign
+ //
+ if ((Index & 0x80000000) != 0) {
+ Offset = Offset * -1;
+ }
+
+ return Offset;
+}
+
+
+/**
+ Decode a 64-bit index to determine the offset.
+
+ @param VmPtr A pointer to VM context.s
+ @param CodeOffset Offset from IP of the location of the 64-bit index
+ to decode.
+
+ @return Converted index per EBC VM specification
+
+**/
+INT64
+VmReadIndex64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 CodeOffset
+ )
+{
+ UINT64 Index;
+ INT64 Offset;
+ INT64 ConstUnits;
+ INT64 NaturalUnits;
+ INT64 NBits;
+ INT64 Mask;
+
+ Index = VmReadCode64 (VmPtr, CodeOffset);
+
+ //
+ // Get the mask for NaturalUnits. First get the number of bits from the index.
+ //
+ NBits = RShiftU64 ((Index & 0x7000000000000000ULL), 60);
+
+ //
+ // Scale it for 64-bit indexes (multiply by 8 by shifting left 3)
+ //
+ NBits = LShiftU64 ((UINT64)NBits, 3);
+
+ //
+ // Now using the number of bits, create a mask.
+ //
+ Mask = (LShiftU64 ((UINT64)~0, (UINTN)NBits));
+
+ //
+ // Now using the mask, extract NaturalUnits from the lower bits of the index.
+ //
+ NaturalUnits = Index &~Mask;
+
+ //
+ // Now compute ConstUnits
+ //
+ ConstUnits = ARShiftU64 (((Index &~0xF000000000000000ULL) & Mask), (UINTN)NBits);
+
+ Offset = MultU64x64 ((UINT64) NaturalUnits, sizeof (UINTN)) + ConstUnits;
+
+ //
+ // Now set the sign
+ //
+ if ((Index & 0x8000000000000000ULL) != 0) {
+ Offset = MultS64x64 (Offset, -1);
+ }
+
+ return Offset;
+}
+
+
+/**
+ Writes 8-bit data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMem8 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINT8 Data
+ )
+{
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+ *(UINT8 *) Addr = Data;
+ return EFI_SUCCESS;
+}
+
+/**
+ Writes 16-bit data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMem16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINT16 Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+
+ //
+ // Do a simple write if aligned
+ //
+ if (IS_ALIGNED (Addr, sizeof (UINT16))) {
+ *(UINT16 *) Addr = Data;
+ } else {
+ //
+ // Write as two bytes
+ //
+ MemoryFence ();
+ if ((Status = VmWriteMem8 (VmPtr, Addr, (UINT8) Data)) != EFI_SUCCESS) {
+ return Status;
+ }
+
+ MemoryFence ();
+ if ((Status = VmWriteMem8 (VmPtr, Addr + 1, (UINT8) (Data >> 8))) != EFI_SUCCESS) {
+ return Status;
+ }
+
+ MemoryFence ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Writes 32-bit data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMem32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINT32 Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+
+ //
+ // Do a simple write if aligned
+ //
+ if (IS_ALIGNED (Addr, sizeof (UINT32))) {
+ *(UINT32 *) Addr = Data;
+ } else {
+ //
+ // Write as two words
+ //
+ MemoryFence ();
+ if ((Status = VmWriteMem16 (VmPtr, Addr, (UINT16) Data)) != EFI_SUCCESS) {
+ return Status;
+ }
+
+ MemoryFence ();
+ if ((Status = VmWriteMem16 (VmPtr, Addr + sizeof (UINT16), (UINT16) (Data >> 16))) != EFI_SUCCESS) {
+ return Status;
+ }
+
+ MemoryFence ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Writes 64-bit data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMem64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINT64 Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+
+ //
+ // Do a simple write if aligned
+ //
+ if (IS_ALIGNED (Addr, sizeof (UINT64))) {
+ *(UINT64 *) Addr = Data;
+ } else {
+ //
+ // Write as two 32-bit words
+ //
+ MemoryFence ();
+ if ((Status = VmWriteMem32 (VmPtr, Addr, (UINT32) Data)) != EFI_SUCCESS) {
+ return Status;
+ }
+
+ MemoryFence ();
+ if ((Status = VmWriteMem32 (VmPtr, Addr + sizeof (UINT32), (UINT32) RShiftU64(Data, 32))) != EFI_SUCCESS) {
+ return Status;
+ }
+
+ MemoryFence ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Writes UINTN data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMemN (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINTN Data
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+
+ //
+ // Do a simple write if aligned
+ //
+ if (IS_ALIGNED (Addr, sizeof (UINTN))) {
+ *(UINTN *) Addr = Data;
+ } else {
+ for (Index = 0; Index < sizeof (UINTN) / sizeof (UINT32); Index++) {
+ MemoryFence ();
+ Status = VmWriteMem32 (VmPtr, Addr + Index * sizeof (UINT32), (UINT32) Data);
+ MemoryFence ();
+ Data = (UINTN) RShiftU64 ((UINT64)Data, 32);
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Reads 8-bit immediate value at the offset.
+
+ This routine is called by the EBC execute
+ functions to read EBC immediate values from the code stream.
+ Since we can't assume alignment, each tries to read in the biggest
+ chunks size available, but will revert to smaller reads if necessary.
+
+ @param VmPtr A pointer to a VM context.
+ @param Offset offset from IP of the code bytes to read.
+
+ @return Signed data of the requested size from the specified address.
+
+**/
+INT8
+VmReadImmed8 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ )
+{
+ //
+ // Simply return the data in flat memory space
+ //
+ return * (INT8 *) (VmPtr->Ip + Offset);
+}
+
+/**
+ Reads 16-bit immediate value at the offset.
+
+ This routine is called by the EBC execute
+ functions to read EBC immediate values from the code stream.
+ Since we can't assume alignment, each tries to read in the biggest
+ chunks size available, but will revert to smaller reads if necessary.
+
+ @param VmPtr A pointer to a VM context.
+ @param Offset offset from IP of the code bytes to read.
+
+ @return Signed data of the requested size from the specified address.
+
+**/
+INT16
+VmReadImmed16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ )
+{
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (INT16))) {
+ return * (INT16 *) (VmPtr->Ip + Offset);
+ } else {
+ //
+ // All code word reads should be aligned
+ //
+ EbcDebugSignalException (
+ EXCEPT_EBC_ALIGNMENT_CHECK,
+ EXCEPTION_FLAG_WARNING,
+ VmPtr
+ );
+ }
+ //
+ // Return unaligned data
+ //
+ return (INT16) (*(UINT8 *) (VmPtr->Ip + Offset) + (*(UINT8 *) (VmPtr->Ip + Offset + 1) << 8));
+}
+
+
+/**
+ Reads 32-bit immediate value at the offset.
+
+ This routine is called by the EBC execute
+ functions to read EBC immediate values from the code stream.
+ Since we can't assume alignment, each tries to read in the biggest
+ chunks size available, but will revert to smaller reads if necessary.
+
+ @param VmPtr A pointer to a VM context.
+ @param Offset offset from IP of the code bytes to read.
+
+ @return Signed data of the requested size from the specified address.
+
+**/
+INT32
+VmReadImmed32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT32))) {
+ return * (INT32 *) (VmPtr->Ip + Offset);
+ }
+ //
+ // Return unaligned data
+ //
+ Data = (UINT32) VmReadCode16 (VmPtr, Offset);
+ Data |= (UINT32)(VmReadCode16 (VmPtr, Offset + 2) << 16);
+ return Data;
+}
+
+
+/**
+ Reads 64-bit immediate value at the offset.
+
+ This routine is called by the EBC execute
+ functions to read EBC immediate values from the code stream.
+ Since we can't assume alignment, each tries to read in the biggest
+ chunks size available, but will revert to smaller reads if necessary.
+
+ @param VmPtr A pointer to a VM context.
+ @param Offset offset from IP of the code bytes to read.
+
+ @return Signed data of the requested size from the specified address.
+
+**/
+INT64
+VmReadImmed64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ )
+{
+ UINT64 Data64;
+ UINT32 Data32;
+ UINT8 *Ptr;
+
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT64))) {
+ return * (UINT64 *) (VmPtr->Ip + Offset);
+ }
+ //
+ // Return unaligned data.
+ //
+ Ptr = (UINT8 *) &Data64;
+ Data32 = VmReadCode32 (VmPtr, Offset);
+ *(UINT32 *) Ptr = Data32;
+ Ptr += sizeof (Data32);
+ Data32 = VmReadCode32 (VmPtr, Offset + sizeof (UINT32));
+ *(UINT32 *) Ptr = Data32;
+ return Data64;
+}
+
+
+/**
+ Reads 16-bit unsigned data from the code stream.
+
+ This routine provides the ability to read raw unsigned data from the code
+ stream.
+
+ @param VmPtr A pointer to VM context
+ @param Offset Offset from current IP to the raw data to read.
+
+ @return The raw unsigned 16-bit value from the code stream.
+
+**/
+UINT16
+VmReadCode16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ )
+{
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT16))) {
+ return * (UINT16 *) (VmPtr->Ip + Offset);
+ } else {
+ //
+ // All code word reads should be aligned
+ //
+ EbcDebugSignalException (
+ EXCEPT_EBC_ALIGNMENT_CHECK,
+ EXCEPTION_FLAG_WARNING,
+ VmPtr
+ );
+ }
+ //
+ // Return unaligned data
+ //
+ return (UINT16) (*(UINT8 *) (VmPtr->Ip + Offset) + (*(UINT8 *) (VmPtr->Ip + Offset + 1) << 8));
+}
+
+
+/**
+ Reads 32-bit unsigned data from the code stream.
+
+ This routine provides the ability to read raw unsigned data from the code
+ stream.
+
+ @param VmPtr A pointer to VM context
+ @param Offset Offset from current IP to the raw data to read.
+
+ @return The raw unsigned 32-bit value from the code stream.
+
+**/
+UINT32
+VmReadCode32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT32))) {
+ return * (UINT32 *) (VmPtr->Ip + Offset);
+ }
+ //
+ // Return unaligned data
+ //
+ Data = (UINT32) VmReadCode16 (VmPtr, Offset);
+ Data |= (VmReadCode16 (VmPtr, Offset + 2) << 16);
+ return Data;
+}
+
+
+/**
+ Reads 64-bit unsigned data from the code stream.
+
+ This routine provides the ability to read raw unsigned data from the code
+ stream.
+
+ @param VmPtr A pointer to VM context
+ @param Offset Offset from current IP to the raw data to read.
+
+ @return The raw unsigned 64-bit value from the code stream.
+
+**/
+UINT64
+VmReadCode64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT32 Offset
+ )
+{
+ UINT64 Data64;
+ UINT32 Data32;
+ UINT8 *Ptr;
+
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT64))) {
+ return * (UINT64 *) (VmPtr->Ip + Offset);
+ }
+ //
+ // Return unaligned data.
+ //
+ Ptr = (UINT8 *) &Data64;
+ Data32 = VmReadCode32 (VmPtr, Offset);
+ *(UINT32 *) Ptr = Data32;
+ Ptr += sizeof (Data32);
+ Data32 = VmReadCode32 (VmPtr, Offset + sizeof (UINT32));
+ *(UINT32 *) Ptr = Data32;
+ return Data64;
+}
+
+
+/**
+ Reads 8-bit data form the memory address.
+
+ @param VmPtr A pointer to VM context.
+ @param Addr The memory address.
+
+ @return The 8-bit value from the memory address.
+
+**/
+UINT8
+VmReadMem8 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ )
+{
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+ //
+ // Simply return the data in flat memory space
+ //
+ return * (UINT8 *) Addr;
+}
+
+/**
+ Reads 16-bit data form the memory address.
+
+ @param VmPtr A pointer to VM context.
+ @param Addr The memory address.
+
+ @return The 16-bit value from the memory address.
+
+**/
+UINT16
+VmReadMem16 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ )
+{
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED (Addr, sizeof (UINT16))) {
+ return * (UINT16 *) Addr;
+ }
+ //
+ // Return unaligned data
+ //
+ return (UINT16) (*(UINT8 *) Addr + (*(UINT8 *) (Addr + 1) << 8));
+}
+
+/**
+ Reads 32-bit data form the memory address.
+
+ @param VmPtr A pointer to VM context.
+ @param Addr The memory address.
+
+ @return The 32-bit value from the memory address.
+
+**/
+UINT32
+VmReadMem32 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ )
+{
+ UINT32 Data;
+
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED (Addr, sizeof (UINT32))) {
+ return * (UINT32 *) Addr;
+ }
+ //
+ // Return unaligned data
+ //
+ Data = (UINT32) VmReadMem16 (VmPtr, Addr);
+ Data |= (VmReadMem16 (VmPtr, Addr + 2) << 16);
+ return Data;
+}
+
+/**
+ Reads 64-bit data form the memory address.
+
+ @param VmPtr A pointer to VM context.
+ @param Addr The memory address.
+
+ @return The 64-bit value from the memory address.
+
+**/
+UINT64
+VmReadMem64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ )
+{
+ UINT64 Data;
+ UINT32 Data32;
+
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED (Addr, sizeof (UINT64))) {
+ return * (UINT64 *) Addr;
+ }
+ //
+ // Return unaligned data. Assume little endian.
+ //
+ Data32 = VmReadMem32 (VmPtr, Addr);
+ Data = (UINT64) VmReadMem32 (VmPtr, Addr + sizeof (UINT32));
+ Data = LShiftU64 (Data, 32) | Data32;
+ return Data;
+}
+
+
+/**
+ Given an address that EBC is going to read from or write to, return
+ an appropriate address that accounts for a gap in the stack.
+ The stack for this application looks like this (high addr on top)
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+ The EBC assumes that its arguments are at the top of its stack, which
+ is where the VM stack is really. Therefore if the EBC does memory
+ accesses into the VM stack area, then we need to convert the address
+ to point to the EBC entry point arguments area. Do this here.
+
+ @param VmPtr A Pointer to VM context.
+ @param Addr Address of interest
+
+ @return The unchanged address if it's not in the VM stack region. Otherwise,
+ adjust for the stack gap and return the modified address.
+
+**/
+UINTN
+ConvertStackAddr (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ )
+{
+ ASSERT(((Addr < VmPtr->LowStackTop) || (Addr > VmPtr->HighStackBottom)));
+ return Addr;
+}
+
+
+/**
+ Read a natural value from memory. May or may not be aligned.
+
+ @param VmPtr current VM context
+ @param Addr the address to read from
+
+ @return The natural value at address Addr.
+
+**/
+UINTN
+VmReadMemN (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr
+ )
+{
+ UINTN Data;
+ volatile UINT32 Size;
+ UINT8 *FromPtr;
+ UINT8 *ToPtr;
+ //
+ // Convert the address if it's in the stack gap
+ //
+ Addr = ConvertStackAddr (VmPtr, Addr);
+ //
+ // Read direct if aligned
+ //
+ if (IS_ALIGNED (Addr, sizeof (UINTN))) {
+ return * (UINTN *) Addr;
+ }
+ //
+ // Return unaligned data
+ //
+ Data = 0;
+ FromPtr = (UINT8 *) Addr;
+ ToPtr = (UINT8 *) &Data;
+
+ for (Size = 0; Size < sizeof (Data); Size++) {
+ *ToPtr = *FromPtr;
+ ToPtr++;
+ FromPtr++;
+ }
+
+ return Data;
+}
+
+/**
+ Returns the version of the EBC virtual machine.
+
+ @return The 64-bit version of EBC virtual machine.
+
+**/
+UINT64
+GetVmVersion (
+ VOID
+ )
+{
+ return (UINT64) (((VM_MAJOR_VERSION & 0xFFFF) << 16) | ((VM_MINOR_VERSION & 0xFFFF)));
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcExecute.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcExecute.h
new file mode 100644
index 000000000..1cb68bc53
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcExecute.h
@@ -0,0 +1,135 @@
+/** @file
+ Header file for Virtual Machine support. Contains EBC defines that can
+ be of use to a disassembler for the most part. Also provides function
+ prototypes for VM functions.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EBC_EXECUTE_H_
+#define _EBC_EXECUTE_H_
+
+//
+// Macros to check and set alignment
+//
+#define ASSERT_ALIGNED(addr, size) ASSERT (!((UINT32) (addr) & (size - 1)))
+#define IS_ALIGNED(addr, size) !((UINT32) (addr) & (size - 1))
+
+//
+// Debug macro
+//
+#define EBCMSG(s) gST->ConOut->OutputString (gST->ConOut, s)
+
+
+/**
+ Execute an EBC image from an entry point or from a published protocol.
+
+ @param VmPtr A pointer to a VM context.
+
+ @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
+ @retval EFI_SUCCESS All of the instructions are executed successfully.
+
+**/
+EFI_STATUS
+EbcExecute (
+ IN VM_CONTEXT *VmPtr
+ );
+
+
+
+/**
+ Returns the version of the EBC virtual machine.
+
+ @return The 64-bit version of EBC virtual machine.
+
+**/
+UINT64
+GetVmVersion (
+ VOID
+ );
+
+/**
+ Writes UINTN data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMemN (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINTN Data
+ );
+
+/**
+ Writes 64-bit data to memory address.
+
+ This routine is called by the EBC data
+ movement instructions that write to memory. Since these writes
+ may be to the stack, which looks like (high address on top) this,
+
+ [EBC entry point arguments]
+ [VM stack]
+ [EBC stack]
+
+ we need to detect all attempts to write to the EBC entry point argument
+ stack area and adjust the address (which will initially point into the
+ VM stack) to point into the EBC entry point arguments.
+
+ @param VmPtr A pointer to a VM context.
+ @param Addr Address to write to.
+ @param Data Value to write to Addr.
+
+ @retval EFI_SUCCESS The instruction is executed successfully.
+ @retval Other Some error occurs when writing data to the address.
+
+**/
+EFI_STATUS
+VmWriteMem64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN Addr,
+ IN UINT64 Data
+ );
+
+/**
+ Given a pointer to a new VM context, execute one or more instructions. This
+ function is only used for test purposes via the EBC VM test protocol.
+
+ @param This A pointer to the EFI_EBC_VM_TEST_PROTOCOL structure.
+ @param VmPtr A pointer to a VM context.
+ @param InstructionCount A pointer to a UINTN value holding the number of
+ instructions to execute. If it holds value of 0,
+ then the instruction to be executed is 1.
+
+ @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
+ @retval EFI_SUCCESS All of the instructions are executed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcExecuteInstructions (
+ IN EFI_EBC_VM_TEST_PROTOCOL *This,
+ IN VM_CONTEXT *VmPtr,
+ IN OUT UINTN *InstructionCount
+ );
+
+#endif // ifndef _EBC_EXECUTE_H_
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcInt.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcInt.c
new file mode 100644
index 000000000..eced1d5c7
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcInt.c
@@ -0,0 +1,1542 @@
+/** @file
+ Top level module for the EBC virtual machine implementation.
+ Provides auxiliary support routines for the VM. That is, routines
+ that are not particularly related to VM execution of EBC instructions.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EbcInt.h"
+#include "EbcExecute.h"
+#include "EbcDebuggerHook.h"
+
+//
+// We'll keep track of all thunks we create in a linked list. Each
+// thunk is tied to an image handle, so we have a linked list of
+// image handles, with each having a linked list of thunks allocated
+// to that image handle.
+//
+typedef struct _EBC_THUNK_LIST EBC_THUNK_LIST;
+struct _EBC_THUNK_LIST {
+ VOID *ThunkBuffer;
+ EBC_THUNK_LIST *Next;
+};
+
+typedef struct _EBC_IMAGE_LIST EBC_IMAGE_LIST;
+struct _EBC_IMAGE_LIST {
+ EBC_IMAGE_LIST *Next;
+ EFI_HANDLE ImageHandle;
+ EBC_THUNK_LIST *ThunkList;
+};
+
+/**
+ This routine is called by the core when an image is being unloaded from
+ memory. Basically we now have the opportunity to do any necessary cleanup.
+ Typically this will include freeing any memory allocated for thunk-creation.
+
+ @param This A pointer to the EFI_EBC_PROTOCOL instance.
+ @param ImageHandle Handle of image for which the thunk is being
+ created.
+
+ @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the
+ internal list of EBC image handles.
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcUnloadImage (
+ IN EFI_EBC_PROTOCOL *This,
+ IN EFI_HANDLE ImageHandle
+ );
+
+/**
+ This is the top-level routine plugged into the EBC protocol. Since thunks
+ are very processor-specific, from here we dispatch directly to the very
+ processor-specific routine EbcCreateThunks().
+
+ @param This A pointer to the EFI_EBC_PROTOCOL instance.
+ @param ImageHandle Handle of image for which the thunk is being
+ created. The EBC interpreter may use this to
+ keep track of any resource allocations
+ performed in loading and executing the image.
+ @param EbcEntryPoint Address of the actual EBC entry point or
+ protocol service the thunk should call.
+ @param Thunk Returned pointer to a thunk created.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Image entry point is not 2-byte aligned.
+ @retval EFI_OUT_OF_RESOURCES Memory could not be allocated for the thunk.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcCreateThunk (
+ IN EFI_EBC_PROTOCOL *This,
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *EbcEntryPoint,
+ OUT VOID **Thunk
+ );
+
+/**
+ Called to get the version of the interpreter.
+
+ @param This A pointer to the EFI_EBC_PROTOCOL instance.
+ @param Version Pointer to where to store the returned version
+ of the interpreter.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Version pointer is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcGetVersion (
+ IN EFI_EBC_PROTOCOL *This,
+ IN OUT UINT64 *Version
+ );
+
+/**
+ To install default Callback function for the VM interpreter.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval Others Some error occurs when creating periodic event.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeEbcCallback (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This
+ );
+
+/**
+ The default Exception Callback for the VM interpreter.
+ In this function, we report status code, and print debug information
+ about EBC_CONTEXT, then dead loop.
+
+ @param InterruptType Interrupt type.
+ @param SystemContext EBC system context.
+
+**/
+VOID
+EFIAPI
+CommonEbcExceptionHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+/**
+ The periodic callback function for EBC VM interpreter, which is used
+ to support the EFI debug support protocol.
+
+ @param Event The Periodic Callback Event.
+ @param Context It should be the address of VM_CONTEXT pointer.
+
+**/
+VOID
+EFIAPI
+EbcPeriodicNotifyFunction (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ The VM interpreter calls this function on a periodic basis to support
+ the EFI debug support protocol.
+
+ @param VmPtr Pointer to a VM context for passing info to the
+ debugger.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugPeriodic (
+ IN VM_CONTEXT *VmPtr
+ );
+
+//
+// These two functions and the GUID are used to produce an EBC test protocol.
+// This functionality is definitely not required for execution.
+//
+/**
+ Produces an EBC VM test protocol that can be used for regression tests.
+
+ @param IHandle Handle on which to install the protocol.
+
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+InitEbcVmTestProtocol (
+ IN EFI_HANDLE *IHandle
+ );
+
+/**
+ Returns the EFI_UNSUPPORTED Status.
+
+ @return EFI_UNSUPPORTED This function always return EFI_UNSUPPORTED status.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcVmTestUnsupported (
+ VOID
+ );
+
+/**
+ Registers a callback function that the EBC interpreter calls to flush the
+ processor instruction cache following creation of thunks.
+
+ @param This A pointer to the EFI_EBC_PROTOCOL instance.
+ @param Flush Pointer to a function of type EBC_ICACH_FLUSH.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcRegisterICacheFlush (
+ IN EFI_EBC_PROTOCOL *This,
+ IN EBC_ICACHE_FLUSH Flush
+ );
+
+/**
+ This EBC debugger protocol service is called by the debug agent
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+ @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the
+ maximum supported processor index is returned.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugGetMaximumProcessorIndex (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ OUT UINTN *MaxProcessorIndex
+ );
+
+/**
+ This protocol service is called by the debug agent to register a function
+ for us to call on a periodic basis.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+ @param ProcessorIndex Specifies which processor the callback function
+ applies to.
+ @param PeriodicCallback A pointer to a function of type
+ PERIODIC_CALLBACK that is the main periodic
+ entry point of the debug agent. It receives as a
+ parameter a pointer to the full context of the
+ interrupted execution thread.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a
+ callback function was previously registered.
+ @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no
+ callback function was previously registered.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugRegisterPeriodicCallback (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_PERIODIC_CALLBACK PeriodicCallback
+ );
+
+/**
+ This protocol service is called by the debug agent to register a function
+ for us to call when we detect an exception.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+ @param ProcessorIndex Specifies which processor the callback function
+ applies to.
+ @param ExceptionCallback A pointer to a function of type
+ EXCEPTION_CALLBACK that is called when the
+ processor exception specified by ExceptionType
+ occurs. Passing NULL unregisters any previously
+ registered function associated with
+ ExceptionType.
+ @param ExceptionType Specifies which processor exception to hook.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ALREADY_STARTED Non-NULL ExceptionCallback parameter when a
+ callback function was previously registered.
+ @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds
+ MAX_EBC_EXCEPTION.
+ @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no
+ callback function was previously registered.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugRegisterExceptionCallback (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
+ IN EFI_EXCEPTION_TYPE ExceptionType
+ );
+
+/**
+ This EBC debugger protocol service is called by the debug agent. Required
+ for DebugSupport compliance but is only stubbed out for EBC.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+ @param ProcessorIndex Specifies which processor the callback function
+ applies to.
+ @param Start StartSpecifies the physical base of the memory
+ range to be invalidated.
+ @param Length Specifies the minimum number of bytes in the
+ processor's instruction cache to invalidate.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugInvalidateInstructionCache (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN VOID *Start,
+ IN UINT64 Length
+ );
+
+//
+// We have one linked list of image handles for the whole world. Since
+// there should only be one interpreter, make them global. They must
+// also be global since the execution of an EBC image does not provide
+// a This pointer.
+//
+EBC_IMAGE_LIST *mEbcImageList = NULL;
+
+//
+// Callback function to flush the icache after thunk creation
+//
+EBC_ICACHE_FLUSH mEbcICacheFlush;
+
+//
+// These get set via calls by the debug agent
+//
+EFI_PERIODIC_CALLBACK mDebugPeriodicCallback = NULL;
+EFI_EXCEPTION_CALLBACK mDebugExceptionCallback[MAX_EBC_EXCEPTION + 1] = {NULL};
+
+VOID *mStackBuffer[MAX_STACK_NUM];
+EFI_HANDLE mStackBufferIndex[MAX_STACK_NUM];
+UINTN mStackNum = 0;
+
+//
+// Event for Periodic callback
+//
+EFI_EVENT mEbcPeriodicEvent;
+VM_CONTEXT *mVmPtr = NULL;
+
+/**
+ Check whether the emulator supports executing a certain PE/COFF image
+
+ @param[in] This This pointer for EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
+ structure
+ @param[in] ImageType Whether the image is an application, a boot time
+ driver or a runtime driver.
+ @param[in] DevicePath Path to device where the image originated
+ (e.g., a PCI option ROM)
+
+ @retval TRUE The image is supported by the emulator
+ @retval FALSE The image is not supported by the emulator.
+**/
+BOOLEAN
+EFIAPI
+EbcIsImageSupported (
+ IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
+ IN UINT16 ImageType,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL
+ )
+{
+ if (ImageType != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION &&
+ ImageType != EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ Register a supported PE/COFF image with the emulator. After this call
+ completes successfully, the PE/COFF image may be started as usual, and
+ it is the responsibility of the emulator implementation that any branch
+ into the code section of the image (including returns from functions called
+ from the foreign code) is executed as if it were running on the machine
+ type it was built for.
+
+ @param[in] This This pointer for
+ EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL structure
+ @param[in] ImageBase The base address in memory of the PE/COFF image
+ @param[in] ImageSize The size in memory of the PE/COFF image
+ @param[in,out] EntryPoint The entry point of the PE/COFF image. Passed by
+ reference so that the emulator may modify it.
+
+ @retval EFI_SUCCESS The image was registered with the emulator and
+ can be started as usual.
+ @retval other The image could not be registered.
+
+ If the PE/COFF machine type or image type are not supported by the emulator,
+ then ASSERT().
+**/
+EFI_STATUS
+EFIAPI
+EbcRegisterImage (
+ IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS ImageBase,
+ IN UINT64 ImageSize,
+ IN OUT EFI_IMAGE_ENTRY_POINT *EntryPoint
+ )
+{
+ DEBUG_CODE_BEGIN ();
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ EFI_STATUS Status;
+
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+
+ ImageContext.Handle = (VOID *)(UINTN)ImageBase;
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (ImageContext.Machine == EFI_IMAGE_MACHINE_EBC);
+ ASSERT (ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION ||
+ ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER);
+ DEBUG_CODE_END ();
+
+ EbcRegisterICacheFlush (NULL,
+ (EBC_ICACHE_FLUSH)InvalidateInstructionCacheRange);
+
+ return EbcCreateThunk (NULL, (VOID *)(UINTN)ImageBase,
+ (VOID *)(UINTN)*EntryPoint, (VOID **)EntryPoint);
+}
+
+/**
+ Unregister a PE/COFF image that has been registered with the emulator.
+ This should be done before the image is unloaded from memory.
+
+ @param[in] This This pointer for EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL
+ structure
+ @param[in] ImageBase The base address in memory of the PE/COFF image
+
+ @retval EFI_SUCCESS The image was unregistered with the emulator.
+ @retval other Image could not be unloaded.
+**/
+EFI_STATUS
+EFIAPI
+EbcUnregisterImage (
+ IN EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS ImageBase
+ )
+{
+ return EbcUnloadImage (NULL, (VOID *)(UINTN)ImageBase);
+}
+
+STATIC EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL mPeCoffEmuProtocol = {
+ EbcIsImageSupported,
+ EbcRegisterImage,
+ EbcUnregisterImage,
+ EDKII_PECOFF_IMAGE_EMULATOR_VERSION,
+ EFI_IMAGE_MACHINE_EBC
+};
+
+/**
+ Initializes the VM EFI interface. Allocates memory for the VM interface
+ and registers the VM protocol.
+
+ @param ImageHandle EFI image handle.
+ @param SystemTable Pointer to the EFI system table.
+
+ @return Standard EFI status code.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeEbcDriver (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_EBC_PROTOCOL *EbcProtocol;
+ EFI_EBC_PROTOCOL *OldEbcProtocol;
+ EFI_STATUS Status;
+ EFI_DEBUG_SUPPORT_PROTOCOL *EbcDebugProtocol;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumHandles;
+ UINTN Index;
+ BOOLEAN Installed;
+
+ EbcProtocol = NULL;
+ EbcDebugProtocol = NULL;
+
+ //
+ // Allocate memory for our protocol. Then fill in the blanks.
+ //
+ EbcProtocol = AllocatePool (sizeof (EFI_EBC_PROTOCOL));
+
+ if (EbcProtocol == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ EbcProtocol->CreateThunk = EbcCreateThunk;
+ EbcProtocol->UnloadImage = EbcUnloadImage;
+ EbcProtocol->RegisterICacheFlush = EbcRegisterICacheFlush;
+ EbcProtocol->GetVersion = EbcGetVersion;
+ mEbcICacheFlush = NULL;
+
+ //
+ // Find any already-installed EBC protocols and uninstall them
+ //
+ Installed = FALSE;
+ HandleBuffer = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiEbcProtocolGuid,
+ NULL,
+ &NumHandles,
+ &HandleBuffer
+ );
+ if (Status == EFI_SUCCESS) {
+ //
+ // Loop through the handles
+ //
+ for (Index = 0; Index < NumHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiEbcProtocolGuid,
+ (VOID **) &OldEbcProtocol
+ );
+ if (Status == EFI_SUCCESS) {
+ if (gBS->ReinstallProtocolInterface (
+ HandleBuffer[Index],
+ &gEfiEbcProtocolGuid,
+ OldEbcProtocol,
+ EbcProtocol
+ ) == EFI_SUCCESS) {
+ Installed = TRUE;
+ }
+ }
+ }
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ HandleBuffer = NULL;
+ }
+ //
+ // Add the protocol so someone can locate us if we haven't already.
+ //
+ if (!Installed) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiEbcProtocolGuid, EbcProtocol,
+ &gEdkiiPeCoffImageEmulatorProtocolGuid, &mPeCoffEmuProtocol,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (EbcProtocol);
+ return Status;
+ }
+ }
+
+ Status = InitEBCStack();
+ if (EFI_ERROR(Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Allocate memory for our debug protocol. Then fill in the blanks.
+ //
+ EbcDebugProtocol = AllocatePool (sizeof (EFI_DEBUG_SUPPORT_PROTOCOL));
+
+ if (EbcDebugProtocol == NULL) {
+ goto ErrorExit;
+ }
+
+ EbcDebugProtocol->Isa = IsaEbc;
+ EbcDebugProtocol->GetMaximumProcessorIndex = EbcDebugGetMaximumProcessorIndex;
+ EbcDebugProtocol->RegisterPeriodicCallback = EbcDebugRegisterPeriodicCallback;
+ EbcDebugProtocol->RegisterExceptionCallback = EbcDebugRegisterExceptionCallback;
+ EbcDebugProtocol->InvalidateInstructionCache = EbcDebugInvalidateInstructionCache;
+
+ //
+ // Add the protocol so the debug agent can find us
+ //
+ Status = gBS->InstallProtocolInterface (
+ &ImageHandle,
+ &gEfiDebugSupportProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ EbcDebugProtocol
+ );
+ //
+ // This is recoverable, so free the memory and continue.
+ //
+ if (EFI_ERROR (Status)) {
+ FreePool (EbcDebugProtocol);
+ goto ErrorExit;
+ }
+ //
+ // Install EbcDebugSupport Protocol Successfully
+ // Now we need to initialize the Ebc default Callback
+ //
+ Status = InitializeEbcCallback (EbcDebugProtocol);
+
+ //
+ // Produce a VM test interface protocol. Not required for execution.
+ //
+ DEBUG_CODE_BEGIN ();
+ InitEbcVmTestProtocol (&ImageHandle);
+ DEBUG_CODE_END ();
+
+ EbcDebuggerHookInit (ImageHandle, EbcDebugProtocol);
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ FreeEBCStack();
+ HandleBuffer = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiEbcProtocolGuid,
+ NULL,
+ &NumHandles,
+ &HandleBuffer
+ );
+ if (Status == EFI_SUCCESS) {
+ //
+ // Loop through the handles
+ //
+ for (Index = 0; Index < NumHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiEbcProtocolGuid,
+ (VOID **) &OldEbcProtocol
+ );
+ if (Status == EFI_SUCCESS) {
+ gBS->UninstallProtocolInterface (
+ HandleBuffer[Index],
+ &gEfiEbcProtocolGuid,
+ OldEbcProtocol
+ );
+ }
+ }
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ HandleBuffer = NULL;
+ }
+
+ FreePool (EbcProtocol);
+
+ return Status;
+}
+
+
+/**
+ This is the top-level routine plugged into the EBC protocol. Since thunks
+ are very processor-specific, from here we dispatch directly to the very
+ processor-specific routine EbcCreateThunks().
+
+ @param This A pointer to the EFI_EBC_PROTOCOL instance.
+ @param ImageHandle Handle of image for which the thunk is being
+ created. The EBC interpreter may use this to
+ keep track of any resource allocations
+ performed in loading and executing the image.
+ @param EbcEntryPoint Address of the actual EBC entry point or
+ protocol service the thunk should call.
+ @param Thunk Returned pointer to a thunk created.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Image entry point is not 2-byte aligned.
+ @retval EFI_OUT_OF_RESOURCES Memory could not be allocated for the thunk.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcCreateThunk (
+ IN EFI_EBC_PROTOCOL *This,
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *EbcEntryPoint,
+ OUT VOID **Thunk
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EbcCreateThunks (
+ ImageHandle,
+ EbcEntryPoint,
+ Thunk,
+ FLAG_THUNK_ENTRY_POINT
+ );
+ return Status;
+}
+
+
+/**
+ This EBC debugger protocol service is called by the debug agent
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+ @param MaxProcessorIndex Pointer to a caller-allocated UINTN in which the
+ maximum supported processor index is returned.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugGetMaximumProcessorIndex (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ OUT UINTN *MaxProcessorIndex
+ )
+{
+ *MaxProcessorIndex = 0;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This protocol service is called by the debug agent to register a function
+ for us to call on a periodic basis.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+ @param ProcessorIndex Specifies which processor the callback function
+ applies to.
+ @param PeriodicCallback A pointer to a function of type
+ PERIODIC_CALLBACK that is the main periodic
+ entry point of the debug agent. It receives as a
+ parameter a pointer to the full context of the
+ interrupted execution thread.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ALREADY_STARTED Non-NULL PeriodicCallback parameter when a
+ callback function was previously registered.
+ @retval EFI_INVALID_PARAMETER Null PeriodicCallback parameter when no
+ callback function was previously registered.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugRegisterPeriodicCallback (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_PERIODIC_CALLBACK PeriodicCallback
+ )
+{
+ if ((mDebugPeriodicCallback == NULL) && (PeriodicCallback == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((mDebugPeriodicCallback != NULL) && (PeriodicCallback != NULL)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ mDebugPeriodicCallback = PeriodicCallback;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This protocol service is called by the debug agent to register a function
+ for us to call when we detect an exception.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+ @param ProcessorIndex Specifies which processor the callback function
+ applies to.
+ @param ExceptionCallback A pointer to a function of type
+ EXCEPTION_CALLBACK that is called when the
+ processor exception specified by ExceptionType
+ occurs. Passing NULL unregisters any previously
+ registered function associated with
+ ExceptionType.
+ @param ExceptionType Specifies which processor exception to hook.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_ALREADY_STARTED Non-NULL ExceptionCallback parameter when a
+ callback function was previously registered.
+ @retval EFI_INVALID_PARAMETER ExceptionType parameter is negative or exceeds
+ MAX_EBC_EXCEPTION.
+ @retval EFI_INVALID_PARAMETER Null ExceptionCallback parameter when no
+ callback function was previously registered.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugRegisterExceptionCallback (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN EFI_EXCEPTION_CALLBACK ExceptionCallback,
+ IN EFI_EXCEPTION_TYPE ExceptionType
+ )
+{
+ if ((ExceptionType < 0) || (ExceptionType > MAX_EBC_EXCEPTION)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((mDebugExceptionCallback[ExceptionType] == NULL) && (ExceptionCallback == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((mDebugExceptionCallback[ExceptionType] != NULL) && (ExceptionCallback != NULL)) {
+ return EFI_ALREADY_STARTED;
+ }
+ mDebugExceptionCallback[ExceptionType] = ExceptionCallback;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This EBC debugger protocol service is called by the debug agent. Required
+ for DebugSupport compliance but is only stubbed out for EBC.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+ @param ProcessorIndex Specifies which processor the callback function
+ applies to.
+ @param Start StartSpecifies the physical base of the memory
+ range to be invalidated.
+ @param Length Specifies the minimum number of bytes in the
+ processor's instruction cache to invalidate.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugInvalidateInstructionCache (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ IN VOID *Start,
+ IN UINT64 Length
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ The VM interpreter calls this function when an exception is detected.
+
+ @param ExceptionType Specifies the processor exception detected.
+ @param ExceptionFlags Specifies the exception context.
+ @param VmPtr Pointer to a VM context for passing info to the
+ EFI debugger.
+
+ @retval EFI_SUCCESS This function completed successfully.
+
+**/
+EFI_STATUS
+EbcDebugSignalException (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EXCEPTION_FLAGS ExceptionFlags,
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EFI_SYSTEM_CONTEXT_EBC EbcContext;
+ EFI_SYSTEM_CONTEXT SystemContext;
+
+ ASSERT ((ExceptionType >= 0) && (ExceptionType <= MAX_EBC_EXCEPTION));
+ //
+ // Save the exception in the context passed in
+ //
+ VmPtr->ExceptionFlags |= ExceptionFlags;
+ VmPtr->LastException = (UINTN) ExceptionType;
+ //
+ // If it's a fatal exception, then flag it in the VM context in case an
+ // attached debugger tries to return from it.
+ //
+ if ((ExceptionFlags & EXCEPTION_FLAG_FATAL) != 0) {
+ VmPtr->StopFlags |= STOPFLAG_APP_DONE;
+ }
+
+ //
+ // If someone's registered for exception callbacks, then call them.
+ //
+ // EBC driver will register default exception callback to report the
+ // status code via the status code API
+ //
+ if (mDebugExceptionCallback[ExceptionType] != NULL) {
+
+ //
+ // Initialize the context structure
+ //
+ EbcContext.R0 = (UINT64) VmPtr->Gpr[0];
+ EbcContext.R1 = (UINT64) VmPtr->Gpr[1];
+ EbcContext.R2 = (UINT64) VmPtr->Gpr[2];
+ EbcContext.R3 = (UINT64) VmPtr->Gpr[3];
+ EbcContext.R4 = (UINT64) VmPtr->Gpr[4];
+ EbcContext.R5 = (UINT64) VmPtr->Gpr[5];
+ EbcContext.R6 = (UINT64) VmPtr->Gpr[6];
+ EbcContext.R7 = (UINT64) VmPtr->Gpr[7];
+ EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;
+ EbcContext.Flags = VmPtr->Flags;
+ EbcContext.ControlFlags = 0;
+ SystemContext.SystemContextEbc = &EbcContext;
+
+ mDebugExceptionCallback[ExceptionType] (ExceptionType, SystemContext);
+ //
+ // Restore the context structure and continue to execute
+ //
+ VmPtr->Gpr[0] = EbcContext.R0;
+ VmPtr->Gpr[1] = EbcContext.R1;
+ VmPtr->Gpr[2] = EbcContext.R2;
+ VmPtr->Gpr[3] = EbcContext.R3;
+ VmPtr->Gpr[4] = EbcContext.R4;
+ VmPtr->Gpr[5] = EbcContext.R5;
+ VmPtr->Gpr[6] = EbcContext.R6;
+ VmPtr->Gpr[7] = EbcContext.R7;
+ VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;
+ VmPtr->Flags = EbcContext.Flags;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ To install default Callback function for the VM interpreter.
+
+ @param This A pointer to the EFI_DEBUG_SUPPORT_PROTOCOL
+ instance.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval Others Some error occurs when creating periodic event.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeEbcCallback (
+ IN EFI_DEBUG_SUPPORT_PROTOCOL *This
+ )
+{
+ INTN Index;
+ EFI_STATUS Status;
+
+ //
+ // For ExceptionCallback
+ //
+ for (Index = 0; Index <= MAX_EBC_EXCEPTION; Index++) {
+ EbcDebugRegisterExceptionCallback (
+ This,
+ 0,
+ CommonEbcExceptionHandler,
+ Index
+ );
+ }
+
+ //
+ // For PeriodicCallback
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ EbcPeriodicNotifyFunction,
+ &mVmPtr,
+ &mEbcPeriodicEvent
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Status = gBS->SetTimer (
+ mEbcPeriodicEvent,
+ TimerPeriodic,
+ EBC_VM_PERIODIC_CALLBACK_RATE
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ The default Exception Callback for the VM interpreter.
+ In this function, we report status code, and print debug information
+ about EBC_CONTEXT, then dead loop.
+
+ @param InterruptType Interrupt type.
+ @param SystemContext EBC system context.
+
+**/
+VOID
+EFIAPI
+CommonEbcExceptionHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ //
+ // We print debug information to let user know what happen.
+ //
+ DEBUG ((
+ EFI_D_ERROR,
+ "EBC Interrupter Version - 0x%016lx\n",
+ (UINT64) (((VM_MAJOR_VERSION & 0xFFFF) << 16) | ((VM_MINOR_VERSION & 0xFFFF)))
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ "Exception Type - 0x%016lx\n",
+ (UINT64)(UINTN)InterruptType
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ " R0 - 0x%016lx, R1 - 0x%016lx\n",
+ SystemContext.SystemContextEbc->R0,
+ SystemContext.SystemContextEbc->R1
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ " R2 - 0x%016lx, R3 - 0x%016lx\n",
+ SystemContext.SystemContextEbc->R2,
+ SystemContext.SystemContextEbc->R3
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ " R4 - 0x%016lx, R5 - 0x%016lx\n",
+ SystemContext.SystemContextEbc->R4,
+ SystemContext.SystemContextEbc->R5
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ " R6 - 0x%016lx, R7 - 0x%016lx\n",
+ SystemContext.SystemContextEbc->R6,
+ SystemContext.SystemContextEbc->R7
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ " Flags - 0x%016lx\n",
+ SystemContext.SystemContextEbc->Flags
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ " ControlFlags - 0x%016lx\n",
+ SystemContext.SystemContextEbc->ControlFlags
+ ));
+ DEBUG ((
+ EFI_D_ERROR,
+ " Ip - 0x%016lx\n\n",
+ SystemContext.SystemContextEbc->Ip
+ ));
+
+ //
+ // We deadloop here to make it easy to debug this issue.
+ //
+ CpuDeadLoop ();
+
+ return ;
+}
+
+
+/**
+ The periodic callback function for EBC VM interpreter, which is used
+ to support the EFI debug support protocol.
+
+ @param Event The Periodic Callback Event.
+ @param Context It should be the address of VM_CONTEXT pointer.
+
+**/
+VOID
+EFIAPI
+EbcPeriodicNotifyFunction (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ VM_CONTEXT *VmPtr;
+
+ VmPtr = *(VM_CONTEXT **)Context;
+
+ if (VmPtr != NULL) {
+ EbcDebugPeriodic (VmPtr);
+ }
+
+ return ;
+}
+
+
+/**
+ The VM interpreter calls this function on a periodic basis to support
+ the EFI debug support protocol.
+
+ @param VmPtr Pointer to a VM context for passing info to the
+ debugger.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcDebugPeriodic (
+ IN VM_CONTEXT *VmPtr
+ )
+{
+ EFI_SYSTEM_CONTEXT_EBC EbcContext;
+ EFI_SYSTEM_CONTEXT SystemContext;
+
+ //
+ // If someone's registered for periodic callbacks, then call them.
+ //
+ if (mDebugPeriodicCallback != NULL) {
+
+ //
+ // Initialize the context structure
+ //
+ EbcContext.R0 = (UINT64) VmPtr->Gpr[0];
+ EbcContext.R1 = (UINT64) VmPtr->Gpr[1];
+ EbcContext.R2 = (UINT64) VmPtr->Gpr[2];
+ EbcContext.R3 = (UINT64) VmPtr->Gpr[3];
+ EbcContext.R4 = (UINT64) VmPtr->Gpr[4];
+ EbcContext.R5 = (UINT64) VmPtr->Gpr[5];
+ EbcContext.R6 = (UINT64) VmPtr->Gpr[6];
+ EbcContext.R7 = (UINT64) VmPtr->Gpr[7];
+ EbcContext.Ip = (UINT64)(UINTN)VmPtr->Ip;
+ EbcContext.Flags = VmPtr->Flags;
+ EbcContext.ControlFlags = 0;
+ SystemContext.SystemContextEbc = &EbcContext;
+
+ mDebugPeriodicCallback (SystemContext);
+
+ //
+ // Restore the context structure and continue to execute
+ //
+ VmPtr->Gpr[0] = EbcContext.R0;
+ VmPtr->Gpr[1] = EbcContext.R1;
+ VmPtr->Gpr[2] = EbcContext.R2;
+ VmPtr->Gpr[3] = EbcContext.R3;
+ VmPtr->Gpr[4] = EbcContext.R4;
+ VmPtr->Gpr[5] = EbcContext.R5;
+ VmPtr->Gpr[6] = EbcContext.R6;
+ VmPtr->Gpr[7] = EbcContext.R7;
+ VmPtr->Ip = (VMIP)(UINTN)EbcContext.Ip;
+ VmPtr->Flags = EbcContext.Flags;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This routine is called by the core when an image is being unloaded from
+ memory. Basically we now have the opportunity to do any necessary cleanup.
+ Typically this will include freeing any memory allocated for thunk-creation.
+
+ @param This A pointer to the EFI_EBC_PROTOCOL instance.
+ @param ImageHandle Handle of image for which the thunk is being
+ created.
+
+ @retval EFI_INVALID_PARAMETER The ImageHandle passed in was not found in the
+ internal list of EBC image handles.
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcUnloadImage (
+ IN EFI_EBC_PROTOCOL *This,
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EBC_THUNK_LIST *ThunkList;
+ EBC_THUNK_LIST *NextThunkList;
+ EBC_IMAGE_LIST *ImageList;
+ EBC_IMAGE_LIST *PrevImageList;
+ //
+ // First go through our list of known image handles and see if we've already
+ // created an image list element for this image handle.
+ //
+ ReturnEBCStackByHandle(ImageHandle);
+ PrevImageList = NULL;
+ for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
+ if (ImageList->ImageHandle == ImageHandle) {
+ break;
+ }
+ //
+ // Save the previous so we can connect the lists when we remove this one
+ //
+ PrevImageList = ImageList;
+ }
+
+ if (ImageList == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Free up all the thunk buffers and thunks list elements for this image
+ // handle.
+ //
+ ThunkList = ImageList->ThunkList;
+ while (ThunkList != NULL) {
+ NextThunkList = ThunkList->Next;
+ FreePool (ThunkList->ThunkBuffer);
+ FreePool (ThunkList);
+ ThunkList = NextThunkList;
+ }
+ //
+ // Now remove this image list element from the chain
+ //
+ if (PrevImageList == NULL) {
+ //
+ // Remove from head
+ //
+ mEbcImageList = ImageList->Next;
+ } else {
+ PrevImageList->Next = ImageList->Next;
+ }
+ //
+ // Now free up the image list element
+ //
+ FreePool (ImageList);
+
+ EbcDebuggerHookEbcUnloadImage (ImageHandle);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Add a thunk to our list of thunks for a given image handle.
+ Also flush the instruction cache since we've written thunk code
+ to memory that will be executed eventually.
+
+ @param ImageHandle The image handle to which the thunk is tied.
+ @param ThunkBuffer The buffer that has been created/allocated.
+ @param ThunkSize The size of the thunk memory allocated.
+
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EbcAddImageThunk (
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *ThunkBuffer,
+ IN UINT32 ThunkSize
+ )
+{
+ EBC_THUNK_LIST *ThunkList;
+ EBC_IMAGE_LIST *ImageList;
+ EFI_STATUS Status;
+
+ //
+ // It so far so good, then flush the instruction cache
+ //
+ if (mEbcICacheFlush != NULL) {
+ Status = mEbcICacheFlush ((EFI_PHYSICAL_ADDRESS) (UINTN) ThunkBuffer, ThunkSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ //
+ // Go through our list of known image handles and see if we've already
+ // created a image list element for this image handle.
+ //
+ for (ImageList = mEbcImageList; ImageList != NULL; ImageList = ImageList->Next) {
+ if (ImageList->ImageHandle == ImageHandle) {
+ break;
+ }
+ }
+
+ if (ImageList == NULL) {
+ //
+ // Allocate a new one
+ //
+ ImageList = AllocatePool (sizeof (EBC_IMAGE_LIST));
+
+ if (ImageList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ImageList->ThunkList = NULL;
+ ImageList->ImageHandle = ImageHandle;
+ ImageList->Next = mEbcImageList;
+ mEbcImageList = ImageList;
+ }
+ //
+ // Ok, now create a new thunk element to add to the list
+ //
+ ThunkList = AllocatePool (sizeof (EBC_THUNK_LIST));
+
+ if (ThunkList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Add it to the head of the list
+ //
+ ThunkList->Next = ImageList->ThunkList;
+ ThunkList->ThunkBuffer = ThunkBuffer;
+ ImageList->ThunkList = ThunkList;
+ return EFI_SUCCESS;
+}
+
+/**
+ Registers a callback function that the EBC interpreter calls to flush the
+ processor instruction cache following creation of thunks.
+
+ @param This A pointer to the EFI_EBC_PROTOCOL instance.
+ @param Flush Pointer to a function of type EBC_ICACH_FLUSH.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcRegisterICacheFlush (
+ IN EFI_EBC_PROTOCOL *This,
+ IN EBC_ICACHE_FLUSH Flush
+ )
+{
+ mEbcICacheFlush = Flush;
+ return EFI_SUCCESS;
+}
+
+/**
+ Called to get the version of the interpreter.
+
+ @param This A pointer to the EFI_EBC_PROTOCOL instance.
+ @param Version Pointer to where to store the returned version
+ of the interpreter.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_INVALID_PARAMETER Version pointer is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcGetVersion (
+ IN EFI_EBC_PROTOCOL *This,
+ IN OUT UINT64 *Version
+ )
+{
+ if (Version == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Version = GetVmVersion ();
+ return EFI_SUCCESS;
+}
+
+/**
+ Returns the stack index and buffer assosicated with the Handle parameter.
+
+ @param Handle The EFI handle as the index to the EBC stack.
+ @param StackBuffer A pointer to hold the returned stack buffer.
+ @param BufferIndex A pointer to hold the returned stack index.
+
+ @retval EFI_OUT_OF_RESOURCES The Handle parameter does not correspond to any
+ existing EBC stack.
+ @retval EFI_SUCCESS The stack index and buffer were found and
+ returned to the caller.
+
+**/
+EFI_STATUS
+GetEBCStack(
+ IN EFI_HANDLE Handle,
+ OUT VOID **StackBuffer,
+ OUT UINTN *BufferIndex
+ )
+{
+ UINTN Index;
+ EFI_TPL OldTpl;
+ OldTpl = gBS->RaiseTPL(TPL_HIGH_LEVEL);
+ for (Index = 0; Index < mStackNum; Index ++) {
+ if (mStackBufferIndex[Index] == NULL) {
+ mStackBufferIndex[Index] = Handle;
+ break;
+ }
+ }
+ gBS->RestoreTPL(OldTpl);
+ if (Index == mStackNum) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *BufferIndex = Index;
+ *StackBuffer = mStackBuffer[Index];
+ return EFI_SUCCESS;
+}
+
+/**
+ Returns from the EBC stack by stack Index.
+
+ @param Index Specifies which EBC stack to return from.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+ReturnEBCStack(
+ IN UINTN Index
+ )
+{
+ mStackBufferIndex[Index] = NULL;
+ return EFI_SUCCESS;
+}
+
+/**
+ Returns from the EBC stack associated with the Handle parameter.
+
+ @param Handle Specifies the EFI handle to find the EBC stack with.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+ReturnEBCStackByHandle(
+ IN EFI_HANDLE Handle
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < mStackNum; Index ++) {
+ if (mStackBufferIndex[Index] == Handle) {
+ break;
+ }
+ }
+ if (Index == mStackNum) {
+ return EFI_NOT_FOUND;
+ }
+ mStackBufferIndex[Index] = NULL;
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocates memory to hold all the EBC stacks.
+
+ @retval EFI_SUCCESS The EBC stacks were allocated successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory available for EBC stacks.
+
+**/
+EFI_STATUS
+InitEBCStack (
+ VOID
+ )
+{
+ for (mStackNum = 0; mStackNum < MAX_STACK_NUM; mStackNum ++) {
+ mStackBuffer[mStackNum] = AllocatePool(STACK_POOL_SIZE);
+ mStackBufferIndex[mStackNum] = NULL;
+ if (mStackBuffer[mStackNum] == NULL) {
+ break;
+ }
+ }
+ if (mStackNum == 0) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Free all EBC stacks allocated before.
+
+ @retval EFI_SUCCESS All the EBC stacks were freed.
+
+**/
+EFI_STATUS
+FreeEBCStack(
+ VOID
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < mStackNum; Index ++) {
+ FreePool(mStackBuffer[Index]);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Produces an EBC VM test protocol that can be used for regression tests.
+
+ @param IHandle Handle on which to install the protocol.
+
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+InitEbcVmTestProtocol (
+ IN EFI_HANDLE *IHandle
+ )
+{
+ EFI_HANDLE Handle;
+ EFI_STATUS Status;
+ EFI_EBC_VM_TEST_PROTOCOL *EbcVmTestProtocol;
+
+ //
+ // Allocate memory for the protocol, then fill in the fields
+ //
+ EbcVmTestProtocol = AllocatePool (sizeof (EFI_EBC_VM_TEST_PROTOCOL));
+ if (EbcVmTestProtocol == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ EbcVmTestProtocol->Execute = (EBC_VM_TEST_EXECUTE) EbcExecuteInstructions;
+
+ DEBUG_CODE_BEGIN ();
+ EbcVmTestProtocol->Assemble = (EBC_VM_TEST_ASM) EbcVmTestUnsupported;
+ EbcVmTestProtocol->Disassemble = (EBC_VM_TEST_DASM) EbcVmTestUnsupported;
+ DEBUG_CODE_END ();
+
+ //
+ // Publish the protocol
+ //
+ Handle = NULL;
+ Status = gBS->InstallProtocolInterface (&Handle, &gEfiEbcVmTestProtocolGuid, EFI_NATIVE_INTERFACE, EbcVmTestProtocol);
+ if (EFI_ERROR (Status)) {
+ FreePool (EbcVmTestProtocol);
+ }
+ return Status;
+}
+
+
+/**
+ Returns the EFI_UNSUPPORTED Status.
+
+ @return EFI_UNSUPPORTED This function always return EFI_UNSUPPORTED status.
+
+**/
+EFI_STATUS
+EFIAPI
+EbcVmTestUnsupported (
+ VOID
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Allocates a buffer of type EfiBootServicesCode.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+EbcAllocatePoolForThunk (
+ IN UINTN AllocationSize
+ )
+{
+ VOID *Buffer;
+ EFI_STATUS Status;
+
+ Status = gBS->AllocatePool (EfiBootServicesCode, AllocationSize, &Buffer);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+ return Buffer;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcInt.h b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcInt.h
new file mode 100644
index 000000000..16f5ed4eb
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/EbcInt.h
@@ -0,0 +1,260 @@
+/** @file
+ Main routines for the EBC interpreter. Includes the initialization and
+ main interpreter routines.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _EBC_INT_H_
+#define _EBC_INT_H_
+
+
+#include <Uefi.h>
+
+#include <Protocol/DebugSupport.h>
+#include <Protocol/Ebc.h>
+#include <Protocol/EbcVmTest.h>
+#include <Protocol/EbcSimpleDebugger.h>
+#include <Protocol/PeCoffImageEmulator.h>
+
+#include <Library/BaseLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+extern VM_CONTEXT *mVmPtr;
+
+//
+// Flags passed to the internal create-thunks function.
+//
+#define FLAG_THUNK_ENTRY_POINT 0x01 // thunk for an image entry point
+#define FLAG_THUNK_PROTOCOL 0x00 // thunk for an EBC protocol service
+//
+// Put this value at the bottom of the VM's stack gap so we can check it on
+// occasion to make sure the stack has not been corrupted.
+//
+#define VM_STACK_KEY_VALUE 0xDEADBEEF
+
+/**
+ Create thunks for an EBC image entry point, or an EBC protocol service.
+
+ @param ImageHandle Image handle for the EBC image. If not null, then
+ we're creating a thunk for an image entry point.
+ @param EbcEntryPoint Address of the EBC code that the thunk is to call
+ @param Thunk Returned thunk we create here
+ @param Flags Flags indicating options for creating the thunk
+
+ @retval EFI_SUCCESS The thunk was created successfully.
+ @retval EFI_INVALID_PARAMETER The parameter of EbcEntryPoint is not 16-bit
+ aligned.
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory to created the EBC
+ Thunk.
+ @retval EFI_BUFFER_TOO_SMALL EBC_THUNK_SIZE is not larger enough.
+
+**/
+EFI_STATUS
+EbcCreateThunks (
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *EbcEntryPoint,
+ OUT VOID **Thunk,
+ IN UINT32 Flags
+ );
+
+/**
+ Add a thunk to our list of thunks for a given image handle.
+ Also flush the instruction cache since we've written thunk code
+ to memory that will be executed eventually.
+
+ @param ImageHandle The image handle to which the thunk is tied.
+ @param ThunkBuffer The buffer that has been created/allocated.
+ @param ThunkSize The size of the thunk memory allocated.
+
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EbcAddImageThunk (
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *ThunkBuffer,
+ IN UINT32 ThunkSize
+ );
+
+//
+// Define a constant of how often to call the debugger periodic callback
+// function.
+//
+#define EFI_TIMER_UNIT_1MS (1000 * 10)
+#define EBC_VM_PERIODIC_CALLBACK_RATE (1000 * EFI_TIMER_UNIT_1MS)
+#define STACK_POOL_SIZE (1024 * 1020)
+#define MAX_STACK_NUM 4
+
+//
+// External low level functions that are native-processor dependent
+//
+/**
+ The VM thunk code stuffs an EBC entry point into a processor
+ register. Since we can't use inline assembly to get it from
+ the interpreter C code, stuff it into the return value
+ register and return.
+
+ @return The contents of the register in which the entry point is passed.
+
+**/
+UINTN
+EFIAPI
+EbcLLGetEbcEntryPoint (
+ VOID
+ );
+
+/**
+ This function is called to execute an EBC CALLEX instruction.
+ This instruction requires that we thunk out to external native
+ code. For x64, we switch stacks, copy the arguments to the stack
+ and jump to the specified function.
+ On return, we restore the stack pointer to its original location.
+ Destroys no working registers.
+
+ @param CallAddr The function address.
+ @param EbcSp The new EBC stack pointer.
+ @param FramePtr The frame pointer.
+
+ @return The unmodified value returned by the native code.
+
+**/
+INT64
+EFIAPI
+EbcLLCALLEXNative (
+ IN UINTN CallAddr,
+ IN UINTN EbcSp,
+ IN VOID *FramePtr
+ );
+
+/**
+ This function is called to execute an EBC CALLEX instruction.
+ The function check the callee's content to see whether it is common native
+ code or a thunk to another piece of EBC code.
+ If the callee is common native code, use EbcLLCAllEXASM to manipulate,
+ otherwise, set the VM->IP to target EBC code directly to avoid another VM
+ be startup which cost time and stack space.
+
+ @param VmPtr Pointer to a VM context.
+ @param FuncAddr Callee's address
+ @param NewStackPointer New stack pointer after the call
+ @param FramePtr New frame pointer after the call
+ @param Size The size of call instruction
+
+**/
+VOID
+EbcLLCALLEX (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN FuncAddr,
+ IN UINTN NewStackPointer,
+ IN VOID *FramePtr,
+ IN UINT8 Size
+ );
+
+/**
+ Returns the stack index and buffer assosicated with the Handle parameter.
+
+ @param Handle The EFI handle as the index to the EBC stack.
+ @param StackBuffer A pointer to hold the returned stack buffer.
+ @param BufferIndex A pointer to hold the returned stack index.
+
+ @retval EFI_OUT_OF_RESOURCES The Handle parameter does not correspond to any
+ existing EBC stack.
+ @retval EFI_SUCCESS The stack index and buffer were found and
+ returned to the caller.
+
+**/
+EFI_STATUS
+GetEBCStack(
+ IN EFI_HANDLE Handle,
+ OUT VOID **StackBuffer,
+ OUT UINTN *BufferIndex
+ );
+
+/**
+ Returns from the EBC stack by stack Index.
+
+ @param Index Specifies which EBC stack to return from.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+ReturnEBCStack(
+ IN UINTN Index
+ );
+
+/**
+ Allocates memory to hold all the EBC stacks.
+
+ @retval EFI_SUCCESS The EBC stacks were allocated successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory available for EBC stacks.
+
+**/
+EFI_STATUS
+InitEBCStack (
+ VOID
+ );
+
+/**
+ Free all EBC stacks allocated before.
+
+ @retval EFI_SUCCESS All the EBC stacks were freed.
+
+**/
+EFI_STATUS
+FreeEBCStack(
+ VOID
+ );
+
+/**
+ Returns from the EBC stack associated with the Handle parameter.
+
+ @param Handle Specifies the EFI handle to find the EBC stack with.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+ReturnEBCStackByHandle(
+ IN EFI_HANDLE Handle
+ );
+
+typedef struct {
+ EFI_EBC_PROTOCOL *This;
+ VOID *EntryPoint;
+ EFI_HANDLE ImageHandle;
+ VM_CONTEXT VmContext;
+} EFI_EBC_THUNK_DATA;
+
+#define EBC_PROTOCOL_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('e', 'b', 'c', 'p')
+
+
+#define EBC_PROTOCOL_PRIVATE_DATA_FROM_THIS(a) \
+ CR(a, EBC_PROTOCOL_PRIVATE_DATA, EbcProtocol, EBC_PROTOCOL_PRIVATE_DATA_SIGNATURE)
+
+
+/**
+ Allocates a buffer of type EfiBootServicesCode.
+
+ @param AllocationSize The number of bytes to allocate.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+
+**/
+VOID *
+EFIAPI
+EbcAllocatePoolForThunk (
+ IN UINTN AllocationSize
+ );
+
+#endif // #ifndef _EBC_INT_H_
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/Ia32/EbcLowLevel.nasm b/roms/edk2/MdeModulePkg/Universal/EbcDxe/Ia32/EbcLowLevel.nasm
new file mode 100644
index 000000000..60e41428b
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/Ia32/EbcLowLevel.nasm
@@ -0,0 +1,191 @@
+;/** @file
+;
+; This code provides low level routines that support the Virtual Machine
+; for option ROMs.
+;
+; Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;**/
+
+;---------------------------------------------------------------------------
+; Equate files needed.
+;---------------------------------------------------------------------------
+
+;---------------------------------------------------------------------------
+; Assembler options
+;---------------------------------------------------------------------------
+
+SECTION .text
+extern ASM_PFX(CopyMem)
+extern ASM_PFX(EbcInterpret)
+extern ASM_PFX(ExecuteEbcImageEntryPoint)
+
+;****************************************************************************
+; EbcLLCALLEXNative
+;
+; This function is called to execute an EBC CALLEX instruction
+; to native code.
+; This instruction requires that we thunk out to external native
+; code. For IA32, we simply switch stacks and jump to the
+; specified function. On return, we restore the stack pointer
+; to its original location.
+;
+; Destroys no working registers.
+;****************************************************************************
+; INT64 EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr)
+global ASM_PFX(EbcLLCALLEXNative)
+ASM_PFX(EbcLLCALLEXNative):
+ push ebp
+ push ebx
+ mov ebp, esp ; standard function prolog
+
+ ; Get function address in a register
+ ; mov ecx, FuncAddr => mov ecx, dword ptr [FuncAddr]
+ mov ecx, dword [esp + 0xC]
+
+ ; Set stack pointer to new value
+ ; mov eax, NewStackPointer => mov eax, dword ptr [NewSp]
+ mov eax, dword [esp + 0x14]
+ mov edx, dword [esp + 0x10]
+ sub eax, edx
+ sub esp, eax
+ mov ebx, esp
+ push ecx
+ push eax
+ push edx
+ push ebx
+ call ASM_PFX(CopyMem)
+ pop eax
+ pop eax
+ pop eax
+ pop ecx
+
+ ; Now call the external routine
+ call ecx
+
+ ; ebp is preserved by the callee. In this function it
+ ; equals the original esp, so set them equal
+ mov esp, ebp
+
+ ; Standard function epilog
+ mov esp, ebp
+ pop ebx
+ pop ebp
+ ret
+
+;****************************************************************************
+; EbcLLEbcInterpret
+;
+; Begin executing an EBC image.
+;****************************************************************************
+; UINT64 EbcLLEbcInterpret(VOID)
+global ASM_PFX(EbcLLEbcInterpret)
+ASM_PFX(EbcLLEbcInterpret):
+ ;
+ ;; mov eax, 0xca112ebc
+ ;; mov eax, EbcEntryPoint
+ ;; mov ecx, EbcLLEbcInterpret
+ ;; jmp ecx
+ ;
+ ; Caller uses above instruction to jump here
+ ; The stack is below:
+ ; +-----------+
+ ; | RetAddr |
+ ; +-----------+
+ ; |EntryPoint | (EAX)
+ ; +-----------+
+ ; | Arg1 | <- EDI
+ ; +-----------+
+ ; | Arg2 |
+ ; +-----------+
+ ; | ... |
+ ; +-----------+
+ ; | Arg16 |
+ ; +-----------+
+ ; | EDI |
+ ; +-----------+
+ ; | ESI |
+ ; +-----------+
+ ; | EBP | <- EBP
+ ; +-----------+
+ ; | RetAddr | <- ESP is here
+ ; +-----------+
+ ; | Arg1 | <- ESI
+ ; +-----------+
+ ; | Arg2 |
+ ; +-----------+
+ ; | ... |
+ ; +-----------+
+ ; | Arg16 |
+ ; +-----------+
+ ;
+
+ ; Construct new stack
+ push ebp
+ mov ebp, esp
+ push esi
+ push edi
+ sub esp, 0x40
+ push eax
+ mov esi, ebp
+ add esi, 8
+ mov edi, esp
+ add edi, 4
+ mov ecx, 16
+ rep movsd
+
+ ; call C-code
+ call ASM_PFX(EbcInterpret)
+ add esp, 0x44
+ pop edi
+ pop esi
+ pop ebp
+ ret
+
+;****************************************************************************
+; EbcLLExecuteEbcImageEntryPoint
+;
+; Begin executing an EBC image.
+;****************************************************************************
+; UINT64 EbcLLExecuteEbcImageEntryPoint(VOID)
+global ASM_PFX(EbcLLExecuteEbcImageEntryPoint)
+ASM_PFX(EbcLLExecuteEbcImageEntryPoint):
+ ;
+ ;; mov eax, 0xca112ebc
+ ;; mov eax, EbcEntryPoint
+ ;; mov ecx, EbcLLExecuteEbcImageEntryPoint
+ ;; jmp ecx
+ ;
+ ; Caller uses above instruction to jump here
+ ; The stack is below:
+ ; +-----------+
+ ; | RetAddr |
+ ; +-----------+
+ ; |EntryPoint | (EAX)
+ ; +-----------+
+ ; |ImageHandle|
+ ; +-----------+
+ ; |SystemTable|
+ ; +-----------+
+ ; | RetAddr | <- ESP is here
+ ; +-----------+
+ ; |ImageHandle|
+ ; +-----------+
+ ; |SystemTable|
+ ; +-----------+
+ ;
+
+ ; Construct new stack
+ mov [esp - 0xC], eax
+ mov eax, [esp + 0x4]
+ mov [esp - 0x8], eax
+ mov eax, [esp + 0x8]
+ mov [esp - 0x4], eax
+
+ ; call C-code
+ sub esp, 0xC
+ call ASM_PFX(ExecuteEbcImageEntryPoint)
+ add esp, 0xC
+ ret
+
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/Ia32/EbcSupport.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/Ia32/EbcSupport.c
new file mode 100644
index 000000000..a25139536
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/Ia32/EbcSupport.c
@@ -0,0 +1,526 @@
+/** @file
+ This module contains EBC support routines that are customized based on
+ the target ia32 processor.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EbcInt.h"
+#include "EbcExecute.h"
+#include "EbcDebuggerHook.h"
+
+//
+// NOTE: This is the stack size allocated for the interpreter
+// when it executes an EBC image. The requirements can change
+// based on whether or not a debugger is present, and other
+// platform-specific configurations.
+//
+#define VM_STACK_SIZE (1024 * 4)
+
+#define STACK_REMAIN_SIZE (1024 * 4)
+
+//
+// This is instruction buffer used to create EBC thunk
+//
+#define EBC_ENTRYPOINT_SIGNATURE 0xAFAFAFAF
+#define EBC_LL_EBC_ENTRYPOINT_SIGNATURE 0xFAFAFAFA
+UINT8 mInstructionBufferTemplate[] = {
+ //
+ // Add a magic code here to help the VM recognize the thunk..
+ // mov eax, 0xca112ebc => B8 BC 2E 11 CA
+ //
+ 0xB8, 0xBC, 0x2E, 0x11, 0xCA,
+ //
+ // Add code bytes to load up a processor register with the EBC entry point.
+ // mov eax, EbcEntryPoint => B8 XX XX XX XX (To be fixed at runtime)
+ // These 4 bytes of the thunk entry is the address of the EBC
+ // entry point.
+ //
+ 0xB8,
+ (UINT8)(EBC_ENTRYPOINT_SIGNATURE & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),
+ //
+ // Stick in a load of ecx with the address of appropriate VM function.
+ // mov ecx, EbcLLEbcInterpret => B9 XX XX XX XX (To be fixed at runtime)
+ //
+ 0xB9,
+ (UINT8)(EBC_LL_EBC_ENTRYPOINT_SIGNATURE & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),
+ //
+ // Stick in jump opcode bytes
+ // jmp ecx => FF E1
+ //
+ 0xFF, 0xE1,
+};
+
+/**
+ Begin executing an EBC image.
+ This is used for Ebc Thunk call.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+EbcLLEbcInterpret (
+ VOID
+ );
+
+/**
+ Begin executing an EBC image.
+ This is used for Ebc image entrypoint.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+EbcLLExecuteEbcImageEntryPoint (
+ VOID
+ );
+
+/**
+ This function is called to execute an EBC CALLEX instruction.
+ The function check the callee's content to see whether it is common native
+ code or a thunk to another piece of EBC code.
+ If the callee is common native code, use EbcLLCAllEXASM to manipulate,
+ otherwise, set the VM->IP to target EBC code directly to avoid another VM
+ be startup which cost time and stack space.
+
+ @param VmPtr Pointer to a VM context.
+ @param FuncAddr Callee's address
+ @param NewStackPointer New stack pointer after the call
+ @param FramePtr New frame pointer after the call
+ @param Size The size of call instruction
+
+**/
+VOID
+EbcLLCALLEX (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN FuncAddr,
+ IN UINTN NewStackPointer,
+ IN VOID *FramePtr,
+ IN UINT8 Size
+ )
+{
+ UINTN IsThunk;
+ UINTN TargetEbcAddr;
+ UINT8 InstructionBuffer[sizeof(mInstructionBufferTemplate)];
+ UINTN Index;
+ UINTN IndexOfEbcEntrypoint;
+
+ IsThunk = 1;
+ TargetEbcAddr = 0;
+ IndexOfEbcEntrypoint = 0;
+
+ //
+ // Processor specific code to check whether the callee is a thunk to EBC.
+ //
+ CopyMem (InstructionBuffer, (VOID *)FuncAddr, sizeof(InstructionBuffer));
+ //
+ // Fill the signature according to mInstructionBufferTemplate
+ //
+ for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {
+ if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_ENTRYPOINT_SIGNATURE) {
+ *(UINTN *)&InstructionBuffer[Index] = EBC_ENTRYPOINT_SIGNATURE;
+ IndexOfEbcEntrypoint = Index;
+ }
+ if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
+ *(UINTN *)&InstructionBuffer[Index] = EBC_LL_EBC_ENTRYPOINT_SIGNATURE;
+ }
+ }
+ //
+ // Check if we need thunk to native
+ //
+ if (CompareMem (InstructionBuffer, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate)) != 0) {
+ IsThunk = 0;
+ }
+
+ if (IsThunk == 1){
+ //
+ // The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and
+ // put our return address and frame pointer on the VM stack.
+ // Then set the VM's IP to new EBC code.
+ //
+ VmPtr->Gpr[0] -= 8;
+ VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], (UINTN) FramePtr);
+ VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0];
+ VmPtr->Gpr[0] -= 8;
+ VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (VmPtr->Ip + Size));
+
+ CopyMem (&TargetEbcAddr, (UINT8 *)FuncAddr + IndexOfEbcEntrypoint, sizeof(UINTN));
+ VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr;
+ } else {
+ //
+ // The callee is not a thunk to EBC, call native code,
+ // and get return value.
+ //
+ VmPtr->Gpr[7] = EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr);
+
+ //
+ // Advance the IP.
+ //
+ VmPtr->Ip += Size;
+ }
+}
+
+
+/**
+ Begin executing an EBC image.
+
+ This is a thunk function. Microsoft x64 compiler only provide fast_call
+ calling convention, so the first four arguments are passed by rcx, rdx,
+ r8, and r9, while other arguments are passed in stack.
+
+ @param EntryPoint The entrypoint of EBC code.
+ @param Arg1 The 1st argument.
+ @param Arg2 The 2nd argument.
+ @param Arg3 The 3rd argument.
+ @param Arg4 The 4th argument.
+ @param Arg5 The 5th argument.
+ @param Arg6 The 6th argument.
+ @param Arg7 The 7th argument.
+ @param Arg8 The 8th argument.
+ @param Arg9 The 9th argument.
+ @param Arg10 The 10th argument.
+ @param Arg11 The 11th argument.
+ @param Arg12 The 12th argument.
+ @param Arg13 The 13th argument.
+ @param Arg14 The 14th argument.
+ @param Arg15 The 15th argument.
+ @param Arg16 The 16th argument.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+EbcInterpret (
+ IN UINTN EntryPoint,
+ IN UINTN Arg1,
+ IN UINTN Arg2,
+ IN UINTN Arg3,
+ IN UINTN Arg4,
+ IN UINTN Arg5,
+ IN UINTN Arg6,
+ IN UINTN Arg7,
+ IN UINTN Arg8,
+ IN UINTN Arg9,
+ IN UINTN Arg10,
+ IN UINTN Arg11,
+ IN UINTN Arg12,
+ IN UINTN Arg13,
+ IN UINTN Arg14,
+ IN UINTN Arg15,
+ IN UINTN Arg16
+ )
+{
+ //
+ // Create a new VM context on the stack
+ //
+ VM_CONTEXT VmContext;
+ UINTN Addr;
+ EFI_STATUS Status;
+ UINTN StackIndex;
+
+ //
+ // Get the EBC entry point
+ //
+ Addr = EntryPoint;
+
+ //
+ // Now clear out our context
+ //
+ ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
+
+ //
+ // Set the VM instruction pointer to the correct location in memory.
+ //
+ VmContext.Ip = (VMIP) Addr;
+ //
+ // Initialize the stack pointer for the EBC. Get the current system stack
+ // pointer and adjust it down by the max needed for the interpreter.
+ //
+
+ //
+ // Align the stack on a natural boundary
+ //
+
+ //
+ // Allocate stack pool
+ //
+ Status = GetEBCStack((EFI_HANDLE)-1, &VmContext.StackPool, &StackIndex);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
+ VmContext.Gpr[0] = (UINT64)(UINTN) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
+ VmContext.HighStackBottom = (UINTN)VmContext.Gpr[0];
+ VmContext.Gpr[0] &= ~((VM_REGISTER)(sizeof (UINTN) - 1));
+ VmContext.Gpr[0] -= sizeof (UINTN);
+
+ //
+ // Put a magic value in the stack gap, then adjust down again
+ //
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) VM_STACK_KEY_VALUE;
+ VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.Gpr[0];
+ VmContext.LowStackTop = (UINTN) VmContext.Gpr[0];
+
+ //
+ // For IA32, this is where we say our return address is
+ //
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg16;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg15;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg14;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg13;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg12;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg11;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg10;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg9;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg8;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg7;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg6;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg5;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg4;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg3;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg2;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) Arg1;
+ VmContext.Gpr[0] -= 16;
+ VmContext.StackRetAddr = (UINT64) VmContext.Gpr[0];
+
+ //
+ // We need to keep track of where the EBC stack starts. This way, if the EBC
+ // accesses any stack variables above its initial stack setting, then we know
+ // it's accessing variables passed into it, which means the data is on the
+ // VM's stack.
+ // When we're called, on the stack (high to low) we have the parameters, the
+ // return address, then the saved ebp. Save the pointer to the return address.
+ // EBC code knows that's there, so should look above it for function parameters.
+ // The offset is the size of locals (VMContext + Addr + saved ebp).
+ // Note that the interpreter assumes there is a 16 bytes of return address on
+ // the stack too, so adjust accordingly.
+ // VmContext.HighStackBottom = (UINTN)(Addr + sizeof (VmContext) + sizeof (Addr));
+ //
+
+ //
+ // Begin executing the EBC code
+ //
+ EbcDebuggerHookEbcInterpret (&VmContext);
+ EbcExecute (&VmContext);
+
+ //
+ // Return the value in Gpr[7] unless there was an error
+ //
+ ReturnEBCStack(StackIndex);
+ return (UINT64) VmContext.Gpr[7];
+}
+
+
+/**
+ Begin executing an EBC image.
+
+ @param EntryPoint The entrypoint of EBC code.
+ @param ImageHandle image handle for the EBC application we're executing
+ @param SystemTable standard system table passed into an driver's entry
+ point
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+ExecuteEbcImageEntryPoint (
+ IN UINTN EntryPoint,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ //
+ // Create a new VM context on the stack
+ //
+ VM_CONTEXT VmContext;
+ UINTN Addr;
+ EFI_STATUS Status;
+ UINTN StackIndex;
+
+ //
+ // Get the EBC entry point
+ //
+ Addr = EntryPoint;
+
+ //
+ // Now clear out our context
+ //
+ ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
+
+ //
+ // Save the image handle so we can track the thunks created for this image
+ //
+ VmContext.ImageHandle = ImageHandle;
+ VmContext.SystemTable = SystemTable;
+
+ //
+ // Set the VM instruction pointer to the correct location in memory.
+ //
+ VmContext.Ip = (VMIP) Addr;
+
+ //
+ // Initialize the stack pointer for the EBC. Get the current system stack
+ // pointer and adjust it down by the max needed for the interpreter.
+ //
+
+ //
+ // Allocate stack pool
+ //
+ Status = GetEBCStack(ImageHandle, &VmContext.StackPool, &StackIndex);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
+ VmContext.Gpr[0] = (UINT64)(UINTN) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
+ VmContext.HighStackBottom = (UINTN)VmContext.Gpr[0];
+ VmContext.Gpr[0] -= sizeof (UINTN);
+
+ //
+ // Put a magic value in the stack gap, then adjust down again
+ //
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) VM_STACK_KEY_VALUE;
+ VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.Gpr[0];
+
+ //
+ // Align the stack on a natural boundary
+ // VmContext.Gpr[0] &= ~(sizeof(UINTN) - 1);
+ //
+ VmContext.LowStackTop = (UINTN) VmContext.Gpr[0];
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) SystemTable;
+ VmContext.Gpr[0] -= sizeof (UINTN);
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) ImageHandle;
+
+ VmContext.Gpr[0] -= 16;
+ VmContext.StackRetAddr = (UINT64) VmContext.Gpr[0];
+ //
+ // VM pushes 16-bytes for return address. Simulate that here.
+ //
+
+ //
+ // Begin executing the EBC code
+ //
+ EbcDebuggerHookExecuteEbcImageEntryPoint (&VmContext);
+ EbcExecute (&VmContext);
+
+ //
+ // Return the value in Gpr[7] unless there was an error
+ //
+ ReturnEBCStack(StackIndex);
+ return (UINT64) VmContext.Gpr[7];
+}
+
+
+/**
+ Create thunks for an EBC image entry point, or an EBC protocol service.
+
+ @param ImageHandle Image handle for the EBC image. If not null, then
+ we're creating a thunk for an image entry point.
+ @param EbcEntryPoint Address of the EBC code that the thunk is to call
+ @param Thunk Returned thunk we create here
+ @param Flags Flags indicating options for creating the thunk
+
+ @retval EFI_SUCCESS The thunk was created successfully.
+ @retval EFI_INVALID_PARAMETER The parameter of EbcEntryPoint is not 16-bit
+ aligned.
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory to created the EBC
+ Thunk.
+ @retval EFI_BUFFER_TOO_SMALL EBC_THUNK_SIZE is not larger enough.
+
+**/
+EFI_STATUS
+EbcCreateThunks (
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *EbcEntryPoint,
+ OUT VOID **Thunk,
+ IN UINT32 Flags
+ )
+{
+ UINT8 *Ptr;
+ UINT8 *ThunkBase;
+ UINT32 Index;
+ INT32 ThunkSize;
+
+ //
+ // Check alignment of pointer to EBC code
+ //
+ if ((UINT32) (UINTN) EbcEntryPoint & 0x01) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ThunkSize = sizeof(mInstructionBufferTemplate);
+
+ Ptr = EbcAllocatePoolForThunk (sizeof(mInstructionBufferTemplate));
+
+ if (Ptr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Print(L"Allocate TH: 0x%X\n", (UINT32)Ptr);
+ //
+ // Save the start address so we can add a pointer to it to a list later.
+ //
+ ThunkBase = Ptr;
+
+ //
+ // Give them the address of our buffer we're going to fix up
+ //
+ *Thunk = (VOID *) Ptr;
+
+ //
+ // Copy whole thunk instruction buffer template
+ //
+ CopyMem (Ptr, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate));
+
+ //
+ // Patch EbcEntryPoint and EbcLLEbcInterpret
+ //
+ for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {
+ if (*(UINTN *)&Ptr[Index] == EBC_ENTRYPOINT_SIGNATURE) {
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcEntryPoint;
+ }
+ if (*(UINTN *)&Ptr[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
+ if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcLLExecuteEbcImageEntryPoint;
+ } else {
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcLLEbcInterpret;
+ }
+ }
+ }
+
+ //
+ // Add the thunk to the list for this image. Do this last since the add
+ // function flushes the cache for us.
+ //
+ EbcAddImageThunk (ImageHandle, (VOID *) ThunkBase, ThunkSize);
+
+ return EFI_SUCCESS;
+}
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/X64/EbcLowLevel.nasm b/roms/edk2/MdeModulePkg/Universal/EbcDxe/X64/EbcLowLevel.nasm
new file mode 100644
index 000000000..3a8707616
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/X64/EbcLowLevel.nasm
@@ -0,0 +1,236 @@
+;/** @file
+;
+; This code provides low level routines that support the Virtual Machine.
+; for option ROMs.
+;
+; Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+; Copyright (c) 2014 Hewlett-Packard Development Company, L.P.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;**/
+
+;---------------------------------------------------------------------------
+; Equate files needed.
+;---------------------------------------------------------------------------
+
+DEFAULT REL
+SECTION .text
+
+extern ASM_PFX(CopyMem)
+extern ASM_PFX(EbcInterpret)
+extern ASM_PFX(ExecuteEbcImageEntryPoint)
+
+;****************************************************************************
+; EbcLLCALLEX
+;
+; This function is called to execute an EBC CALLEX instruction.
+; This instruction requires that we thunk out to external native
+; code. For x64, we switch stacks, copy the arguments to the stack
+; and jump to the specified function.
+; On return, we restore the stack pointer to its original location.
+;
+; Destroys no working registers.
+;****************************************************************************
+; INT64 EbcLLCALLEXNative(UINTN FuncAddr, UINTN NewStackPointer, VOID *FramePtr)
+global ASM_PFX(EbcLLCALLEXNative)
+ASM_PFX(EbcLLCALLEXNative):
+ push rbp
+ push rbx
+ mov rbp, rsp
+ ; Function prolog
+
+ ; Copy FuncAddr to a preserved register.
+ mov rbx, rcx
+
+ ; Set stack pointer to new value
+ sub r8, rdx
+
+ ;
+ ; Fix X64 native function call prolog. Prepare space for at least 4 arguments,
+ ; even if the native function's arguments are less than 4.
+ ;
+ ; From MSDN x64 Software Conventions, Overview of x64 Calling Conventions:
+ ; "The caller is responsible for allocating space for parameters to the
+ ; callee, and must always allocate sufficient space for the 4 register
+ ; parameters, even if the callee doesn't have that many parameters.
+ ; This aids in the simplicity of supporting C unprototyped functions,
+ ; and vararg C/C++ functions."
+ ;
+ cmp r8, 0x20
+ jae skip_expansion
+ mov r8, dword 0x20
+skip_expansion:
+
+ sub rsp, r8
+
+ ;
+ ; Fix X64 native function call 16-byte alignment.
+ ;
+ ; From MSDN x64 Software Conventions, Stack Usage:
+ ; "The stack will always be maintained 16-byte aligned, except within
+ ; the prolog (for example, after the return address is pushed)."
+ ;
+ and rsp, ~ 0xf
+
+ mov rcx, rsp
+ sub rsp, 0x20
+ call ASM_PFX(CopyMem)
+ add rsp, 0x20
+
+ ; Considering the worst case, load 4 potiential arguments
+ ; into registers.
+ mov rcx, qword [rsp]
+ mov rdx, qword [rsp+0x8]
+ mov r8, qword [rsp+0x10]
+ mov r9, qword [rsp+0x18]
+
+ ; Now call the external routine
+ call rbx
+
+ ; Function epilog
+ mov rsp, rbp
+ pop rbx
+ pop rbp
+ ret
+
+;****************************************************************************
+; EbcLLEbcInterpret
+;
+; Begin executing an EBC image.
+;****************************************************************************
+; UINT64 EbcLLEbcInterpret(VOID)
+global ASM_PFX(EbcLLEbcInterpret)
+ASM_PFX(EbcLLEbcInterpret):
+ ;
+ ;; mov rax, ca112ebccall2ebch
+ ;; mov r10, EbcEntryPoint
+ ;; mov r11, EbcLLEbcInterpret
+ ;; jmp r11
+ ;
+ ; Caller uses above instruction to jump here
+ ; The stack is below:
+ ; +-----------+
+ ; | RetAddr |
+ ; +-----------+
+ ; |EntryPoint | (R10)
+ ; +-----------+
+ ; | Arg1 | <- RDI
+ ; +-----------+
+ ; | Arg2 |
+ ; +-----------+
+ ; | ... |
+ ; +-----------+
+ ; | Arg16 |
+ ; +-----------+
+ ; | Dummy |
+ ; +-----------+
+ ; | RDI |
+ ; +-----------+
+ ; | RSI |
+ ; +-----------+
+ ; | RBP | <- RBP
+ ; +-----------+
+ ; | RetAddr | <- RSP is here
+ ; +-----------+
+ ; | Scratch1 | (RCX) <- RSI
+ ; +-----------+
+ ; | Scratch2 | (RDX)
+ ; +-----------+
+ ; | Scratch3 | (R8)
+ ; +-----------+
+ ; | Scratch4 | (R9)
+ ; +-----------+
+ ; | Arg5 |
+ ; +-----------+
+ ; | Arg6 |
+ ; +-----------+
+ ; | ... |
+ ; +-----------+
+ ; | Arg16 |
+ ; +-----------+
+ ;
+
+ ; save old parameter to stack
+ mov [rsp + 0x8], rcx
+ mov [rsp + 0x10], rdx
+ mov [rsp + 0x18], r8
+ mov [rsp + 0x20], r9
+
+ ; Construct new stack
+ push rbp
+ mov rbp, rsp
+ push rsi
+ push rdi
+ push rbx
+ sub rsp, 0x80
+ push r10
+ mov rsi, rbp
+ add rsi, 0x10
+ mov rdi, rsp
+ add rdi, 8
+ mov rcx, dword 16
+ rep movsq
+
+ ; build new paramater calling convention
+ mov r9, [rsp + 0x18]
+ mov r8, [rsp + 0x10]
+ mov rdx, [rsp + 0x8]
+ mov rcx, r10
+
+ ; call C-code
+ call ASM_PFX(EbcInterpret)
+ add rsp, 0x88
+ pop rbx
+ pop rdi
+ pop rsi
+ pop rbp
+ ret
+
+;****************************************************************************
+; EbcLLExecuteEbcImageEntryPoint
+;
+; Begin executing an EBC image.
+;****************************************************************************
+; UINT64 EbcLLExecuteEbcImageEntryPoint(VOID)
+global ASM_PFX(EbcLLExecuteEbcImageEntryPoint)
+ASM_PFX(EbcLLExecuteEbcImageEntryPoint):
+ ;
+ ;; mov rax, ca112ebccall2ebch
+ ;; mov r10, EbcEntryPoint
+ ;; mov r11, EbcLLExecuteEbcImageEntryPoint
+ ;; jmp r11
+ ;
+ ; Caller uses above instruction to jump here
+ ; The stack is below:
+ ; +-----------+
+ ; | RetAddr |
+ ; +-----------+
+ ; |EntryPoint | (R10)
+ ; +-----------+
+ ; |ImageHandle|
+ ; +-----------+
+ ; |SystemTable|
+ ; +-----------+
+ ; | Dummy |
+ ; +-----------+
+ ; | Dummy |
+ ; +-----------+
+ ; | RetAddr | <- RSP is here
+ ; +-----------+
+ ; |ImageHandle| (RCX)
+ ; +-----------+
+ ; |SystemTable| (RDX)
+ ; +-----------+
+ ;
+
+ ; build new paramater calling convention
+ mov r8, rdx
+ mov rdx, rcx
+ mov rcx, r10
+
+ ; call C-code
+ sub rsp, 0x28
+ call ASM_PFX(ExecuteEbcImageEntryPoint)
+ add rsp, 0x28
+ ret
+
diff --git a/roms/edk2/MdeModulePkg/Universal/EbcDxe/X64/EbcSupport.c b/roms/edk2/MdeModulePkg/Universal/EbcDxe/X64/EbcSupport.c
new file mode 100644
index 000000000..25ca8dbc4
--- /dev/null
+++ b/roms/edk2/MdeModulePkg/Universal/EbcDxe/X64/EbcSupport.c
@@ -0,0 +1,570 @@
+/** @file
+ This module contains EBC support routines that are customized based on
+ the target x64 processor.
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "EbcInt.h"
+#include "EbcExecute.h"
+#include "EbcDebuggerHook.h"
+
+//
+// NOTE: This is the stack size allocated for the interpreter
+// when it executes an EBC image. The requirements can change
+// based on whether or not a debugger is present, and other
+// platform-specific configurations.
+//
+#define VM_STACK_SIZE (1024 * 8)
+
+#define STACK_REMAIN_SIZE (1024 * 4)
+
+//
+// This is instruction buffer used to create EBC thunk
+//
+#define EBC_ENTRYPOINT_SIGNATURE 0xAFAFAFAFAFAFAFAFull
+#define EBC_LL_EBC_ENTRYPOINT_SIGNATURE 0xFAFAFAFAFAFAFAFAull
+UINT8 mInstructionBufferTemplate[] = {
+ //
+ // Add a magic code here to help the VM recognize the thunk..
+ // mov rax, 0xca112ebcca112ebc => 48 B8 BC 2E 11 CA BC 2E 11 CA
+ //
+ 0x48, 0xB8, 0xBC, 0x2E, 0x11, 0xCA, 0xBC, 0x2E, 0x11, 0xCA,
+ //
+ // Add code bytes to load up a processor register with the EBC entry point.
+ // mov r10, EbcEntryPoint => 49 BA XX XX XX XX XX XX XX XX (To be fixed at runtime)
+ // These 8 bytes of the thunk entry is the address of the EBC
+ // entry point.
+ //
+ 0x49, 0xBA,
+ (UINT8)(EBC_ENTRYPOINT_SIGNATURE & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 32) & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 40) & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 48) & 0xFF),
+ (UINT8)((EBC_ENTRYPOINT_SIGNATURE >> 56) & 0xFF),
+ //
+ // Stick in a load of r11 with the address of appropriate VM function.
+ // mov r11, EbcLLEbcInterpret => 49 BB XX XX XX XX XX XX XX XX (To be fixed at runtime)
+ //
+ 0x49, 0xBB,
+ (UINT8)(EBC_LL_EBC_ENTRYPOINT_SIGNATURE & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 8) & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 16) & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 24) & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 32) & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 40) & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 48) & 0xFF),
+ (UINT8)((EBC_LL_EBC_ENTRYPOINT_SIGNATURE >> 56) & 0xFF),
+ //
+ // Stick in jump opcode bytes
+ // jmp r11 => 41 FF E3
+ //
+ 0x41, 0xFF, 0xE3,
+};
+
+/**
+ Begin executing an EBC image.
+ This is used for Ebc Thunk call.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+EbcLLEbcInterpret (
+ VOID
+ );
+
+/**
+ Begin executing an EBC image.
+ This is used for Ebc image entrypoint.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+EbcLLExecuteEbcImageEntryPoint (
+ VOID
+ );
+
+/**
+ Pushes a 64 bit unsigned value to the VM stack.
+
+ @param VmPtr The pointer to current VM context.
+ @param Arg The value to be pushed.
+
+**/
+VOID
+PushU64 (
+ IN VM_CONTEXT *VmPtr,
+ IN UINT64 Arg
+ )
+{
+ //
+ // Advance the VM stack down, and then copy the argument to the stack.
+ // Hope it's aligned.
+ //
+ VmPtr->Gpr[0] -= sizeof (UINT64);
+ *(UINT64 *) VmPtr->Gpr[0] = Arg;
+ return;
+}
+
+
+/**
+ Begin executing an EBC image.
+
+ This is a thunk function. Microsoft x64 compiler only provide fast_call
+ calling convention, so the first four arguments are passed by rcx, rdx,
+ r8, and r9, while other arguments are passed in stack.
+
+ @param EntryPoint The entrypoint of EBC code.
+ @param Arg1 The 1st argument.
+ @param Arg2 The 2nd argument.
+ @param Arg3 The 3rd argument.
+ @param Arg4 The 4th argument.
+ @param Arg5 The 5th argument.
+ @param Arg6 The 6th argument.
+ @param Arg7 The 7th argument.
+ @param Arg8 The 8th argument.
+ @param Arg9 The 9th argument.
+ @param Arg10 The 10th argument.
+ @param Arg11 The 11th argument.
+ @param Arg12 The 12th argument.
+ @param Arg13 The 13th argument.
+ @param Arg14 The 14th argument.
+ @param Arg15 The 15th argument.
+ @param Arg16 The 16th argument.
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+EbcInterpret (
+ IN UINTN EntryPoint,
+ IN UINTN Arg1,
+ IN UINTN Arg2,
+ IN UINTN Arg3,
+ IN UINTN Arg4,
+ IN UINTN Arg5,
+ IN UINTN Arg6,
+ IN UINTN Arg7,
+ IN UINTN Arg8,
+ IN UINTN Arg9,
+ IN UINTN Arg10,
+ IN UINTN Arg11,
+ IN UINTN Arg12,
+ IN UINTN Arg13,
+ IN UINTN Arg14,
+ IN UINTN Arg15,
+ IN UINTN Arg16
+ )
+{
+ //
+ // Create a new VM context on the stack
+ //
+ VM_CONTEXT VmContext;
+ UINTN Addr;
+ EFI_STATUS Status;
+ UINTN StackIndex;
+
+ //
+ // Get the EBC entry point
+ //
+ Addr = EntryPoint;
+
+ //
+ // Now clear out our context
+ //
+ ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
+
+ //
+ // Set the VM instruction pointer to the correct location in memory.
+ //
+ VmContext.Ip = (VMIP) Addr;
+
+ //
+ // Initialize the stack pointer for the EBC. Get the current system stack
+ // pointer and adjust it down by the max needed for the interpreter.
+ //
+
+ //
+ // Adjust the VM's stack pointer down.
+ //
+
+ Status = GetEBCStack((EFI_HANDLE)(UINTN)-1, &VmContext.StackPool, &StackIndex);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
+ VmContext.Gpr[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
+ VmContext.HighStackBottom = (UINTN) VmContext.Gpr[0];
+ VmContext.Gpr[0] -= sizeof (UINTN);
+
+ //
+ // Align the stack on a natural boundary.
+ //
+ VmContext.Gpr[0] &= ~(VM_REGISTER)(sizeof (UINTN) - 1);
+
+ //
+ // Put a magic value in the stack gap, then adjust down again.
+ //
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) VM_STACK_KEY_VALUE;
+ VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.Gpr[0];
+
+ //
+ // The stack upper to LowStackTop is belong to the VM.
+ //
+ VmContext.LowStackTop = (UINTN) VmContext.Gpr[0];
+
+ //
+ // For the worst case, assume there are 4 arguments passed in registers, store
+ // them to VM's stack.
+ //
+ PushU64 (&VmContext, (UINT64) Arg16);
+ PushU64 (&VmContext, (UINT64) Arg15);
+ PushU64 (&VmContext, (UINT64) Arg14);
+ PushU64 (&VmContext, (UINT64) Arg13);
+ PushU64 (&VmContext, (UINT64) Arg12);
+ PushU64 (&VmContext, (UINT64) Arg11);
+ PushU64 (&VmContext, (UINT64) Arg10);
+ PushU64 (&VmContext, (UINT64) Arg9);
+ PushU64 (&VmContext, (UINT64) Arg8);
+ PushU64 (&VmContext, (UINT64) Arg7);
+ PushU64 (&VmContext, (UINT64) Arg6);
+ PushU64 (&VmContext, (UINT64) Arg5);
+ PushU64 (&VmContext, (UINT64) Arg4);
+ PushU64 (&VmContext, (UINT64) Arg3);
+ PushU64 (&VmContext, (UINT64) Arg2);
+ PushU64 (&VmContext, (UINT64) Arg1);
+
+ //
+ // Interpreter assumes 64-bit return address is pushed on the stack.
+ // The x64 does not do this so pad the stack accordingly.
+ //
+ PushU64 (&VmContext, (UINT64) 0);
+ PushU64 (&VmContext, (UINT64) 0x1234567887654321ULL);
+
+ //
+ // For x64, this is where we say our return address is
+ //
+ VmContext.StackRetAddr = (UINT64) VmContext.Gpr[0];
+
+ //
+ // We need to keep track of where the EBC stack starts. This way, if the EBC
+ // accesses any stack variables above its initial stack setting, then we know
+ // it's accessing variables passed into it, which means the data is on the
+ // VM's stack.
+ // When we're called, on the stack (high to low) we have the parameters, the
+ // return address, then the saved ebp. Save the pointer to the return address.
+ // EBC code knows that's there, so should look above it for function parameters.
+ // The offset is the size of locals (VMContext + Addr + saved ebp).
+ // Note that the interpreter assumes there is a 16 bytes of return address on
+ // the stack too, so adjust accordingly.
+ // VmContext.HighStackBottom = (UINTN)(Addr + sizeof (VmContext) + sizeof (Addr));
+ //
+
+ //
+ // Begin executing the EBC code
+ //
+ EbcDebuggerHookEbcInterpret (&VmContext);
+ EbcExecute (&VmContext);
+
+ //
+ // Return the value in Gpr[7] unless there was an error
+ //
+ ReturnEBCStack(StackIndex);
+ return (UINT64) VmContext.Gpr[7];
+}
+
+
+/**
+ Begin executing an EBC image.
+
+ @param EntryPoint The entrypoint of EBC code.
+ @param ImageHandle image handle for the EBC application we're executing
+ @param SystemTable standard system table passed into an driver's entry
+ point
+
+ @return The value returned by the EBC application we're going to run.
+
+**/
+UINT64
+EFIAPI
+ExecuteEbcImageEntryPoint (
+ IN UINTN EntryPoint,
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ //
+ // Create a new VM context on the stack
+ //
+ VM_CONTEXT VmContext;
+ UINTN Addr;
+ EFI_STATUS Status;
+ UINTN StackIndex;
+
+ //
+ // Get the EBC entry point
+ //
+ Addr = EntryPoint;
+
+ //
+ // Now clear out our context
+ //
+ ZeroMem ((VOID *) &VmContext, sizeof (VM_CONTEXT));
+
+ //
+ // Save the image handle so we can track the thunks created for this image
+ //
+ VmContext.ImageHandle = ImageHandle;
+ VmContext.SystemTable = SystemTable;
+
+ //
+ // Set the VM instruction pointer to the correct location in memory.
+ //
+ VmContext.Ip = (VMIP) Addr;
+
+ //
+ // Initialize the stack pointer for the EBC. Get the current system stack
+ // pointer and adjust it down by the max needed for the interpreter.
+ //
+
+ Status = GetEBCStack(ImageHandle, &VmContext.StackPool, &StackIndex);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ VmContext.StackTop = (UINT8*)VmContext.StackPool + (STACK_REMAIN_SIZE);
+ VmContext.Gpr[0] = (UINT64) ((UINT8*)VmContext.StackPool + STACK_POOL_SIZE);
+ VmContext.HighStackBottom = (UINTN) VmContext.Gpr[0];
+ VmContext.Gpr[0] -= sizeof (UINTN);
+
+
+ //
+ // Put a magic value in the stack gap, then adjust down again
+ //
+ *(UINTN *) (UINTN) (VmContext.Gpr[0]) = (UINTN) VM_STACK_KEY_VALUE;
+ VmContext.StackMagicPtr = (UINTN *) (UINTN) VmContext.Gpr[0];
+
+ //
+ // Align the stack on a natural boundary
+ VmContext.Gpr[0] &= ~(VM_REGISTER)(sizeof(UINTN) - 1);
+ //
+ VmContext.LowStackTop = (UINTN) VmContext.Gpr[0];
+
+ //
+ // Simply copy the image handle and system table onto the EBC stack.
+ // Greatly simplifies things by not having to spill the args.
+ //
+ PushU64 (&VmContext, (UINT64) SystemTable);
+ PushU64 (&VmContext, (UINT64) ImageHandle);
+
+ //
+ // VM pushes 16-bytes for return address. Simulate that here.
+ //
+ PushU64 (&VmContext, (UINT64) 0);
+ PushU64 (&VmContext, (UINT64) 0x1234567887654321ULL);
+
+ //
+ // For x64, this is where we say our return address is
+ //
+ VmContext.StackRetAddr = (UINT64) VmContext.Gpr[0];
+
+ //
+ // Entry function needn't access high stack context, simply
+ // put the stack pointer here.
+ //
+
+ //
+ // Begin executing the EBC code
+ //
+ EbcDebuggerHookExecuteEbcImageEntryPoint (&VmContext);
+ EbcExecute (&VmContext);
+
+ //
+ // Return the value in Gpr[7] unless there was an error
+ //
+ ReturnEBCStack(StackIndex);
+ return (UINT64) VmContext.Gpr[7];
+}
+
+
+/**
+ Create thunks for an EBC image entry point, or an EBC protocol service.
+
+ @param ImageHandle Image handle for the EBC image. If not null, then
+ we're creating a thunk for an image entry point.
+ @param EbcEntryPoint Address of the EBC code that the thunk is to call
+ @param Thunk Returned thunk we create here
+ @param Flags Flags indicating options for creating the thunk
+
+ @retval EFI_SUCCESS The thunk was created successfully.
+ @retval EFI_INVALID_PARAMETER The parameter of EbcEntryPoint is not 16-bit
+ aligned.
+ @retval EFI_OUT_OF_RESOURCES There is not enough memory to created the EBC
+ Thunk.
+ @retval EFI_BUFFER_TOO_SMALL EBC_THUNK_SIZE is not larger enough.
+
+**/
+EFI_STATUS
+EbcCreateThunks (
+ IN EFI_HANDLE ImageHandle,
+ IN VOID *EbcEntryPoint,
+ OUT VOID **Thunk,
+ IN UINT32 Flags
+ )
+{
+ UINT8 *Ptr;
+ UINT8 *ThunkBase;
+ UINT32 Index;
+ INT32 ThunkSize;
+
+ //
+ // Check alignment of pointer to EBC code
+ //
+ if ((UINT32) (UINTN) EbcEntryPoint & 0x01) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ThunkSize = sizeof(mInstructionBufferTemplate);
+
+ Ptr = EbcAllocatePoolForThunk (sizeof(mInstructionBufferTemplate));
+
+ if (Ptr == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Print(L"Allocate TH: 0x%X\n", (UINT32)Ptr);
+ //
+ // Save the start address so we can add a pointer to it to a list later.
+ //
+ ThunkBase = Ptr;
+
+ //
+ // Give them the address of our buffer we're going to fix up
+ //
+ *Thunk = (VOID *) Ptr;
+
+ //
+ // Copy whole thunk instruction buffer template
+ //
+ CopyMem (Ptr, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate));
+
+ //
+ // Patch EbcEntryPoint and EbcLLEbcInterpret
+ //
+ for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {
+ if (*(UINTN *)&Ptr[Index] == EBC_ENTRYPOINT_SIGNATURE) {
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcEntryPoint;
+ }
+ if (*(UINTN *)&Ptr[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
+ if ((Flags & FLAG_THUNK_ENTRY_POINT) != 0) {
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcLLExecuteEbcImageEntryPoint;
+ } else {
+ *(UINTN *)&Ptr[Index] = (UINTN)EbcLLEbcInterpret;
+ }
+ }
+ }
+
+ //
+ // Add the thunk to the list for this image. Do this last since the add
+ // function flushes the cache for us.
+ //
+ EbcAddImageThunk (ImageHandle, (VOID *) ThunkBase, ThunkSize);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function is called to execute an EBC CALLEX instruction.
+ The function check the callee's content to see whether it is common native
+ code or a thunk to another piece of EBC code.
+ If the callee is common native code, use EbcLLCAllEXASM to manipulate,
+ otherwise, set the VM->IP to target EBC code directly to avoid another VM
+ be startup which cost time and stack space.
+
+ @param VmPtr Pointer to a VM context.
+ @param FuncAddr Callee's address
+ @param NewStackPointer New stack pointer after the call
+ @param FramePtr New frame pointer after the call
+ @param Size The size of call instruction
+
+**/
+VOID
+EbcLLCALLEX (
+ IN VM_CONTEXT *VmPtr,
+ IN UINTN FuncAddr,
+ IN UINTN NewStackPointer,
+ IN VOID *FramePtr,
+ IN UINT8 Size
+ )
+{
+ UINTN IsThunk;
+ UINTN TargetEbcAddr;
+ UINT8 InstructionBuffer[sizeof(mInstructionBufferTemplate)];
+ UINTN Index;
+ UINTN IndexOfEbcEntrypoint;
+
+ IsThunk = 1;
+ TargetEbcAddr = 0;
+ IndexOfEbcEntrypoint = 0;
+
+ //
+ // Processor specific code to check whether the callee is a thunk to EBC.
+ //
+ CopyMem (InstructionBuffer, (VOID *)FuncAddr, sizeof(InstructionBuffer));
+ //
+ // Fill the signature according to mInstructionBufferTemplate
+ //
+ for (Index = 0; Index < sizeof(mInstructionBufferTemplate) - sizeof(UINTN); Index++) {
+ if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_ENTRYPOINT_SIGNATURE) {
+ *(UINTN *)&InstructionBuffer[Index] = EBC_ENTRYPOINT_SIGNATURE;
+ IndexOfEbcEntrypoint = Index;
+ }
+ if (*(UINTN *)&mInstructionBufferTemplate[Index] == EBC_LL_EBC_ENTRYPOINT_SIGNATURE) {
+ *(UINTN *)&InstructionBuffer[Index] = EBC_LL_EBC_ENTRYPOINT_SIGNATURE;
+ }
+ }
+ //
+ // Check if we need thunk to native
+ //
+ if (CompareMem (InstructionBuffer, mInstructionBufferTemplate, sizeof(mInstructionBufferTemplate)) != 0) {
+ IsThunk = 0;
+ }
+
+ if (IsThunk == 1){
+ //
+ // The callee is a thunk to EBC, adjust the stack pointer down 16 bytes and
+ // put our return address and frame pointer on the VM stack.
+ // Then set the VM's IP to new EBC code.
+ //
+ VmPtr->Gpr[0] -= 8;
+ VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], (UINTN) FramePtr);
+ VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0];
+ VmPtr->Gpr[0] -= 8;
+ VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (VmPtr->Ip + Size));
+
+ CopyMem (&TargetEbcAddr, (UINT8 *)FuncAddr + IndexOfEbcEntrypoint, sizeof(UINTN));
+ VmPtr->Ip = (VMIP) (UINTN) TargetEbcAddr;
+ } else {
+ //
+ // The callee is not a thunk to EBC, call native code,
+ // and get return value.
+ //
+ VmPtr->Gpr[7] = EbcLLCALLEXNative (FuncAddr, NewStackPointer, FramePtr);
+
+ //
+ // Advance the IP.
+ //
+ VmPtr->Ip += Size;
+ }
+}
+