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