Home | History | Annotate | Download | only in EbcDxe
      1 /** @file
      2   Contains code that implements the virtual machine.
      3 
      4 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "EbcInt.h"
     16 #include "EbcExecute.h"
     17 #include "EbcDebuggerHook.h"
     18 
     19 
     20 //
     21 // Define some useful data size constants to allow switch statements based on
     22 // size of operands or data.
     23 //
     24 #define DATA_SIZE_INVALID 0
     25 #define DATA_SIZE_8       1
     26 #define DATA_SIZE_16      2
     27 #define DATA_SIZE_32      4
     28 #define DATA_SIZE_64      8
     29 #define DATA_SIZE_N       48  // 4 or 8
     30 //
     31 // Structure we'll use to dispatch opcodes to execute functions.
     32 //
     33 typedef struct {
     34   EFI_STATUS (*ExecuteFunction) (IN VM_CONTEXT * VmPtr);
     35 }
     36 VM_TABLE_ENTRY;
     37 
     38 typedef
     39 UINT64
     40 (*DATA_MANIP_EXEC_FUNCTION) (
     41   IN VM_CONTEXT * VmPtr,
     42   IN UINT64     Op1,
     43   IN UINT64     Op2
     44   );
     45 
     46 /**
     47   Decode a 16-bit index to determine the offset. Given an index value:
     48 
     49     b15     - sign bit
     50     b14:12  - number of bits in this index assigned to natural units (=a)
     51     ba:11   - constant units = ConstUnits
     52     b0:a    - natural units = NaturalUnits
     53 
     54   Given this info, the offset can be computed by:
     55     offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
     56 
     57   Max offset is achieved with index = 0x7FFF giving an offset of
     58   0x27B (32-bit machine) or 0x477 (64-bit machine).
     59   Min offset is achieved with index =
     60 
     61   @param  VmPtr             A pointer to VM context.
     62   @param  CodeOffset        Offset from IP of the location of the 16-bit index
     63                             to decode.
     64 
     65   @return The decoded offset.
     66 
     67 **/
     68 INT16
     69 VmReadIndex16 (
     70   IN VM_CONTEXT     *VmPtr,
     71   IN UINT32         CodeOffset
     72   );
     73 
     74 /**
     75   Decode a 32-bit index to determine the offset.
     76 
     77   @param  VmPtr             A pointer to VM context.
     78   @param  CodeOffset        Offset from IP of the location of the 32-bit index
     79                             to decode.
     80 
     81   @return Converted index per EBC VM specification.
     82 
     83 **/
     84 INT32
     85 VmReadIndex32 (
     86   IN VM_CONTEXT     *VmPtr,
     87   IN UINT32         CodeOffset
     88   );
     89 
     90 /**
     91   Decode a 64-bit index to determine the offset.
     92 
     93   @param  VmPtr             A pointer to VM context.s
     94   @param  CodeOffset        Offset from IP of the location of the 64-bit index
     95                             to decode.
     96 
     97   @return Converted index per EBC VM specification
     98 
     99 **/
    100 INT64
    101 VmReadIndex64 (
    102   IN VM_CONTEXT     *VmPtr,
    103   IN UINT32         CodeOffset
    104   );
    105 
    106 /**
    107   Reads 8-bit data form the memory address.
    108 
    109   @param  VmPtr             A pointer to VM context.
    110   @param  Addr              The memory address.
    111 
    112   @return The 8-bit value from the memory address.
    113 
    114 **/
    115 UINT8
    116 VmReadMem8 (
    117   IN VM_CONTEXT   *VmPtr,
    118   IN UINTN        Addr
    119   );
    120 
    121 /**
    122   Reads 16-bit data form the memory address.
    123 
    124   @param  VmPtr             A pointer to VM context.
    125   @param  Addr              The memory address.
    126 
    127   @return The 16-bit value from the memory address.
    128 
    129 **/
    130 UINT16
    131 VmReadMem16 (
    132   IN VM_CONTEXT *VmPtr,
    133   IN UINTN      Addr
    134   );
    135 
    136 /**
    137   Reads 32-bit data form the memory address.
    138 
    139   @param  VmPtr             A pointer to VM context.
    140   @param  Addr              The memory address.
    141 
    142   @return The 32-bit value from the memory address.
    143 
    144 **/
    145 UINT32
    146 VmReadMem32 (
    147   IN VM_CONTEXT *VmPtr,
    148   IN UINTN      Addr
    149   );
    150 
    151 /**
    152   Reads 64-bit data form the memory address.
    153 
    154   @param  VmPtr             A pointer to VM context.
    155   @param  Addr              The memory address.
    156 
    157   @return The 64-bit value from the memory address.
    158 
    159 **/
    160 UINT64
    161 VmReadMem64 (
    162   IN VM_CONTEXT   *VmPtr,
    163   IN UINTN        Addr
    164   );
    165 
    166 /**
    167   Read a natural value from memory. May or may not be aligned.
    168 
    169   @param  VmPtr             current VM context
    170   @param  Addr              the address to read from
    171 
    172   @return The natural value at address Addr.
    173 
    174 **/
    175 UINTN
    176 VmReadMemN (
    177   IN VM_CONTEXT    *VmPtr,
    178   IN UINTN         Addr
    179   );
    180 
    181 /**
    182   Writes 8-bit data to memory address.
    183 
    184   This routine is called by the EBC data
    185   movement instructions that write to memory. Since these writes
    186   may be to the stack, which looks like (high address on top) this,
    187 
    188   [EBC entry point arguments]
    189   [VM stack]
    190   [EBC stack]
    191 
    192   we need to detect all attempts to write to the EBC entry point argument
    193   stack area and adjust the address (which will initially point into the
    194   VM stack) to point into the EBC entry point arguments.
    195 
    196   @param  VmPtr             A pointer to a VM context.
    197   @param  Addr              Address to write to.
    198   @param  Data              Value to write to Addr.
    199 
    200   @retval EFI_SUCCESS       The instruction is executed successfully.
    201   @retval Other             Some error occurs when writing data to the address.
    202 
    203 **/
    204 EFI_STATUS
    205 VmWriteMem8 (
    206   IN VM_CONTEXT    *VmPtr,
    207   IN UINTN         Addr,
    208   IN UINT8         Data
    209   );
    210 
    211 /**
    212   Writes 16-bit data to memory address.
    213 
    214   This routine is called by the EBC data
    215   movement instructions that write to memory. Since these writes
    216   may be to the stack, which looks like (high address on top) this,
    217 
    218   [EBC entry point arguments]
    219   [VM stack]
    220   [EBC stack]
    221 
    222   we need to detect all attempts to write to the EBC entry point argument
    223   stack area and adjust the address (which will initially point into the
    224   VM stack) to point into the EBC entry point arguments.
    225 
    226   @param  VmPtr             A pointer to a VM context.
    227   @param  Addr              Address to write to.
    228   @param  Data              Value to write to Addr.
    229 
    230   @retval EFI_SUCCESS       The instruction is executed successfully.
    231   @retval Other             Some error occurs when writing data to the address.
    232 
    233 **/
    234 EFI_STATUS
    235 VmWriteMem16 (
    236   IN VM_CONTEXT   *VmPtr,
    237   IN UINTN        Addr,
    238   IN UINT16       Data
    239   );
    240 
    241 /**
    242   Writes 32-bit data to memory address.
    243 
    244   This routine is called by the EBC data
    245   movement instructions that write to memory. Since these writes
    246   may be to the stack, which looks like (high address on top) this,
    247 
    248   [EBC entry point arguments]
    249   [VM stack]
    250   [EBC stack]
    251 
    252   we need to detect all attempts to write to the EBC entry point argument
    253   stack area and adjust the address (which will initially point into the
    254   VM stack) to point into the EBC entry point arguments.
    255 
    256   @param  VmPtr             A pointer to a VM context.
    257   @param  Addr              Address to write to.
    258   @param  Data              Value to write to Addr.
    259 
    260   @retval EFI_SUCCESS       The instruction is executed successfully.
    261   @retval Other             Some error occurs when writing data to the address.
    262 
    263 **/
    264 EFI_STATUS
    265 VmWriteMem32 (
    266   IN VM_CONTEXT   *VmPtr,
    267   IN UINTN        Addr,
    268   IN UINT32       Data
    269   );
    270 
    271 /**
    272   Reads 16-bit unsigned data from the code stream.
    273 
    274   This routine provides the ability to read raw unsigned data from the code
    275   stream.
    276 
    277   @param  VmPtr             A pointer to VM context
    278   @param  Offset            Offset from current IP to the raw data to read.
    279 
    280   @return The raw unsigned 16-bit value from the code stream.
    281 
    282 **/
    283 UINT16
    284 VmReadCode16 (
    285   IN VM_CONTEXT *VmPtr,
    286   IN UINT32     Offset
    287   );
    288 
    289 /**
    290   Reads 32-bit unsigned data from the code stream.
    291 
    292   This routine provides the ability to read raw unsigned data from the code
    293   stream.
    294 
    295   @param  VmPtr             A pointer to VM context
    296   @param  Offset            Offset from current IP to the raw data to read.
    297 
    298   @return The raw unsigned 32-bit value from the code stream.
    299 
    300 **/
    301 UINT32
    302 VmReadCode32 (
    303   IN VM_CONTEXT *VmPtr,
    304   IN UINT32     Offset
    305   );
    306 
    307 /**
    308   Reads 64-bit unsigned data from the code stream.
    309 
    310   This routine provides the ability to read raw unsigned data from the code
    311   stream.
    312 
    313   @param  VmPtr             A pointer to VM context
    314   @param  Offset            Offset from current IP to the raw data to read.
    315 
    316   @return The raw unsigned 64-bit value from the code stream.
    317 
    318 **/
    319 UINT64
    320 VmReadCode64 (
    321   IN VM_CONTEXT *VmPtr,
    322   IN UINT32     Offset
    323   );
    324 
    325 /**
    326   Reads 8-bit immediate value at the offset.
    327 
    328   This routine is called by the EBC execute
    329   functions to read EBC immediate values from the code stream.
    330   Since we can't assume alignment, each tries to read in the biggest
    331   chunks size available, but will revert to smaller reads if necessary.
    332 
    333   @param  VmPtr             A pointer to a VM context.
    334   @param  Offset            offset from IP of the code bytes to read.
    335 
    336   @return Signed data of the requested size from the specified address.
    337 
    338 **/
    339 INT8
    340 VmReadImmed8 (
    341   IN VM_CONTEXT *VmPtr,
    342   IN UINT32     Offset
    343   );
    344 
    345 /**
    346   Reads 16-bit immediate value at the offset.
    347 
    348   This routine is called by the EBC execute
    349   functions to read EBC immediate values from the code stream.
    350   Since we can't assume alignment, each tries to read in the biggest
    351   chunks size available, but will revert to smaller reads if necessary.
    352 
    353   @param  VmPtr             A pointer to a VM context.
    354   @param  Offset            offset from IP of the code bytes to read.
    355 
    356   @return Signed data of the requested size from the specified address.
    357 
    358 **/
    359 INT16
    360 VmReadImmed16 (
    361   IN VM_CONTEXT *VmPtr,
    362   IN UINT32     Offset
    363   );
    364 
    365 /**
    366   Reads 32-bit immediate value at the offset.
    367 
    368   This routine is called by the EBC execute
    369   functions to read EBC immediate values from the code stream.
    370   Since we can't assume alignment, each tries to read in the biggest
    371   chunks size available, but will revert to smaller reads if necessary.
    372 
    373   @param  VmPtr             A pointer to a VM context.
    374   @param  Offset            offset from IP of the code bytes to read.
    375 
    376   @return Signed data of the requested size from the specified address.
    377 
    378 **/
    379 INT32
    380 VmReadImmed32 (
    381   IN VM_CONTEXT *VmPtr,
    382   IN UINT32     Offset
    383   );
    384 
    385 /**
    386   Reads 64-bit immediate value at the offset.
    387 
    388   This routine is called by the EBC execute
    389   functions to read EBC immediate values from the code stream.
    390   Since we can't assume alignment, each tries to read in the biggest
    391   chunks size available, but will revert to smaller reads if necessary.
    392 
    393   @param  VmPtr             A pointer to a VM context.
    394   @param  Offset            offset from IP of the code bytes to read.
    395 
    396   @return Signed data of the requested size from the specified address.
    397 
    398 **/
    399 INT64
    400 VmReadImmed64 (
    401   IN VM_CONTEXT *VmPtr,
    402   IN UINT32     Offset
    403   );
    404 
    405 /**
    406   Given an address that EBC is going to read from or write to, return
    407   an appropriate address that accounts for a gap in the stack.
    408   The stack for this application looks like this (high addr on top)
    409   [EBC entry point arguments]
    410   [VM stack]
    411   [EBC stack]
    412   The EBC assumes that its arguments are at the top of its stack, which
    413   is where the VM stack is really. Therefore if the EBC does memory
    414   accesses into the VM stack area, then we need to convert the address
    415   to point to the EBC entry point arguments area. Do this here.
    416 
    417   @param  VmPtr             A Pointer to VM context.
    418   @param  Addr              Address of interest
    419 
    420   @return The unchanged address if it's not in the VM stack region. Otherwise,
    421           adjust for the stack gap and return the modified address.
    422 
    423 **/
    424 UINTN
    425 ConvertStackAddr (
    426   IN VM_CONTEXT    *VmPtr,
    427   IN UINTN         Addr
    428   );
    429 
    430 /**
    431   Execute all the EBC data manipulation instructions.
    432   Since the EBC data manipulation instructions all have the same basic form,
    433   they can share the code that does the fetch of operands and the write-back
    434   of the result. This function performs the fetch of the operands (even if
    435   both are not needed to be fetched, like NOT instruction), dispatches to the
    436   appropriate subfunction, then writes back the returned result.
    437 
    438   Format:
    439     INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
    440 
    441   @param  VmPtr             A pointer to VM context.
    442   @param  IsSignedOp        Indicates whether the operand is signed or not.
    443 
    444   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
    445   @retval EFI_SUCCESS       The instruction is executed successfully.
    446 
    447 **/
    448 EFI_STATUS
    449 ExecuteDataManip (
    450   IN VM_CONTEXT   *VmPtr,
    451   IN BOOLEAN      IsSignedOp
    452   );
    453 
    454 //
    455 // Functions that execute VM opcodes
    456 //
    457 /**
    458   Execute the EBC BREAK instruction.
    459 
    460   @param  VmPtr             A pointer to a VM context.
    461 
    462   @retval EFI_SUCCESS       The instruction is executed successfully.
    463 
    464 **/
    465 EFI_STATUS
    466 ExecuteBREAK (
    467   IN VM_CONTEXT *VmPtr
    468   );
    469 
    470 /**
    471   Execute the JMP instruction.
    472 
    473   Instruction syntax:
    474     JMP64{cs|cc} Immed64
    475     JMP32{cs|cc} {@}R1 {Immed32|Index32}
    476 
    477   Encoding:
    478     b0.7 -  immediate data present
    479     b0.6 -  1 = 64 bit immediate data
    480             0 = 32 bit immediate data
    481     b1.7 -  1 = conditional
    482     b1.6    1 = CS (condition set)
    483             0 = CC (condition clear)
    484     b1.4    1 = relative address
    485             0 = absolute address
    486     b1.3    1 = operand1 indirect
    487     b1.2-0  operand 1
    488 
    489   @param  VmPtr             A pointer to a VM context.
    490 
    491   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
    492   @retval EFI_SUCCESS       The instruction is executed successfully.
    493 
    494 **/
    495 EFI_STATUS
    496 ExecuteJMP (
    497   IN VM_CONTEXT *VmPtr
    498   );
    499 
    500 /**
    501   Execute the EBC JMP8 instruction.
    502 
    503   Instruction syntax:
    504     JMP8{cs|cc}  Offset/2
    505 
    506   @param  VmPtr             A pointer to a VM context.
    507 
    508   @retval EFI_SUCCESS       The instruction is executed successfully.
    509 
    510 **/
    511 EFI_STATUS
    512 ExecuteJMP8 (
    513   IN VM_CONTEXT *VmPtr
    514   );
    515 
    516 /**
    517   Implements the EBC CALL instruction.
    518 
    519   Instruction format:
    520     CALL64 Immed64
    521     CALL32 {@}R1 {Immed32|Index32}
    522     CALLEX64 Immed64
    523     CALLEX16 {@}R1 {Immed32}
    524 
    525     If Rx == R0, then it's a PC relative call to PC = PC + imm32.
    526 
    527   @param  VmPtr             A pointer to a VM context.
    528 
    529   @retval EFI_SUCCESS       The instruction is executed successfully.
    530 
    531 **/
    532 EFI_STATUS
    533 ExecuteCALL (
    534   IN VM_CONTEXT *VmPtr
    535   );
    536 
    537 /**
    538   Execute the EBC RET instruction.
    539 
    540   Instruction syntax:
    541     RET
    542 
    543   @param  VmPtr             A pointer to a VM context.
    544 
    545   @retval EFI_SUCCESS       The instruction is executed successfully.
    546 
    547 **/
    548 EFI_STATUS
    549 ExecuteRET (
    550   IN VM_CONTEXT *VmPtr
    551   );
    552 
    553 /**
    554   Execute the EBC CMP instruction.
    555 
    556   Instruction syntax:
    557     CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
    558 
    559   @param  VmPtr             A pointer to a VM context.
    560 
    561   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
    562   @retval EFI_SUCCESS       The instruction is executed successfully.
    563 
    564 **/
    565 EFI_STATUS
    566 ExecuteCMP (
    567   IN VM_CONTEXT *VmPtr
    568   );
    569 
    570 /**
    571   Execute the EBC CMPI instruction
    572 
    573   Instruction syntax:
    574     CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
    575 
    576   @param  VmPtr             A pointer to a VM context.
    577 
    578   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
    579   @retval EFI_SUCCESS       The instruction is executed successfully.
    580 
    581 **/
    582 EFI_STATUS
    583 ExecuteCMPI (
    584   IN VM_CONTEXT *VmPtr
    585   );
    586 
    587 /**
    588   Execute the MOVxx instructions.
    589 
    590   Instruction format:
    591 
    592     MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
    593     MOVqq {@}R1 {Index64}, {@}R2 {Index64}
    594 
    595     Copies contents of [R2] -> [R1], zero extending where required.
    596 
    597     First character indicates the size of the move.
    598     Second character indicates the size of the index(s).
    599 
    600     Invalid to have R1 direct with index.
    601 
    602   @param  VmPtr             A pointer to a VM context.
    603 
    604   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
    605   @retval EFI_SUCCESS       The instruction is executed successfully.
    606 
    607 **/
    608 EFI_STATUS
    609 ExecuteMOVxx (
    610   IN VM_CONTEXT *VmPtr
    611   );
    612 
    613 /**
    614   Execute the EBC MOVI.
    615 
    616   Instruction syntax:
    617 
    618     MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
    619 
    620     First variable character specifies the move size
    621     Second variable character specifies size of the immediate data
    622 
    623     Sign-extend the immediate data to the size of the operation, and zero-extend
    624     if storing to a register.
    625 
    626     Operand1 direct with index/immed is invalid.
    627 
    628   @param  VmPtr             A pointer to a VM context.
    629 
    630   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
    631   @retval EFI_SUCCESS       The instruction is executed successfully.
    632 
    633 **/
    634 EFI_STATUS
    635 ExecuteMOVI (
    636   IN VM_CONTEXT *VmPtr
    637   );
    638 
    639 /**
    640   Execute the EBC MOV immediate natural. This instruction moves an immediate
    641   index value into a register or memory location.
    642 
    643   Instruction syntax:
    644 
    645     MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
    646 
    647   @param  VmPtr             A pointer to a VM context.
    648 
    649   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
    650   @retval EFI_SUCCESS       The instruction is executed successfully.
    651 
    652 **/
    653 EFI_STATUS
    654 ExecuteMOVIn (
    655   IN VM_CONTEXT *VmPtr
    656   );
    657 
    658 /**
    659   Execute the EBC MOVREL instruction.
    660   Dest <- Ip + ImmData
    661 
    662   Instruction syntax:
    663 
    664     MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
    665 
    666   @param  VmPtr             A pointer to a VM context.
    667 
    668   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
    669   @retval EFI_SUCCESS       The instruction is executed successfully.
    670 
    671 **/
    672 EFI_STATUS
    673 ExecuteMOVREL (
    674   IN VM_CONTEXT *VmPtr
    675   );
    676 
    677 /**
    678   Execute the EBC PUSHn instruction
    679 
    680   Instruction syntax:
    681     PUSHn {@}R1 {Index16|Immed16}
    682 
    683   @param  VmPtr             A pointer to a VM context.
    684 
    685   @retval EFI_SUCCESS       The instruction is executed successfully.
    686 
    687 **/
    688 EFI_STATUS
    689 ExecutePUSHn (
    690   IN VM_CONTEXT *VmPtr
    691   );
    692 
    693 /**
    694   Execute the EBC PUSH instruction.
    695 
    696   Instruction syntax:
    697     PUSH[32|64] {@}R1 {Index16|Immed16}
    698 
    699   @param  VmPtr             A pointer to a VM context.
    700 
    701   @retval EFI_SUCCESS       The instruction is executed successfully.
    702 
    703 **/
    704 EFI_STATUS
    705 ExecutePUSH (
    706   IN VM_CONTEXT *VmPtr
    707   );
    708 
    709 /**
    710   Execute the EBC POPn instruction.
    711 
    712   Instruction syntax:
    713     POPn {@}R1 {Index16|Immed16}
    714 
    715   @param  VmPtr             A pointer to a VM context.
    716 
    717   @retval EFI_SUCCESS       The instruction is executed successfully.
    718 
    719 **/
    720 EFI_STATUS
    721 ExecutePOPn (
    722   IN VM_CONTEXT *VmPtr
    723   );
    724 
    725 /**
    726   Execute the EBC POP instruction.
    727 
    728   Instruction syntax:
    729     POPn {@}R1 {Index16|Immed16}
    730 
    731   @param  VmPtr             A pointer to a VM context.
    732 
    733   @retval EFI_SUCCESS       The instruction is executed successfully.
    734 
    735 **/
    736 EFI_STATUS
    737 ExecutePOP (
    738   IN VM_CONTEXT *VmPtr
    739   );
    740 
    741 /**
    742   Execute all the EBC signed data manipulation instructions.
    743   Since the EBC data manipulation instructions all have the same basic form,
    744   they can share the code that does the fetch of operands and the write-back
    745   of the result. This function performs the fetch of the operands (even if
    746   both are not needed to be fetched, like NOT instruction), dispatches to the
    747   appropriate subfunction, then writes back the returned result.
    748 
    749   Format:
    750     INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
    751 
    752   @param  VmPtr             A pointer to VM context.
    753 
    754   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
    755   @retval EFI_SUCCESS       The instruction is executed successfully.
    756 
    757 **/
    758 EFI_STATUS
    759 ExecuteSignedDataManip (
    760   IN VM_CONTEXT   *VmPtr
    761   );
    762 
    763 /**
    764   Execute all the EBC unsigned data manipulation instructions.
    765   Since the EBC data manipulation instructions all have the same basic form,
    766   they can share the code that does the fetch of operands and the write-back
    767   of the result. This function performs the fetch of the operands (even if
    768   both are not needed to be fetched, like NOT instruction), dispatches to the
    769   appropriate subfunction, then writes back the returned result.
    770 
    771   Format:
    772     INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
    773 
    774   @param  VmPtr             A pointer to VM context.
    775 
    776   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
    777   @retval EFI_SUCCESS       The instruction is executed successfully.
    778 
    779 **/
    780 EFI_STATUS
    781 ExecuteUnsignedDataManip (
    782   IN VM_CONTEXT   *VmPtr
    783   );
    784 
    785 /**
    786   Execute the EBC LOADSP instruction.
    787 
    788   Instruction syntax:
    789     LOADSP  SP1, R2
    790 
    791   @param  VmPtr             A pointer to a VM context.
    792 
    793   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
    794   @retval EFI_SUCCESS       The instruction is executed successfully.
    795 
    796 **/
    797 EFI_STATUS
    798 ExecuteLOADSP (
    799   IN VM_CONTEXT *VmPtr
    800   );
    801 
    802 /**
    803   Execute the EBC STORESP instruction.
    804 
    805   Instruction syntax:
    806     STORESP  Rx, FLAGS|IP
    807 
    808   @param  VmPtr             A pointer to a VM context.
    809 
    810   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
    811   @retval EFI_SUCCESS       The instruction is executed successfully.
    812 
    813 **/
    814 EFI_STATUS
    815 ExecuteSTORESP (
    816   IN VM_CONTEXT *VmPtr
    817   );
    818 
    819 /**
    820   Execute the EBC MOVsnw instruction. This instruction loads a signed
    821   natural value from memory or register to another memory or register. On
    822   32-bit machines, the value gets sign-extended to 64 bits if the destination
    823   is a register.
    824 
    825   Instruction syntax:
    826 
    827     MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
    828 
    829     0:7 1=>operand1 index present
    830     0:6 1=>operand2 index present
    831 
    832   @param  VmPtr             A pointer to a VM context.
    833 
    834   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
    835   @retval EFI_SUCCESS       The instruction is executed successfully.
    836 
    837 **/
    838 EFI_STATUS
    839 ExecuteMOVsnd (
    840   IN VM_CONTEXT *VmPtr
    841   );
    842 
    843 /**
    844   Execute the EBC MOVsnw instruction. This instruction loads a signed
    845   natural value from memory or register to another memory or register. On
    846   32-bit machines, the value gets sign-extended to 64 bits if the destination
    847   is a register.
    848 
    849   Instruction syntax:
    850 
    851     MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
    852 
    853     0:7 1=>operand1 index present
    854     0:6 1=>operand2 index present
    855 
    856   @param  VmPtr             A pointer to a VM context.
    857 
    858   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
    859   @retval EFI_SUCCESS       The instruction is executed successfully.
    860 
    861 **/
    862 EFI_STATUS
    863 ExecuteMOVsnw (
    864   IN VM_CONTEXT *VmPtr
    865   );
    866 
    867 //
    868 // Data manipulation subfunctions
    869 //
    870 /**
    871   Execute the EBC NOT instruction.s
    872 
    873   Instruction syntax:
    874     NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
    875 
    876   @param  VmPtr             A pointer to a VM context.
    877   @param  Op1               Operand 1 from the instruction
    878   @param  Op2               Operand 2 from the instruction
    879 
    880   @return ~Op2
    881 
    882 **/
    883 UINT64
    884 ExecuteNOT (
    885   IN VM_CONTEXT     *VmPtr,
    886   IN UINT64         Op1,
    887   IN UINT64         Op2
    888   );
    889 
    890 /**
    891   Execute the EBC NEG instruction.
    892 
    893   Instruction syntax:
    894     NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
    895 
    896   @param  VmPtr             A pointer to a VM context.
    897   @param  Op1               Operand 1 from the instruction
    898   @param  Op2               Operand 2 from the instruction
    899 
    900   @return Op2 * -1
    901 
    902 **/
    903 UINT64
    904 ExecuteNEG (
    905   IN VM_CONTEXT   *VmPtr,
    906   IN UINT64       Op1,
    907   IN UINT64       Op2
    908   );
    909 
    910 /**
    911   Execute the EBC ADD instruction.
    912 
    913   Instruction syntax:
    914     ADD[32|64] {@}R1, {@}R2 {Index16}
    915 
    916   @param  VmPtr             A pointer to a VM context.
    917   @param  Op1               Operand 1 from the instruction
    918   @param  Op2               Operand 2 from the instruction
    919 
    920   @return Op1 + Op2
    921 
    922 **/
    923 UINT64
    924 ExecuteADD (
    925   IN VM_CONTEXT   *VmPtr,
    926   IN UINT64       Op1,
    927   IN UINT64       Op2
    928   );
    929 
    930 /**
    931   Execute the EBC SUB instruction.
    932 
    933   Instruction syntax:
    934     SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
    935 
    936   @param  VmPtr             A pointer to a VM context.
    937   @param  Op1               Operand 1 from the instruction
    938   @param  Op2               Operand 2 from the instruction
    939 
    940   @return Op1 - Op2
    941 
    942 **/
    943 UINT64
    944 ExecuteSUB (
    945   IN VM_CONTEXT   *VmPtr,
    946   IN UINT64       Op1,
    947   IN UINT64       Op2
    948   );
    949 
    950 /**
    951   Execute the EBC MUL instruction.
    952 
    953   Instruction syntax:
    954     SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
    955 
    956   @param  VmPtr             A pointer to a VM context.
    957   @param  Op1               Operand 1 from the instruction
    958   @param  Op2               Operand 2 from the instruction
    959 
    960   @return Op1 * Op2
    961 
    962 **/
    963 UINT64
    964 ExecuteMUL (
    965   IN VM_CONTEXT   *VmPtr,
    966   IN UINT64       Op1,
    967   IN UINT64       Op2
    968   );
    969 
    970 /**
    971   Execute the EBC MULU instruction
    972 
    973   Instruction syntax:
    974     MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
    975 
    976   @param  VmPtr             A pointer to a VM context.
    977   @param  Op1               Operand 1 from the instruction
    978   @param  Op2               Operand 2 from the instruction
    979 
    980   @return (unsigned)Op1 * (unsigned)Op2
    981 
    982 **/
    983 UINT64
    984 ExecuteMULU (
    985   IN VM_CONTEXT   *VmPtr,
    986   IN UINT64       Op1,
    987   IN UINT64       Op2
    988   );
    989 
    990 /**
    991   Execute the EBC DIV instruction.
    992 
    993   Instruction syntax:
    994     DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
    995 
    996   @param  VmPtr             A pointer to a VM context.
    997   @param  Op1               Operand 1 from the instruction
    998   @param  Op2               Operand 2 from the instruction
    999 
   1000   @return Op1 / Op2
   1001 
   1002 **/
   1003 UINT64
   1004 ExecuteDIV (
   1005   IN VM_CONTEXT   *VmPtr,
   1006   IN UINT64       Op1,
   1007   IN UINT64       Op2
   1008   );
   1009 
   1010 /**
   1011   Execute the EBC DIVU instruction
   1012 
   1013   Instruction syntax:
   1014     DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
   1015 
   1016   @param  VmPtr             A pointer to a VM context.
   1017   @param  Op1               Operand 1 from the instruction
   1018   @param  Op2               Operand 2 from the instruction
   1019 
   1020   @return (unsigned)Op1 / (unsigned)Op2
   1021 
   1022 **/
   1023 UINT64
   1024 ExecuteDIVU (
   1025   IN VM_CONTEXT   *VmPtr,
   1026   IN UINT64       Op1,
   1027   IN UINT64       Op2
   1028   );
   1029 
   1030 /**
   1031   Execute the EBC MOD instruction.
   1032 
   1033   Instruction syntax:
   1034     MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
   1035 
   1036   @param  VmPtr             A pointer to a VM context.
   1037   @param  Op1               Operand 1 from the instruction
   1038   @param  Op2               Operand 2 from the instruction
   1039 
   1040   @return Op1 MODULUS Op2
   1041 
   1042 **/
   1043 UINT64
   1044 ExecuteMOD (
   1045   IN VM_CONTEXT   *VmPtr,
   1046   IN UINT64       Op1,
   1047   IN UINT64       Op2
   1048   );
   1049 
   1050 /**
   1051   Execute the EBC MODU instruction.
   1052 
   1053   Instruction syntax:
   1054     MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
   1055 
   1056   @param  VmPtr             A pointer to a VM context.
   1057   @param  Op1               Operand 1 from the instruction
   1058   @param  Op2               Operand 2 from the instruction
   1059 
   1060   @return Op1 UNSIGNED_MODULUS Op2
   1061 
   1062 **/
   1063 UINT64
   1064 ExecuteMODU (
   1065   IN VM_CONTEXT   *VmPtr,
   1066   IN UINT64       Op1,
   1067   IN UINT64       Op2
   1068   );
   1069 
   1070 /**
   1071   Execute the EBC AND instruction.
   1072 
   1073   Instruction syntax:
   1074     AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
   1075 
   1076   @param  VmPtr             A pointer to a VM context.
   1077   @param  Op1               Operand 1 from the instruction
   1078   @param  Op2               Operand 2 from the instruction
   1079 
   1080   @return Op1 AND Op2
   1081 
   1082 **/
   1083 UINT64
   1084 ExecuteAND (
   1085   IN VM_CONTEXT   *VmPtr,
   1086   IN UINT64       Op1,
   1087   IN UINT64       Op2
   1088   );
   1089 
   1090 /**
   1091   Execute the EBC OR instruction.
   1092 
   1093   Instruction syntax:
   1094     OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
   1095 
   1096   @param  VmPtr             A pointer to a VM context.
   1097   @param  Op1               Operand 1 from the instruction
   1098   @param  Op2               Operand 2 from the instruction
   1099 
   1100   @return Op1 OR Op2
   1101 
   1102 **/
   1103 UINT64
   1104 ExecuteOR (
   1105   IN VM_CONTEXT   *VmPtr,
   1106   IN UINT64       Op1,
   1107   IN UINT64       Op2
   1108   );
   1109 
   1110 /**
   1111   Execute the EBC XOR instruction.
   1112 
   1113   Instruction syntax:
   1114     XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
   1115 
   1116   @param  VmPtr             A pointer to a VM context.
   1117   @param  Op1               Operand 1 from the instruction
   1118   @param  Op2               Operand 2 from the instruction
   1119 
   1120   @return Op1 XOR Op2
   1121 
   1122 **/
   1123 UINT64
   1124 ExecuteXOR (
   1125   IN VM_CONTEXT   *VmPtr,
   1126   IN UINT64       Op1,
   1127   IN UINT64       Op2
   1128   );
   1129 
   1130 /**
   1131   Execute the EBC SHL shift left instruction.
   1132 
   1133   Instruction syntax:
   1134     SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
   1135 
   1136   @param  VmPtr             A pointer to a VM context.
   1137   @param  Op1               Operand 1 from the instruction
   1138   @param  Op2               Operand 2 from the instruction
   1139 
   1140   @return Op1 << Op2
   1141 
   1142 **/
   1143 UINT64
   1144 ExecuteSHL (
   1145   IN VM_CONTEXT   *VmPtr,
   1146   IN UINT64       Op1,
   1147   IN UINT64       Op2
   1148   );
   1149 
   1150 /**
   1151   Execute the EBC SHR instruction.
   1152 
   1153   Instruction syntax:
   1154     SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
   1155 
   1156   @param  VmPtr             A pointer to a VM context.
   1157   @param  Op1               Operand 1 from the instruction
   1158   @param  Op2               Operand 2 from the instruction
   1159 
   1160   @return Op1 >> Op2  (unsigned operands)
   1161 
   1162 **/
   1163 UINT64
   1164 ExecuteSHR (
   1165   IN VM_CONTEXT   *VmPtr,
   1166   IN UINT64       Op1,
   1167   IN UINT64       Op2
   1168   );
   1169 
   1170 /**
   1171   Execute the EBC ASHR instruction.
   1172 
   1173   Instruction syntax:
   1174     ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
   1175 
   1176   @param  VmPtr             A pointer to a VM context.
   1177   @param  Op1               Operand 1 from the instruction
   1178   @param  Op2               Operand 2 from the instruction
   1179 
   1180   @return Op1 >> Op2 (signed)
   1181 
   1182 **/
   1183 UINT64
   1184 ExecuteASHR (
   1185   IN VM_CONTEXT   *VmPtr,
   1186   IN UINT64       Op1,
   1187   IN UINT64       Op2
   1188   );
   1189 
   1190 /**
   1191   Execute the EBC EXTNDB instruction to sign-extend a byte value.
   1192 
   1193   Instruction syntax:
   1194     EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
   1195 
   1196   @param  VmPtr             A pointer to a VM context.
   1197   @param  Op1               Operand 1 from the instruction
   1198   @param  Op2               Operand 2 from the instruction
   1199 
   1200   @return (INT64)(INT8)Op2
   1201 
   1202 **/
   1203 UINT64
   1204 ExecuteEXTNDB (
   1205   IN VM_CONTEXT   *VmPtr,
   1206   IN UINT64       Op1,
   1207   IN UINT64       Op2
   1208   );
   1209 
   1210 /**
   1211   Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
   1212 
   1213   Instruction syntax:
   1214     EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
   1215 
   1216   @param  VmPtr             A pointer to a VM context.
   1217   @param  Op1               Operand 1 from the instruction
   1218   @param  Op2               Operand 2 from the instruction
   1219 
   1220   @return (INT64)(INT16)Op2
   1221 
   1222 **/
   1223 UINT64
   1224 ExecuteEXTNDW (
   1225   IN VM_CONTEXT   *VmPtr,
   1226   IN UINT64       Op1,
   1227   IN UINT64       Op2
   1228   );
   1229 
   1230 /**
   1231   Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
   1232 
   1233   Instruction syntax:
   1234     EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
   1235 
   1236   @param  VmPtr             A pointer to a VM context.
   1237   @param  Op1               Operand 1 from the instruction
   1238   @param  Op2               Operand 2 from the instruction
   1239 
   1240   @return (INT64)(INT32)Op2
   1241 
   1242 **/
   1243 UINT64
   1244 ExecuteEXTNDD (
   1245   IN VM_CONTEXT   *VmPtr,
   1246   IN UINT64       Op1,
   1247   IN UINT64       Op2
   1248   );
   1249 
   1250 //
   1251 // Once we retrieve the operands for the data manipulation instructions,
   1252 // call these functions to perform the operation.
   1253 //
   1254 CONST DATA_MANIP_EXEC_FUNCTION mDataManipDispatchTable[] = {
   1255   ExecuteNOT,
   1256   ExecuteNEG,
   1257   ExecuteADD,
   1258   ExecuteSUB,
   1259   ExecuteMUL,
   1260   ExecuteMULU,
   1261   ExecuteDIV,
   1262   ExecuteDIVU,
   1263   ExecuteMOD,
   1264   ExecuteMODU,
   1265   ExecuteAND,
   1266   ExecuteOR,
   1267   ExecuteXOR,
   1268   ExecuteSHL,
   1269   ExecuteSHR,
   1270   ExecuteASHR,
   1271   ExecuteEXTNDB,
   1272   ExecuteEXTNDW,
   1273   ExecuteEXTNDD,
   1274 };
   1275 
   1276 CONST VM_TABLE_ENTRY           mVmOpcodeTable[] = {
   1277   { ExecuteBREAK },             // opcode 0x00
   1278   { ExecuteJMP },               // opcode 0x01
   1279   { ExecuteJMP8 },              // opcode 0x02
   1280   { ExecuteCALL },              // opcode 0x03
   1281   { ExecuteRET },               // opcode 0x04
   1282   { ExecuteCMP },               // opcode 0x05 CMPeq
   1283   { ExecuteCMP },               // opcode 0x06 CMPlte
   1284   { ExecuteCMP },               // opcode 0x07 CMPgte
   1285   { ExecuteCMP },               // opcode 0x08 CMPulte
   1286   { ExecuteCMP },               // opcode 0x09 CMPugte
   1287   { ExecuteUnsignedDataManip }, // opcode 0x0A NOT
   1288   { ExecuteSignedDataManip },   // opcode 0x0B NEG
   1289   { ExecuteSignedDataManip },   // opcode 0x0C ADD
   1290   { ExecuteSignedDataManip },   // opcode 0x0D SUB
   1291   { ExecuteSignedDataManip },   // opcode 0x0E MUL
   1292   { ExecuteUnsignedDataManip }, // opcode 0x0F MULU
   1293   { ExecuteSignedDataManip },   // opcode 0x10 DIV
   1294   { ExecuteUnsignedDataManip }, // opcode 0x11 DIVU
   1295   { ExecuteSignedDataManip },   // opcode 0x12 MOD
   1296   { ExecuteUnsignedDataManip }, // opcode 0x13 MODU
   1297   { ExecuteUnsignedDataManip }, // opcode 0x14 AND
   1298   { ExecuteUnsignedDataManip }, // opcode 0x15 OR
   1299   { ExecuteUnsignedDataManip }, // opcode 0x16 XOR
   1300   { ExecuteUnsignedDataManip }, // opcode 0x17 SHL
   1301   { ExecuteUnsignedDataManip }, // opcode 0x18 SHR
   1302   { ExecuteSignedDataManip },   // opcode 0x19 ASHR
   1303   { ExecuteUnsignedDataManip }, // opcode 0x1A EXTNDB
   1304   { ExecuteUnsignedDataManip }, // opcode 0x1B EXTNDW
   1305   { ExecuteUnsignedDataManip }, // opcode 0x1C EXTNDD
   1306   { ExecuteMOVxx },             // opcode 0x1D MOVBW
   1307   { ExecuteMOVxx },             // opcode 0x1E MOVWW
   1308   { ExecuteMOVxx },             // opcode 0x1F MOVDW
   1309   { ExecuteMOVxx },             // opcode 0x20 MOVQW
   1310   { ExecuteMOVxx },             // opcode 0x21 MOVBD
   1311   { ExecuteMOVxx },             // opcode 0x22 MOVWD
   1312   { ExecuteMOVxx },             // opcode 0x23 MOVDD
   1313   { ExecuteMOVxx },             // opcode 0x24 MOVQD
   1314   { ExecuteMOVsnw },            // opcode 0x25 MOVsnw
   1315   { ExecuteMOVsnd },            // opcode 0x26 MOVsnd
   1316   { NULL },                     // opcode 0x27
   1317   { ExecuteMOVxx },             // opcode 0x28 MOVqq
   1318   { ExecuteLOADSP },            // opcode 0x29 LOADSP SP1, R2
   1319   { ExecuteSTORESP },           // opcode 0x2A STORESP R1, SP2
   1320   { ExecutePUSH },              // opcode 0x2B PUSH {@}R1 [imm16]
   1321   { ExecutePOP },               // opcode 0x2C POP {@}R1 [imm16]
   1322   { ExecuteCMPI },              // opcode 0x2D CMPIEQ
   1323   { ExecuteCMPI },              // opcode 0x2E CMPILTE
   1324   { ExecuteCMPI },              // opcode 0x2F CMPIGTE
   1325   { ExecuteCMPI },              // opcode 0x30 CMPIULTE
   1326   { ExecuteCMPI },              // opcode 0x31 CMPIUGTE
   1327   { ExecuteMOVxx },             // opcode 0x32 MOVN
   1328   { ExecuteMOVxx },             // opcode 0x33 MOVND
   1329   { NULL },                     // opcode 0x34
   1330   { ExecutePUSHn },             // opcode 0x35
   1331   { ExecutePOPn },              // opcode 0x36
   1332   { ExecuteMOVI },              // opcode 0x37 - mov immediate data
   1333   { ExecuteMOVIn },             // opcode 0x38 - mov immediate natural
   1334   { ExecuteMOVREL },            // opcode 0x39 - move data relative to PC
   1335   { NULL },                     // opcode 0x3a
   1336   { NULL },                     // opcode 0x3b
   1337   { NULL },                     // opcode 0x3c
   1338   { NULL },                     // opcode 0x3d
   1339   { NULL },                     // opcode 0x3e
   1340   { NULL }                      // opcode 0x3f
   1341 };
   1342 
   1343 //
   1344 // Length of JMP instructions, depending on upper two bits of opcode.
   1345 //
   1346 CONST UINT8                    mJMPLen[] = { 2, 2, 6, 10 };
   1347 
   1348 /**
   1349   Given a pointer to a new VM context, execute one or more instructions. This
   1350   function is only used for test purposes via the EBC VM test protocol.
   1351 
   1352   @param  This              A pointer to the EFI_EBC_VM_TEST_PROTOCOL structure.
   1353   @param  VmPtr             A pointer to a VM context.
   1354   @param  InstructionCount  A pointer to a UINTN value holding the number of
   1355                             instructions to execute. If it holds value of 0,
   1356                             then the instruction to be executed is 1.
   1357 
   1358   @retval EFI_UNSUPPORTED   At least one of the opcodes is not supported.
   1359   @retval EFI_SUCCESS       All of the instructions are executed successfully.
   1360 
   1361 **/
   1362 EFI_STATUS
   1363 EFIAPI
   1364 EbcExecuteInstructions (
   1365   IN EFI_EBC_VM_TEST_PROTOCOL *This,
   1366   IN VM_CONTEXT               *VmPtr,
   1367   IN OUT UINTN                *InstructionCount
   1368   )
   1369 {
   1370   UINTN       ExecFunc;
   1371   EFI_STATUS  Status;
   1372   UINTN       InstructionsLeft;
   1373   UINTN       SavedInstructionCount;
   1374 
   1375   Status = EFI_SUCCESS;
   1376 
   1377   if (*InstructionCount == 0) {
   1378     InstructionsLeft = 1;
   1379   } else {
   1380     InstructionsLeft = *InstructionCount;
   1381   }
   1382 
   1383   SavedInstructionCount = *InstructionCount;
   1384   *InstructionCount     = 0;
   1385 
   1386   //
   1387   // Index into the opcode table using the opcode byte for this instruction.
   1388   // This gives you the execute function, which we first test for null, then
   1389   // call it if it's not null.
   1390   //
   1391   while (InstructionsLeft != 0) {
   1392     ExecFunc = (UINTN) mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction;
   1393     if (ExecFunc == (UINTN) NULL) {
   1394       EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE, EXCEPTION_FLAG_FATAL, VmPtr);
   1395       return EFI_UNSUPPORTED;
   1396     } else {
   1397       mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction (VmPtr);
   1398       *InstructionCount = *InstructionCount + 1;
   1399     }
   1400 
   1401     //
   1402     // Decrement counter if applicable
   1403     //
   1404     if (SavedInstructionCount != 0) {
   1405       InstructionsLeft--;
   1406     }
   1407   }
   1408 
   1409   return Status;
   1410 }
   1411 
   1412 
   1413 /**
   1414   Execute an EBC image from an entry point or from a published protocol.
   1415 
   1416   @param  VmPtr             A pointer to a VM context.
   1417 
   1418   @retval EFI_UNSUPPORTED   At least one of the opcodes is not supported.
   1419   @retval EFI_SUCCESS       All of the instructions are executed successfully.
   1420 
   1421 **/
   1422 EFI_STATUS
   1423 EbcExecute (
   1424   IN VM_CONTEXT *VmPtr
   1425   )
   1426 {
   1427   UINTN                             ExecFunc;
   1428   UINT8                             StackCorrupted;
   1429   EFI_STATUS                        Status;
   1430   EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL  *EbcSimpleDebugger;
   1431 
   1432   mVmPtr            = VmPtr;
   1433   EbcSimpleDebugger = NULL;
   1434   Status            = EFI_SUCCESS;
   1435   StackCorrupted    = 0;
   1436 
   1437   //
   1438   // Make sure the magic value has been put on the stack before we got here.
   1439   //
   1440   if (*VmPtr->StackMagicPtr != (UINTN) VM_STACK_KEY_VALUE) {
   1441     StackCorrupted = 1;
   1442   }
   1443 
   1444   VmPtr->FramePtr = (VOID *) ((UINT8 *) (UINTN) VmPtr->Gpr[0] + 8);
   1445 
   1446   //
   1447   // Try to get the debug support for EBC
   1448   //
   1449   DEBUG_CODE_BEGIN ();
   1450     Status = gBS->LocateProtocol (
   1451                     &gEfiEbcSimpleDebuggerProtocolGuid,
   1452                     NULL,
   1453                     (VOID **) &EbcSimpleDebugger
   1454                     );
   1455     if (EFI_ERROR (Status)) {
   1456       EbcSimpleDebugger = NULL;
   1457     }
   1458   DEBUG_CODE_END ();
   1459 
   1460   //
   1461   // Save the start IP for debug. For example, if we take an exception we
   1462   // can print out the location of the exception relative to the entry point,
   1463   // which could then be used in a disassembly listing to find the problem.
   1464   //
   1465   VmPtr->EntryPoint = (VOID *) VmPtr->Ip;
   1466 
   1467   //
   1468   // We'll wait for this flag to know when we're done. The RET
   1469   // instruction sets it if it runs out of stack.
   1470   //
   1471   VmPtr->StopFlags = 0;
   1472   while ((VmPtr->StopFlags & STOPFLAG_APP_DONE) == 0) {
   1473     //
   1474     // If we've found a simple debugger protocol, call it
   1475     //
   1476     DEBUG_CODE_BEGIN ();
   1477       if (EbcSimpleDebugger != NULL) {
   1478         EbcSimpleDebugger->Debugger (EbcSimpleDebugger, VmPtr);
   1479       }
   1480     DEBUG_CODE_END ();
   1481 
   1482     //
   1483     // Use the opcode bits to index into the opcode dispatch table. If the
   1484     // function pointer is null then generate an exception.
   1485     //
   1486     ExecFunc = (UINTN) mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction;
   1487     if (ExecFunc == (UINTN) NULL) {
   1488       EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE, EXCEPTION_FLAG_FATAL, VmPtr);
   1489       Status = EFI_UNSUPPORTED;
   1490       goto Done;
   1491     }
   1492 
   1493     EbcDebuggerHookExecuteStart (VmPtr);
   1494 
   1495     //
   1496     // The EBC VM is a strongly ordered processor, so perform a fence operation before
   1497     // and after each instruction is executed.
   1498     //
   1499     MemoryFence ();
   1500 
   1501     mVmOpcodeTable[(*VmPtr->Ip & OPCODE_M_OPCODE)].ExecuteFunction (VmPtr);
   1502 
   1503     MemoryFence ();
   1504 
   1505     EbcDebuggerHookExecuteEnd (VmPtr);
   1506 
   1507     //
   1508     // If the step flag is set, signal an exception and continue. We don't
   1509     // clear it here. Assuming the debugger is responsible for clearing it.
   1510     //
   1511     if (VMFLAG_ISSET (VmPtr, VMFLAGS_STEP)) {
   1512       EbcDebugSignalException (EXCEPT_EBC_STEP, EXCEPTION_FLAG_NONE, VmPtr);
   1513     }
   1514     //
   1515     // Make sure stack has not been corrupted. Only report it once though.
   1516     //
   1517     if ((StackCorrupted == 0) && (*VmPtr->StackMagicPtr != (UINTN) VM_STACK_KEY_VALUE)) {
   1518       EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT, EXCEPTION_FLAG_FATAL, VmPtr);
   1519       StackCorrupted = 1;
   1520     }
   1521     if ((StackCorrupted == 0) && ((UINT64)VmPtr->Gpr[0] <= (UINT64)(UINTN) VmPtr->StackTop)) {
   1522       EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT, EXCEPTION_FLAG_FATAL, VmPtr);
   1523       StackCorrupted = 1;
   1524     }
   1525   }
   1526 
   1527 Done:
   1528   mVmPtr          = NULL;
   1529 
   1530   return Status;
   1531 }
   1532 
   1533 
   1534 /**
   1535   Execute the MOVxx instructions.
   1536 
   1537   Instruction format:
   1538 
   1539     MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
   1540     MOVqq {@}R1 {Index64}, {@}R2 {Index64}
   1541 
   1542     Copies contents of [R2] -> [R1], zero extending where required.
   1543 
   1544     First character indicates the size of the move.
   1545     Second character indicates the size of the index(s).
   1546 
   1547     Invalid to have R1 direct with index.
   1548 
   1549   @param  VmPtr             A pointer to a VM context.
   1550 
   1551   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
   1552   @retval EFI_SUCCESS       The instruction is executed successfully.
   1553 
   1554 **/
   1555 EFI_STATUS
   1556 ExecuteMOVxx (
   1557   IN VM_CONTEXT *VmPtr
   1558   )
   1559 {
   1560   UINT8   Opcode;
   1561   UINT8   OpcMasked;
   1562   UINT8   Operands;
   1563   UINT8   Size;
   1564   UINT8   MoveSize;
   1565   INT16   Index16;
   1566   INT32   Index32;
   1567   INT64   Index64Op1;
   1568   INT64   Index64Op2;
   1569   UINT64  Data64;
   1570   UINT64  DataMask;
   1571   UINTN   Source;
   1572 
   1573   Opcode    = GETOPCODE (VmPtr);
   1574   OpcMasked = (UINT8) (Opcode & OPCODE_M_OPCODE);
   1575 
   1576   //
   1577   // Get the operands byte so we can get R1 and R2
   1578   //
   1579   Operands = GETOPERANDS (VmPtr);
   1580 
   1581   //
   1582   // Assume no indexes
   1583   //
   1584   Index64Op1  = 0;
   1585   Index64Op2  = 0;
   1586   Data64      = 0;
   1587 
   1588   //
   1589   // Determine if we have an index/immediate data. Base instruction size
   1590   // is 2 (opcode + operands). Add to this size each index specified.
   1591   //
   1592   Size = 2;
   1593   if ((Opcode & (OPCODE_M_IMMED_OP1 | OPCODE_M_IMMED_OP2)) != 0) {
   1594     //
   1595     // Determine size of the index from the opcode. Then get it.
   1596     //
   1597     if ((OpcMasked <= OPCODE_MOVQW) || (OpcMasked == OPCODE_MOVNW)) {
   1598       //
   1599       // MOVBW, MOVWW, MOVDW, MOVQW, and MOVNW have 16-bit immediate index.
   1600       // Get one or both index values.
   1601       //
   1602       if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
   1603         Index16     = VmReadIndex16 (VmPtr, 2);
   1604         Index64Op1  = (INT64) Index16;
   1605         Size += sizeof (UINT16);
   1606       }
   1607 
   1608       if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
   1609         Index16     = VmReadIndex16 (VmPtr, Size);
   1610         Index64Op2  = (INT64) Index16;
   1611         Size += sizeof (UINT16);
   1612       }
   1613     } else if ((OpcMasked <= OPCODE_MOVQD) || (OpcMasked == OPCODE_MOVND)) {
   1614       //
   1615       // MOVBD, MOVWD, MOVDD, MOVQD, and MOVND have 32-bit immediate index
   1616       //
   1617       if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
   1618         Index32     = VmReadIndex32 (VmPtr, 2);
   1619         Index64Op1  = (INT64) Index32;
   1620         Size += sizeof (UINT32);
   1621       }
   1622 
   1623       if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
   1624         Index32     = VmReadIndex32 (VmPtr, Size);
   1625         Index64Op2  = (INT64) Index32;
   1626         Size += sizeof (UINT32);
   1627       }
   1628     } else if (OpcMasked == OPCODE_MOVQQ) {
   1629       //
   1630       // MOVqq -- only form with a 64-bit index
   1631       //
   1632       if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
   1633         Index64Op1 = VmReadIndex64 (VmPtr, 2);
   1634         Size += sizeof (UINT64);
   1635       }
   1636 
   1637       if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
   1638         Index64Op2 = VmReadIndex64 (VmPtr, Size);
   1639         Size += sizeof (UINT64);
   1640       }
   1641     } else {
   1642       //
   1643       // Obsolete MOVBQ, MOVWQ, MOVDQ, and MOVNQ have 64-bit immediate index
   1644       //
   1645       EbcDebugSignalException (
   1646         EXCEPT_EBC_INSTRUCTION_ENCODING,
   1647         EXCEPTION_FLAG_FATAL,
   1648         VmPtr
   1649         );
   1650       return EFI_UNSUPPORTED;
   1651     }
   1652   }
   1653   //
   1654   // Determine the size of the move, and create a mask for it so we can
   1655   // clear unused bits.
   1656   //
   1657   if ((OpcMasked == OPCODE_MOVBW) || (OpcMasked == OPCODE_MOVBD)) {
   1658     MoveSize  = DATA_SIZE_8;
   1659     DataMask  = 0xFF;
   1660   } else if ((OpcMasked == OPCODE_MOVWW) || (OpcMasked == OPCODE_MOVWD)) {
   1661     MoveSize  = DATA_SIZE_16;
   1662     DataMask  = 0xFFFF;
   1663   } else if ((OpcMasked == OPCODE_MOVDW) || (OpcMasked == OPCODE_MOVDD)) {
   1664     MoveSize  = DATA_SIZE_32;
   1665     DataMask  = 0xFFFFFFFF;
   1666   } else if ((OpcMasked == OPCODE_MOVQW) || (OpcMasked == OPCODE_MOVQD) || (OpcMasked == OPCODE_MOVQQ)) {
   1667     MoveSize  = DATA_SIZE_64;
   1668     DataMask  = (UINT64)~0;
   1669   } else if ((OpcMasked == OPCODE_MOVNW) || (OpcMasked == OPCODE_MOVND)) {
   1670     MoveSize  = DATA_SIZE_N;
   1671     DataMask  = (UINT64)~0 >> (64 - 8 * sizeof (UINTN));
   1672   } else {
   1673     //
   1674     // We were dispatched to this function and we don't recognize the opcode
   1675     //
   1676     EbcDebugSignalException (EXCEPT_EBC_UNDEFINED, EXCEPTION_FLAG_FATAL, VmPtr);
   1677     return EFI_UNSUPPORTED;
   1678   }
   1679   //
   1680   // Now get the source address
   1681   //
   1682   if (OPERAND2_INDIRECT (Operands)) {
   1683     //
   1684     // Indirect form @R2. Compute address of operand2
   1685     //
   1686     Source = (UINTN) (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index64Op2);
   1687     //
   1688     // Now get the data from the source. Always 0-extend and let the compiler
   1689     // sign-extend where required.
   1690     //
   1691     switch (MoveSize) {
   1692     case DATA_SIZE_8:
   1693       Data64 = (UINT64) (UINT8) VmReadMem8 (VmPtr, Source);
   1694       break;
   1695 
   1696     case DATA_SIZE_16:
   1697       Data64 = (UINT64) (UINT16) VmReadMem16 (VmPtr, Source);
   1698       break;
   1699 
   1700     case DATA_SIZE_32:
   1701       Data64 = (UINT64) (UINT32) VmReadMem32 (VmPtr, Source);
   1702       break;
   1703 
   1704     case DATA_SIZE_64:
   1705       Data64 = (UINT64) VmReadMem64 (VmPtr, Source);
   1706       break;
   1707 
   1708     case DATA_SIZE_N:
   1709       Data64 = (UINT64) (UINTN) VmReadMemN (VmPtr, Source);
   1710       break;
   1711 
   1712     default:
   1713       //
   1714       // not reached
   1715       //
   1716       break;
   1717     }
   1718   } else {
   1719     //
   1720     // Not indirect source: MOVxx {@}Rx, Ry [Index]
   1721     //
   1722     Data64 = (UINT64) (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index64Op2);
   1723     //
   1724     // Did Operand2 have an index? If so, treat as two signed values since
   1725     // indexes are signed values.
   1726     //
   1727     if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
   1728       //
   1729       // NOTE: need to find a way to fix this, most likely by changing the VM
   1730       // implementation to remove the stack gap. To do that, we'd need to
   1731       // allocate stack space for the VM and actually set the system
   1732       // stack pointer to the allocated buffer when the VM starts.
   1733       //
   1734       // Special case -- if someone took the address of a function parameter
   1735       // then we need to make sure it's not in the stack gap. We can identify
   1736       // this situation if (Operand2 register == 0) && (Operand2 is direct)
   1737       // && (Index applies to Operand2) && (Index > 0) && (Operand1 register != 0)
   1738       // Situations that to be aware of:
   1739       //   * stack adjustments at beginning and end of functions R0 = R0 += stacksize
   1740       //
   1741       if ((OPERAND2_REGNUM (Operands) == 0) &&
   1742           (!OPERAND2_INDIRECT (Operands)) &&
   1743           (Index64Op2 > 0) &&
   1744           (OPERAND1_REGNUM (Operands) == 0) &&
   1745           (OPERAND1_INDIRECT (Operands))
   1746           ) {
   1747         Data64 = (UINT64) ConvertStackAddr (VmPtr, (UINTN) (INT64) Data64);
   1748       }
   1749     }
   1750   }
   1751   //
   1752   // Now write it back
   1753   //
   1754   if (OPERAND1_INDIRECT (Operands)) {
   1755     //
   1756     // Reuse the Source variable to now be dest.
   1757     //
   1758     Source = (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index64Op1);
   1759     //
   1760     // Do the write based on the size
   1761     //
   1762     switch (MoveSize) {
   1763     case DATA_SIZE_8:
   1764       VmWriteMem8 (VmPtr, Source, (UINT8) Data64);
   1765       break;
   1766 
   1767     case DATA_SIZE_16:
   1768       VmWriteMem16 (VmPtr, Source, (UINT16) Data64);
   1769       break;
   1770 
   1771     case DATA_SIZE_32:
   1772       VmWriteMem32 (VmPtr, Source, (UINT32) Data64);
   1773       break;
   1774 
   1775     case DATA_SIZE_64:
   1776       VmWriteMem64 (VmPtr, Source, Data64);
   1777       break;
   1778 
   1779     case DATA_SIZE_N:
   1780       VmWriteMemN (VmPtr, Source, (UINTN) Data64);
   1781       break;
   1782 
   1783     default:
   1784       //
   1785       // not reached
   1786       //
   1787       break;
   1788     }
   1789   } else {
   1790     //
   1791     // Operand1 direct.
   1792     // Make sure we didn't have an index on operand1.
   1793     //
   1794     if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
   1795       EbcDebugSignalException (
   1796         EXCEPT_EBC_INSTRUCTION_ENCODING,
   1797         EXCEPTION_FLAG_FATAL,
   1798         VmPtr
   1799         );
   1800       return EFI_UNSUPPORTED;
   1801     }
   1802     //
   1803     // Direct storage in register. Clear unused bits and store back to
   1804     // register.
   1805     //
   1806     VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Data64 & DataMask;
   1807   }
   1808   //
   1809   // Advance the instruction pointer
   1810   //
   1811   VmPtr->Ip += Size;
   1812   return EFI_SUCCESS;
   1813 }
   1814 
   1815 
   1816 /**
   1817   Execute the EBC BREAK instruction.
   1818 
   1819   @param  VmPtr             A pointer to a VM context.
   1820 
   1821   @retval EFI_SUCCESS       The instruction is executed successfully.
   1822 
   1823 **/
   1824 EFI_STATUS
   1825 ExecuteBREAK (
   1826   IN VM_CONTEXT *VmPtr
   1827   )
   1828 {
   1829   EFI_STATUS  Status;
   1830   UINT8       Operands;
   1831   VOID        *EbcEntryPoint;
   1832   VOID        *Thunk;
   1833   UINT64      U64EbcEntryPoint;
   1834   INT32       Offset;
   1835 
   1836   Thunk = NULL;
   1837   Operands = GETOPERANDS (VmPtr);
   1838   switch (Operands) {
   1839   //
   1840   // Runaway program break. Generate an exception and terminate
   1841   //
   1842   case 0:
   1843     EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK, EXCEPTION_FLAG_FATAL, VmPtr);
   1844     break;
   1845 
   1846   //
   1847   // Get VM version -- return VM revision number in R7
   1848   //
   1849   case 1:
   1850     //
   1851     // Bits:
   1852     //  63-17 = 0
   1853     //  16-8  = Major version
   1854     //  7-0   = Minor version
   1855     //
   1856     VmPtr->Gpr[7] = GetVmVersion ();
   1857     break;
   1858 
   1859   //
   1860   // Debugger breakpoint
   1861   //
   1862   case 3:
   1863     VmPtr->StopFlags |= STOPFLAG_BREAKPOINT;
   1864     //
   1865     // See if someone has registered a handler
   1866     //
   1867     EbcDebugSignalException (
   1868       EXCEPT_EBC_BREAKPOINT,
   1869       EXCEPTION_FLAG_NONE,
   1870       VmPtr
   1871       );
   1872     break;
   1873 
   1874   //
   1875   // System call, which there are none, so NOP it.
   1876   //
   1877   case 4:
   1878     break;
   1879 
   1880   //
   1881   // Create a thunk for EBC code. R7 points to a 32-bit (in a 64-bit slot)
   1882   // "offset from self" pointer to the EBC entry point.
   1883   // After we're done, *(UINT64 *)R7 will be the address of the new thunk.
   1884   //
   1885   case 5:
   1886     Offset            = (INT32) VmReadMem32 (VmPtr, (UINTN) VmPtr->Gpr[7]);
   1887     U64EbcEntryPoint  = (UINT64) (VmPtr->Gpr[7] + Offset + 4);
   1888     EbcEntryPoint     = (VOID *) (UINTN) U64EbcEntryPoint;
   1889 
   1890     //
   1891     // Now create a new thunk
   1892     //
   1893     Status = EbcCreateThunks (VmPtr->ImageHandle, EbcEntryPoint, &Thunk, 0);
   1894     if (EFI_ERROR (Status)) {
   1895       return Status;
   1896     }
   1897 
   1898     //
   1899     // Finally replace the EBC entry point memory with the thunk address
   1900     //
   1901     VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[7], (UINT64) (UINTN) Thunk);
   1902     break;
   1903 
   1904   //
   1905   // Compiler setting version per value in R7
   1906   //
   1907   case 6:
   1908     VmPtr->CompilerVersion = (UINT32) VmPtr->Gpr[7];
   1909     //
   1910     // Check compiler version against VM version?
   1911     //
   1912     break;
   1913 
   1914   //
   1915   // Unhandled break code. Signal exception.
   1916   //
   1917   default:
   1918     EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK, EXCEPTION_FLAG_FATAL, VmPtr);
   1919     break;
   1920   }
   1921   //
   1922   // Advance IP
   1923   //
   1924   VmPtr->Ip += 2;
   1925   return EFI_SUCCESS;
   1926 }
   1927 
   1928 
   1929 /**
   1930   Execute the JMP instruction.
   1931 
   1932   Instruction syntax:
   1933     JMP64{cs|cc} Immed64
   1934     JMP32{cs|cc} {@}R1 {Immed32|Index32}
   1935 
   1936   Encoding:
   1937     b0.7 -  immediate data present
   1938     b0.6 -  1 = 64 bit immediate data
   1939             0 = 32 bit immediate data
   1940     b1.7 -  1 = conditional
   1941     b1.6    1 = CS (condition set)
   1942             0 = CC (condition clear)
   1943     b1.4    1 = relative address
   1944             0 = absolute address
   1945     b1.3    1 = operand1 indirect
   1946     b1.2-0  operand 1
   1947 
   1948   @param  VmPtr             A pointer to a VM context.
   1949 
   1950   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
   1951   @retval EFI_SUCCESS       The instruction is executed successfully.
   1952 
   1953 **/
   1954 EFI_STATUS
   1955 ExecuteJMP (
   1956   IN VM_CONTEXT *VmPtr
   1957   )
   1958 {
   1959   UINT8   Opcode;
   1960   UINT8   CompareSet;
   1961   UINT8   ConditionFlag;
   1962   UINT8   Size;
   1963   UINT8   Operand;
   1964   UINT64  Data64;
   1965   INT32   Index32;
   1966   UINTN   Addr;
   1967 
   1968   Operand = GETOPERANDS (VmPtr);
   1969   Opcode  = GETOPCODE (VmPtr);
   1970 
   1971   //
   1972   // Get instruction length from the opcode. The upper two bits are used here
   1973   // to index into the length array.
   1974   //
   1975   Size = mJMPLen[(Opcode >> 6) & 0x03];
   1976 
   1977   //
   1978   // Decode instruction conditions
   1979   // If we haven't met the condition, then simply advance the IP and return.
   1980   //
   1981   CompareSet    = (UINT8) (((Operand & JMP_M_CS) != 0) ? 1 : 0);
   1982   ConditionFlag = (UINT8) VMFLAG_ISSET (VmPtr, VMFLAGS_CC);
   1983   if ((Operand & CONDITION_M_CONDITIONAL) != 0) {
   1984     if (CompareSet != ConditionFlag) {
   1985       EbcDebuggerHookJMPStart (VmPtr);
   1986       VmPtr->Ip += Size;
   1987       EbcDebuggerHookJMPEnd (VmPtr);
   1988       return EFI_SUCCESS;
   1989     }
   1990   }
   1991   //
   1992   // Check for 64-bit form and do it right away since it's the most
   1993   // straight-forward form.
   1994   //
   1995   if ((Opcode & OPCODE_M_IMMDATA64) != 0) {
   1996     //
   1997     // Double check for immediate-data, which is required. If not there,
   1998     // then signal an exception
   1999     //
   2000     if ((Opcode & OPCODE_M_IMMDATA) == 0) {
   2001       EbcDebugSignalException (
   2002         EXCEPT_EBC_INSTRUCTION_ENCODING,
   2003         EXCEPTION_FLAG_ERROR,
   2004         VmPtr
   2005         );
   2006       return EFI_UNSUPPORTED;
   2007     }
   2008     //
   2009     // 64-bit immediate data is full address. Read the immediate data,
   2010     // check for alignment, and jump absolute.
   2011     //
   2012     Data64 = (UINT64) VmReadImmed64 (VmPtr, 2);
   2013     if (!IS_ALIGNED ((UINTN) Data64, sizeof (UINT16))) {
   2014       EbcDebugSignalException (
   2015         EXCEPT_EBC_ALIGNMENT_CHECK,
   2016         EXCEPTION_FLAG_FATAL,
   2017         VmPtr
   2018         );
   2019 
   2020       return EFI_UNSUPPORTED;
   2021     }
   2022 
   2023     //
   2024     // Take jump -- relative or absolute
   2025     //
   2026     EbcDebuggerHookJMPStart (VmPtr);
   2027     if ((Operand & JMP_M_RELATIVE) != 0) {
   2028       VmPtr->Ip += (UINTN) Data64 + Size;
   2029     } else {
   2030       VmPtr->Ip = (VMIP) (UINTN) Data64;
   2031     }
   2032     EbcDebuggerHookJMPEnd (VmPtr);
   2033 
   2034     return EFI_SUCCESS;
   2035   }
   2036   //
   2037   // 32-bit forms:
   2038   // Get the index if there is one. May be either an index, or an immediate
   2039   // offset depending on indirect operand.
   2040   //   JMP32 @R1 Index32 -- immediate data is an index
   2041   //   JMP32 R1 Immed32  -- immedate data is an offset
   2042   //
   2043   if ((Opcode & OPCODE_M_IMMDATA) != 0) {
   2044     if (OPERAND1_INDIRECT (Operand)) {
   2045       Index32 = VmReadIndex32 (VmPtr, 2);
   2046     } else {
   2047       Index32 = VmReadImmed32 (VmPtr, 2);
   2048     }
   2049   } else {
   2050     Index32 = 0;
   2051   }
   2052   //
   2053   // Get the register data. If R == 0, then special case where it's ignored.
   2054   //
   2055   if (OPERAND1_REGNUM (Operand) == 0) {
   2056     Data64 = 0;
   2057   } else {
   2058     Data64 = (UINT64) OPERAND1_REGDATA (VmPtr, Operand);
   2059   }
   2060   //
   2061   // Decode the forms
   2062   //
   2063   if (OPERAND1_INDIRECT (Operand)) {
   2064     //
   2065     // Form: JMP32 @Rx {Index32}
   2066     //
   2067     Addr = VmReadMemN (VmPtr, (UINTN) Data64 + Index32);
   2068     if (!IS_ALIGNED ((UINTN) Addr, sizeof (UINT16))) {
   2069       EbcDebugSignalException (
   2070         EXCEPT_EBC_ALIGNMENT_CHECK,
   2071         EXCEPTION_FLAG_FATAL,
   2072         VmPtr
   2073         );
   2074 
   2075       return EFI_UNSUPPORTED;
   2076     }
   2077 
   2078     EbcDebuggerHookJMPStart (VmPtr);
   2079     if ((Operand & JMP_M_RELATIVE) != 0) {
   2080       VmPtr->Ip += (UINTN) Addr + Size;
   2081     } else {
   2082       VmPtr->Ip = (VMIP) Addr;
   2083     }
   2084     EbcDebuggerHookJMPEnd (VmPtr);
   2085 
   2086   } else {
   2087     //
   2088     // Form: JMP32 Rx {Immed32}
   2089     //
   2090     Addr = (UINTN) (Data64 + Index32);
   2091     if (!IS_ALIGNED ((UINTN) Addr, sizeof (UINT16))) {
   2092       EbcDebugSignalException (
   2093         EXCEPT_EBC_ALIGNMENT_CHECK,
   2094         EXCEPTION_FLAG_FATAL,
   2095         VmPtr
   2096         );
   2097 
   2098       return EFI_UNSUPPORTED;
   2099     }
   2100 
   2101     EbcDebuggerHookJMPStart (VmPtr);
   2102     if ((Operand & JMP_M_RELATIVE) != 0) {
   2103       VmPtr->Ip += (UINTN) Addr + Size;
   2104     } else {
   2105       VmPtr->Ip = (VMIP) Addr;
   2106     }
   2107     EbcDebuggerHookJMPEnd (VmPtr);
   2108 
   2109   }
   2110 
   2111   return EFI_SUCCESS;
   2112 }
   2113 
   2114 
   2115 /**
   2116   Execute the EBC JMP8 instruction.
   2117 
   2118   Instruction syntax:
   2119     JMP8{cs|cc}  Offset/2
   2120 
   2121   @param  VmPtr             A pointer to a VM context.
   2122 
   2123   @retval EFI_SUCCESS       The instruction is executed successfully.
   2124 
   2125 **/
   2126 EFI_STATUS
   2127 ExecuteJMP8 (
   2128   IN VM_CONTEXT *VmPtr
   2129   )
   2130 {
   2131   UINT8 Opcode;
   2132   UINT8 ConditionFlag;
   2133   UINT8 CompareSet;
   2134   INT8  Offset;
   2135 
   2136   //
   2137   // Decode instruction.
   2138   //
   2139   Opcode        = GETOPCODE (VmPtr);
   2140   CompareSet    = (UINT8) (((Opcode & JMP_M_CS) != 0) ? 1 : 0);
   2141   ConditionFlag = (UINT8) VMFLAG_ISSET (VmPtr, VMFLAGS_CC);
   2142 
   2143   //
   2144   // If we haven't met the condition, then simply advance the IP and return
   2145   //
   2146   if ((Opcode & CONDITION_M_CONDITIONAL) != 0) {
   2147     if (CompareSet != ConditionFlag) {
   2148       EbcDebuggerHookJMP8Start (VmPtr);
   2149       VmPtr->Ip += 2;
   2150       EbcDebuggerHookJMP8End (VmPtr);
   2151       return EFI_SUCCESS;
   2152     }
   2153   }
   2154   //
   2155   // Get the offset from the instruction stream. It's relative to the
   2156   // following instruction, and divided by 2.
   2157   //
   2158   Offset = VmReadImmed8 (VmPtr, 1);
   2159   //
   2160   // Want to check for offset == -2 and then raise an exception?
   2161   //
   2162   EbcDebuggerHookJMP8Start (VmPtr);
   2163   VmPtr->Ip += (Offset * 2) + 2;
   2164   EbcDebuggerHookJMP8End (VmPtr);
   2165   return EFI_SUCCESS;
   2166 }
   2167 
   2168 
   2169 /**
   2170   Execute the EBC MOVI.
   2171 
   2172   Instruction syntax:
   2173 
   2174     MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
   2175 
   2176     First variable character specifies the move size
   2177     Second variable character specifies size of the immediate data
   2178 
   2179     Sign-extend the immediate data to the size of the operation, and zero-extend
   2180     if storing to a register.
   2181 
   2182     Operand1 direct with index/immed is invalid.
   2183 
   2184   @param  VmPtr             A pointer to a VM context.
   2185 
   2186   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
   2187   @retval EFI_SUCCESS       The instruction is executed successfully.
   2188 
   2189 **/
   2190 EFI_STATUS
   2191 ExecuteMOVI (
   2192   IN VM_CONTEXT *VmPtr
   2193   )
   2194 {
   2195   UINT8   Opcode;
   2196   UINT8   Operands;
   2197   UINT8   Size;
   2198   INT16   Index16;
   2199   INT64   ImmData64;
   2200   UINT64  Op1;
   2201   UINT64  Mask64;
   2202 
   2203   //
   2204   // Get the opcode and operands byte so we can get R1 and R2
   2205   //
   2206   Opcode    = GETOPCODE (VmPtr);
   2207   Operands  = GETOPERANDS (VmPtr);
   2208 
   2209   //
   2210   // Get the index (16-bit) if present
   2211   //
   2212   if ((Operands & MOVI_M_IMMDATA) != 0) {
   2213     Index16 = VmReadIndex16 (VmPtr, 2);
   2214     Size    = 4;
   2215   } else {
   2216     Index16 = 0;
   2217     Size    = 2;
   2218   }
   2219   //
   2220   // Extract the immediate data. Sign-extend always.
   2221   //
   2222   if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
   2223     ImmData64 = (INT64) (INT16) VmReadImmed16 (VmPtr, Size);
   2224     Size += 2;
   2225   } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
   2226     ImmData64 = (INT64) (INT32) VmReadImmed32 (VmPtr, Size);
   2227     Size += 4;
   2228   } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
   2229     ImmData64 = (INT64) VmReadImmed64 (VmPtr, Size);
   2230     Size += 8;
   2231   } else {
   2232     //
   2233     // Invalid encoding
   2234     //
   2235     EbcDebugSignalException (
   2236       EXCEPT_EBC_INSTRUCTION_ENCODING,
   2237       EXCEPTION_FLAG_FATAL,
   2238       VmPtr
   2239       );
   2240     return EFI_UNSUPPORTED;
   2241   }
   2242   //
   2243   // Now write back the result
   2244   //
   2245   if (!OPERAND1_INDIRECT (Operands)) {
   2246     //
   2247     // Operand1 direct. Make sure it didn't have an index.
   2248     //
   2249     if ((Operands & MOVI_M_IMMDATA) != 0) {
   2250       EbcDebugSignalException (
   2251         EXCEPT_EBC_INSTRUCTION_ENCODING,
   2252         EXCEPTION_FLAG_FATAL,
   2253         VmPtr
   2254         );
   2255       return EFI_UNSUPPORTED;
   2256     }
   2257     //
   2258     // Writing directly to a register. Clear unused bits.
   2259     //
   2260     if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH8) {
   2261       Mask64 = 0x000000FF;
   2262     } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH16) {
   2263       Mask64 = 0x0000FFFF;
   2264     } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH32) {
   2265       Mask64 = 0x00000000FFFFFFFF;
   2266     } else {
   2267       Mask64 = (UINT64)~0;
   2268     }
   2269 
   2270     VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = ImmData64 & Mask64;
   2271   } else {
   2272     //
   2273     // Get the address then write back based on size of the move
   2274     //
   2275     Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;
   2276     if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH8) {
   2277       VmWriteMem8 (VmPtr, (UINTN) Op1, (UINT8) ImmData64);
   2278     } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH16) {
   2279       VmWriteMem16 (VmPtr, (UINTN) Op1, (UINT16) ImmData64);
   2280     } else if ((Operands & MOVI_M_MOVEWIDTH) == MOVI_MOVEWIDTH32) {
   2281       VmWriteMem32 (VmPtr, (UINTN) Op1, (UINT32) ImmData64);
   2282     } else {
   2283       VmWriteMem64 (VmPtr, (UINTN) Op1, (UINT64) ImmData64);
   2284     }
   2285   }
   2286   //
   2287   // Advance the instruction pointer
   2288   //
   2289   VmPtr->Ip += Size;
   2290   return EFI_SUCCESS;
   2291 }
   2292 
   2293 
   2294 /**
   2295   Execute the EBC MOV immediate natural. This instruction moves an immediate
   2296   index value into a register or memory location.
   2297 
   2298   Instruction syntax:
   2299 
   2300     MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
   2301 
   2302   @param  VmPtr             A pointer to a VM context.
   2303 
   2304   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
   2305   @retval EFI_SUCCESS       The instruction is executed successfully.
   2306 
   2307 **/
   2308 EFI_STATUS
   2309 ExecuteMOVIn (
   2310   IN VM_CONTEXT *VmPtr
   2311   )
   2312 {
   2313   UINT8   Opcode;
   2314   UINT8   Operands;
   2315   UINT8   Size;
   2316   INT16   Index16;
   2317   INT16   ImmedIndex16;
   2318   INT32   ImmedIndex32;
   2319   INT64   ImmedIndex64;
   2320   UINT64  Op1;
   2321 
   2322   //
   2323   // Get the opcode and operands byte so we can get R1 and R2
   2324   //
   2325   Opcode    = GETOPCODE (VmPtr);
   2326   Operands  = GETOPERANDS (VmPtr);
   2327 
   2328   //
   2329   // Get the operand1 index (16-bit) if present
   2330   //
   2331   if ((Operands & MOVI_M_IMMDATA) != 0) {
   2332     Index16 = VmReadIndex16 (VmPtr, 2);
   2333     Size    = 4;
   2334   } else {
   2335     Index16 = 0;
   2336     Size    = 2;
   2337   }
   2338   //
   2339   // Extract the immediate data and convert to a 64-bit index.
   2340   //
   2341   if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
   2342     ImmedIndex16  = VmReadIndex16 (VmPtr, Size);
   2343     ImmedIndex64  = (INT64) ImmedIndex16;
   2344     Size += 2;
   2345   } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
   2346     ImmedIndex32  = VmReadIndex32 (VmPtr, Size);
   2347     ImmedIndex64  = (INT64) ImmedIndex32;
   2348     Size += 4;
   2349   } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
   2350     ImmedIndex64 = VmReadIndex64 (VmPtr, Size);
   2351     Size += 8;
   2352   } else {
   2353     //
   2354     // Invalid encoding
   2355     //
   2356     EbcDebugSignalException (
   2357       EXCEPT_EBC_INSTRUCTION_ENCODING,
   2358       EXCEPTION_FLAG_FATAL,
   2359       VmPtr
   2360       );
   2361     return EFI_UNSUPPORTED;
   2362   }
   2363   //
   2364   // Now write back the result
   2365   //
   2366   if (!OPERAND1_INDIRECT (Operands)) {
   2367     //
   2368     // Check for MOVIn R1 Index16, Immed (not indirect, with index), which
   2369     // is illegal
   2370     //
   2371     if ((Operands & MOVI_M_IMMDATA) != 0) {
   2372       EbcDebugSignalException (
   2373         EXCEPT_EBC_INSTRUCTION_ENCODING,
   2374         EXCEPTION_FLAG_FATAL,
   2375         VmPtr
   2376         );
   2377       return EFI_UNSUPPORTED;
   2378     }
   2379 
   2380     VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = ImmedIndex64;
   2381   } else {
   2382     //
   2383     // Get the address
   2384     //
   2385     Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;
   2386     VmWriteMemN (VmPtr, (UINTN) Op1, (UINTN)(INTN) ImmedIndex64);
   2387   }
   2388   //
   2389   // Advance the instruction pointer
   2390   //
   2391   VmPtr->Ip += Size;
   2392   return EFI_SUCCESS;
   2393 }
   2394 
   2395 
   2396 /**
   2397   Execute the EBC MOVREL instruction.
   2398   Dest <- Ip + ImmData
   2399 
   2400   Instruction syntax:
   2401 
   2402     MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
   2403 
   2404   @param  VmPtr             A pointer to a VM context.
   2405 
   2406   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
   2407   @retval EFI_SUCCESS       The instruction is executed successfully.
   2408 
   2409 **/
   2410 EFI_STATUS
   2411 ExecuteMOVREL (
   2412   IN VM_CONTEXT *VmPtr
   2413   )
   2414 {
   2415   UINT8   Opcode;
   2416   UINT8   Operands;
   2417   UINT8   Size;
   2418   INT16   Index16;
   2419   INT64   ImmData64;
   2420   UINT64  Op1;
   2421   UINT64  Op2;
   2422 
   2423   //
   2424   // Get the opcode and operands byte so we can get R1 and R2
   2425   //
   2426   Opcode    = GETOPCODE (VmPtr);
   2427   Operands  = GETOPERANDS (VmPtr);
   2428 
   2429   //
   2430   // Get the Operand 1 index (16-bit) if present
   2431   //
   2432   if ((Operands & MOVI_M_IMMDATA) != 0) {
   2433     Index16 = VmReadIndex16 (VmPtr, 2);
   2434     Size    = 4;
   2435   } else {
   2436     Index16 = 0;
   2437     Size    = 2;
   2438   }
   2439   //
   2440   // Get the immediate data.
   2441   //
   2442   if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH16) {
   2443     ImmData64 = (INT64) VmReadImmed16 (VmPtr, Size);
   2444     Size += 2;
   2445   } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH32) {
   2446     ImmData64 = (INT64) VmReadImmed32 (VmPtr, Size);
   2447     Size += 4;
   2448   } else if ((Opcode & MOVI_M_DATAWIDTH) == MOVI_DATAWIDTH64) {
   2449     ImmData64 = VmReadImmed64 (VmPtr, Size);
   2450     Size += 8;
   2451   } else {
   2452     //
   2453     // Invalid encoding
   2454     //
   2455     EbcDebugSignalException (
   2456       EXCEPT_EBC_INSTRUCTION_ENCODING,
   2457       EXCEPTION_FLAG_FATAL,
   2458       VmPtr
   2459       );
   2460     return EFI_UNSUPPORTED;
   2461   }
   2462   //
   2463   // Compute the value and write back the result
   2464   //
   2465   Op2 = (UINT64) ((INT64) ((UINT64) (UINTN) VmPtr->Ip) + (INT64) ImmData64 + Size);
   2466   if (!OPERAND1_INDIRECT (Operands)) {
   2467     //
   2468     // Check for illegal combination of operand1 direct with immediate data
   2469     //
   2470     if ((Operands & MOVI_M_IMMDATA) != 0) {
   2471       EbcDebugSignalException (
   2472         EXCEPT_EBC_INSTRUCTION_ENCODING,
   2473         EXCEPTION_FLAG_FATAL,
   2474         VmPtr
   2475         );
   2476       return EFI_UNSUPPORTED;
   2477     }
   2478 
   2479     VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (VM_REGISTER) Op2;
   2480   } else {
   2481     //
   2482     // Get the address = [Rx] + Index16
   2483     // Write back the result. Always a natural size write, since
   2484     // we're talking addresses here.
   2485     //
   2486     Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;
   2487     VmWriteMemN (VmPtr, (UINTN) Op1, (UINTN) Op2);
   2488   }
   2489   //
   2490   // Advance the instruction pointer
   2491   //
   2492   VmPtr->Ip += Size;
   2493   return EFI_SUCCESS;
   2494 }
   2495 
   2496 
   2497 /**
   2498   Execute the EBC MOVsnw instruction. This instruction loads a signed
   2499   natural value from memory or register to another memory or register. On
   2500   32-bit machines, the value gets sign-extended to 64 bits if the destination
   2501   is a register.
   2502 
   2503   Instruction syntax:
   2504 
   2505     MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
   2506 
   2507     0:7 1=>operand1 index present
   2508     0:6 1=>operand2 index present
   2509 
   2510   @param  VmPtr             A pointer to a VM context.
   2511 
   2512   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
   2513   @retval EFI_SUCCESS       The instruction is executed successfully.
   2514 
   2515 **/
   2516 EFI_STATUS
   2517 ExecuteMOVsnw (
   2518   IN VM_CONTEXT *VmPtr
   2519   )
   2520 {
   2521   UINT8   Opcode;
   2522   UINT8   Operands;
   2523   UINT8   Size;
   2524   INT16   Op1Index;
   2525   INT16   Op2Index;
   2526   UINT64  Op2;
   2527 
   2528   //
   2529   // Get the opcode and operand bytes
   2530   //
   2531   Opcode              = GETOPCODE (VmPtr);
   2532   Operands            = GETOPERANDS (VmPtr);
   2533 
   2534   Op1Index            = Op2Index = 0;
   2535 
   2536   //
   2537   // Get the indexes if present.
   2538   //
   2539   Size = 2;
   2540   if ((Opcode & OPCODE_M_IMMED_OP1) !=0) {
   2541     if (OPERAND1_INDIRECT (Operands)) {
   2542       Op1Index = VmReadIndex16 (VmPtr, 2);
   2543     } else {
   2544       //
   2545       // Illegal form operand1 direct with index:  MOVsnw R1 Index16, {@}R2
   2546       //
   2547       EbcDebugSignalException (
   2548         EXCEPT_EBC_INSTRUCTION_ENCODING,
   2549         EXCEPTION_FLAG_FATAL,
   2550         VmPtr
   2551         );
   2552       return EFI_UNSUPPORTED;
   2553     }
   2554 
   2555     Size += sizeof (UINT16);
   2556   }
   2557 
   2558   if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
   2559     if (OPERAND2_INDIRECT (Operands)) {
   2560       Op2Index = VmReadIndex16 (VmPtr, Size);
   2561     } else {
   2562       Op2Index = VmReadImmed16 (VmPtr, Size);
   2563     }
   2564 
   2565     Size += sizeof (UINT16);
   2566   }
   2567   //
   2568   // Get the data from the source.
   2569   //
   2570   Op2 = (UINT64)(INT64)(INTN)(VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Op2Index);
   2571   if (OPERAND2_INDIRECT (Operands)) {
   2572     Op2 = (UINT64)(INT64)(INTN)VmReadMemN (VmPtr, (UINTN) Op2);
   2573   }
   2574   //
   2575   // Now write back the result.
   2576   //
   2577   if (!OPERAND1_INDIRECT (Operands)) {
   2578     VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Op2;
   2579   } else {
   2580     VmWriteMemN (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Op1Index), (UINTN) Op2);
   2581   }
   2582   //
   2583   // Advance the instruction pointer
   2584   //
   2585   VmPtr->Ip += Size;
   2586   return EFI_SUCCESS;
   2587 }
   2588 
   2589 
   2590 /**
   2591   Execute the EBC MOVsnw instruction. This instruction loads a signed
   2592   natural value from memory or register to another memory or register. On
   2593   32-bit machines, the value gets sign-extended to 64 bits if the destination
   2594   is a register.
   2595 
   2596   Instruction syntax:
   2597 
   2598     MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
   2599 
   2600     0:7 1=>operand1 index present
   2601     0:6 1=>operand2 index present
   2602 
   2603   @param  VmPtr             A pointer to a VM context.
   2604 
   2605   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
   2606   @retval EFI_SUCCESS       The instruction is executed successfully.
   2607 
   2608 **/
   2609 EFI_STATUS
   2610 ExecuteMOVsnd (
   2611   IN VM_CONTEXT *VmPtr
   2612   )
   2613 {
   2614   UINT8   Opcode;
   2615   UINT8   Operands;
   2616   UINT8   Size;
   2617   INT32   Op1Index;
   2618   INT32   Op2Index;
   2619   UINT64  Op2;
   2620 
   2621   //
   2622   // Get the opcode and operand bytes
   2623   //
   2624   Opcode              = GETOPCODE (VmPtr);
   2625   Operands            = GETOPERANDS (VmPtr);
   2626 
   2627   Op1Index            = Op2Index = 0;
   2628 
   2629   //
   2630   // Get the indexes if present.
   2631   //
   2632   Size = 2;
   2633   if ((Opcode & OPCODE_M_IMMED_OP1) != 0) {
   2634     if (OPERAND1_INDIRECT (Operands)) {
   2635       Op1Index = VmReadIndex32 (VmPtr, 2);
   2636     } else {
   2637       //
   2638       // Illegal form operand1 direct with index:  MOVsnd R1 Index16,..
   2639       //
   2640       EbcDebugSignalException (
   2641         EXCEPT_EBC_INSTRUCTION_ENCODING,
   2642         EXCEPTION_FLAG_FATAL,
   2643         VmPtr
   2644         );
   2645       return EFI_UNSUPPORTED;
   2646     }
   2647 
   2648     Size += sizeof (UINT32);
   2649   }
   2650 
   2651   if ((Opcode & OPCODE_M_IMMED_OP2) != 0) {
   2652     if (OPERAND2_INDIRECT (Operands)) {
   2653       Op2Index = VmReadIndex32 (VmPtr, Size);
   2654     } else {
   2655       Op2Index = VmReadImmed32 (VmPtr, Size);
   2656     }
   2657 
   2658     Size += sizeof (UINT32);
   2659   }
   2660   //
   2661   // Get the data from the source.
   2662   //
   2663   Op2 = (UINT64)(INT64)(INTN)(INT64)(VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Op2Index);
   2664   if (OPERAND2_INDIRECT (Operands)) {
   2665     Op2 = (UINT64)(INT64)(INTN)(INT64)VmReadMemN (VmPtr, (UINTN) Op2);
   2666   }
   2667   //
   2668   // Now write back the result.
   2669   //
   2670   if (!OPERAND1_INDIRECT (Operands)) {
   2671     VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Op2;
   2672   } else {
   2673     VmWriteMemN (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Op1Index), (UINTN) Op2);
   2674   }
   2675   //
   2676   // Advance the instruction pointer
   2677   //
   2678   VmPtr->Ip += Size;
   2679   return EFI_SUCCESS;
   2680 }
   2681 
   2682 
   2683 /**
   2684   Execute the EBC PUSHn instruction
   2685 
   2686   Instruction syntax:
   2687     PUSHn {@}R1 {Index16|Immed16}
   2688 
   2689   @param  VmPtr             A pointer to a VM context.
   2690 
   2691   @retval EFI_SUCCESS       The instruction is executed successfully.
   2692 
   2693 **/
   2694 EFI_STATUS
   2695 ExecutePUSHn (
   2696   IN VM_CONTEXT *VmPtr
   2697   )
   2698 {
   2699   UINT8 Opcode;
   2700   UINT8 Operands;
   2701   INT16 Index16;
   2702   UINTN DataN;
   2703 
   2704   //
   2705   // Get opcode and operands
   2706   //
   2707   Opcode    = GETOPCODE (VmPtr);
   2708   Operands  = GETOPERANDS (VmPtr);
   2709 
   2710   //
   2711   // Get index if present
   2712   //
   2713   if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {
   2714     if (OPERAND1_INDIRECT (Operands)) {
   2715       Index16 = VmReadIndex16 (VmPtr, 2);
   2716     } else {
   2717       Index16 = VmReadImmed16 (VmPtr, 2);
   2718     }
   2719 
   2720     VmPtr->Ip += 4;
   2721   } else {
   2722     Index16 = 0;
   2723     VmPtr->Ip += 2;
   2724   }
   2725   //
   2726   // Get the data to push
   2727   //
   2728   if (OPERAND1_INDIRECT (Operands)) {
   2729     DataN = VmReadMemN (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16));
   2730   } else {
   2731     DataN = (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16);
   2732   }
   2733   //
   2734   // Adjust the stack down.
   2735   //
   2736   VmPtr->Gpr[0] -= sizeof (UINTN);
   2737   VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], DataN);
   2738   return EFI_SUCCESS;
   2739 }
   2740 
   2741 
   2742 /**
   2743   Execute the EBC PUSH instruction.
   2744 
   2745   Instruction syntax:
   2746     PUSH[32|64] {@}R1 {Index16|Immed16}
   2747 
   2748   @param  VmPtr             A pointer to a VM context.
   2749 
   2750   @retval EFI_SUCCESS       The instruction is executed successfully.
   2751 
   2752 **/
   2753 EFI_STATUS
   2754 ExecutePUSH (
   2755   IN VM_CONTEXT *VmPtr
   2756   )
   2757 {
   2758   UINT8   Opcode;
   2759   UINT8   Operands;
   2760   UINT32  Data32;
   2761   UINT64  Data64;
   2762   INT16   Index16;
   2763 
   2764   //
   2765   // Get opcode and operands
   2766   //
   2767   Opcode    = GETOPCODE (VmPtr);
   2768   Operands  = GETOPERANDS (VmPtr);
   2769   //
   2770   // Get immediate index if present, then advance the IP.
   2771   //
   2772   if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {
   2773     if (OPERAND1_INDIRECT (Operands)) {
   2774       Index16 = VmReadIndex16 (VmPtr, 2);
   2775     } else {
   2776       Index16 = VmReadImmed16 (VmPtr, 2);
   2777     }
   2778 
   2779     VmPtr->Ip += 4;
   2780   } else {
   2781     Index16 = 0;
   2782     VmPtr->Ip += 2;
   2783   }
   2784   //
   2785   // Get the data to push
   2786   //
   2787   if ((Opcode & PUSHPOP_M_64) != 0) {
   2788     if (OPERAND1_INDIRECT (Operands)) {
   2789       Data64 = VmReadMem64 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16));
   2790     } else {
   2791       Data64 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;
   2792     }
   2793     //
   2794     // Adjust the stack down, then write back the data
   2795     //
   2796     VmPtr->Gpr[0] -= sizeof (UINT64);
   2797     VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], Data64);
   2798   } else {
   2799     //
   2800     // 32-bit data
   2801     //
   2802     if (OPERAND1_INDIRECT (Operands)) {
   2803       Data32 = VmReadMem32 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16));
   2804     } else {
   2805       Data32 = (UINT32) VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16;
   2806     }
   2807     //
   2808     // Adjust the stack down and write the data
   2809     //
   2810     VmPtr->Gpr[0] -= sizeof (UINT32);
   2811     VmWriteMem32 (VmPtr, (UINTN) VmPtr->Gpr[0], Data32);
   2812   }
   2813 
   2814   return EFI_SUCCESS;
   2815 }
   2816 
   2817 
   2818 /**
   2819   Execute the EBC POPn instruction.
   2820 
   2821   Instruction syntax:
   2822     POPn {@}R1 {Index16|Immed16}
   2823 
   2824   @param  VmPtr             A pointer to a VM context.
   2825 
   2826   @retval EFI_SUCCESS       The instruction is executed successfully.
   2827 
   2828 **/
   2829 EFI_STATUS
   2830 ExecutePOPn (
   2831   IN VM_CONTEXT *VmPtr
   2832   )
   2833 {
   2834   UINT8 Opcode;
   2835   UINT8 Operands;
   2836   INT16 Index16;
   2837   UINTN DataN;
   2838 
   2839   //
   2840   // Get opcode and operands
   2841   //
   2842   Opcode    = GETOPCODE (VmPtr);
   2843   Operands  = GETOPERANDS (VmPtr);
   2844   //
   2845   // Get immediate data if present, and advance the IP
   2846   //
   2847   if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {
   2848     if (OPERAND1_INDIRECT (Operands)) {
   2849       Index16 = VmReadIndex16 (VmPtr, 2);
   2850     } else {
   2851       Index16 = VmReadImmed16 (VmPtr, 2);
   2852     }
   2853 
   2854     VmPtr->Ip += 4;
   2855   } else {
   2856     Index16 = 0;
   2857     VmPtr->Ip += 2;
   2858   }
   2859   //
   2860   // Read the data off the stack, then adjust the stack pointer
   2861   //
   2862   DataN = VmReadMemN (VmPtr, (UINTN) VmPtr->Gpr[0]);
   2863   VmPtr->Gpr[0] += sizeof (UINTN);
   2864   //
   2865   // Do the write-back
   2866   //
   2867   if (OPERAND1_INDIRECT (Operands)) {
   2868     VmWriteMemN (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16), DataN);
   2869   } else {
   2870     VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (INT64) (UINT64) ((UINTN) DataN + Index16);
   2871   }
   2872 
   2873   return EFI_SUCCESS;
   2874 }
   2875 
   2876 
   2877 /**
   2878   Execute the EBC POP instruction.
   2879 
   2880   Instruction syntax:
   2881     POPn {@}R1 {Index16|Immed16}
   2882 
   2883   @param  VmPtr             A pointer to a VM context.
   2884 
   2885   @retval EFI_SUCCESS       The instruction is executed successfully.
   2886 
   2887 **/
   2888 EFI_STATUS
   2889 ExecutePOP (
   2890   IN VM_CONTEXT *VmPtr
   2891   )
   2892 {
   2893   UINT8   Opcode;
   2894   UINT8   Operands;
   2895   INT16   Index16;
   2896   INT32   Data32;
   2897   UINT64  Data64;
   2898 
   2899   //
   2900   // Get opcode and operands
   2901   //
   2902   Opcode    = GETOPCODE (VmPtr);
   2903   Operands  = GETOPERANDS (VmPtr);
   2904   //
   2905   // Get immediate data if present, and advance the IP.
   2906   //
   2907   if ((Opcode & PUSHPOP_M_IMMDATA) != 0) {
   2908     if (OPERAND1_INDIRECT (Operands)) {
   2909       Index16 = VmReadIndex16 (VmPtr, 2);
   2910     } else {
   2911       Index16 = VmReadImmed16 (VmPtr, 2);
   2912     }
   2913 
   2914     VmPtr->Ip += 4;
   2915   } else {
   2916     Index16 = 0;
   2917     VmPtr->Ip += 2;
   2918   }
   2919   //
   2920   // Get the data off the stack, then write it to the appropriate location
   2921   //
   2922   if ((Opcode & PUSHPOP_M_64) != 0) {
   2923     //
   2924     // Read the data off the stack, then adjust the stack pointer
   2925     //
   2926     Data64 = VmReadMem64 (VmPtr, (UINTN) VmPtr->Gpr[0]);
   2927     VmPtr->Gpr[0] += sizeof (UINT64);
   2928     //
   2929     // Do the write-back
   2930     //
   2931     if (OPERAND1_INDIRECT (Operands)) {
   2932       VmWriteMem64 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16), Data64);
   2933     } else {
   2934       VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Data64 + Index16;
   2935     }
   2936   } else {
   2937     //
   2938     // 32-bit pop. Read it off the stack and adjust the stack pointer
   2939     //
   2940     Data32 = (INT32) VmReadMem32 (VmPtr, (UINTN) VmPtr->Gpr[0]);
   2941     VmPtr->Gpr[0] += sizeof (UINT32);
   2942     //
   2943     // Do the write-back
   2944     //
   2945     if (OPERAND1_INDIRECT (Operands)) {
   2946       VmWriteMem32 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND1_REGNUM (Operands)] + Index16), Data32);
   2947     } else {
   2948       VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (INT64) Data32 + Index16;
   2949     }
   2950   }
   2951 
   2952   return EFI_SUCCESS;
   2953 }
   2954 
   2955 
   2956 /**
   2957   Implements the EBC CALL instruction.
   2958 
   2959   Instruction format:
   2960     CALL64 Immed64
   2961     CALL32 {@}R1 {Immed32|Index32}
   2962     CALLEX64 Immed64
   2963     CALLEX16 {@}R1 {Immed32}
   2964 
   2965     If Rx == R0, then it's a PC relative call to PC = PC + imm32.
   2966 
   2967   @param  VmPtr             A pointer to a VM context.
   2968 
   2969   @retval EFI_SUCCESS       The instruction is executed successfully.
   2970 
   2971 **/
   2972 EFI_STATUS
   2973 ExecuteCALL (
   2974   IN VM_CONTEXT *VmPtr
   2975   )
   2976 {
   2977   UINT8 Opcode;
   2978   UINT8 Operands;
   2979   INT32 Immed32;
   2980   UINT8 Size;
   2981   INT64 Immed64;
   2982   VOID  *FramePtr;
   2983 
   2984   //
   2985   // Get opcode and operands
   2986   //
   2987   Opcode    = GETOPCODE (VmPtr);
   2988   Operands  = GETOPERANDS (VmPtr);
   2989 
   2990   if ((Operands & OPERAND_M_NATIVE_CALL) != 0) {
   2991     EbcDebuggerHookCALLEXStart (VmPtr);
   2992   } else {
   2993     EbcDebuggerHookCALLStart (VmPtr);
   2994   }
   2995 
   2996   //
   2997   // Assign these as well to avoid compiler warnings
   2998   //
   2999   Immed64   = 0;
   3000   Immed32   = 0;
   3001 
   3002   FramePtr  = VmPtr->FramePtr;
   3003   //
   3004   // Determine the instruction size, and get immediate data if present
   3005   //
   3006   if ((Opcode & OPCODE_M_IMMDATA) != 0) {
   3007     if ((Opcode & OPCODE_M_IMMDATA64) != 0) {
   3008       Immed64 = VmReadImmed64 (VmPtr, 2);
   3009       Size    = 10;
   3010     } else {
   3011       //
   3012       // If register operand is indirect, then the immediate data is an index
   3013       //
   3014       if (OPERAND1_INDIRECT (Operands)) {
   3015         Immed32 = VmReadIndex32 (VmPtr, 2);
   3016       } else {
   3017         Immed32 = VmReadImmed32 (VmPtr, 2);
   3018       }
   3019 
   3020       Size = 6;
   3021     }
   3022   } else {
   3023     Size = 2;
   3024   }
   3025   //
   3026   // If it's a call to EBC, adjust the stack pointer down 16 bytes and
   3027   // put our return address and frame pointer on the VM stack.
   3028   //
   3029   if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {
   3030     VmPtr->Gpr[0] -= 8;
   3031     VmWriteMemN (VmPtr, (UINTN) VmPtr->Gpr[0], (UINTN) FramePtr);
   3032     VmPtr->FramePtr = (VOID *) (UINTN) VmPtr->Gpr[0];
   3033     VmPtr->Gpr[0] -= 8;
   3034     VmWriteMem64 (VmPtr, (UINTN) VmPtr->Gpr[0], (UINT64) (UINTN) (VmPtr->Ip + Size));
   3035   }
   3036   //
   3037   // If 64-bit data, then absolute jump only
   3038   //
   3039   if ((Opcode & OPCODE_M_IMMDATA64) != 0) {
   3040     //
   3041     // Native or EBC call?
   3042     //
   3043     if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {
   3044       VmPtr->Ip = (VMIP) (UINTN) Immed64;
   3045     } else {
   3046       //
   3047       // Call external function, get the return value, and advance the IP
   3048       //
   3049       EbcLLCALLEX (VmPtr, (UINTN) Immed64, (UINTN) VmPtr->Gpr[0], FramePtr, Size);
   3050     }
   3051   } else {
   3052     //
   3053     // Get the register data. If operand1 == 0, then ignore register and
   3054     // take immediate data as relative or absolute address.
   3055     // Compiler should take care of upper bits if 32-bit machine.
   3056     //
   3057     if (OPERAND1_REGNUM (Operands) != 0) {
   3058       Immed64 = (UINT64) (UINTN) VmPtr->Gpr[OPERAND1_REGNUM (Operands)];
   3059     }
   3060     //
   3061     // Get final address
   3062     //
   3063     if (OPERAND1_INDIRECT (Operands)) {
   3064       Immed64 = (INT64) (UINT64) (UINTN) VmReadMemN (VmPtr, (UINTN) (Immed64 + Immed32));
   3065     } else {
   3066       Immed64 += Immed32;
   3067     }
   3068     //
   3069     // Now determine if external call, and then if relative or absolute
   3070     //
   3071     if ((Operands & OPERAND_M_NATIVE_CALL) == 0) {
   3072       //
   3073       // EBC call. Relative or absolute? If relative, then it's relative to the
   3074       // start of the next instruction.
   3075       //
   3076       if ((Operands & OPERAND_M_RELATIVE_ADDR) != 0) {
   3077         VmPtr->Ip += Immed64 + Size;
   3078       } else {
   3079         VmPtr->Ip = (VMIP) (UINTN) Immed64;
   3080       }
   3081     } else {
   3082       //
   3083       // Native call. Relative or absolute?
   3084       //
   3085       if ((Operands & OPERAND_M_RELATIVE_ADDR) != 0) {
   3086         EbcLLCALLEX (VmPtr, (UINTN) (Immed64 + VmPtr->Ip + Size), (UINTN) VmPtr->Gpr[0], FramePtr, Size);
   3087       } else {
   3088         if ((VmPtr->StopFlags & STOPFLAG_BREAK_ON_CALLEX) != 0) {
   3089           CpuBreakpoint ();
   3090         }
   3091 
   3092         EbcLLCALLEX (VmPtr, (UINTN) Immed64, (UINTN) VmPtr->Gpr[0], FramePtr, Size);
   3093       }
   3094     }
   3095   }
   3096 
   3097   if ((Operands & OPERAND_M_NATIVE_CALL) != 0) {
   3098     EbcDebuggerHookCALLEXEnd (VmPtr);
   3099   } else {
   3100     EbcDebuggerHookCALLEnd (VmPtr);
   3101   }
   3102 
   3103   return EFI_SUCCESS;
   3104 }
   3105 
   3106 
   3107 /**
   3108   Execute the EBC RET instruction.
   3109 
   3110   Instruction syntax:
   3111     RET
   3112 
   3113   @param  VmPtr             A pointer to a VM context.
   3114 
   3115   @retval EFI_SUCCESS       The instruction is executed successfully.
   3116 
   3117 **/
   3118 EFI_STATUS
   3119 ExecuteRET (
   3120   IN VM_CONTEXT *VmPtr
   3121   )
   3122 {
   3123 
   3124   EbcDebuggerHookRETStart (VmPtr);
   3125 
   3126   //
   3127   // If we're at the top of the stack, then simply set the done
   3128   // flag and return
   3129   //
   3130   if (VmPtr->StackRetAddr == (UINT64) VmPtr->Gpr[0]) {
   3131     VmPtr->StopFlags |= STOPFLAG_APP_DONE;
   3132   } else {
   3133     //
   3134     // Pull the return address off the VM app's stack and set the IP
   3135     // to it
   3136     //
   3137     if (!IS_ALIGNED ((UINTN) VmPtr->Gpr[0], sizeof (UINT16))) {
   3138       EbcDebugSignalException (
   3139         EXCEPT_EBC_ALIGNMENT_CHECK,
   3140         EXCEPTION_FLAG_FATAL,
   3141         VmPtr
   3142         );
   3143     }
   3144     //
   3145     // Restore the IP and frame pointer from the stack
   3146     //
   3147     VmPtr->Ip = (VMIP) (UINTN) VmReadMem64 (VmPtr, (UINTN) VmPtr->Gpr[0]);
   3148     VmPtr->Gpr[0] += 8;
   3149     VmPtr->FramePtr = (VOID *) VmReadMemN (VmPtr, (UINTN) VmPtr->Gpr[0]);
   3150     VmPtr->Gpr[0] += 8;
   3151   }
   3152 
   3153 
   3154   EbcDebuggerHookRETEnd (VmPtr);
   3155 
   3156   return EFI_SUCCESS;
   3157 }
   3158 
   3159 
   3160 /**
   3161   Execute the EBC CMP instruction.
   3162 
   3163   Instruction syntax:
   3164     CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
   3165 
   3166   @param  VmPtr             A pointer to a VM context.
   3167 
   3168   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
   3169   @retval EFI_SUCCESS       The instruction is executed successfully.
   3170 
   3171 **/
   3172 EFI_STATUS
   3173 ExecuteCMP (
   3174   IN VM_CONTEXT *VmPtr
   3175   )
   3176 {
   3177   UINT8   Opcode;
   3178   UINT8   Operands;
   3179   UINT8   Size;
   3180   INT16   Index16;
   3181   UINT32  Flag;
   3182   INT64   Op2;
   3183   INT64   Op1;
   3184 
   3185   //
   3186   // Get opcode and operands
   3187   //
   3188   Opcode    = GETOPCODE (VmPtr);
   3189   Operands  = GETOPERANDS (VmPtr);
   3190   //
   3191   // Get the register data we're going to compare to
   3192   //
   3193   Op1 = VmPtr->Gpr[OPERAND1_REGNUM (Operands)];
   3194   //
   3195   // Get immediate data
   3196   //
   3197   if ((Opcode & OPCODE_M_IMMDATA) != 0) {
   3198     if (OPERAND2_INDIRECT (Operands)) {
   3199       Index16 = VmReadIndex16 (VmPtr, 2);
   3200     } else {
   3201       Index16 = VmReadImmed16 (VmPtr, 2);
   3202     }
   3203 
   3204     Size = 4;
   3205   } else {
   3206     Index16 = 0;
   3207     Size    = 2;
   3208   }
   3209   //
   3210   // Now get Op2
   3211   //
   3212   if (OPERAND2_INDIRECT (Operands)) {
   3213     if ((Opcode & OPCODE_M_64BIT) != 0) {
   3214       Op2 = (INT64) VmReadMem64 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index16));
   3215     } else {
   3216       //
   3217       // 32-bit operations. 0-extend the values for all cases.
   3218       //
   3219       Op2 = (INT64) (UINT64) ((UINT32) VmReadMem32 (VmPtr, (UINTN) (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index16)));
   3220     }
   3221   } else {
   3222     Op2 = VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index16;
   3223   }
   3224   //
   3225   // Now do the compare
   3226   //
   3227   Flag = 0;
   3228   if ((Opcode & OPCODE_M_64BIT) != 0) {
   3229     //
   3230     // 64-bit compares
   3231     //
   3232     switch (Opcode & OPCODE_M_OPCODE) {
   3233     case OPCODE_CMPEQ:
   3234       if (Op1 == Op2) {
   3235         Flag = 1;
   3236       }
   3237       break;
   3238 
   3239     case OPCODE_CMPLTE:
   3240       if (Op1 <= Op2) {
   3241         Flag = 1;
   3242       }
   3243       break;
   3244 
   3245     case OPCODE_CMPGTE:
   3246       if (Op1 >= Op2) {
   3247         Flag = 1;
   3248       }
   3249       break;
   3250 
   3251     case OPCODE_CMPULTE:
   3252       if ((UINT64) Op1 <= (UINT64) Op2) {
   3253         Flag = 1;
   3254       }
   3255       break;
   3256 
   3257     case OPCODE_CMPUGTE:
   3258       if ((UINT64) Op1 >= (UINT64) Op2) {
   3259         Flag = 1;
   3260       }
   3261       break;
   3262 
   3263     default:
   3264       ASSERT (0);
   3265     }
   3266   } else {
   3267     //
   3268     // 32-bit compares
   3269     //
   3270     switch (Opcode & OPCODE_M_OPCODE) {
   3271     case OPCODE_CMPEQ:
   3272       if ((INT32) Op1 == (INT32) Op2) {
   3273         Flag = 1;
   3274       }
   3275       break;
   3276 
   3277     case OPCODE_CMPLTE:
   3278       if ((INT32) Op1 <= (INT32) Op2) {
   3279         Flag = 1;
   3280       }
   3281       break;
   3282 
   3283     case OPCODE_CMPGTE:
   3284       if ((INT32) Op1 >= (INT32) Op2) {
   3285         Flag = 1;
   3286       }
   3287       break;
   3288 
   3289     case OPCODE_CMPULTE:
   3290       if ((UINT32) Op1 <= (UINT32) Op2) {
   3291         Flag = 1;
   3292       }
   3293       break;
   3294 
   3295     case OPCODE_CMPUGTE:
   3296       if ((UINT32) Op1 >= (UINT32) Op2) {
   3297         Flag = 1;
   3298       }
   3299       break;
   3300 
   3301     default:
   3302       ASSERT (0);
   3303     }
   3304   }
   3305   //
   3306   // Now set the flag accordingly for the comparison
   3307   //
   3308   if (Flag != 0) {
   3309     VMFLAG_SET (VmPtr, VMFLAGS_CC);
   3310   } else {
   3311     VMFLAG_CLEAR (VmPtr, (UINT64)VMFLAGS_CC);
   3312   }
   3313   //
   3314   // Advance the IP
   3315   //
   3316   VmPtr->Ip += Size;
   3317   return EFI_SUCCESS;
   3318 }
   3319 
   3320 
   3321 /**
   3322   Execute the EBC CMPI instruction
   3323 
   3324   Instruction syntax:
   3325     CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
   3326 
   3327   @param  VmPtr             A pointer to a VM context.
   3328 
   3329   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
   3330   @retval EFI_SUCCESS       The instruction is executed successfully.
   3331 
   3332 **/
   3333 EFI_STATUS
   3334 ExecuteCMPI (
   3335   IN VM_CONTEXT *VmPtr
   3336   )
   3337 {
   3338   UINT8   Opcode;
   3339   UINT8   Operands;
   3340   UINT8   Size;
   3341   INT64   Op1;
   3342   INT64   Op2;
   3343   INT16   Index16;
   3344   UINT32  Flag;
   3345 
   3346   //
   3347   // Get opcode and operands
   3348   //
   3349   Opcode    = GETOPCODE (VmPtr);
   3350   Operands  = GETOPERANDS (VmPtr);
   3351 
   3352   //
   3353   // Get operand1 index if present
   3354   //
   3355   Size = 2;
   3356   if ((Operands & OPERAND_M_CMPI_INDEX) != 0) {
   3357     Index16 = VmReadIndex16 (VmPtr, 2);
   3358     Size += 2;
   3359   } else {
   3360     Index16 = 0;
   3361   }
   3362   //
   3363   // Get operand1 data we're going to compare to
   3364   //
   3365   Op1 = (INT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)];
   3366   if (OPERAND1_INDIRECT (Operands)) {
   3367     //
   3368     // Indirect operand1. Fetch 32 or 64-bit value based on compare size.
   3369     //
   3370     if ((Opcode & OPCODE_M_CMPI64) != 0) {
   3371       Op1 = (INT64) VmReadMem64 (VmPtr, (UINTN) Op1 + Index16);
   3372     } else {
   3373       Op1 = (INT64) VmReadMem32 (VmPtr, (UINTN) Op1 + Index16);
   3374     }
   3375   } else {
   3376     //
   3377     // Better not have been an index with direct. That is, CMPI R1 Index,...
   3378     // is illegal.
   3379     //
   3380     if ((Operands & OPERAND_M_CMPI_INDEX) != 0) {
   3381       EbcDebugSignalException (
   3382         EXCEPT_EBC_INSTRUCTION_ENCODING,
   3383         EXCEPTION_FLAG_ERROR,
   3384         VmPtr
   3385         );
   3386       VmPtr->Ip += Size;
   3387       return EFI_UNSUPPORTED;
   3388     }
   3389   }
   3390   //
   3391   // Get immediate data -- 16- or 32-bit sign extended
   3392   //
   3393   if ((Opcode & OPCODE_M_CMPI32_DATA) != 0) {
   3394     Op2 = (INT64) VmReadImmed32 (VmPtr, Size);
   3395     Size += 4;
   3396   } else {
   3397     //
   3398     // 16-bit immediate data. Sign extend always.
   3399     //
   3400     Op2 = (INT64) ((INT16) VmReadImmed16 (VmPtr, Size));
   3401     Size += 2;
   3402   }
   3403   //
   3404   // Now do the compare
   3405   //
   3406   Flag = 0;
   3407   if ((Opcode & OPCODE_M_CMPI64) != 0) {
   3408     //
   3409     // 64 bit comparison
   3410     //
   3411     switch (Opcode & OPCODE_M_OPCODE) {
   3412     case OPCODE_CMPIEQ:
   3413       if (Op1 == (INT64) Op2) {
   3414         Flag = 1;
   3415       }
   3416       break;
   3417 
   3418     case OPCODE_CMPILTE:
   3419       if (Op1 <= (INT64) Op2) {
   3420         Flag = 1;
   3421       }
   3422       break;
   3423 
   3424     case OPCODE_CMPIGTE:
   3425       if (Op1 >= (INT64) Op2) {
   3426         Flag = 1;
   3427       }
   3428       break;
   3429 
   3430     case OPCODE_CMPIULTE:
   3431       if ((UINT64) Op1 <= (UINT64) ((UINT32) Op2)) {
   3432         Flag = 1;
   3433       }
   3434       break;
   3435 
   3436     case OPCODE_CMPIUGTE:
   3437       if ((UINT64) Op1 >= (UINT64) ((UINT32) Op2)) {
   3438         Flag = 1;
   3439       }
   3440       break;
   3441 
   3442     default:
   3443       ASSERT (0);
   3444     }
   3445   } else {
   3446     //
   3447     // 32-bit comparisons
   3448     //
   3449     switch (Opcode & OPCODE_M_OPCODE) {
   3450     case OPCODE_CMPIEQ:
   3451       if ((INT32) Op1 == Op2) {
   3452         Flag = 1;
   3453       }
   3454       break;
   3455 
   3456     case OPCODE_CMPILTE:
   3457       if ((INT32) Op1 <= Op2) {
   3458         Flag = 1;
   3459       }
   3460       break;
   3461 
   3462     case OPCODE_CMPIGTE:
   3463       if ((INT32) Op1 >= Op2) {
   3464         Flag = 1;
   3465       }
   3466       break;
   3467 
   3468     case OPCODE_CMPIULTE:
   3469       if ((UINT32) Op1 <= (UINT32) Op2) {
   3470         Flag = 1;
   3471       }
   3472       break;
   3473 
   3474     case OPCODE_CMPIUGTE:
   3475       if ((UINT32) Op1 >= (UINT32) Op2) {
   3476         Flag = 1;
   3477       }
   3478       break;
   3479 
   3480     default:
   3481       ASSERT (0);
   3482     }
   3483   }
   3484   //
   3485   // Now set the flag accordingly for the comparison
   3486   //
   3487   if (Flag != 0) {
   3488     VMFLAG_SET (VmPtr, VMFLAGS_CC);
   3489   } else {
   3490     VMFLAG_CLEAR (VmPtr, (UINT64)VMFLAGS_CC);
   3491   }
   3492   //
   3493   // Advance the IP
   3494   //
   3495   VmPtr->Ip += Size;
   3496   return EFI_SUCCESS;
   3497 }
   3498 
   3499 
   3500 /**
   3501   Execute the EBC NOT instruction.s
   3502 
   3503   Instruction syntax:
   3504     NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
   3505 
   3506   @param  VmPtr             A pointer to a VM context.
   3507   @param  Op1               Operand 1 from the instruction
   3508   @param  Op2               Operand 2 from the instruction
   3509 
   3510   @return ~Op2
   3511 
   3512 **/
   3513 UINT64
   3514 ExecuteNOT (
   3515   IN VM_CONTEXT     *VmPtr,
   3516   IN UINT64         Op1,
   3517   IN UINT64         Op2
   3518   )
   3519 {
   3520   return ~Op2;
   3521 }
   3522 
   3523 
   3524 /**
   3525   Execute the EBC NEG instruction.
   3526 
   3527   Instruction syntax:
   3528     NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
   3529 
   3530   @param  VmPtr             A pointer to a VM context.
   3531   @param  Op1               Operand 1 from the instruction
   3532   @param  Op2               Operand 2 from the instruction
   3533 
   3534   @return Op2 * -1
   3535 
   3536 **/
   3537 UINT64
   3538 ExecuteNEG (
   3539   IN VM_CONTEXT   *VmPtr,
   3540   IN UINT64       Op1,
   3541   IN UINT64       Op2
   3542   )
   3543 {
   3544   return ~Op2 + 1;
   3545 }
   3546 
   3547 
   3548 /**
   3549   Execute the EBC ADD instruction.
   3550 
   3551   Instruction syntax:
   3552     ADD[32|64] {@}R1, {@}R2 {Index16}
   3553 
   3554   @param  VmPtr             A pointer to a VM context.
   3555   @param  Op1               Operand 1 from the instruction
   3556   @param  Op2               Operand 2 from the instruction
   3557 
   3558   @return Op1 + Op2
   3559 
   3560 **/
   3561 UINT64
   3562 ExecuteADD (
   3563   IN VM_CONTEXT   *VmPtr,
   3564   IN UINT64       Op1,
   3565   IN UINT64       Op2
   3566   )
   3567 {
   3568   return Op1 + Op2;
   3569 }
   3570 
   3571 
   3572 /**
   3573   Execute the EBC SUB instruction.
   3574 
   3575   Instruction syntax:
   3576     SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
   3577 
   3578   @param  VmPtr             A pointer to a VM context.
   3579   @param  Op1               Operand 1 from the instruction
   3580   @param  Op2               Operand 2 from the instruction
   3581 
   3582   @return Op1 - Op2
   3583 
   3584 **/
   3585 UINT64
   3586 ExecuteSUB (
   3587   IN VM_CONTEXT   *VmPtr,
   3588   IN UINT64       Op1,
   3589   IN UINT64       Op2
   3590   )
   3591 {
   3592   if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
   3593     return (UINT64) ((INT64) ((INT64) Op1 - (INT64) Op2));
   3594   } else {
   3595     return (UINT64) ((INT64) ((INT32) Op1 - (INT32) Op2));
   3596   }
   3597 }
   3598 
   3599 
   3600 /**
   3601   Execute the EBC MUL instruction.
   3602 
   3603   Instruction syntax:
   3604     SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
   3605 
   3606   @param  VmPtr             A pointer to a VM context.
   3607   @param  Op1               Operand 1 from the instruction
   3608   @param  Op2               Operand 2 from the instruction
   3609 
   3610   @return Op1 * Op2
   3611 
   3612 **/
   3613 UINT64
   3614 ExecuteMUL (
   3615   IN VM_CONTEXT   *VmPtr,
   3616   IN UINT64       Op1,
   3617   IN UINT64       Op2
   3618   )
   3619 {
   3620   if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
   3621     return MultS64x64 ((INT64)Op1, (INT64)Op2);
   3622   } else {
   3623     return (UINT64) ((INT64) ((INT32) Op1 * (INT32) Op2));
   3624   }
   3625 }
   3626 
   3627 
   3628 /**
   3629   Execute the EBC MULU instruction
   3630 
   3631   Instruction syntax:
   3632     MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
   3633 
   3634   @param  VmPtr             A pointer to a VM context.
   3635   @param  Op1               Operand 1 from the instruction
   3636   @param  Op2               Operand 2 from the instruction
   3637 
   3638   @return (unsigned)Op1 * (unsigned)Op2
   3639 
   3640 **/
   3641 UINT64
   3642 ExecuteMULU (
   3643   IN VM_CONTEXT   *VmPtr,
   3644   IN UINT64       Op1,
   3645   IN UINT64       Op2
   3646   )
   3647 {
   3648   if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
   3649     return MultU64x64 (Op1, Op2);
   3650   } else {
   3651     return (UINT64) ((UINT32) Op1 * (UINT32) Op2);
   3652   }
   3653 }
   3654 
   3655 
   3656 /**
   3657   Execute the EBC DIV instruction.
   3658 
   3659   Instruction syntax:
   3660     DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
   3661 
   3662   @param  VmPtr             A pointer to a VM context.
   3663   @param  Op1               Operand 1 from the instruction
   3664   @param  Op2               Operand 2 from the instruction
   3665 
   3666   @return Op1 / Op2
   3667 
   3668 **/
   3669 UINT64
   3670 ExecuteDIV (
   3671   IN VM_CONTEXT   *VmPtr,
   3672   IN UINT64       Op1,
   3673   IN UINT64       Op2
   3674   )
   3675 {
   3676   INT64   Remainder;
   3677 
   3678   //
   3679   // Check for divide-by-0
   3680   //
   3681   if (Op2 == 0) {
   3682     EbcDebugSignalException (
   3683       EXCEPT_EBC_DIVIDE_ERROR,
   3684       EXCEPTION_FLAG_FATAL,
   3685       VmPtr
   3686       );
   3687 
   3688     return 0;
   3689   } else {
   3690     if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
   3691       return (UINT64) (DivS64x64Remainder (Op1, Op2, &Remainder));
   3692     } else {
   3693       return (UINT64) ((INT64) ((INT32) Op1 / (INT32) Op2));
   3694     }
   3695   }
   3696 }
   3697 
   3698 
   3699 /**
   3700   Execute the EBC DIVU instruction
   3701 
   3702   Instruction syntax:
   3703     DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
   3704 
   3705   @param  VmPtr             A pointer to a VM context.
   3706   @param  Op1               Operand 1 from the instruction
   3707   @param  Op2               Operand 2 from the instruction
   3708 
   3709   @return (unsigned)Op1 / (unsigned)Op2
   3710 
   3711 **/
   3712 UINT64
   3713 ExecuteDIVU (
   3714   IN VM_CONTEXT   *VmPtr,
   3715   IN UINT64       Op1,
   3716   IN UINT64       Op2
   3717   )
   3718 {
   3719   UINT64  Remainder;
   3720 
   3721   //
   3722   // Check for divide-by-0
   3723   //
   3724   if (Op2 == 0) {
   3725     EbcDebugSignalException (
   3726       EXCEPT_EBC_DIVIDE_ERROR,
   3727       EXCEPTION_FLAG_FATAL,
   3728       VmPtr
   3729       );
   3730     return 0;
   3731   } else {
   3732     //
   3733     // Get the destination register
   3734     //
   3735     if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
   3736       return (UINT64) (DivU64x64Remainder (Op1, Op2, &Remainder));
   3737     } else {
   3738       return (UINT64) ((UINT32) Op1 / (UINT32) Op2);
   3739     }
   3740   }
   3741 }
   3742 
   3743 
   3744 /**
   3745   Execute the EBC MOD instruction.
   3746 
   3747   Instruction syntax:
   3748     MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
   3749 
   3750   @param  VmPtr             A pointer to a VM context.
   3751   @param  Op1               Operand 1 from the instruction
   3752   @param  Op2               Operand 2 from the instruction
   3753 
   3754   @return Op1 MODULUS Op2
   3755 
   3756 **/
   3757 UINT64
   3758 ExecuteMOD (
   3759   IN VM_CONTEXT   *VmPtr,
   3760   IN UINT64       Op1,
   3761   IN UINT64       Op2
   3762   )
   3763 {
   3764   INT64   Remainder;
   3765 
   3766   //
   3767   // Check for divide-by-0
   3768   //
   3769   if (Op2 == 0) {
   3770     EbcDebugSignalException (
   3771       EXCEPT_EBC_DIVIDE_ERROR,
   3772       EXCEPTION_FLAG_FATAL,
   3773       VmPtr
   3774       );
   3775     return 0;
   3776   } else {
   3777     DivS64x64Remainder ((INT64)Op1, (INT64)Op2, &Remainder);
   3778     return Remainder;
   3779   }
   3780 }
   3781 
   3782 
   3783 /**
   3784   Execute the EBC MODU instruction.
   3785 
   3786   Instruction syntax:
   3787     MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
   3788 
   3789   @param  VmPtr             A pointer to a VM context.
   3790   @param  Op1               Operand 1 from the instruction
   3791   @param  Op2               Operand 2 from the instruction
   3792 
   3793   @return Op1 UNSIGNED_MODULUS Op2
   3794 
   3795 **/
   3796 UINT64
   3797 ExecuteMODU (
   3798   IN VM_CONTEXT   *VmPtr,
   3799   IN UINT64       Op1,
   3800   IN UINT64       Op2
   3801   )
   3802 {
   3803   UINT64  Remainder;
   3804 
   3805   //
   3806   // Check for divide-by-0
   3807   //
   3808   if (Op2 == 0) {
   3809     EbcDebugSignalException (
   3810       EXCEPT_EBC_DIVIDE_ERROR,
   3811       EXCEPTION_FLAG_FATAL,
   3812       VmPtr
   3813       );
   3814     return 0;
   3815   } else {
   3816     DivU64x64Remainder (Op1, Op2, &Remainder);
   3817     return Remainder;
   3818   }
   3819 }
   3820 
   3821 
   3822 /**
   3823   Execute the EBC AND instruction.
   3824 
   3825   Instruction syntax:
   3826     AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
   3827 
   3828   @param  VmPtr             A pointer to a VM context.
   3829   @param  Op1               Operand 1 from the instruction
   3830   @param  Op2               Operand 2 from the instruction
   3831 
   3832   @return Op1 AND Op2
   3833 
   3834 **/
   3835 UINT64
   3836 ExecuteAND (
   3837   IN VM_CONTEXT   *VmPtr,
   3838   IN UINT64       Op1,
   3839   IN UINT64       Op2
   3840   )
   3841 {
   3842   return Op1 & Op2;
   3843 }
   3844 
   3845 
   3846 /**
   3847   Execute the EBC OR instruction.
   3848 
   3849   Instruction syntax:
   3850     OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
   3851 
   3852   @param  VmPtr             A pointer to a VM context.
   3853   @param  Op1               Operand 1 from the instruction
   3854   @param  Op2               Operand 2 from the instruction
   3855 
   3856   @return Op1 OR Op2
   3857 
   3858 **/
   3859 UINT64
   3860 ExecuteOR (
   3861   IN VM_CONTEXT   *VmPtr,
   3862   IN UINT64       Op1,
   3863   IN UINT64       Op2
   3864   )
   3865 {
   3866   return Op1 | Op2;
   3867 }
   3868 
   3869 
   3870 /**
   3871   Execute the EBC XOR instruction.
   3872 
   3873   Instruction syntax:
   3874     XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
   3875 
   3876   @param  VmPtr             A pointer to a VM context.
   3877   @param  Op1               Operand 1 from the instruction
   3878   @param  Op2               Operand 2 from the instruction
   3879 
   3880   @return Op1 XOR Op2
   3881 
   3882 **/
   3883 UINT64
   3884 ExecuteXOR (
   3885   IN VM_CONTEXT   *VmPtr,
   3886   IN UINT64       Op1,
   3887   IN UINT64       Op2
   3888   )
   3889 {
   3890   return Op1 ^ Op2;
   3891 }
   3892 
   3893 
   3894 /**
   3895   Execute the EBC SHL shift left instruction.
   3896 
   3897   Instruction syntax:
   3898     SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
   3899 
   3900   @param  VmPtr             A pointer to a VM context.
   3901   @param  Op1               Operand 1 from the instruction
   3902   @param  Op2               Operand 2 from the instruction
   3903 
   3904   @return Op1 << Op2
   3905 
   3906 **/
   3907 UINT64
   3908 ExecuteSHL (
   3909   IN VM_CONTEXT   *VmPtr,
   3910   IN UINT64       Op1,
   3911   IN UINT64       Op2
   3912   )
   3913 {
   3914   if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
   3915     return LShiftU64 (Op1, (UINTN)Op2);
   3916   } else {
   3917     return (UINT64) ((UINT32) ((UINT32) Op1 << (UINT32) Op2));
   3918   }
   3919 }
   3920 
   3921 
   3922 /**
   3923   Execute the EBC SHR instruction.
   3924 
   3925   Instruction syntax:
   3926     SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
   3927 
   3928   @param  VmPtr             A pointer to a VM context.
   3929   @param  Op1               Operand 1 from the instruction
   3930   @param  Op2               Operand 2 from the instruction
   3931 
   3932   @return Op1 >> Op2  (unsigned operands)
   3933 
   3934 **/
   3935 UINT64
   3936 ExecuteSHR (
   3937   IN VM_CONTEXT   *VmPtr,
   3938   IN UINT64       Op1,
   3939   IN UINT64       Op2
   3940   )
   3941 {
   3942   if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
   3943     return RShiftU64 (Op1, (UINTN)Op2);
   3944   } else {
   3945     return (UINT64) ((UINT32) Op1 >> (UINT32) Op2);
   3946   }
   3947 }
   3948 
   3949 
   3950 /**
   3951   Execute the EBC ASHR instruction.
   3952 
   3953   Instruction syntax:
   3954     ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
   3955 
   3956   @param  VmPtr             A pointer to a VM context.
   3957   @param  Op1               Operand 1 from the instruction
   3958   @param  Op2               Operand 2 from the instruction
   3959 
   3960   @return Op1 >> Op2 (signed)
   3961 
   3962 **/
   3963 UINT64
   3964 ExecuteASHR (
   3965   IN VM_CONTEXT   *VmPtr,
   3966   IN UINT64       Op1,
   3967   IN UINT64       Op2
   3968   )
   3969 {
   3970   if ((*VmPtr->Ip & DATAMANIP_M_64) != 0) {
   3971     return ARShiftU64 (Op1, (UINTN)Op2);
   3972   } else {
   3973     return (UINT64) ((INT64) ((INT32) Op1 >> (UINT32) Op2));
   3974   }
   3975 }
   3976 
   3977 
   3978 /**
   3979   Execute the EBC EXTNDB instruction to sign-extend a byte value.
   3980 
   3981   Instruction syntax:
   3982     EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
   3983 
   3984   @param  VmPtr             A pointer to a VM context.
   3985   @param  Op1               Operand 1 from the instruction
   3986   @param  Op2               Operand 2 from the instruction
   3987 
   3988   @return (INT64)(INT8)Op2
   3989 
   3990 **/
   3991 UINT64
   3992 ExecuteEXTNDB (
   3993   IN VM_CONTEXT   *VmPtr,
   3994   IN UINT64       Op1,
   3995   IN UINT64       Op2
   3996   )
   3997 {
   3998   INT8  Data8;
   3999   INT64 Data64;
   4000   //
   4001   // Convert to byte, then return as 64-bit signed value to let compiler
   4002   // sign-extend the value
   4003   //
   4004   Data8   = (INT8) Op2;
   4005   Data64  = (INT64) Data8;
   4006 
   4007   return (UINT64) Data64;
   4008 }
   4009 
   4010 
   4011 /**
   4012   Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
   4013 
   4014   Instruction syntax:
   4015     EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
   4016 
   4017   @param  VmPtr             A pointer to a VM context.
   4018   @param  Op1               Operand 1 from the instruction
   4019   @param  Op2               Operand 2 from the instruction
   4020 
   4021   @return (INT64)(INT16)Op2
   4022 
   4023 **/
   4024 UINT64
   4025 ExecuteEXTNDW (
   4026   IN VM_CONTEXT   *VmPtr,
   4027   IN UINT64       Op1,
   4028   IN UINT64       Op2
   4029   )
   4030 {
   4031   INT16 Data16;
   4032   INT64 Data64;
   4033   //
   4034   // Convert to word, then return as 64-bit signed value to let compiler
   4035   // sign-extend the value
   4036   //
   4037   Data16  = (INT16) Op2;
   4038   Data64  = (INT64) Data16;
   4039 
   4040   return (UINT64) Data64;
   4041 }
   4042 //
   4043 // Execute the EBC EXTNDD instruction.
   4044 //
   4045 // Format: EXTNDD {@}Rx, {@}Ry [Index16|Immed16]
   4046 //         EXTNDD Dest, Source
   4047 //
   4048 // Operation:  Dest <- SignExtended((DWORD)Source))
   4049 //
   4050 
   4051 /**
   4052   Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
   4053 
   4054   Instruction syntax:
   4055     EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
   4056 
   4057   @param  VmPtr             A pointer to a VM context.
   4058   @param  Op1               Operand 1 from the instruction
   4059   @param  Op2               Operand 2 from the instruction
   4060 
   4061   @return (INT64)(INT32)Op2
   4062 
   4063 **/
   4064 UINT64
   4065 ExecuteEXTNDD (
   4066   IN VM_CONTEXT   *VmPtr,
   4067   IN UINT64       Op1,
   4068   IN UINT64       Op2
   4069   )
   4070 {
   4071   INT32 Data32;
   4072   INT64 Data64;
   4073   //
   4074   // Convert to 32-bit value, then return as 64-bit signed value to let compiler
   4075   // sign-extend the value
   4076   //
   4077   Data32  = (INT32) Op2;
   4078   Data64  = (INT64) Data32;
   4079 
   4080   return (UINT64) Data64;
   4081 }
   4082 
   4083 
   4084 /**
   4085   Execute all the EBC signed data manipulation instructions.
   4086   Since the EBC data manipulation instructions all have the same basic form,
   4087   they can share the code that does the fetch of operands and the write-back
   4088   of the result. This function performs the fetch of the operands (even if
   4089   both are not needed to be fetched, like NOT instruction), dispatches to the
   4090   appropriate subfunction, then writes back the returned result.
   4091 
   4092   Format:
   4093     INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
   4094 
   4095   @param  VmPtr             A pointer to VM context.
   4096 
   4097   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
   4098   @retval EFI_SUCCESS       The instruction is executed successfully.
   4099 
   4100 **/
   4101 EFI_STATUS
   4102 ExecuteSignedDataManip (
   4103   IN VM_CONTEXT   *VmPtr
   4104   )
   4105 {
   4106   //
   4107   // Just call the data manipulation function with a flag indicating this
   4108   // is a signed operation.
   4109   //
   4110   return ExecuteDataManip (VmPtr, TRUE);
   4111 }
   4112 
   4113 
   4114 /**
   4115   Execute all the EBC unsigned data manipulation instructions.
   4116   Since the EBC data manipulation instructions all have the same basic form,
   4117   they can share the code that does the fetch of operands and the write-back
   4118   of the result. This function performs the fetch of the operands (even if
   4119   both are not needed to be fetched, like NOT instruction), dispatches to the
   4120   appropriate subfunction, then writes back the returned result.
   4121 
   4122   Format:
   4123     INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
   4124 
   4125   @param  VmPtr             A pointer to VM context.
   4126 
   4127   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
   4128   @retval EFI_SUCCESS       The instruction is executed successfully.
   4129 
   4130 **/
   4131 EFI_STATUS
   4132 ExecuteUnsignedDataManip (
   4133   IN VM_CONTEXT   *VmPtr
   4134   )
   4135 {
   4136   //
   4137   // Just call the data manipulation function with a flag indicating this
   4138   // is not a signed operation.
   4139   //
   4140   return ExecuteDataManip (VmPtr, FALSE);
   4141 }
   4142 
   4143 
   4144 /**
   4145   Execute all the EBC data manipulation instructions.
   4146   Since the EBC data manipulation instructions all have the same basic form,
   4147   they can share the code that does the fetch of operands and the write-back
   4148   of the result. This function performs the fetch of the operands (even if
   4149   both are not needed to be fetched, like NOT instruction), dispatches to the
   4150   appropriate subfunction, then writes back the returned result.
   4151 
   4152   Format:
   4153     INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
   4154 
   4155   @param  VmPtr             A pointer to VM context.
   4156   @param  IsSignedOp        Indicates whether the operand is signed or not.
   4157 
   4158   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
   4159   @retval EFI_SUCCESS       The instruction is executed successfully.
   4160 
   4161 **/
   4162 EFI_STATUS
   4163 ExecuteDataManip (
   4164   IN VM_CONTEXT   *VmPtr,
   4165   IN BOOLEAN      IsSignedOp
   4166   )
   4167 {
   4168   UINT8   Opcode;
   4169   INT16   Index16;
   4170   UINT8   Operands;
   4171   UINT8   Size;
   4172   UINT64  Op1;
   4173   UINT64  Op2;
   4174   INTN    DataManipDispatchTableIndex;
   4175 
   4176   //
   4177   // Get opcode and operands
   4178   //
   4179   Opcode    = GETOPCODE (VmPtr);
   4180   Operands  = GETOPERANDS (VmPtr);
   4181 
   4182   //
   4183   // Determine if we have immediate data by the opcode
   4184   //
   4185   if ((Opcode & DATAMANIP_M_IMMDATA) != 0) {
   4186     //
   4187     // Index16 if Ry is indirect, or Immed16 if Ry direct.
   4188     //
   4189     if (OPERAND2_INDIRECT (Operands)) {
   4190       Index16 = VmReadIndex16 (VmPtr, 2);
   4191     } else {
   4192       Index16 = VmReadImmed16 (VmPtr, 2);
   4193     }
   4194 
   4195     Size = 4;
   4196   } else {
   4197     Index16 = 0;
   4198     Size    = 2;
   4199   }
   4200   //
   4201   // Now get operand2 (source). It's of format {@}R2 {Index16|Immed16}
   4202   //
   4203   Op2 = (UINT64) VmPtr->Gpr[OPERAND2_REGNUM (Operands)] + Index16;
   4204   if (OPERAND2_INDIRECT (Operands)) {
   4205     //
   4206     // Indirect form: @R2 Index16. Fetch as 32- or 64-bit data
   4207     //
   4208     if ((Opcode & DATAMANIP_M_64) != 0) {
   4209       Op2 = VmReadMem64 (VmPtr, (UINTN) Op2);
   4210     } else {
   4211       //
   4212       // Read as signed value where appropriate.
   4213       //
   4214       if (IsSignedOp) {
   4215         Op2 = (UINT64) (INT64) ((INT32) VmReadMem32 (VmPtr, (UINTN) Op2));
   4216       } else {
   4217         Op2 = (UINT64) VmReadMem32 (VmPtr, (UINTN) Op2);
   4218       }
   4219     }
   4220   } else {
   4221     if ((Opcode & DATAMANIP_M_64) == 0) {
   4222       if (IsSignedOp) {
   4223         Op2 = (UINT64) (INT64) ((INT32) Op2);
   4224       } else {
   4225         Op2 = (UINT64) ((UINT32) Op2);
   4226       }
   4227     }
   4228   }
   4229   //
   4230   // Get operand1 (destination and sometimes also an actual operand)
   4231   // of form {@}R1
   4232   //
   4233   Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)];
   4234   if (OPERAND1_INDIRECT (Operands)) {
   4235     if ((Opcode & DATAMANIP_M_64) != 0) {
   4236       Op1 = VmReadMem64 (VmPtr, (UINTN) Op1);
   4237     } else {
   4238       if (IsSignedOp) {
   4239         Op1 = (UINT64) (INT64) ((INT32) VmReadMem32 (VmPtr, (UINTN) Op1));
   4240       } else {
   4241         Op1 = (UINT64) VmReadMem32 (VmPtr, (UINTN) Op1);
   4242       }
   4243     }
   4244   } else {
   4245     if ((Opcode & DATAMANIP_M_64) == 0) {
   4246       if (IsSignedOp) {
   4247         Op1 = (UINT64) (INT64) ((INT32) Op1);
   4248       } else {
   4249         Op1 = (UINT64) ((UINT32) Op1);
   4250       }
   4251     }
   4252   }
   4253   //
   4254   // Dispatch to the computation function
   4255   //
   4256   DataManipDispatchTableIndex = (Opcode & OPCODE_M_OPCODE) - OPCODE_NOT;
   4257   if ((DataManipDispatchTableIndex < 0) ||
   4258       (DataManipDispatchTableIndex >= ARRAY_SIZE (mDataManipDispatchTable))) {
   4259     EbcDebugSignalException (
   4260       EXCEPT_EBC_INVALID_OPCODE,
   4261       EXCEPTION_FLAG_ERROR,
   4262       VmPtr
   4263       );
   4264     //
   4265     // Advance and return
   4266     //
   4267     VmPtr->Ip += Size;
   4268     return EFI_UNSUPPORTED;
   4269   } else {
   4270     Op2 = mDataManipDispatchTable[DataManipDispatchTableIndex](VmPtr, Op1, Op2);
   4271   }
   4272   //
   4273   // Write back the result.
   4274   //
   4275   if (OPERAND1_INDIRECT (Operands)) {
   4276     Op1 = (UINT64) VmPtr->Gpr[OPERAND1_REGNUM (Operands)];
   4277     if ((Opcode & DATAMANIP_M_64) != 0) {
   4278       VmWriteMem64 (VmPtr, (UINTN) Op1, Op2);
   4279     } else {
   4280       VmWriteMem32 (VmPtr, (UINTN) Op1, (UINT32) Op2);
   4281     }
   4282   } else {
   4283     //
   4284     // Storage back to a register. Write back, clearing upper bits (as per
   4285     // the specification) if 32-bit operation.
   4286     //
   4287     VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = Op2;
   4288     if ((Opcode & DATAMANIP_M_64) == 0) {
   4289       VmPtr->Gpr[OPERAND1_REGNUM (Operands)] &= 0xFFFFFFFF;
   4290     }
   4291   }
   4292   //
   4293   // Advance the instruction pointer
   4294   //
   4295   VmPtr->Ip += Size;
   4296   return EFI_SUCCESS;
   4297 }
   4298 
   4299 
   4300 /**
   4301   Execute the EBC LOADSP instruction.
   4302 
   4303   Instruction syntax:
   4304     LOADSP  SP1, R2
   4305 
   4306   @param  VmPtr             A pointer to a VM context.
   4307 
   4308   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
   4309   @retval EFI_SUCCESS       The instruction is executed successfully.
   4310 
   4311 **/
   4312 EFI_STATUS
   4313 ExecuteLOADSP (
   4314   IN VM_CONTEXT *VmPtr
   4315   )
   4316 {
   4317   UINT8 Operands;
   4318 
   4319   //
   4320   // Get the operands
   4321   //
   4322   Operands = GETOPERANDS (VmPtr);
   4323 
   4324   //
   4325   // Do the operation
   4326   //
   4327   switch (OPERAND1_REGNUM (Operands)) {
   4328   //
   4329   // Set flags
   4330   //
   4331   case 0:
   4332     //
   4333     // Spec states that this instruction will not modify reserved bits in
   4334     // the flags register.
   4335     //
   4336     VmPtr->Flags = (VmPtr->Flags &~VMFLAGS_ALL_VALID) | (VmPtr->Gpr[OPERAND2_REGNUM (Operands)] & VMFLAGS_ALL_VALID);
   4337     break;
   4338 
   4339   default:
   4340     EbcDebugSignalException (
   4341       EXCEPT_EBC_INSTRUCTION_ENCODING,
   4342       EXCEPTION_FLAG_WARNING,
   4343       VmPtr
   4344       );
   4345     VmPtr->Ip += 2;
   4346     return EFI_UNSUPPORTED;
   4347   }
   4348 
   4349   VmPtr->Ip += 2;
   4350   return EFI_SUCCESS;
   4351 }
   4352 
   4353 
   4354 /**
   4355   Execute the EBC STORESP instruction.
   4356 
   4357   Instruction syntax:
   4358     STORESP  Rx, FLAGS|IP
   4359 
   4360   @param  VmPtr             A pointer to a VM context.
   4361 
   4362   @retval EFI_UNSUPPORTED   The opcodes/operands is not supported.
   4363   @retval EFI_SUCCESS       The instruction is executed successfully.
   4364 
   4365 **/
   4366 EFI_STATUS
   4367 ExecuteSTORESP (
   4368   IN VM_CONTEXT *VmPtr
   4369   )
   4370 {
   4371   UINT8 Operands;
   4372 
   4373   //
   4374   // Get the operands
   4375   //
   4376   Operands = GETOPERANDS (VmPtr);
   4377 
   4378   //
   4379   // Do the operation
   4380   //
   4381   switch (OPERAND2_REGNUM (Operands)) {
   4382   //
   4383   // Get flags
   4384   //
   4385   case 0:
   4386     //
   4387     // Retrieve the value in the flags register, then clear reserved bits
   4388     //
   4389     VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (UINT64) (VmPtr->Flags & VMFLAGS_ALL_VALID);
   4390     break;
   4391 
   4392   //
   4393   // Get IP -- address of following instruction
   4394   //
   4395   case 1:
   4396     VmPtr->Gpr[OPERAND1_REGNUM (Operands)] = (UINT64) (UINTN) VmPtr->Ip + 2;
   4397     break;
   4398 
   4399   default:
   4400     EbcDebugSignalException (
   4401       EXCEPT_EBC_INSTRUCTION_ENCODING,
   4402       EXCEPTION_FLAG_WARNING,
   4403       VmPtr
   4404       );
   4405     VmPtr->Ip += 2;
   4406     return EFI_UNSUPPORTED;
   4407     break;
   4408   }
   4409 
   4410   VmPtr->Ip += 2;
   4411   return EFI_SUCCESS;
   4412 }
   4413 
   4414 
   4415 /**
   4416   Decode a 16-bit index to determine the offset. Given an index value:
   4417 
   4418     b15     - sign bit
   4419     b14:12  - number of bits in this index assigned to natural units (=a)
   4420     ba:11   - constant units = ConstUnits
   4421     b0:a    - natural units = NaturalUnits
   4422 
   4423   Given this info, the offset can be computed by:
   4424     offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
   4425 
   4426   Max offset is achieved with index = 0x7FFF giving an offset of
   4427   0x27B (32-bit machine) or 0x477 (64-bit machine).
   4428   Min offset is achieved with index =
   4429 
   4430   @param  VmPtr             A pointer to VM context.
   4431   @param  CodeOffset        Offset from IP of the location of the 16-bit index
   4432                             to decode.
   4433 
   4434   @return The decoded offset.
   4435 
   4436 **/
   4437 INT16
   4438 VmReadIndex16 (
   4439   IN VM_CONTEXT     *VmPtr,
   4440   IN UINT32         CodeOffset
   4441   )
   4442 {
   4443   UINT16  Index;
   4444   INT16   Offset;
   4445   INT16   ConstUnits;
   4446   INT16   NaturalUnits;
   4447   INT16   NBits;
   4448   INT16   Mask;
   4449 
   4450   //
   4451   // First read the index from the code stream
   4452   //
   4453   Index = VmReadCode16 (VmPtr, CodeOffset);
   4454 
   4455   //
   4456   // Get the mask for NaturalUnits. First get the number of bits from the index.
   4457   //
   4458   NBits = (INT16) ((Index & 0x7000) >> 12);
   4459 
   4460   //
   4461   // Scale it for 16-bit indexes
   4462   //
   4463   NBits *= 2;
   4464 
   4465   //
   4466   // Now using the number of bits, create a mask.
   4467   //
   4468   Mask = (INT16) ((INT16)~0 << NBits);
   4469 
   4470   //
   4471   // Now using the mask, extract NaturalUnits from the lower bits of the index.
   4472   //
   4473   NaturalUnits = (INT16) (Index &~Mask);
   4474 
   4475   //
   4476   // Now compute ConstUnits
   4477   //
   4478   ConstUnits       = (INT16) (((Index &~0xF000) & Mask) >> NBits);
   4479 
   4480   Offset  = (INT16) (NaturalUnits * sizeof (UINTN) + ConstUnits);
   4481 
   4482   //
   4483   // Now set the sign
   4484   //
   4485   if ((Index & 0x8000) != 0) {
   4486     //
   4487     // Do it the hard way to work around a bogus compiler warning
   4488     //
   4489     // Offset = -1 * Offset;
   4490     //
   4491     Offset = (INT16) ((INT32) Offset * -1);
   4492   }
   4493 
   4494   return Offset;
   4495 }
   4496 
   4497 
   4498 /**
   4499   Decode a 32-bit index to determine the offset.
   4500 
   4501   @param  VmPtr             A pointer to VM context.
   4502   @param  CodeOffset        Offset from IP of the location of the 32-bit index
   4503                             to decode.
   4504 
   4505   @return Converted index per EBC VM specification.
   4506 
   4507 **/
   4508 INT32
   4509 VmReadIndex32 (
   4510   IN VM_CONTEXT     *VmPtr,
   4511   IN UINT32         CodeOffset
   4512   )
   4513 {
   4514   UINT32  Index;
   4515   INT32   Offset;
   4516   INT32   ConstUnits;
   4517   INT32   NaturalUnits;
   4518   INT32   NBits;
   4519   INT32   Mask;
   4520 
   4521   Index = VmReadImmed32 (VmPtr, CodeOffset);
   4522 
   4523   //
   4524   // Get the mask for NaturalUnits. First get the number of bits from the index.
   4525   //
   4526   NBits = (Index & 0x70000000) >> 28;
   4527 
   4528   //
   4529   // Scale it for 32-bit indexes
   4530   //
   4531   NBits *= 4;
   4532 
   4533   //
   4534   // Now using the number of bits, create a mask.
   4535   //
   4536   Mask = (INT32)~0 << NBits;
   4537 
   4538   //
   4539   // Now using the mask, extract NaturalUnits from the lower bits of the index.
   4540   //
   4541   NaturalUnits = Index &~Mask;
   4542 
   4543   //
   4544   // Now compute ConstUnits
   4545   //
   4546   ConstUnits       = ((Index &~0xF0000000) & Mask) >> NBits;
   4547 
   4548   Offset  = NaturalUnits * sizeof (UINTN) + ConstUnits;
   4549 
   4550   //
   4551   // Now set the sign
   4552   //
   4553   if ((Index & 0x80000000) != 0) {
   4554     Offset = Offset * -1;
   4555   }
   4556 
   4557   return Offset;
   4558 }
   4559 
   4560 
   4561 /**
   4562   Decode a 64-bit index to determine the offset.
   4563 
   4564   @param  VmPtr             A pointer to VM context.s
   4565   @param  CodeOffset        Offset from IP of the location of the 64-bit index
   4566                             to decode.
   4567 
   4568   @return Converted index per EBC VM specification
   4569 
   4570 **/
   4571 INT64
   4572 VmReadIndex64 (
   4573   IN VM_CONTEXT     *VmPtr,
   4574   IN UINT32         CodeOffset
   4575   )
   4576 {
   4577   UINT64  Index;
   4578   INT64   Offset;
   4579   INT64   ConstUnits;
   4580   INT64   NaturalUnits;
   4581   INT64   NBits;
   4582   INT64   Mask;
   4583 
   4584   Index = VmReadCode64 (VmPtr, CodeOffset);
   4585 
   4586   //
   4587   // Get the mask for NaturalUnits. First get the number of bits from the index.
   4588   //
   4589   NBits = RShiftU64 ((Index & 0x7000000000000000ULL), 60);
   4590 
   4591   //
   4592   // Scale it for 64-bit indexes (multiply by 8 by shifting left 3)
   4593   //
   4594   NBits = LShiftU64 ((UINT64)NBits, 3);
   4595 
   4596   //
   4597   // Now using the number of bits, create a mask.
   4598   //
   4599   Mask = (LShiftU64 ((UINT64)~0, (UINTN)NBits));
   4600 
   4601   //
   4602   // Now using the mask, extract NaturalUnits from the lower bits of the index.
   4603   //
   4604   NaturalUnits = Index &~Mask;
   4605 
   4606   //
   4607   // Now compute ConstUnits
   4608   //
   4609   ConstUnits = ARShiftU64 (((Index &~0xF000000000000000ULL) & Mask), (UINTN)NBits);
   4610 
   4611   Offset  = MultU64x64 ((UINT64) NaturalUnits, sizeof (UINTN)) + ConstUnits;
   4612 
   4613   //
   4614   // Now set the sign
   4615   //
   4616   if ((Index & 0x8000000000000000ULL) != 0) {
   4617     Offset = MultS64x64 (Offset, -1);
   4618   }
   4619 
   4620   return Offset;
   4621 }
   4622 
   4623 
   4624 /**
   4625   Writes 8-bit data to memory address.
   4626 
   4627   This routine is called by the EBC data
   4628   movement instructions that write to memory. Since these writes
   4629   may be to the stack, which looks like (high address on top) this,
   4630 
   4631   [EBC entry point arguments]
   4632   [VM stack]
   4633   [EBC stack]
   4634 
   4635   we need to detect all attempts to write to the EBC entry point argument
   4636   stack area and adjust the address (which will initially point into the
   4637   VM stack) to point into the EBC entry point arguments.
   4638 
   4639   @param  VmPtr             A pointer to a VM context.
   4640   @param  Addr              Address to write to.
   4641   @param  Data              Value to write to Addr.
   4642 
   4643   @retval EFI_SUCCESS       The instruction is executed successfully.
   4644   @retval Other             Some error occurs when writing data to the address.
   4645 
   4646 **/
   4647 EFI_STATUS
   4648 VmWriteMem8 (
   4649   IN VM_CONTEXT    *VmPtr,
   4650   IN UINTN         Addr,
   4651   IN UINT8         Data
   4652   )
   4653 {
   4654   //
   4655   // Convert the address if it's in the stack gap
   4656   //
   4657   Addr            = ConvertStackAddr (VmPtr, Addr);
   4658   *(UINT8 *) Addr = Data;
   4659   return EFI_SUCCESS;
   4660 }
   4661 
   4662 /**
   4663   Writes 16-bit data to memory address.
   4664 
   4665   This routine is called by the EBC data
   4666   movement instructions that write to memory. Since these writes
   4667   may be to the stack, which looks like (high address on top) this,
   4668 
   4669   [EBC entry point arguments]
   4670   [VM stack]
   4671   [EBC stack]
   4672 
   4673   we need to detect all attempts to write to the EBC entry point argument
   4674   stack area and adjust the address (which will initially point into the
   4675   VM stack) to point into the EBC entry point arguments.
   4676 
   4677   @param  VmPtr             A pointer to a VM context.
   4678   @param  Addr              Address to write to.
   4679   @param  Data              Value to write to Addr.
   4680 
   4681   @retval EFI_SUCCESS       The instruction is executed successfully.
   4682   @retval Other             Some error occurs when writing data to the address.
   4683 
   4684 **/
   4685 EFI_STATUS
   4686 VmWriteMem16 (
   4687   IN VM_CONTEXT   *VmPtr,
   4688   IN UINTN        Addr,
   4689   IN UINT16       Data
   4690   )
   4691 {
   4692   EFI_STATUS  Status;
   4693 
   4694   //
   4695   // Convert the address if it's in the stack gap
   4696   //
   4697   Addr = ConvertStackAddr (VmPtr, Addr);
   4698 
   4699   //
   4700   // Do a simple write if aligned
   4701   //
   4702   if (IS_ALIGNED (Addr, sizeof (UINT16))) {
   4703     *(UINT16 *) Addr = Data;
   4704   } else {
   4705     //
   4706     // Write as two bytes
   4707     //
   4708     MemoryFence ();
   4709     if ((Status = VmWriteMem8 (VmPtr, Addr, (UINT8) Data)) != EFI_SUCCESS) {
   4710       return Status;
   4711     }
   4712 
   4713     MemoryFence ();
   4714     if ((Status = VmWriteMem8 (VmPtr, Addr + 1, (UINT8) (Data >> 8))) != EFI_SUCCESS) {
   4715       return Status;
   4716     }
   4717 
   4718     MemoryFence ();
   4719   }
   4720 
   4721   return EFI_SUCCESS;
   4722 }
   4723 
   4724 
   4725 /**
   4726   Writes 32-bit data to memory address.
   4727 
   4728   This routine is called by the EBC data
   4729   movement instructions that write to memory. Since these writes
   4730   may be to the stack, which looks like (high address on top) this,
   4731 
   4732   [EBC entry point arguments]
   4733   [VM stack]
   4734   [EBC stack]
   4735 
   4736   we need to detect all attempts to write to the EBC entry point argument
   4737   stack area and adjust the address (which will initially point into the
   4738   VM stack) to point into the EBC entry point arguments.
   4739 
   4740   @param  VmPtr             A pointer to a VM context.
   4741   @param  Addr              Address to write to.
   4742   @param  Data              Value to write to Addr.
   4743 
   4744   @retval EFI_SUCCESS       The instruction is executed successfully.
   4745   @retval Other             Some error occurs when writing data to the address.
   4746 
   4747 **/
   4748 EFI_STATUS
   4749 VmWriteMem32 (
   4750   IN VM_CONTEXT   *VmPtr,
   4751   IN UINTN        Addr,
   4752   IN UINT32       Data
   4753   )
   4754 {
   4755   EFI_STATUS  Status;
   4756 
   4757   //
   4758   // Convert the address if it's in the stack gap
   4759   //
   4760   Addr = ConvertStackAddr (VmPtr, Addr);
   4761 
   4762   //
   4763   // Do a simple write if aligned
   4764   //
   4765   if (IS_ALIGNED (Addr, sizeof (UINT32))) {
   4766     *(UINT32 *) Addr = Data;
   4767   } else {
   4768     //
   4769     // Write as two words
   4770     //
   4771     MemoryFence ();
   4772     if ((Status = VmWriteMem16 (VmPtr, Addr, (UINT16) Data)) != EFI_SUCCESS) {
   4773       return Status;
   4774     }
   4775 
   4776     MemoryFence ();
   4777     if ((Status = VmWriteMem16 (VmPtr, Addr + sizeof (UINT16), (UINT16) (Data >> 16))) != EFI_SUCCESS) {
   4778       return Status;
   4779     }
   4780 
   4781     MemoryFence ();
   4782   }
   4783 
   4784   return EFI_SUCCESS;
   4785 }
   4786 
   4787 
   4788 /**
   4789   Writes 64-bit data to memory address.
   4790 
   4791   This routine is called by the EBC data
   4792   movement instructions that write to memory. Since these writes
   4793   may be to the stack, which looks like (high address on top) this,
   4794 
   4795   [EBC entry point arguments]
   4796   [VM stack]
   4797   [EBC stack]
   4798 
   4799   we need to detect all attempts to write to the EBC entry point argument
   4800   stack area and adjust the address (which will initially point into the
   4801   VM stack) to point into the EBC entry point arguments.
   4802 
   4803   @param  VmPtr             A pointer to a VM context.
   4804   @param  Addr              Address to write to.
   4805   @param  Data              Value to write to Addr.
   4806 
   4807   @retval EFI_SUCCESS       The instruction is executed successfully.
   4808   @retval Other             Some error occurs when writing data to the address.
   4809 
   4810 **/
   4811 EFI_STATUS
   4812 VmWriteMem64 (
   4813   IN VM_CONTEXT   *VmPtr,
   4814   IN UINTN        Addr,
   4815   IN UINT64       Data
   4816   )
   4817 {
   4818   EFI_STATUS  Status;
   4819 
   4820   //
   4821   // Convert the address if it's in the stack gap
   4822   //
   4823   Addr = ConvertStackAddr (VmPtr, Addr);
   4824 
   4825   //
   4826   // Do a simple write if aligned
   4827   //
   4828   if (IS_ALIGNED (Addr, sizeof (UINT64))) {
   4829     *(UINT64 *) Addr = Data;
   4830   } else {
   4831     //
   4832     // Write as two 32-bit words
   4833     //
   4834     MemoryFence ();
   4835     if ((Status = VmWriteMem32 (VmPtr, Addr, (UINT32) Data)) != EFI_SUCCESS) {
   4836       return Status;
   4837     }
   4838 
   4839     MemoryFence ();
   4840     if ((Status = VmWriteMem32 (VmPtr, Addr + sizeof (UINT32), (UINT32) RShiftU64(Data, 32))) != EFI_SUCCESS) {
   4841       return Status;
   4842     }
   4843 
   4844     MemoryFence ();
   4845   }
   4846 
   4847   return EFI_SUCCESS;
   4848 }
   4849 
   4850 
   4851 /**
   4852   Writes UINTN data to memory address.
   4853 
   4854   This routine is called by the EBC data
   4855   movement instructions that write to memory. Since these writes
   4856   may be to the stack, which looks like (high address on top) this,
   4857 
   4858   [EBC entry point arguments]
   4859   [VM stack]
   4860   [EBC stack]
   4861 
   4862   we need to detect all attempts to write to the EBC entry point argument
   4863   stack area and adjust the address (which will initially point into the
   4864   VM stack) to point into the EBC entry point arguments.
   4865 
   4866   @param  VmPtr             A pointer to a VM context.
   4867   @param  Addr              Address to write to.
   4868   @param  Data              Value to write to Addr.
   4869 
   4870   @retval EFI_SUCCESS       The instruction is executed successfully.
   4871   @retval Other             Some error occurs when writing data to the address.
   4872 
   4873 **/
   4874 EFI_STATUS
   4875 VmWriteMemN (
   4876   IN VM_CONTEXT   *VmPtr,
   4877   IN UINTN        Addr,
   4878   IN UINTN        Data
   4879   )
   4880 {
   4881   EFI_STATUS  Status;
   4882   UINTN       Index;
   4883 
   4884   Status = EFI_SUCCESS;
   4885 
   4886   //
   4887   // Convert the address if it's in the stack gap
   4888   //
   4889   Addr = ConvertStackAddr (VmPtr, Addr);
   4890 
   4891   //
   4892   // Do a simple write if aligned
   4893   //
   4894   if (IS_ALIGNED (Addr, sizeof (UINTN))) {
   4895     *(UINTN *) Addr = Data;
   4896   } else {
   4897     for (Index = 0; Index < sizeof (UINTN) / sizeof (UINT32); Index++) {
   4898       MemoryFence ();
   4899       Status = VmWriteMem32 (VmPtr, Addr + Index * sizeof (UINT32), (UINT32) Data);
   4900       MemoryFence ();
   4901       Data = (UINTN) RShiftU64 ((UINT64)Data, 32);
   4902     }
   4903   }
   4904 
   4905   return Status;
   4906 }
   4907 
   4908 
   4909 /**
   4910   Reads 8-bit immediate value at the offset.
   4911 
   4912   This routine is called by the EBC execute
   4913   functions to read EBC immediate values from the code stream.
   4914   Since we can't assume alignment, each tries to read in the biggest
   4915   chunks size available, but will revert to smaller reads if necessary.
   4916 
   4917   @param  VmPtr             A pointer to a VM context.
   4918   @param  Offset            offset from IP of the code bytes to read.
   4919 
   4920   @return Signed data of the requested size from the specified address.
   4921 
   4922 **/
   4923 INT8
   4924 VmReadImmed8 (
   4925   IN VM_CONTEXT *VmPtr,
   4926   IN UINT32     Offset
   4927   )
   4928 {
   4929   //
   4930   // Simply return the data in flat memory space
   4931   //
   4932   return * (INT8 *) (VmPtr->Ip + Offset);
   4933 }
   4934 
   4935 /**
   4936   Reads 16-bit immediate value at the offset.
   4937 
   4938   This routine is called by the EBC execute
   4939   functions to read EBC immediate values from the code stream.
   4940   Since we can't assume alignment, each tries to read in the biggest
   4941   chunks size available, but will revert to smaller reads if necessary.
   4942 
   4943   @param  VmPtr             A pointer to a VM context.
   4944   @param  Offset            offset from IP of the code bytes to read.
   4945 
   4946   @return Signed data of the requested size from the specified address.
   4947 
   4948 **/
   4949 INT16
   4950 VmReadImmed16 (
   4951   IN VM_CONTEXT *VmPtr,
   4952   IN UINT32     Offset
   4953   )
   4954 {
   4955   //
   4956   // Read direct if aligned
   4957   //
   4958   if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (INT16))) {
   4959     return * (INT16 *) (VmPtr->Ip + Offset);
   4960   } else {
   4961     //
   4962     // All code word reads should be aligned
   4963     //
   4964     EbcDebugSignalException (
   4965       EXCEPT_EBC_ALIGNMENT_CHECK,
   4966       EXCEPTION_FLAG_WARNING,
   4967       VmPtr
   4968       );
   4969   }
   4970   //
   4971   // Return unaligned data
   4972   //
   4973   return (INT16) (*(UINT8 *) (VmPtr->Ip + Offset) + (*(UINT8 *) (VmPtr->Ip + Offset + 1) << 8));
   4974 }
   4975 
   4976 
   4977 /**
   4978   Reads 32-bit immediate value at the offset.
   4979 
   4980   This routine is called by the EBC execute
   4981   functions to read EBC immediate values from the code stream.
   4982   Since we can't assume alignment, each tries to read in the biggest
   4983   chunks size available, but will revert to smaller reads if necessary.
   4984 
   4985   @param  VmPtr             A pointer to a VM context.
   4986   @param  Offset            offset from IP of the code bytes to read.
   4987 
   4988   @return Signed data of the requested size from the specified address.
   4989 
   4990 **/
   4991 INT32
   4992 VmReadImmed32 (
   4993   IN VM_CONTEXT *VmPtr,
   4994   IN UINT32     Offset
   4995   )
   4996 {
   4997   UINT32  Data;
   4998 
   4999   //
   5000   // Read direct if aligned
   5001   //
   5002   if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT32))) {
   5003     return * (INT32 *) (VmPtr->Ip + Offset);
   5004   }
   5005   //
   5006   // Return unaligned data
   5007   //
   5008   Data  = (UINT32) VmReadCode16 (VmPtr, Offset);
   5009   Data |= (UINT32)(VmReadCode16 (VmPtr, Offset + 2) << 16);
   5010   return Data;
   5011 }
   5012 
   5013 
   5014 /**
   5015   Reads 64-bit immediate value at the offset.
   5016 
   5017   This routine is called by the EBC execute
   5018   functions to read EBC immediate values from the code stream.
   5019   Since we can't assume alignment, each tries to read in the biggest
   5020   chunks size available, but will revert to smaller reads if necessary.
   5021 
   5022   @param  VmPtr             A pointer to a VM context.
   5023   @param  Offset            offset from IP of the code bytes to read.
   5024 
   5025   @return Signed data of the requested size from the specified address.
   5026 
   5027 **/
   5028 INT64
   5029 VmReadImmed64 (
   5030   IN VM_CONTEXT *VmPtr,
   5031   IN UINT32     Offset
   5032   )
   5033 {
   5034   UINT64  Data64;
   5035   UINT32  Data32;
   5036   UINT8   *Ptr;
   5037 
   5038   //
   5039   // Read direct if aligned
   5040   //
   5041   if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT64))) {
   5042     return * (UINT64 *) (VmPtr->Ip + Offset);
   5043   }
   5044   //
   5045   // Return unaligned data.
   5046   //
   5047   Ptr             = (UINT8 *) &Data64;
   5048   Data32          = VmReadCode32 (VmPtr, Offset);
   5049   *(UINT32 *) Ptr = Data32;
   5050   Ptr            += sizeof (Data32);
   5051   Data32          = VmReadCode32 (VmPtr, Offset + sizeof (UINT32));
   5052   *(UINT32 *) Ptr = Data32;
   5053   return Data64;
   5054 }
   5055 
   5056 
   5057 /**
   5058   Reads 16-bit unsigned data from the code stream.
   5059 
   5060   This routine provides the ability to read raw unsigned data from the code
   5061   stream.
   5062 
   5063   @param  VmPtr             A pointer to VM context
   5064   @param  Offset            Offset from current IP to the raw data to read.
   5065 
   5066   @return The raw unsigned 16-bit value from the code stream.
   5067 
   5068 **/
   5069 UINT16
   5070 VmReadCode16 (
   5071   IN VM_CONTEXT *VmPtr,
   5072   IN UINT32     Offset
   5073   )
   5074 {
   5075   //
   5076   // Read direct if aligned
   5077   //
   5078   if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT16))) {
   5079     return * (UINT16 *) (VmPtr->Ip + Offset);
   5080   } else {
   5081     //
   5082     // All code word reads should be aligned
   5083     //
   5084     EbcDebugSignalException (
   5085       EXCEPT_EBC_ALIGNMENT_CHECK,
   5086       EXCEPTION_FLAG_WARNING,
   5087       VmPtr
   5088       );
   5089   }
   5090   //
   5091   // Return unaligned data
   5092   //
   5093   return (UINT16) (*(UINT8 *) (VmPtr->Ip + Offset) + (*(UINT8 *) (VmPtr->Ip + Offset + 1) << 8));
   5094 }
   5095 
   5096 
   5097 /**
   5098   Reads 32-bit unsigned data from the code stream.
   5099 
   5100   This routine provides the ability to read raw unsigned data from the code
   5101   stream.
   5102 
   5103   @param  VmPtr             A pointer to VM context
   5104   @param  Offset            Offset from current IP to the raw data to read.
   5105 
   5106   @return The raw unsigned 32-bit value from the code stream.
   5107 
   5108 **/
   5109 UINT32
   5110 VmReadCode32 (
   5111   IN VM_CONTEXT *VmPtr,
   5112   IN UINT32     Offset
   5113   )
   5114 {
   5115   UINT32  Data;
   5116   //
   5117   // Read direct if aligned
   5118   //
   5119   if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT32))) {
   5120     return * (UINT32 *) (VmPtr->Ip + Offset);
   5121   }
   5122   //
   5123   // Return unaligned data
   5124   //
   5125   Data = (UINT32) VmReadCode16 (VmPtr, Offset);
   5126   Data |= (VmReadCode16 (VmPtr, Offset + 2) << 16);
   5127   return Data;
   5128 }
   5129 
   5130 
   5131 /**
   5132   Reads 64-bit unsigned data from the code stream.
   5133 
   5134   This routine provides the ability to read raw unsigned data from the code
   5135   stream.
   5136 
   5137   @param  VmPtr             A pointer to VM context
   5138   @param  Offset            Offset from current IP to the raw data to read.
   5139 
   5140   @return The raw unsigned 64-bit value from the code stream.
   5141 
   5142 **/
   5143 UINT64
   5144 VmReadCode64 (
   5145   IN VM_CONTEXT *VmPtr,
   5146   IN UINT32     Offset
   5147   )
   5148 {
   5149   UINT64  Data64;
   5150   UINT32  Data32;
   5151   UINT8   *Ptr;
   5152 
   5153   //
   5154   // Read direct if aligned
   5155   //
   5156   if (IS_ALIGNED ((UINTN) VmPtr->Ip + Offset, sizeof (UINT64))) {
   5157     return * (UINT64 *) (VmPtr->Ip + Offset);
   5158   }
   5159   //
   5160   // Return unaligned data.
   5161   //
   5162   Ptr             = (UINT8 *) &Data64;
   5163   Data32          = VmReadCode32 (VmPtr, Offset);
   5164   *(UINT32 *) Ptr = Data32;
   5165   Ptr            += sizeof (Data32);
   5166   Data32          = VmReadCode32 (VmPtr, Offset + sizeof (UINT32));
   5167   *(UINT32 *) Ptr = Data32;
   5168   return Data64;
   5169 }
   5170 
   5171 
   5172 /**
   5173   Reads 8-bit data form the memory address.
   5174 
   5175   @param  VmPtr             A pointer to VM context.
   5176   @param  Addr              The memory address.
   5177 
   5178   @return The 8-bit value from the memory address.
   5179 
   5180 **/
   5181 UINT8
   5182 VmReadMem8 (
   5183   IN VM_CONTEXT   *VmPtr,
   5184   IN UINTN        Addr
   5185   )
   5186 {
   5187   //
   5188   // Convert the address if it's in the stack gap
   5189   //
   5190   Addr = ConvertStackAddr (VmPtr, Addr);
   5191   //
   5192   // Simply return the data in flat memory space
   5193   //
   5194   return * (UINT8 *) Addr;
   5195 }
   5196 
   5197 /**
   5198   Reads 16-bit data form the memory address.
   5199 
   5200   @param  VmPtr             A pointer to VM context.
   5201   @param  Addr              The memory address.
   5202 
   5203   @return The 16-bit value from the memory address.
   5204 
   5205 **/
   5206 UINT16
   5207 VmReadMem16 (
   5208   IN VM_CONTEXT *VmPtr,
   5209   IN UINTN      Addr
   5210   )
   5211 {
   5212   //
   5213   // Convert the address if it's in the stack gap
   5214   //
   5215   Addr = ConvertStackAddr (VmPtr, Addr);
   5216   //
   5217   // Read direct if aligned
   5218   //
   5219   if (IS_ALIGNED (Addr, sizeof (UINT16))) {
   5220     return * (UINT16 *) Addr;
   5221   }
   5222   //
   5223   // Return unaligned data
   5224   //
   5225   return (UINT16) (*(UINT8 *) Addr + (*(UINT8 *) (Addr + 1) << 8));
   5226 }
   5227 
   5228 /**
   5229   Reads 32-bit data form the memory address.
   5230 
   5231   @param  VmPtr             A pointer to VM context.
   5232   @param  Addr              The memory address.
   5233 
   5234   @return The 32-bit value from the memory address.
   5235 
   5236 **/
   5237 UINT32
   5238 VmReadMem32 (
   5239   IN VM_CONTEXT *VmPtr,
   5240   IN UINTN      Addr
   5241   )
   5242 {
   5243   UINT32  Data;
   5244 
   5245   //
   5246   // Convert the address if it's in the stack gap
   5247   //
   5248   Addr = ConvertStackAddr (VmPtr, Addr);
   5249   //
   5250   // Read direct if aligned
   5251   //
   5252   if (IS_ALIGNED (Addr, sizeof (UINT32))) {
   5253     return * (UINT32 *) Addr;
   5254   }
   5255   //
   5256   // Return unaligned data
   5257   //
   5258   Data = (UINT32) VmReadMem16 (VmPtr, Addr);
   5259   Data |= (VmReadMem16 (VmPtr, Addr + 2) << 16);
   5260   return Data;
   5261 }
   5262 
   5263 /**
   5264   Reads 64-bit data form the memory address.
   5265 
   5266   @param  VmPtr             A pointer to VM context.
   5267   @param  Addr              The memory address.
   5268 
   5269   @return The 64-bit value from the memory address.
   5270 
   5271 **/
   5272 UINT64
   5273 VmReadMem64 (
   5274   IN VM_CONTEXT   *VmPtr,
   5275   IN UINTN        Addr
   5276   )
   5277 {
   5278   UINT64  Data;
   5279   UINT32  Data32;
   5280 
   5281   //
   5282   // Convert the address if it's in the stack gap
   5283   //
   5284   Addr = ConvertStackAddr (VmPtr, Addr);
   5285 
   5286   //
   5287   // Read direct if aligned
   5288   //
   5289   if (IS_ALIGNED (Addr, sizeof (UINT64))) {
   5290     return * (UINT64 *) Addr;
   5291   }
   5292   //
   5293   // Return unaligned data. Assume little endian.
   5294   //
   5295   Data32 = VmReadMem32 (VmPtr, Addr);
   5296   Data  = (UINT64) VmReadMem32 (VmPtr, Addr + sizeof (UINT32));
   5297   Data  = LShiftU64 (Data, 32) | Data32;
   5298   return Data;
   5299 }
   5300 
   5301 
   5302 /**
   5303   Given an address that EBC is going to read from or write to, return
   5304   an appropriate address that accounts for a gap in the stack.
   5305   The stack for this application looks like this (high addr on top)
   5306   [EBC entry point arguments]
   5307   [VM stack]
   5308   [EBC stack]
   5309   The EBC assumes that its arguments are at the top of its stack, which
   5310   is where the VM stack is really. Therefore if the EBC does memory
   5311   accesses into the VM stack area, then we need to convert the address
   5312   to point to the EBC entry point arguments area. Do this here.
   5313 
   5314   @param  VmPtr             A Pointer to VM context.
   5315   @param  Addr              Address of interest
   5316 
   5317   @return The unchanged address if it's not in the VM stack region. Otherwise,
   5318           adjust for the stack gap and return the modified address.
   5319 
   5320 **/
   5321 UINTN
   5322 ConvertStackAddr (
   5323   IN VM_CONTEXT    *VmPtr,
   5324   IN UINTN         Addr
   5325   )
   5326 {
   5327   ASSERT(((Addr < VmPtr->LowStackTop) || (Addr > VmPtr->HighStackBottom)));
   5328   return Addr;
   5329 }
   5330 
   5331 
   5332 /**
   5333   Read a natural value from memory. May or may not be aligned.
   5334 
   5335   @param  VmPtr             current VM context
   5336   @param  Addr              the address to read from
   5337 
   5338   @return The natural value at address Addr.
   5339 
   5340 **/
   5341 UINTN
   5342 VmReadMemN (
   5343   IN VM_CONTEXT    *VmPtr,
   5344   IN UINTN         Addr
   5345   )
   5346 {
   5347   UINTN   Data;
   5348   volatile UINT32  Size;
   5349   UINT8   *FromPtr;
   5350   UINT8   *ToPtr;
   5351   //
   5352   // Convert the address if it's in the stack gap
   5353   //
   5354   Addr = ConvertStackAddr (VmPtr, Addr);
   5355   //
   5356   // Read direct if aligned
   5357   //
   5358   if (IS_ALIGNED (Addr, sizeof (UINTN))) {
   5359     return * (UINTN *) Addr;
   5360   }
   5361   //
   5362   // Return unaligned data
   5363   //
   5364   Data    = 0;
   5365   FromPtr = (UINT8 *) Addr;
   5366   ToPtr   = (UINT8 *) &Data;
   5367 
   5368   for (Size = 0; Size < sizeof (Data); Size++) {
   5369     *ToPtr = *FromPtr;
   5370     ToPtr++;
   5371     FromPtr++;
   5372   }
   5373 
   5374   return Data;
   5375 }
   5376 
   5377 /**
   5378   Returns the version of the EBC virtual machine.
   5379 
   5380   @return The 64-bit version of EBC virtual machine.
   5381 
   5382 **/
   5383 UINT64
   5384 GetVmVersion (
   5385   VOID
   5386   )
   5387 {
   5388   return (UINT64) (((VM_MAJOR_VERSION & 0xFFFF) << 16) | ((VM_MINOR_VERSION & 0xFFFF)));
   5389 }
   5390