2 Contains code that implements the virtual machine.
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
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.
16 #include "EbcExecute.h"
20 // Define some useful data size constants to allow switch statements based on
21 // size of operands or data.
23 #define DATA_SIZE_INVALID 0
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
30 // Structure we'll use to dispatch opcodes to execute functions.
33 EFI_STATUS (*ExecuteFunction
) (IN VM_CONTEXT
* VmPtr
);
39 (*DATA_MANIP_EXEC_FUNCTION
) (
40 IN VM_CONTEXT
* VmPtr
,
46 Decode a 16-bit index to determine the offset. Given an index value:
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
53 Given this info, the offset can be computed by:
54 offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
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 =
60 @param VmPtr A pointer to VM context.
61 @param CodeOffset Offset from IP of the location of the 16-bit index
64 @return The decoded offset.
74 Decode a 32-bit index to determine the offset.
76 @param VmPtr A pointer to VM context.
77 @param CodeOffset Offset from IP of the location of the 32-bit index
80 @return Converted index per EBC VM specification.
90 Decode a 64-bit index to determine the offset.
92 @param VmPtr A pointer to VM context.s
93 @param CodeOffset Offset from IP of the location of the 64-bit index
96 @return Converted index per EBC VM specification
101 IN VM_CONTEXT
*VmPtr
,
106 Reads 8-bit data form the memory address.
108 @param VmPtr A pointer to VM context.
109 @param Addr The memory address.
111 @return The 8-bit value from the memory address.
116 IN VM_CONTEXT
*VmPtr
,
121 Reads 16-bit data form the memory address.
123 @param VmPtr A pointer to VM context.
124 @param Addr The memory address.
126 @return The 16-bit value from the memory address.
131 IN VM_CONTEXT
*VmPtr
,
136 Reads 32-bit data form the memory address.
138 @param VmPtr A pointer to VM context.
139 @param Addr The memory address.
141 @return The 32-bit value from the memory address.
146 IN VM_CONTEXT
*VmPtr
,
151 Reads 64-bit data form the memory address.
153 @param VmPtr A pointer to VM context.
154 @param Addr The memory address.
156 @return The 64-bit value from the memory address.
161 IN VM_CONTEXT
*VmPtr
,
166 Read a natural value from memory. May or may not be aligned.
168 @param VmPtr current VM context
169 @param Addr the address to read from
171 @return The natural value at address Addr.
176 IN VM_CONTEXT
*VmPtr
,
181 Writes 8-bit data to memory address.
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,
187 [EBC entry point arguments]
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.
195 @param VmPtr A pointer to a VM context.
196 @param Addr Address to write to.
197 @param Data Value to write to Addr.
199 @retval EFI_SUCCESS The instruction is executed successfully.
200 @retval Other Some error occurs when writing data to the address.
205 IN VM_CONTEXT
*VmPtr
,
211 Writes 16-bit data to memory address.
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,
217 [EBC entry point arguments]
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.
225 @param VmPtr A pointer to a VM context.
226 @param Addr Address to write to.
227 @param Data Value to write to Addr.
229 @retval EFI_SUCCESS The instruction is executed successfully.
230 @retval Other Some error occurs when writing data to the address.
235 IN VM_CONTEXT
*VmPtr
,
241 Writes 32-bit data to memory address.
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,
247 [EBC entry point arguments]
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.
255 @param VmPtr A pointer to a VM context.
256 @param Addr Address to write to.
257 @param Data Value to write to Addr.
259 @retval EFI_SUCCESS The instruction is executed successfully.
260 @retval Other Some error occurs when writing data to the address.
265 IN VM_CONTEXT
*VmPtr
,
271 Reads 16-bit unsigned data from the code stream.
273 This routine provides the ability to read raw unsigned data from the code
276 @param VmPtr A pointer to VM context
277 @param Offset Offset from current IP to the raw data to read.
279 @return The raw unsigned 16-bit value from the code stream.
284 IN VM_CONTEXT
*VmPtr
,
289 Reads 32-bit unsigned data from the code stream.
291 This routine provides the ability to read raw unsigned data from the code
294 @param VmPtr A pointer to VM context
295 @param Offset Offset from current IP to the raw data to read.
297 @return The raw unsigned 32-bit value from the code stream.
302 IN VM_CONTEXT
*VmPtr
,
307 Reads 64-bit unsigned data from the code stream.
309 This routine provides the ability to read raw unsigned data from the code
312 @param VmPtr A pointer to VM context
313 @param Offset Offset from current IP to the raw data to read.
315 @return The raw unsigned 64-bit value from the code stream.
320 IN VM_CONTEXT
*VmPtr
,
325 Reads 8-bit immediate value at the offset.
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.
332 @param VmPtr A pointer to a VM context.
333 @param Offset offset from IP of the code bytes to read.
335 @return Signed data of the requested size from the specified address.
340 IN VM_CONTEXT
*VmPtr
,
345 Reads 16-bit immediate value at the offset.
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.
352 @param VmPtr A pointer to a VM context.
353 @param Offset offset from IP of the code bytes to read.
355 @return Signed data of the requested size from the specified address.
360 IN VM_CONTEXT
*VmPtr
,
365 Reads 32-bit immediate value at the offset.
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.
372 @param VmPtr A pointer to a VM context.
373 @param Offset offset from IP of the code bytes to read.
375 @return Signed data of the requested size from the specified address.
380 IN VM_CONTEXT
*VmPtr
,
385 Reads 64-bit immediate value at the offset.
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.
392 @param VmPtr A pointer to a VM context.
393 @param Offset offset from IP of the code bytes to read.
395 @return Signed data of the requested size from the specified address.
400 IN VM_CONTEXT
*VmPtr
,
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]
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.
416 @param VmPtr A Pointer to VM context.
417 @param Addr Address of interest
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.
425 IN VM_CONTEXT
*VmPtr
,
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.
438 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
440 @param VmPtr A pointer to VM context.
441 @param IsSignedOp Indicates whether the operand is signed or not.
443 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
444 @retval EFI_SUCCESS The instruction is executed successfully.
449 IN VM_CONTEXT
*VmPtr
,
450 IN BOOLEAN IsSignedOp
454 // Functions that execute VM opcodes
457 Execute the EBC BREAK instruction.
459 @param VmPtr A pointer to a VM context.
461 @retval EFI_SUCCESS The instruction is executed successfully.
470 Execute the JMP instruction.
474 JMP32{cs|cc} {@}R1 {Immed32|Index32}
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
485 b1.3 1 = operand1 indirect
488 @param VmPtr A pointer to a VM context.
490 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
491 @retval EFI_SUCCESS The instruction is executed successfully.
500 Execute the EBC JMP8 instruction.
505 @param VmPtr A pointer to a VM context.
507 @retval EFI_SUCCESS The instruction is executed successfully.
516 Implements the EBC CALL instruction.
520 CALL32 {@}R1 {Immed32|Index32}
522 CALLEX16 {@}R1 {Immed32}
524 If Rx == R0, then it's a PC relative call to PC = PC + imm32.
526 @param VmPtr A pointer to a VM context.
528 @retval EFI_SUCCESS The instruction is executed successfully.
537 Execute the EBC RET instruction.
542 @param VmPtr A pointer to a VM context.
544 @retval EFI_SUCCESS The instruction is executed successfully.
553 Execute the EBC CMP instruction.
556 CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
558 @param VmPtr A pointer to a VM context.
560 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
561 @retval EFI_SUCCESS The instruction is executed successfully.
570 Execute the EBC CMPI instruction
573 CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
575 @param VmPtr A pointer to a VM context.
577 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
578 @retval EFI_SUCCESS The instruction is executed successfully.
587 Execute the MOVxx instructions.
591 MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
592 MOVqq {@}R1 {Index64}, {@}R2 {Index64}
594 Copies contents of [R2] -> [R1], zero extending where required.
596 First character indicates the size of the move.
597 Second character indicates the size of the index(s).
599 Invalid to have R1 direct with index.
601 @param VmPtr A pointer to a VM context.
603 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
604 @retval EFI_SUCCESS The instruction is executed successfully.
613 Execute the EBC MOVI.
617 MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
619 First variable character specifies the move size
620 Second variable character specifies size of the immediate data
622 Sign-extend the immediate data to the size of the operation, and zero-extend
623 if storing to a register.
625 Operand1 direct with index/immed is invalid.
627 @param VmPtr A pointer to a VM context.
629 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
630 @retval EFI_SUCCESS The instruction is executed successfully.
639 Execute the EBC MOV immediate natural. This instruction moves an immediate
640 index value into a register or memory location.
644 MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
646 @param VmPtr A pointer to a VM context.
648 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
649 @retval EFI_SUCCESS The instruction is executed successfully.
658 Execute the EBC MOVREL instruction.
663 MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
665 @param VmPtr A pointer to a VM context.
667 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
668 @retval EFI_SUCCESS The instruction is executed successfully.
677 Execute the EBC PUSHn instruction
680 PUSHn {@}R1 {Index16|Immed16}
682 @param VmPtr A pointer to a VM context.
684 @retval EFI_SUCCESS The instruction is executed successfully.
693 Execute the EBC PUSH instruction.
696 PUSH[32|64] {@}R1 {Index16|Immed16}
698 @param VmPtr A pointer to a VM context.
700 @retval EFI_SUCCESS The instruction is executed successfully.
709 Execute the EBC POPn instruction.
712 POPn {@}R1 {Index16|Immed16}
714 @param VmPtr A pointer to a VM context.
716 @retval EFI_SUCCESS The instruction is executed successfully.
725 Execute the EBC POP instruction.
728 POPn {@}R1 {Index16|Immed16}
730 @param VmPtr A pointer to a VM context.
732 @retval EFI_SUCCESS The instruction is executed successfully.
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.
749 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
751 @param VmPtr A pointer to VM context.
753 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
754 @retval EFI_SUCCESS The instruction is executed successfully.
758 ExecuteSignedDataManip (
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.
771 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
773 @param VmPtr A pointer to VM context.
775 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
776 @retval EFI_SUCCESS The instruction is executed successfully.
780 ExecuteUnsignedDataManip (
785 Execute the EBC LOADSP instruction.
790 @param VmPtr A pointer to a VM context.
792 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
793 @retval EFI_SUCCESS The instruction is executed successfully.
802 Execute the EBC STORESP instruction.
807 @param VmPtr A pointer to a VM context.
809 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
810 @retval EFI_SUCCESS The instruction is executed successfully.
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
826 MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
828 0:7 1=>operand1 index present
829 0:6 1=>operand2 index present
831 @param VmPtr A pointer to a VM context.
833 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
834 @retval EFI_SUCCESS The instruction is executed successfully.
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
850 MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
852 0:7 1=>operand1 index present
853 0:6 1=>operand2 index present
855 @param VmPtr A pointer to a VM context.
857 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
858 @retval EFI_SUCCESS The instruction is executed successfully.
867 // Data manipulation subfunctions
870 Execute the EBC NOT instruction.s
873 NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
884 IN VM_CONTEXT
*VmPtr
,
890 Execute the EBC NEG instruction.
893 NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
904 IN VM_CONTEXT
*VmPtr
,
910 Execute the EBC ADD instruction.
913 ADD[32|64] {@}R1, {@}R2 {Index16}
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
924 IN VM_CONTEXT
*VmPtr
,
930 Execute the EBC SUB instruction.
933 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
944 IN VM_CONTEXT
*VmPtr
,
950 Execute the EBC MUL instruction.
953 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
964 IN VM_CONTEXT
*VmPtr
,
970 Execute the EBC MULU instruction
973 MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
979 @return (unsigned)Op1 * (unsigned)Op2
984 IN VM_CONTEXT
*VmPtr
,
990 Execute the EBC DIV instruction.
993 DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
1004 IN VM_CONTEXT
*VmPtr
,
1010 Execute the EBC DIVU instruction
1013 DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
1019 @return (unsigned)Op1 / (unsigned)Op2
1024 IN VM_CONTEXT
*VmPtr
,
1030 Execute the EBC MOD instruction.
1033 MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
1039 @return Op1 MODULUS Op2
1044 IN VM_CONTEXT
*VmPtr
,
1050 Execute the EBC MODU instruction.
1053 MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
1059 @return Op1 UNSIGNED_MODULUS Op2
1064 IN VM_CONTEXT
*VmPtr
,
1070 Execute the EBC AND instruction.
1073 AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
1084 IN VM_CONTEXT
*VmPtr
,
1090 Execute the EBC OR instruction.
1093 OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
1104 IN VM_CONTEXT
*VmPtr
,
1110 Execute the EBC XOR instruction.
1113 XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
1124 IN VM_CONTEXT
*VmPtr
,
1130 Execute the EBC SHL shift left instruction.
1133 SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
1144 IN VM_CONTEXT
*VmPtr
,
1150 Execute the EBC SHR instruction.
1153 SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
1159 @return Op1 >> Op2 (unsigned operands)
1164 IN VM_CONTEXT
*VmPtr
,
1170 Execute the EBC ASHR instruction.
1173 ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
1179 @return Op1 >> Op2 (signed)
1184 IN VM_CONTEXT
*VmPtr
,
1190 Execute the EBC EXTNDB instruction to sign-extend a byte value.
1193 EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
1199 @return (INT64)(INT8)Op2
1204 IN VM_CONTEXT
*VmPtr
,
1210 Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
1213 EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
1219 @return (INT64)(INT16)Op2
1224 IN VM_CONTEXT
*VmPtr
,
1230 Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
1233 EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
1239 @return (INT64)(INT32)Op2
1244 IN VM_CONTEXT
*VmPtr
,
1250 // Once we retrieve the operands for the data manipulation instructions,
1251 // call these functions to perform the operation.
1253 CONST DATA_MANIP_EXEC_FUNCTION mDataManipDispatchTable
[] = {
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
1343 // Length of JMP instructions, depending on upper two bits of opcode.
1345 CONST UINT8 mJMPLen
[] = { 2, 2, 6, 10 };
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.
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.
1357 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
1358 @retval EFI_SUCCESS All of the instructions are executed successfully.
1363 EbcExecuteInstructions (
1364 IN EFI_EBC_VM_TEST_PROTOCOL
*This
,
1365 IN VM_CONTEXT
*VmPtr
,
1366 IN OUT UINTN
*InstructionCount
1371 UINTN InstructionsLeft
;
1372 UINTN SavedInstructionCount
;
1374 Status
= EFI_SUCCESS
;
1376 if (*InstructionCount
== 0) {
1377 InstructionsLeft
= 1;
1379 InstructionsLeft
= *InstructionCount
;
1382 SavedInstructionCount
= *InstructionCount
;
1383 *InstructionCount
= 0;
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.
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
;
1396 mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction (VmPtr
);
1397 *InstructionCount
= *InstructionCount
+ 1;
1401 // Decrement counter if applicable
1403 if (SavedInstructionCount
!= 0) {
1413 Execute an EBC image from an entry point or from a published protocol.
1415 @param VmPtr A pointer to a VM context.
1417 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
1418 @retval EFI_SUCCESS All of the instructions are executed successfully.
1423 IN VM_CONTEXT
*VmPtr
1427 UINT8 StackCorrupted
;
1429 EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL
*EbcSimpleDebugger
;
1432 EbcSimpleDebugger
= NULL
;
1433 Status
= EFI_SUCCESS
;
1437 // Make sure the magic value has been put on the stack before we got here.
1439 if (*VmPtr
->StackMagicPtr
!= (UINTN
) VM_STACK_KEY_VALUE
) {
1443 VmPtr
->FramePtr
= (VOID
*) ((UINT8
*) (UINTN
) VmPtr
->Gpr
[0] + 8);
1446 // Try to get the debug support for EBC
1448 DEBUG_CODE_BEGIN ();
1449 Status
= gBS
->LocateProtocol (
1450 &gEfiEbcSimpleDebuggerProtocolGuid
,
1452 (VOID
**) &EbcSimpleDebugger
1454 if (EFI_ERROR (Status
)) {
1455 EbcSimpleDebugger
= NULL
;
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.
1464 VmPtr
->EntryPoint
= (VOID
*) VmPtr
->Ip
;
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.
1470 VmPtr
->StopFlags
= 0;
1471 while ((VmPtr
->StopFlags
& STOPFLAG_APP_DONE
) == 0) {
1473 // If we've found a simple debugger protocol, call it
1475 DEBUG_CODE_BEGIN ();
1476 if (EbcSimpleDebugger
!= NULL
) {
1477 EbcSimpleDebugger
->Debugger (EbcSimpleDebugger
, VmPtr
);
1482 // Use the opcode bits to index into the opcode dispatch table. If the
1483 // function pointer is null then generate an exception.
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
;
1492 // The EBC VM is a strongly ordered processor, so perform a fence operation before
1493 // and after each instruction is executed.
1497 mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction (VmPtr
);
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.
1505 if (VMFLAG_ISSET (VmPtr
, VMFLAGS_STEP
)) {
1506 EbcDebugSignalException (EXCEPT_EBC_STEP
, EXCEPTION_FLAG_NONE
, VmPtr
);
1509 // Make sure stack has not been corrupted. Only report it once though.
1511 if ((StackCorrupted
== 0) && (*VmPtr
->StackMagicPtr
!= (UINTN
) VM_STACK_KEY_VALUE
)) {
1512 EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1515 if ((StackCorrupted
== 0) && ((UINT64
)VmPtr
->Gpr
[0] <= (UINT64
)(UINTN
) VmPtr
->StackTop
)) {
1516 EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1529 Execute the MOVxx instructions.
1533 MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
1534 MOVqq {@}R1 {Index64}, {@}R2 {Index64}
1536 Copies contents of [R2] -> [R1], zero extending where required.
1538 First character indicates the size of the move.
1539 Second character indicates the size of the index(s).
1541 Invalid to have R1 direct with index.
1543 @param VmPtr A pointer to a VM context.
1545 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
1546 @retval EFI_SUCCESS The instruction is executed successfully.
1551 IN VM_CONTEXT
*VmPtr
1567 Opcode
= GETOPCODE (VmPtr
);
1568 OpcMasked
= (UINT8
) (Opcode
& OPCODE_M_OPCODE
);
1571 // Get the operands byte so we can get R1 and R2
1573 Operands
= GETOPERANDS (VmPtr
);
1576 // Assume no indexes
1583 // Determine if we have an index/immediate data. Base instruction size
1584 // is 2 (opcode + operands). Add to this size each index specified.
1587 if ((Opcode
& (OPCODE_M_IMMED_OP1
| OPCODE_M_IMMED_OP2
)) != 0) {
1589 // Determine size of the index from the opcode. Then get it.
1591 if ((OpcMasked
<= OPCODE_MOVQW
) || (OpcMasked
== OPCODE_MOVNW
)) {
1593 // MOVBW, MOVWW, MOVDW, MOVQW, and MOVNW have 16-bit immediate index.
1594 // Get one or both index values.
1596 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1597 Index16
= VmReadIndex16 (VmPtr
, 2);
1598 Index64Op1
= (INT64
) Index16
;
1599 Size
+= sizeof (UINT16
);
1602 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1603 Index16
= VmReadIndex16 (VmPtr
, Size
);
1604 Index64Op2
= (INT64
) Index16
;
1605 Size
+= sizeof (UINT16
);
1607 } else if ((OpcMasked
<= OPCODE_MOVQD
) || (OpcMasked
== OPCODE_MOVND
)) {
1609 // MOVBD, MOVWD, MOVDD, MOVQD, and MOVND have 32-bit immediate index
1611 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1612 Index32
= VmReadIndex32 (VmPtr
, 2);
1613 Index64Op1
= (INT64
) Index32
;
1614 Size
+= sizeof (UINT32
);
1617 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1618 Index32
= VmReadIndex32 (VmPtr
, Size
);
1619 Index64Op2
= (INT64
) Index32
;
1620 Size
+= sizeof (UINT32
);
1622 } else if (OpcMasked
== OPCODE_MOVQQ
) {
1624 // MOVqq -- only form with a 64-bit index
1626 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1627 Index64Op1
= VmReadIndex64 (VmPtr
, 2);
1628 Size
+= sizeof (UINT64
);
1631 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1632 Index64Op2
= VmReadIndex64 (VmPtr
, Size
);
1633 Size
+= sizeof (UINT64
);
1637 // Obsolete MOVBQ, MOVWQ, MOVDQ, and MOVNQ have 64-bit immediate index
1639 EbcDebugSignalException (
1640 EXCEPT_EBC_INSTRUCTION_ENCODING
,
1641 EXCEPTION_FLAG_FATAL
,
1644 return EFI_UNSUPPORTED
;
1648 // Determine the size of the move, and create a mask for it so we can
1649 // clear unused bits.
1651 if ((OpcMasked
== OPCODE_MOVBW
) || (OpcMasked
== OPCODE_MOVBD
)) {
1652 MoveSize
= DATA_SIZE_8
;
1654 } else if ((OpcMasked
== OPCODE_MOVWW
) || (OpcMasked
== OPCODE_MOVWD
)) {
1655 MoveSize
= DATA_SIZE_16
;
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
));
1668 // We were dispatched to this function and we don't recognize the opcode
1670 EbcDebugSignalException (EXCEPT_EBC_UNDEFINED
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1671 return EFI_UNSUPPORTED
;
1674 // Now get the source address
1676 if (OPERAND2_INDIRECT (Operands
)) {
1678 // Indirect form @R2. Compute address of operand2
1680 Source
= (UINTN
) (VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index64Op2
);
1682 // Now get the data from the source. Always 0-extend and let the compiler
1683 // sign-extend where required.
1687 Data64
= (UINT64
) (UINT8
) VmReadMem8 (VmPtr
, Source
);
1691 Data64
= (UINT64
) (UINT16
) VmReadMem16 (VmPtr
, Source
);
1695 Data64
= (UINT64
) (UINT32
) VmReadMem32 (VmPtr
, Source
);
1699 Data64
= (UINT64
) VmReadMem64 (VmPtr
, Source
);
1703 Data64
= (UINT64
) (UINTN
) VmReadMemN (VmPtr
, Source
);
1714 // Not indirect source: MOVxx {@}Rx, Ry [Index]
1716 Data64
= (UINT64
) (VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index64Op2
);
1718 // Did Operand2 have an index? If so, treat as two signed values since
1719 // indexes are signed values.
1721 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
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.
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
1735 if ((OPERAND2_REGNUM (Operands
) == 0) &&
1736 (!OPERAND2_INDIRECT (Operands
)) &&
1738 (OPERAND1_REGNUM (Operands
) == 0) &&
1739 (OPERAND1_INDIRECT (Operands
))
1741 Data64
= (UINT64
) ConvertStackAddr (VmPtr
, (UINTN
) (INT64
) Data64
);
1746 // Now write it back
1748 if (OPERAND1_INDIRECT (Operands
)) {
1750 // Reuse the Source variable to now be dest.
1752 Source
= (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index64Op1
);
1754 // Do the write based on the size
1758 VmWriteMem8 (VmPtr
, Source
, (UINT8
) Data64
);
1762 VmWriteMem16 (VmPtr
, Source
, (UINT16
) Data64
);
1766 VmWriteMem32 (VmPtr
, Source
, (UINT32
) Data64
);
1770 VmWriteMem64 (VmPtr
, Source
, Data64
);
1774 VmWriteMemN (VmPtr
, Source
, (UINTN
) Data64
);
1786 // Make sure we didn't have an index on operand1.
1788 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1789 EbcDebugSignalException (
1790 EXCEPT_EBC_INSTRUCTION_ENCODING
,
1791 EXCEPTION_FLAG_FATAL
,
1794 return EFI_UNSUPPORTED
;
1797 // Direct storage in register. Clear unused bits and store back to
1800 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = Data64
& DataMask
;
1803 // Advance the instruction pointer
1811 Execute the EBC BREAK instruction.
1813 @param VmPtr A pointer to a VM context.
1815 @retval EFI_SUCCESS The instruction is executed successfully.
1820 IN VM_CONTEXT
*VmPtr
1825 VOID
*EbcEntryPoint
;
1827 UINT64 U64EbcEntryPoint
;
1831 Operands
= GETOPERANDS (VmPtr
);
1834 // Runaway program break. Generate an exception and terminate
1837 EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1841 // Get VM version -- return VM revision number in R7
1847 // 16-8 = Major version
1848 // 7-0 = Minor version
1850 VmPtr
->Gpr
[7] = GetVmVersion ();
1854 // Debugger breakpoint
1857 VmPtr
->StopFlags
|= STOPFLAG_BREAKPOINT
;
1859 // See if someone has registered a handler
1861 EbcDebugSignalException (
1862 EXCEPT_EBC_BREAKPOINT
,
1863 EXCEPTION_FLAG_NONE
,
1869 // System call, which there are none, so NOP it.
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.
1880 Offset
= (INT32
) VmReadMem32 (VmPtr
, (UINTN
) VmPtr
->Gpr
[7]);
1881 U64EbcEntryPoint
= (UINT64
) (VmPtr
->Gpr
[7] + Offset
+ 4);
1882 EbcEntryPoint
= (VOID
*) (UINTN
) U64EbcEntryPoint
;
1885 // Now create a new thunk
1887 Status
= EbcCreateThunks (VmPtr
->ImageHandle
, EbcEntryPoint
, &Thunk
, 0);
1888 if (EFI_ERROR (Status
)) {
1893 // Finally replace the EBC entry point memory with the thunk address
1895 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->Gpr
[7], (UINT64
) (UINTN
) Thunk
);
1899 // Compiler setting version per value in R7
1902 VmPtr
->CompilerVersion
= (UINT32
) VmPtr
->Gpr
[7];
1904 // Check compiler version against VM version?
1909 // Unhandled break code. Signal exception.
1912 EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1924 Execute the JMP instruction.
1927 JMP64{cs|cc} Immed64
1928 JMP32{cs|cc} {@}R1 {Immed32|Index32}
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
1942 @param VmPtr A pointer to a VM context.
1944 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
1945 @retval EFI_SUCCESS The instruction is executed successfully.
1950 IN VM_CONTEXT
*VmPtr
1955 UINT8 ConditionFlag
;
1962 Operand
= GETOPERANDS (VmPtr
);
1963 Opcode
= GETOPCODE (VmPtr
);
1966 // Get instruction length from the opcode. The upper two bits are used here
1967 // to index into the length array.
1969 Size
= mJMPLen
[(Opcode
>> 6) & 0x03];
1972 // Decode instruction conditions
1973 // If we haven't met the condition, then simply advance the IP and return.
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
) {
1984 // Check for 64-bit form and do it right away since it's the most
1985 // straight-forward form.
1987 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
1989 // Double check for immediate-data, which is required. If not there,
1990 // then signal an exception
1992 if ((Opcode
& OPCODE_M_IMMDATA
) == 0) {
1993 EbcDebugSignalException (
1994 EXCEPT_EBC_INSTRUCTION_ENCODING
,
1995 EXCEPTION_FLAG_ERROR
,
1998 return EFI_UNSUPPORTED
;
2001 // 64-bit immediate data is full address. Read the immediate data,
2002 // check for alignment, and jump absolute.
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
,
2012 return EFI_UNSUPPORTED
;
2016 // Take jump -- relative or absolute
2018 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2019 VmPtr
->Ip
+= (UINTN
) Data64
+ Size
;
2021 VmPtr
->Ip
= (VMIP
) (UINTN
) Data64
;
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
2033 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
2034 if (OPERAND1_INDIRECT (Operand
)) {
2035 Index32
= VmReadIndex32 (VmPtr
, 2);
2037 Index32
= VmReadImmed32 (VmPtr
, 2);
2043 // Get the register data. If R == 0, then special case where it's ignored.
2045 if (OPERAND1_REGNUM (Operand
) == 0) {
2048 Data64
= (UINT64
) OPERAND1_REGDATA (VmPtr
, Operand
);
2053 if (OPERAND1_INDIRECT (Operand
)) {
2055 // Form: JMP32 @Rx {Index32}
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
,
2065 return EFI_UNSUPPORTED
;
2068 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2069 VmPtr
->Ip
+= (UINTN
) Addr
+ Size
;
2071 VmPtr
->Ip
= (VMIP
) Addr
;
2075 // Form: JMP32 Rx {Immed32}
2077 Addr
= (UINTN
) (Data64
+ Index32
);
2078 if (!IS_ALIGNED ((UINTN
) Addr
, sizeof (UINT16
))) {
2079 EbcDebugSignalException (
2080 EXCEPT_EBC_ALIGNMENT_CHECK
,
2081 EXCEPTION_FLAG_FATAL
,
2085 return EFI_UNSUPPORTED
;
2088 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2089 VmPtr
->Ip
+= (UINTN
) Addr
+ Size
;
2091 VmPtr
->Ip
= (VMIP
) Addr
;
2100 Execute the EBC JMP8 instruction.
2103 JMP8{cs|cc} Offset/2
2105 @param VmPtr A pointer to a VM context.
2107 @retval EFI_SUCCESS The instruction is executed successfully.
2112 IN VM_CONTEXT
*VmPtr
2116 UINT8 ConditionFlag
;
2121 // Decode instruction.
2123 Opcode
= GETOPCODE (VmPtr
);
2124 CompareSet
= (UINT8
) (((Opcode
& JMP_M_CS
) != 0) ? 1 : 0);
2125 ConditionFlag
= (UINT8
) VMFLAG_ISSET (VmPtr
, VMFLAGS_CC
);
2128 // If we haven't met the condition, then simply advance the IP and return
2130 if ((Opcode
& CONDITION_M_CONDITIONAL
) != 0) {
2131 if (CompareSet
!= ConditionFlag
) {
2137 // Get the offset from the instruction stream. It's relative to the
2138 // following instruction, and divided by 2.
2140 Offset
= VmReadImmed8 (VmPtr
, 1);
2142 // Want to check for offset == -2 and then raise an exception?
2144 VmPtr
->Ip
+= (Offset
* 2) + 2;
2150 Execute the EBC MOVI.
2154 MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
2156 First variable character specifies the move size
2157 Second variable character specifies size of the immediate data
2159 Sign-extend the immediate data to the size of the operation, and zero-extend
2160 if storing to a register.
2162 Operand1 direct with index/immed is invalid.
2164 @param VmPtr A pointer to a VM context.
2166 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2167 @retval EFI_SUCCESS The instruction is executed successfully.
2172 IN VM_CONTEXT
*VmPtr
2184 // Get the opcode and operands byte so we can get R1 and R2
2186 Opcode
= GETOPCODE (VmPtr
);
2187 Operands
= GETOPERANDS (VmPtr
);
2190 // Get the index (16-bit) if present
2192 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2193 Index16
= VmReadIndex16 (VmPtr
, 2);
2200 // Extract the immediate data. Sign-extend always.
2202 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2203 ImmData64
= (INT64
) (INT16
) VmReadImmed16 (VmPtr
, Size
);
2205 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2206 ImmData64
= (INT64
) (INT32
) VmReadImmed32 (VmPtr
, Size
);
2208 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2209 ImmData64
= (INT64
) VmReadImmed64 (VmPtr
, Size
);
2215 EbcDebugSignalException (
2216 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2217 EXCEPTION_FLAG_FATAL
,
2220 return EFI_UNSUPPORTED
;
2223 // Now write back the result
2225 if (!OPERAND1_INDIRECT (Operands
)) {
2227 // Operand1 direct. Make sure it didn't have an index.
2229 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2230 EbcDebugSignalException (
2231 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2232 EXCEPTION_FLAG_FATAL
,
2235 return EFI_UNSUPPORTED
;
2238 // Writing directly to a register. Clear unused bits.
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;
2247 Mask64
= (UINT64
)~0;
2250 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = ImmData64
& Mask64
;
2253 // Get the address then write back based on size of the move
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
);
2263 VmWriteMem64 (VmPtr
, (UINTN
) Op1
, (UINT64
) ImmData64
);
2267 // Advance the instruction pointer
2275 Execute the EBC MOV immediate natural. This instruction moves an immediate
2276 index value into a register or memory location.
2280 MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
2282 @param VmPtr A pointer to a VM context.
2284 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2285 @retval EFI_SUCCESS The instruction is executed successfully.
2290 IN VM_CONTEXT
*VmPtr
2303 // Get the opcode and operands byte so we can get R1 and R2
2305 Opcode
= GETOPCODE (VmPtr
);
2306 Operands
= GETOPERANDS (VmPtr
);
2309 // Get the operand1 index (16-bit) if present
2311 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2312 Index16
= VmReadIndex16 (VmPtr
, 2);
2319 // Extract the immediate data and convert to a 64-bit index.
2321 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2322 ImmedIndex16
= VmReadIndex16 (VmPtr
, Size
);
2323 ImmedIndex64
= (INT64
) ImmedIndex16
;
2325 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2326 ImmedIndex32
= VmReadIndex32 (VmPtr
, Size
);
2327 ImmedIndex64
= (INT64
) ImmedIndex32
;
2329 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2330 ImmedIndex64
= VmReadIndex64 (VmPtr
, Size
);
2336 EbcDebugSignalException (
2337 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2338 EXCEPTION_FLAG_FATAL
,
2341 return EFI_UNSUPPORTED
;
2344 // Now write back the result
2346 if (!OPERAND1_INDIRECT (Operands
)) {
2348 // Check for MOVIn R1 Index16, Immed (not indirect, with index), which
2351 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2352 EbcDebugSignalException (
2353 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2354 EXCEPTION_FLAG_FATAL
,
2357 return EFI_UNSUPPORTED
;
2360 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = ImmedIndex64
;
2365 Op1
= (UINT64
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
;
2366 VmWriteMemN (VmPtr
, (UINTN
) Op1
, (UINTN
)(INTN
) ImmedIndex64
);
2369 // Advance the instruction pointer
2377 Execute the EBC MOVREL instruction.
2378 Dest <- Ip + ImmData
2382 MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
2384 @param VmPtr A pointer to a VM context.
2386 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2387 @retval EFI_SUCCESS The instruction is executed successfully.
2392 IN VM_CONTEXT
*VmPtr
2404 // Get the opcode and operands byte so we can get R1 and R2
2406 Opcode
= GETOPCODE (VmPtr
);
2407 Operands
= GETOPERANDS (VmPtr
);
2410 // Get the Operand 1 index (16-bit) if present
2412 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2413 Index16
= VmReadIndex16 (VmPtr
, 2);
2420 // Get the immediate data.
2422 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2423 ImmData64
= (INT64
) VmReadImmed16 (VmPtr
, Size
);
2425 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2426 ImmData64
= (INT64
) VmReadImmed32 (VmPtr
, Size
);
2428 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2429 ImmData64
= VmReadImmed64 (VmPtr
, Size
);
2435 EbcDebugSignalException (
2436 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2437 EXCEPTION_FLAG_FATAL
,
2440 return EFI_UNSUPPORTED
;
2443 // Compute the value and write back the result
2445 Op2
= (UINT64
) ((INT64
) ((UINT64
) (UINTN
) VmPtr
->Ip
) + (INT64
) ImmData64
+ Size
);
2446 if (!OPERAND1_INDIRECT (Operands
)) {
2448 // Check for illegal combination of operand1 direct with immediate data
2450 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2451 EbcDebugSignalException (
2452 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2453 EXCEPTION_FLAG_FATAL
,
2456 return EFI_UNSUPPORTED
;
2459 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (VM_REGISTER
) Op2
;
2462 // Get the address = [Rx] + Index16
2463 // Write back the result. Always a natural size write, since
2464 // we're talking addresses here.
2466 Op1
= (UINT64
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
;
2467 VmWriteMemN (VmPtr
, (UINTN
) Op1
, (UINTN
) Op2
);
2470 // Advance the instruction pointer
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
2485 MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
2487 0:7 1=>operand1 index present
2488 0:6 1=>operand2 index present
2490 @param VmPtr A pointer to a VM context.
2492 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2493 @retval EFI_SUCCESS The instruction is executed successfully.
2498 IN VM_CONTEXT
*VmPtr
2509 // Get the opcode and operand bytes
2511 Opcode
= GETOPCODE (VmPtr
);
2512 Operands
= GETOPERANDS (VmPtr
);
2514 Op1Index
= Op2Index
= 0;
2517 // Get the indexes if present.
2520 if ((Opcode
& OPCODE_M_IMMED_OP1
) !=0) {
2521 if (OPERAND1_INDIRECT (Operands
)) {
2522 Op1Index
= VmReadIndex16 (VmPtr
, 2);
2525 // Illegal form operand1 direct with index: MOVsnw R1 Index16, {@}R2
2527 EbcDebugSignalException (
2528 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2529 EXCEPTION_FLAG_FATAL
,
2532 return EFI_UNSUPPORTED
;
2535 Size
+= sizeof (UINT16
);
2538 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
2539 if (OPERAND2_INDIRECT (Operands
)) {
2540 Op2Index
= VmReadIndex16 (VmPtr
, Size
);
2542 Op2Index
= VmReadImmed16 (VmPtr
, Size
);
2545 Size
+= sizeof (UINT16
);
2548 // Get the data from the source.
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
);
2555 // Now write back the result.
2557 if (!OPERAND1_INDIRECT (Operands
)) {
2558 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = Op2
;
2560 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Op1Index
), (UINTN
) Op2
);
2563 // Advance the instruction pointer
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
2578 MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
2580 0:7 1=>operand1 index present
2581 0:6 1=>operand2 index present
2583 @param VmPtr A pointer to a VM context.
2585 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2586 @retval EFI_SUCCESS The instruction is executed successfully.
2591 IN VM_CONTEXT
*VmPtr
2602 // Get the opcode and operand bytes
2604 Opcode
= GETOPCODE (VmPtr
);
2605 Operands
= GETOPERANDS (VmPtr
);
2607 Op1Index
= Op2Index
= 0;
2610 // Get the indexes if present.
2613 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
2614 if (OPERAND1_INDIRECT (Operands
)) {
2615 Op1Index
= VmReadIndex32 (VmPtr
, 2);
2618 // Illegal form operand1 direct with index: MOVsnd R1 Index16,..
2620 EbcDebugSignalException (
2621 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2622 EXCEPTION_FLAG_FATAL
,
2625 return EFI_UNSUPPORTED
;
2628 Size
+= sizeof (UINT32
);
2631 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
2632 if (OPERAND2_INDIRECT (Operands
)) {
2633 Op2Index
= VmReadIndex32 (VmPtr
, Size
);
2635 Op2Index
= VmReadImmed32 (VmPtr
, Size
);
2638 Size
+= sizeof (UINT32
);
2641 // Get the data from the source.
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
);
2648 // Now write back the result.
2650 if (!OPERAND1_INDIRECT (Operands
)) {
2651 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = Op2
;
2653 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Op1Index
), (UINTN
) Op2
);
2656 // Advance the instruction pointer
2664 Execute the EBC PUSHn instruction
2667 PUSHn {@}R1 {Index16|Immed16}
2669 @param VmPtr A pointer to a VM context.
2671 @retval EFI_SUCCESS The instruction is executed successfully.
2676 IN VM_CONTEXT
*VmPtr
2685 // Get opcode and operands
2687 Opcode
= GETOPCODE (VmPtr
);
2688 Operands
= GETOPERANDS (VmPtr
);
2691 // Get index if present
2693 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2694 if (OPERAND1_INDIRECT (Operands
)) {
2695 Index16
= VmReadIndex16 (VmPtr
, 2);
2697 Index16
= VmReadImmed16 (VmPtr
, 2);
2706 // Get the data to push
2708 if (OPERAND1_INDIRECT (Operands
)) {
2709 DataN
= VmReadMemN (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
));
2711 DataN
= (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
);
2714 // Adjust the stack down.
2716 VmPtr
->Gpr
[0] -= sizeof (UINTN
);
2717 VmWriteMemN (VmPtr
, (UINTN
) VmPtr
->Gpr
[0], DataN
);
2723 Execute the EBC PUSH instruction.
2726 PUSH[32|64] {@}R1 {Index16|Immed16}
2728 @param VmPtr A pointer to a VM context.
2730 @retval EFI_SUCCESS The instruction is executed successfully.
2735 IN VM_CONTEXT
*VmPtr
2745 // Get opcode and operands
2747 Opcode
= GETOPCODE (VmPtr
);
2748 Operands
= GETOPERANDS (VmPtr
);
2750 // Get immediate index if present, then advance the IP.
2752 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2753 if (OPERAND1_INDIRECT (Operands
)) {
2754 Index16
= VmReadIndex16 (VmPtr
, 2);
2756 Index16
= VmReadImmed16 (VmPtr
, 2);
2765 // Get the data to push
2767 if ((Opcode
& PUSHPOP_M_64
) != 0) {
2768 if (OPERAND1_INDIRECT (Operands
)) {
2769 Data64
= VmReadMem64 (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
));
2771 Data64
= (UINT64
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
;
2774 // Adjust the stack down, then write back the data
2776 VmPtr
->Gpr
[0] -= sizeof (UINT64
);
2777 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->Gpr
[0], Data64
);
2782 if (OPERAND1_INDIRECT (Operands
)) {
2783 Data32
= VmReadMem32 (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
));
2785 Data32
= (UINT32
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
;
2788 // Adjust the stack down and write the data
2790 VmPtr
->Gpr
[0] -= sizeof (UINT32
);
2791 VmWriteMem32 (VmPtr
, (UINTN
) VmPtr
->Gpr
[0], Data32
);
2799 Execute the EBC POPn instruction.
2802 POPn {@}R1 {Index16|Immed16}
2804 @param VmPtr A pointer to a VM context.
2806 @retval EFI_SUCCESS The instruction is executed successfully.
2811 IN VM_CONTEXT
*VmPtr
2820 // Get opcode and operands
2822 Opcode
= GETOPCODE (VmPtr
);
2823 Operands
= GETOPERANDS (VmPtr
);
2825 // Get immediate data if present, and advance the IP
2827 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2828 if (OPERAND1_INDIRECT (Operands
)) {
2829 Index16
= VmReadIndex16 (VmPtr
, 2);
2831 Index16
= VmReadImmed16 (VmPtr
, 2);
2840 // Read the data off the stack, then adjust the stack pointer
2842 DataN
= VmReadMemN (VmPtr
, (UINTN
) VmPtr
->Gpr
[0]);
2843 VmPtr
->Gpr
[0] += sizeof (UINTN
);
2845 // Do the write-back
2847 if (OPERAND1_INDIRECT (Operands
)) {
2848 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
), DataN
);
2850 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (INT64
) (UINT64
) ((UINTN
) DataN
+ Index16
);
2858 Execute the EBC POP instruction.
2861 POPn {@}R1 {Index16|Immed16}
2863 @param VmPtr A pointer to a VM context.
2865 @retval EFI_SUCCESS The instruction is executed successfully.
2870 IN VM_CONTEXT
*VmPtr
2880 // Get opcode and operands
2882 Opcode
= GETOPCODE (VmPtr
);
2883 Operands
= GETOPERANDS (VmPtr
);
2885 // Get immediate data if present, and advance the IP.
2887 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2888 if (OPERAND1_INDIRECT (Operands
)) {
2889 Index16
= VmReadIndex16 (VmPtr
, 2);
2891 Index16
= VmReadImmed16 (VmPtr
, 2);
2900 // Get the data off the stack, then write it to the appropriate location
2902 if ((Opcode
& PUSHPOP_M_64
) != 0) {
2904 // Read the data off the stack, then adjust the stack pointer
2906 Data64
= VmReadMem64 (VmPtr
, (UINTN
) VmPtr
->Gpr
[0]);
2907 VmPtr
->Gpr
[0] += sizeof (UINT64
);
2909 // Do the write-back
2911 if (OPERAND1_INDIRECT (Operands
)) {
2912 VmWriteMem64 (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
), Data64
);
2914 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = Data64
+ Index16
;
2918 // 32-bit pop. Read it off the stack and adjust the stack pointer
2920 Data32
= (INT32
) VmReadMem32 (VmPtr
, (UINTN
) VmPtr
->Gpr
[0]);
2921 VmPtr
->Gpr
[0] += sizeof (UINT32
);
2923 // Do the write-back
2925 if (OPERAND1_INDIRECT (Operands
)) {
2926 VmWriteMem32 (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
), Data32
);
2928 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (INT64
) Data32
+ Index16
;
2937 Implements the EBC CALL instruction.
2941 CALL32 {@}R1 {Immed32|Index32}
2943 CALLEX16 {@}R1 {Immed32}
2945 If Rx == R0, then it's a PC relative call to PC = PC + imm32.
2947 @param VmPtr A pointer to a VM context.
2949 @retval EFI_SUCCESS The instruction is executed successfully.
2954 IN VM_CONTEXT
*VmPtr
2965 // Get opcode and operands
2967 Opcode
= GETOPCODE (VmPtr
);
2968 Operands
= GETOPERANDS (VmPtr
);
2970 // Assign these as well to avoid compiler warnings
2975 FramePtr
= VmPtr
->FramePtr
;
2977 // Determine the instruction size, and get immediate data if present
2979 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
2980 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
2981 Immed64
= VmReadImmed64 (VmPtr
, 2);
2985 // If register operand is indirect, then the immediate data is an index
2987 if (OPERAND1_INDIRECT (Operands
)) {
2988 Immed32
= VmReadIndex32 (VmPtr
, 2);
2990 Immed32
= VmReadImmed32 (VmPtr
, 2);
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.
3002 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3004 VmWriteMemN (VmPtr
, (UINTN
) VmPtr
->Gpr
[0], (UINTN
) FramePtr
);
3005 VmPtr
->FramePtr
= (VOID
*) (UINTN
) VmPtr
->Gpr
[0];
3007 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->Gpr
[0], (UINT64
) (UINTN
) (VmPtr
->Ip
+ Size
));
3010 // If 64-bit data, then absolute jump only
3012 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
3014 // Native or EBC call?
3016 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3017 VmPtr
->Ip
= (VMIP
) (UINTN
) Immed64
;
3020 // Call external function, get the return value, and advance the IP
3022 EbcLLCALLEX (VmPtr
, (UINTN
) Immed64
, (UINTN
) VmPtr
->Gpr
[0], FramePtr
, Size
);
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.
3030 if (OPERAND1_REGNUM (Operands
) != 0) {
3031 Immed64
= (UINT64
) (UINTN
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)];
3034 // Get final address
3036 if (OPERAND1_INDIRECT (Operands
)) {
3037 Immed64
= (INT64
) (UINT64
) (UINTN
) VmReadMemN (VmPtr
, (UINTN
) (Immed64
+ Immed32
));
3042 // Now determine if external call, and then if relative or absolute
3044 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3046 // EBC call. Relative or absolute? If relative, then it's relative to the
3047 // start of the next instruction.
3049 if ((Operands
& OPERAND_M_RELATIVE_ADDR
) != 0) {
3050 VmPtr
->Ip
+= Immed64
+ Size
;
3052 VmPtr
->Ip
= (VMIP
) (UINTN
) Immed64
;
3056 // Native call. Relative or absolute?
3058 if ((Operands
& OPERAND_M_RELATIVE_ADDR
) != 0) {
3059 EbcLLCALLEX (VmPtr
, (UINTN
) (Immed64
+ VmPtr
->Ip
+ Size
), (UINTN
) VmPtr
->Gpr
[0], FramePtr
, Size
);
3061 if ((VmPtr
->StopFlags
& STOPFLAG_BREAK_ON_CALLEX
) != 0) {
3065 EbcLLCALLEX (VmPtr
, (UINTN
) Immed64
, (UINTN
) VmPtr
->Gpr
[0], FramePtr
, Size
);
3075 Execute the EBC RET instruction.
3080 @param VmPtr A pointer to a VM context.
3082 @retval EFI_SUCCESS The instruction is executed successfully.
3087 IN VM_CONTEXT
*VmPtr
3091 // If we're at the top of the stack, then simply set the done
3094 if (VmPtr
->StackRetAddr
== (UINT64
) VmPtr
->Gpr
[0]) {
3095 VmPtr
->StopFlags
|= STOPFLAG_APP_DONE
;
3098 // Pull the return address off the VM app's stack and set the IP
3101 if (!IS_ALIGNED ((UINTN
) VmPtr
->Gpr
[0], sizeof (UINT16
))) {
3102 EbcDebugSignalException (
3103 EXCEPT_EBC_ALIGNMENT_CHECK
,
3104 EXCEPTION_FLAG_FATAL
,
3109 // Restore the IP and frame pointer from the stack
3111 VmPtr
->Ip
= (VMIP
) (UINTN
) VmReadMem64 (VmPtr
, (UINTN
) VmPtr
->Gpr
[0]);
3113 VmPtr
->FramePtr
= (VOID
*) VmReadMemN (VmPtr
, (UINTN
) VmPtr
->Gpr
[0]);
3122 Execute the EBC CMP instruction.
3125 CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
3127 @param VmPtr A pointer to a VM context.
3129 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
3130 @retval EFI_SUCCESS The instruction is executed successfully.
3135 IN VM_CONTEXT
*VmPtr
3147 // Get opcode and operands
3149 Opcode
= GETOPCODE (VmPtr
);
3150 Operands
= GETOPERANDS (VmPtr
);
3152 // Get the register data we're going to compare to
3154 Op1
= VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)];
3156 // Get immediate data
3158 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
3159 if (OPERAND2_INDIRECT (Operands
)) {
3160 Index16
= VmReadIndex16 (VmPtr
, 2);
3162 Index16
= VmReadImmed16 (VmPtr
, 2);
3173 if (OPERAND2_INDIRECT (Operands
)) {
3174 if ((Opcode
& OPCODE_M_64BIT
) != 0) {
3175 Op2
= (INT64
) VmReadMem64 (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index16
));
3178 // 32-bit operations. 0-extend the values for all cases.
3180 Op2
= (INT64
) (UINT64
) ((UINT32
) VmReadMem32 (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index16
)));
3183 Op2
= VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index16
;
3186 // Now do the compare
3189 if ((Opcode
& OPCODE_M_64BIT
) != 0) {
3193 switch (Opcode
& OPCODE_M_OPCODE
) {
3212 case OPCODE_CMPULTE
:
3213 if ((UINT64
) Op1
<= (UINT64
) Op2
) {
3218 case OPCODE_CMPUGTE
:
3219 if ((UINT64
) Op1
>= (UINT64
) Op2
) {
3231 switch (Opcode
& OPCODE_M_OPCODE
) {
3233 if ((INT32
) Op1
== (INT32
) Op2
) {
3239 if ((INT32
) Op1
<= (INT32
) Op2
) {
3245 if ((INT32
) Op1
>= (INT32
) Op2
) {
3250 case OPCODE_CMPULTE
:
3251 if ((UINT32
) Op1
<= (UINT32
) Op2
) {
3256 case OPCODE_CMPUGTE
:
3257 if ((UINT32
) Op1
>= (UINT32
) Op2
) {
3267 // Now set the flag accordingly for the comparison
3270 VMFLAG_SET (VmPtr
, VMFLAGS_CC
);
3272 VMFLAG_CLEAR (VmPtr
, (UINT64
)VMFLAGS_CC
);
3283 Execute the EBC CMPI instruction
3286 CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
3288 @param VmPtr A pointer to a VM context.
3290 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
3291 @retval EFI_SUCCESS The instruction is executed successfully.
3296 IN VM_CONTEXT
*VmPtr
3308 // Get opcode and operands
3310 Opcode
= GETOPCODE (VmPtr
);
3311 Operands
= GETOPERANDS (VmPtr
);
3314 // Get operand1 index if present
3317 if ((Operands
& OPERAND_M_CMPI_INDEX
) != 0) {
3318 Index16
= VmReadIndex16 (VmPtr
, 2);
3324 // Get operand1 data we're going to compare to
3326 Op1
= (INT64
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)];
3327 if (OPERAND1_INDIRECT (Operands
)) {
3329 // Indirect operand1. Fetch 32 or 64-bit value based on compare size.
3331 if ((Opcode
& OPCODE_M_CMPI64
) != 0) {
3332 Op1
= (INT64
) VmReadMem64 (VmPtr
, (UINTN
) Op1
+ Index16
);
3334 Op1
= (INT64
) VmReadMem32 (VmPtr
, (UINTN
) Op1
+ Index16
);
3338 // Better not have been an index with direct. That is, CMPI R1 Index,...
3341 if ((Operands
& OPERAND_M_CMPI_INDEX
) != 0) {
3342 EbcDebugSignalException (
3343 EXCEPT_EBC_INSTRUCTION_ENCODING
,
3344 EXCEPTION_FLAG_ERROR
,
3348 return EFI_UNSUPPORTED
;
3352 // Get immediate data -- 16- or 32-bit sign extended
3354 if ((Opcode
& OPCODE_M_CMPI32_DATA
) != 0) {
3355 Op2
= (INT64
) VmReadImmed32 (VmPtr
, Size
);
3359 // 16-bit immediate data. Sign extend always.
3361 Op2
= (INT64
) ((INT16
) VmReadImmed16 (VmPtr
, Size
));
3365 // Now do the compare
3368 if ((Opcode
& OPCODE_M_CMPI64
) != 0) {
3370 // 64 bit comparison
3372 switch (Opcode
& OPCODE_M_OPCODE
) {
3374 if (Op1
== (INT64
) Op2
) {
3379 case OPCODE_CMPILTE
:
3380 if (Op1
<= (INT64
) Op2
) {
3385 case OPCODE_CMPIGTE
:
3386 if (Op1
>= (INT64
) Op2
) {
3391 case OPCODE_CMPIULTE
:
3392 if ((UINT64
) Op1
<= (UINT64
) ((UINT32
) Op2
)) {
3397 case OPCODE_CMPIUGTE
:
3398 if ((UINT64
) Op1
>= (UINT64
) ((UINT32
) Op2
)) {
3408 // 32-bit comparisons
3410 switch (Opcode
& OPCODE_M_OPCODE
) {
3412 if ((INT32
) Op1
== Op2
) {
3417 case OPCODE_CMPILTE
:
3418 if ((INT32
) Op1
<= Op2
) {
3423 case OPCODE_CMPIGTE
:
3424 if ((INT32
) Op1
>= Op2
) {
3429 case OPCODE_CMPIULTE
:
3430 if ((UINT32
) Op1
<= (UINT32
) Op2
) {
3435 case OPCODE_CMPIUGTE
:
3436 if ((UINT32
) Op1
>= (UINT32
) Op2
) {
3446 // Now set the flag accordingly for the comparison
3449 VMFLAG_SET (VmPtr
, VMFLAGS_CC
);
3451 VMFLAG_CLEAR (VmPtr
, (UINT64
)VMFLAGS_CC
);
3462 Execute the EBC NOT instruction.s
3465 NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
3476 IN VM_CONTEXT
*VmPtr
,
3486 Execute the EBC NEG instruction.
3489 NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
3500 IN VM_CONTEXT
*VmPtr
,
3510 Execute the EBC ADD instruction.
3513 ADD[32|64] {@}R1, {@}R2 {Index16}
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
3524 IN VM_CONTEXT
*VmPtr
,
3534 Execute the EBC SUB instruction.
3537 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
3548 IN VM_CONTEXT
*VmPtr
,
3553 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3554 return (UINT64
) ((INT64
) ((INT64
) Op1
- (INT64
) Op2
));
3556 return (UINT64
) ((INT64
) ((INT32
) Op1
- (INT32
) Op2
));
3562 Execute the EBC MUL instruction.
3565 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
3576 IN VM_CONTEXT
*VmPtr
,
3581 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3582 return MultS64x64 ((INT64
)Op1
, (INT64
)Op2
);
3584 return (UINT64
) ((INT64
) ((INT32
) Op1
* (INT32
) Op2
));
3590 Execute the EBC MULU instruction
3593 MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
3599 @return (unsigned)Op1 * (unsigned)Op2
3604 IN VM_CONTEXT
*VmPtr
,
3609 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3610 return MultU64x64 (Op1
, Op2
);
3612 return (UINT64
) ((UINT32
) Op1
* (UINT32
) Op2
);
3618 Execute the EBC DIV instruction.
3621 DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
3632 IN VM_CONTEXT
*VmPtr
,
3640 // Check for divide-by-0
3643 EbcDebugSignalException (
3644 EXCEPT_EBC_DIVIDE_ERROR
,
3645 EXCEPTION_FLAG_FATAL
,
3651 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3652 return (UINT64
) (DivS64x64Remainder (Op1
, Op2
, &Remainder
));
3654 return (UINT64
) ((INT64
) ((INT32
) Op1
/ (INT32
) Op2
));
3661 Execute the EBC DIVU instruction
3664 DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
3670 @return (unsigned)Op1 / (unsigned)Op2
3675 IN VM_CONTEXT
*VmPtr
,
3683 // Check for divide-by-0
3686 EbcDebugSignalException (
3687 EXCEPT_EBC_DIVIDE_ERROR
,
3688 EXCEPTION_FLAG_FATAL
,
3694 // Get the destination register
3696 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3697 return (UINT64
) (DivU64x64Remainder (Op1
, Op2
, &Remainder
));
3699 return (UINT64
) ((UINT32
) Op1
/ (UINT32
) Op2
);
3706 Execute the EBC MOD instruction.
3709 MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
3715 @return Op1 MODULUS Op2
3720 IN VM_CONTEXT
*VmPtr
,
3728 // Check for divide-by-0
3731 EbcDebugSignalException (
3732 EXCEPT_EBC_DIVIDE_ERROR
,
3733 EXCEPTION_FLAG_FATAL
,
3738 DivS64x64Remainder ((INT64
)Op1
, (INT64
)Op2
, &Remainder
);
3745 Execute the EBC MODU instruction.
3748 MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
3754 @return Op1 UNSIGNED_MODULUS Op2
3759 IN VM_CONTEXT
*VmPtr
,
3767 // Check for divide-by-0
3770 EbcDebugSignalException (
3771 EXCEPT_EBC_DIVIDE_ERROR
,
3772 EXCEPTION_FLAG_FATAL
,
3777 DivU64x64Remainder (Op1
, Op2
, &Remainder
);
3784 Execute the EBC AND instruction.
3787 AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
3798 IN VM_CONTEXT
*VmPtr
,
3808 Execute the EBC OR instruction.
3811 OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
3822 IN VM_CONTEXT
*VmPtr
,
3832 Execute the EBC XOR instruction.
3835 XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
3846 IN VM_CONTEXT
*VmPtr
,
3856 Execute the EBC SHL shift left instruction.
3859 SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
3870 IN VM_CONTEXT
*VmPtr
,
3875 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3876 return LShiftU64 (Op1
, (UINTN
)Op2
);
3878 return (UINT64
) ((UINT32
) ((UINT32
) Op1
<< (UINT32
) Op2
));
3884 Execute the EBC SHR instruction.
3887 SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
3893 @return Op1 >> Op2 (unsigned operands)
3898 IN VM_CONTEXT
*VmPtr
,
3903 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3904 return RShiftU64 (Op1
, (UINTN
)Op2
);
3906 return (UINT64
) ((UINT32
) Op1
>> (UINT32
) Op2
);
3912 Execute the EBC ASHR instruction.
3915 ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
3921 @return Op1 >> Op2 (signed)
3926 IN VM_CONTEXT
*VmPtr
,
3931 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3932 return ARShiftU64 (Op1
, (UINTN
)Op2
);
3934 return (UINT64
) ((INT64
) ((INT32
) Op1
>> (UINT32
) Op2
));
3940 Execute the EBC EXTNDB instruction to sign-extend a byte value.
3943 EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
3949 @return (INT64)(INT8)Op2
3954 IN VM_CONTEXT
*VmPtr
,
3962 // Convert to byte, then return as 64-bit signed value to let compiler
3963 // sign-extend the value
3966 Data64
= (INT64
) Data8
;
3968 return (UINT64
) Data64
;
3973 Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
3976 EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
3982 @return (INT64)(INT16)Op2
3987 IN VM_CONTEXT
*VmPtr
,
3995 // Convert to word, then return as 64-bit signed value to let compiler
3996 // sign-extend the value
3998 Data16
= (INT16
) Op2
;
3999 Data64
= (INT64
) Data16
;
4001 return (UINT64
) Data64
;
4004 // Execute the EBC EXTNDD instruction.
4006 // Format: EXTNDD {@}Rx, {@}Ry [Index16|Immed16]
4007 // EXTNDD Dest, Source
4009 // Operation: Dest <- SignExtended((DWORD)Source))
4013 Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
4016 EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
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
4022 @return (INT64)(INT32)Op2
4027 IN VM_CONTEXT
*VmPtr
,
4035 // Convert to 32-bit value, then return as 64-bit signed value to let compiler
4036 // sign-extend the value
4038 Data32
= (INT32
) Op2
;
4039 Data64
= (INT64
) Data32
;
4041 return (UINT64
) Data64
;
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.
4054 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4056 @param VmPtr A pointer to VM context.
4058 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4059 @retval EFI_SUCCESS The instruction is executed successfully.
4063 ExecuteSignedDataManip (
4064 IN VM_CONTEXT
*VmPtr
4068 // Just call the data manipulation function with a flag indicating this
4069 // is a signed operation.
4071 return ExecuteDataManip (VmPtr
, TRUE
);
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.
4084 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4086 @param VmPtr A pointer to VM context.
4088 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4089 @retval EFI_SUCCESS The instruction is executed successfully.
4093 ExecuteUnsignedDataManip (
4094 IN VM_CONTEXT
*VmPtr
4098 // Just call the data manipulation function with a flag indicating this
4099 // is not a signed operation.
4101 return ExecuteDataManip (VmPtr
, FALSE
);
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.
4114 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4116 @param VmPtr A pointer to VM context.
4117 @param IsSignedOp Indicates whether the operand is signed or not.
4119 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4120 @retval EFI_SUCCESS The instruction is executed successfully.
4125 IN VM_CONTEXT
*VmPtr
,
4126 IN BOOLEAN IsSignedOp
4135 INTN DataManipDispatchTableIndex
;
4138 // Get opcode and operands
4140 Opcode
= GETOPCODE (VmPtr
);
4141 Operands
= GETOPERANDS (VmPtr
);
4144 // Determine if we have immediate data by the opcode
4146 if ((Opcode
& DATAMANIP_M_IMMDATA
) != 0) {
4148 // Index16 if Ry is indirect, or Immed16 if Ry direct.
4150 if (OPERAND2_INDIRECT (Operands
)) {
4151 Index16
= VmReadIndex16 (VmPtr
, 2);
4153 Index16
= VmReadImmed16 (VmPtr
, 2);
4162 // Now get operand2 (source). It's of format {@}R2 {Index16|Immed16}
4164 Op2
= (UINT64
) VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index16
;
4165 if (OPERAND2_INDIRECT (Operands
)) {
4167 // Indirect form: @R2 Index16. Fetch as 32- or 64-bit data
4169 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4170 Op2
= VmReadMem64 (VmPtr
, (UINTN
) Op2
);
4173 // Read as signed value where appropriate.
4176 Op2
= (UINT64
) (INT64
) ((INT32
) VmReadMem32 (VmPtr
, (UINTN
) Op2
));
4178 Op2
= (UINT64
) VmReadMem32 (VmPtr
, (UINTN
) Op2
);
4182 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4184 Op2
= (UINT64
) (INT64
) ((INT32
) Op2
);
4186 Op2
= (UINT64
) ((UINT32
) Op2
);
4191 // Get operand1 (destination and sometimes also an actual operand)
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
);
4200 Op1
= (UINT64
) (INT64
) ((INT32
) VmReadMem32 (VmPtr
, (UINTN
) Op1
));
4202 Op1
= (UINT64
) VmReadMem32 (VmPtr
, (UINTN
) Op1
);
4206 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4208 Op1
= (UINT64
) (INT64
) ((INT32
) Op1
);
4210 Op1
= (UINT64
) ((UINT32
) Op1
);
4215 // Dispatch to the computation function
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
,
4226 // Advance and return
4229 return EFI_UNSUPPORTED
;
4231 Op2
= mDataManipDispatchTable
[DataManipDispatchTableIndex
](VmPtr
, Op1
, Op2
);
4234 // Write back the result.
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
);
4241 VmWriteMem32 (VmPtr
, (UINTN
) Op1
, (UINT32
) Op2
);
4245 // Storage back to a register. Write back, clearing upper bits (as per
4246 // the specification) if 32-bit operation.
4248 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = Op2
;
4249 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4250 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] &= 0xFFFFFFFF;
4254 // Advance the instruction pointer
4262 Execute the EBC LOADSP instruction.
4267 @param VmPtr A pointer to a VM context.
4269 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4270 @retval EFI_SUCCESS The instruction is executed successfully.
4275 IN VM_CONTEXT
*VmPtr
4283 Operands
= GETOPERANDS (VmPtr
);
4288 switch (OPERAND1_REGNUM (Operands
)) {
4294 // Spec states that this instruction will not modify reserved bits in
4295 // the flags register.
4297 VmPtr
->Flags
= (VmPtr
->Flags
&~VMFLAGS_ALL_VALID
) | (VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] & VMFLAGS_ALL_VALID
);
4301 EbcDebugSignalException (
4302 EXCEPT_EBC_INSTRUCTION_ENCODING
,
4303 EXCEPTION_FLAG_WARNING
,
4307 return EFI_UNSUPPORTED
;
4316 Execute the EBC STORESP instruction.
4319 STORESP Rx, FLAGS|IP
4321 @param VmPtr A pointer to a VM context.
4323 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4324 @retval EFI_SUCCESS The instruction is executed successfully.
4329 IN VM_CONTEXT
*VmPtr
4337 Operands
= GETOPERANDS (VmPtr
);
4342 switch (OPERAND2_REGNUM (Operands
)) {
4348 // Retrieve the value in the flags register, then clear reserved bits
4350 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (UINT64
) (VmPtr
->Flags
& VMFLAGS_ALL_VALID
);
4354 // Get IP -- address of following instruction
4357 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (UINT64
) (UINTN
) VmPtr
->Ip
+ 2;
4361 EbcDebugSignalException (
4362 EXCEPT_EBC_INSTRUCTION_ENCODING
,
4363 EXCEPTION_FLAG_WARNING
,
4367 return EFI_UNSUPPORTED
;
4377 Decode a 16-bit index to determine the offset. Given an index value:
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
4384 Given this info, the offset can be computed by:
4385 offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
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 =
4391 @param VmPtr A pointer to VM context.
4392 @param CodeOffset Offset from IP of the location of the 16-bit index
4395 @return The decoded offset.
4400 IN VM_CONTEXT
*VmPtr
,
4401 IN UINT32 CodeOffset
4412 // First read the index from the code stream
4414 Index
= VmReadCode16 (VmPtr
, CodeOffset
);
4417 // Get the mask for NaturalUnits. First get the number of bits from the index.
4419 NBits
= (INT16
) ((Index
& 0x7000) >> 12);
4422 // Scale it for 16-bit indexes
4427 // Now using the number of bits, create a mask.
4429 Mask
= (INT16
) ((INT16
)~0 << NBits
);
4432 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4434 NaturalUnits
= (INT16
) (Index
&~Mask
);
4437 // Now compute ConstUnits
4439 ConstUnits
= (INT16
) (((Index
&~0xF000) & Mask
) >> NBits
);
4441 Offset
= (INT16
) (NaturalUnits
* sizeof (UINTN
) + ConstUnits
);
4446 if ((Index
& 0x8000) != 0) {
4448 // Do it the hard way to work around a bogus compiler warning
4450 // Offset = -1 * Offset;
4452 Offset
= (INT16
) ((INT32
) Offset
* -1);
4460 Decode a 32-bit index to determine the offset.
4462 @param VmPtr A pointer to VM context.
4463 @param CodeOffset Offset from IP of the location of the 32-bit index
4466 @return Converted index per EBC VM specification.
4471 IN VM_CONTEXT
*VmPtr
,
4472 IN UINT32 CodeOffset
4482 Index
= VmReadImmed32 (VmPtr
, CodeOffset
);
4485 // Get the mask for NaturalUnits. First get the number of bits from the index.
4487 NBits
= (Index
& 0x70000000) >> 28;
4490 // Scale it for 32-bit indexes
4495 // Now using the number of bits, create a mask.
4497 Mask
= (INT32
)~0 << NBits
;
4500 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4502 NaturalUnits
= Index
&~Mask
;
4505 // Now compute ConstUnits
4507 ConstUnits
= ((Index
&~0xF0000000) & Mask
) >> NBits
;
4509 Offset
= NaturalUnits
* sizeof (UINTN
) + ConstUnits
;
4514 if ((Index
& 0x80000000) != 0) {
4515 Offset
= Offset
* -1;
4523 Decode a 64-bit index to determine the offset.
4525 @param VmPtr A pointer to VM context.s
4526 @param CodeOffset Offset from IP of the location of the 64-bit index
4529 @return Converted index per EBC VM specification
4534 IN VM_CONTEXT
*VmPtr
,
4535 IN UINT32 CodeOffset
4545 Index
= VmReadCode64 (VmPtr
, CodeOffset
);
4548 // Get the mask for NaturalUnits. First get the number of bits from the index.
4550 NBits
= RShiftU64 ((Index
& 0x7000000000000000ULL
), 60);
4553 // Scale it for 64-bit indexes (multiply by 8 by shifting left 3)
4555 NBits
= LShiftU64 ((UINT64
)NBits
, 3);
4558 // Now using the number of bits, create a mask.
4560 Mask
= (LShiftU64 ((UINT64
)~0, (UINTN
)NBits
));
4563 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4565 NaturalUnits
= Index
&~Mask
;
4568 // Now compute ConstUnits
4570 ConstUnits
= ARShiftU64 (((Index
&~0xF000000000000000ULL
) & Mask
), (UINTN
)NBits
);
4572 Offset
= MultU64x64 ((UINT64
) NaturalUnits
, sizeof (UINTN
)) + ConstUnits
;
4577 if ((Index
& 0x8000000000000000ULL
) != 0) {
4578 Offset
= MultS64x64 (Offset
, -1);
4586 Writes 8-bit data to memory address.
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,
4592 [EBC entry point arguments]
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.
4600 @param VmPtr A pointer to a VM context.
4601 @param Addr Address to write to.
4602 @param Data Value to write to Addr.
4604 @retval EFI_SUCCESS The instruction is executed successfully.
4605 @retval Other Some error occurs when writing data to the address.
4610 IN VM_CONTEXT
*VmPtr
,
4616 // Convert the address if it's in the stack gap
4618 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4619 *(UINT8
*) Addr
= Data
;
4624 Writes 16-bit data to memory address.
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,
4630 [EBC entry point arguments]
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.
4638 @param VmPtr A pointer to a VM context.
4639 @param Addr Address to write to.
4640 @param Data Value to write to Addr.
4642 @retval EFI_SUCCESS The instruction is executed successfully.
4643 @retval Other Some error occurs when writing data to the address.
4648 IN VM_CONTEXT
*VmPtr
,
4656 // Convert the address if it's in the stack gap
4658 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4661 // Do a simple write if aligned
4663 if (IS_ALIGNED (Addr
, sizeof (UINT16
))) {
4664 *(UINT16
*) Addr
= Data
;
4667 // Write as two bytes
4670 if ((Status
= VmWriteMem8 (VmPtr
, Addr
, (UINT8
) Data
)) != EFI_SUCCESS
) {
4675 if ((Status
= VmWriteMem8 (VmPtr
, Addr
+ 1, (UINT8
) (Data
>> 8))) != EFI_SUCCESS
) {
4687 Writes 32-bit data to memory address.
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,
4693 [EBC entry point arguments]
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.
4701 @param VmPtr A pointer to a VM context.
4702 @param Addr Address to write to.
4703 @param Data Value to write to Addr.
4705 @retval EFI_SUCCESS The instruction is executed successfully.
4706 @retval Other Some error occurs when writing data to the address.
4711 IN VM_CONTEXT
*VmPtr
,
4719 // Convert the address if it's in the stack gap
4721 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4724 // Do a simple write if aligned
4726 if (IS_ALIGNED (Addr
, sizeof (UINT32
))) {
4727 *(UINT32
*) Addr
= Data
;
4730 // Write as two words
4733 if ((Status
= VmWriteMem16 (VmPtr
, Addr
, (UINT16
) Data
)) != EFI_SUCCESS
) {
4738 if ((Status
= VmWriteMem16 (VmPtr
, Addr
+ sizeof (UINT16
), (UINT16
) (Data
>> 16))) != EFI_SUCCESS
) {
4750 Writes 64-bit data to memory address.
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,
4756 [EBC entry point arguments]
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.
4764 @param VmPtr A pointer to a VM context.
4765 @param Addr Address to write to.
4766 @param Data Value to write to Addr.
4768 @retval EFI_SUCCESS The instruction is executed successfully.
4769 @retval Other Some error occurs when writing data to the address.
4774 IN VM_CONTEXT
*VmPtr
,
4782 // Convert the address if it's in the stack gap
4784 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4787 // Do a simple write if aligned
4789 if (IS_ALIGNED (Addr
, sizeof (UINT64
))) {
4790 *(UINT64
*) Addr
= Data
;
4793 // Write as two 32-bit words
4796 if ((Status
= VmWriteMem32 (VmPtr
, Addr
, (UINT32
) Data
)) != EFI_SUCCESS
) {
4801 if ((Status
= VmWriteMem32 (VmPtr
, Addr
+ sizeof (UINT32
), (UINT32
) RShiftU64(Data
, 32))) != EFI_SUCCESS
) {
4813 Writes UINTN data to memory address.
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,
4819 [EBC entry point arguments]
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.
4827 @param VmPtr A pointer to a VM context.
4828 @param Addr Address to write to.
4829 @param Data Value to write to Addr.
4831 @retval EFI_SUCCESS The instruction is executed successfully.
4832 @retval Other Some error occurs when writing data to the address.
4837 IN VM_CONTEXT
*VmPtr
,
4845 Status
= EFI_SUCCESS
;
4848 // Convert the address if it's in the stack gap
4850 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4853 // Do a simple write if aligned
4855 if (IS_ALIGNED (Addr
, sizeof (UINTN
))) {
4856 *(UINTN
*) Addr
= Data
;
4858 for (Index
= 0; Index
< sizeof (UINTN
) / sizeof (UINT32
); Index
++) {
4860 Status
= VmWriteMem32 (VmPtr
, Addr
+ Index
* sizeof (UINT32
), (UINT32
) Data
);
4862 Data
= (UINTN
) RShiftU64 ((UINT64
)Data
, 32);
4871 Reads 8-bit immediate value at the offset.
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.
4878 @param VmPtr A pointer to a VM context.
4879 @param Offset offset from IP of the code bytes to read.
4881 @return Signed data of the requested size from the specified address.
4886 IN VM_CONTEXT
*VmPtr
,
4891 // Simply return the data in flat memory space
4893 return * (INT8
*) (VmPtr
->Ip
+ Offset
);
4897 Reads 16-bit immediate value at the offset.
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.
4904 @param VmPtr A pointer to a VM context.
4905 @param Offset offset from IP of the code bytes to read.
4907 @return Signed data of the requested size from the specified address.
4912 IN VM_CONTEXT
*VmPtr
,
4917 // Read direct if aligned
4919 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (INT16
))) {
4920 return * (INT16
*) (VmPtr
->Ip
+ Offset
);
4923 // All code word reads should be aligned
4925 EbcDebugSignalException (
4926 EXCEPT_EBC_ALIGNMENT_CHECK
,
4927 EXCEPTION_FLAG_WARNING
,
4932 // Return unaligned data
4934 return (INT16
) (*(UINT8
*) (VmPtr
->Ip
+ Offset
) + (*(UINT8
*) (VmPtr
->Ip
+ Offset
+ 1) << 8));
4939 Reads 32-bit immediate value at the offset.
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.
4946 @param VmPtr A pointer to a VM context.
4947 @param Offset offset from IP of the code bytes to read.
4949 @return Signed data of the requested size from the specified address.
4954 IN VM_CONTEXT
*VmPtr
,
4961 // Read direct if aligned
4963 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT32
))) {
4964 return * (INT32
*) (VmPtr
->Ip
+ Offset
);
4967 // Return unaligned data
4969 Data
= (UINT32
) VmReadCode16 (VmPtr
, Offset
);
4970 Data
|= (UINT32
)(VmReadCode16 (VmPtr
, Offset
+ 2) << 16);
4976 Reads 64-bit immediate value at the offset.
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.
4983 @param VmPtr A pointer to a VM context.
4984 @param Offset offset from IP of the code bytes to read.
4986 @return Signed data of the requested size from the specified address.
4991 IN VM_CONTEXT
*VmPtr
,
5000 // Read direct if aligned
5002 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT64
))) {
5003 return * (UINT64
*) (VmPtr
->Ip
+ Offset
);
5006 // Return unaligned data.
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
;
5019 Reads 16-bit unsigned data from the code stream.
5021 This routine provides the ability to read raw unsigned data from the code
5024 @param VmPtr A pointer to VM context
5025 @param Offset Offset from current IP to the raw data to read.
5027 @return The raw unsigned 16-bit value from the code stream.
5032 IN VM_CONTEXT
*VmPtr
,
5037 // Read direct if aligned
5039 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT16
))) {
5040 return * (UINT16
*) (VmPtr
->Ip
+ Offset
);
5043 // All code word reads should be aligned
5045 EbcDebugSignalException (
5046 EXCEPT_EBC_ALIGNMENT_CHECK
,
5047 EXCEPTION_FLAG_WARNING
,
5052 // Return unaligned data
5054 return (UINT16
) (*(UINT8
*) (VmPtr
->Ip
+ Offset
) + (*(UINT8
*) (VmPtr
->Ip
+ Offset
+ 1) << 8));
5059 Reads 32-bit unsigned data from the code stream.
5061 This routine provides the ability to read raw unsigned data from the code
5064 @param VmPtr A pointer to VM context
5065 @param Offset Offset from current IP to the raw data to read.
5067 @return The raw unsigned 32-bit value from the code stream.
5072 IN VM_CONTEXT
*VmPtr
,
5078 // Read direct if aligned
5080 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT32
))) {
5081 return * (UINT32
*) (VmPtr
->Ip
+ Offset
);
5084 // Return unaligned data
5086 Data
= (UINT32
) VmReadCode16 (VmPtr
, Offset
);
5087 Data
|= (VmReadCode16 (VmPtr
, Offset
+ 2) << 16);
5093 Reads 64-bit unsigned data from the code stream.
5095 This routine provides the ability to read raw unsigned data from the code
5098 @param VmPtr A pointer to VM context
5099 @param Offset Offset from current IP to the raw data to read.
5101 @return The raw unsigned 64-bit value from the code stream.
5106 IN VM_CONTEXT
*VmPtr
,
5115 // Read direct if aligned
5117 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT64
))) {
5118 return * (UINT64
*) (VmPtr
->Ip
+ Offset
);
5121 // Return unaligned data.
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
;
5134 Reads 8-bit data form the memory address.
5136 @param VmPtr A pointer to VM context.
5137 @param Addr The memory address.
5139 @return The 8-bit value from the memory address.
5144 IN VM_CONTEXT
*VmPtr
,
5149 // Convert the address if it's in the stack gap
5151 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5153 // Simply return the data in flat memory space
5155 return * (UINT8
*) Addr
;
5159 Reads 16-bit data form the memory address.
5161 @param VmPtr A pointer to VM context.
5162 @param Addr The memory address.
5164 @return The 16-bit value from the memory address.
5169 IN VM_CONTEXT
*VmPtr
,
5174 // Convert the address if it's in the stack gap
5176 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5178 // Read direct if aligned
5180 if (IS_ALIGNED (Addr
, sizeof (UINT16
))) {
5181 return * (UINT16
*) Addr
;
5184 // Return unaligned data
5186 return (UINT16
) (*(UINT8
*) Addr
+ (*(UINT8
*) (Addr
+ 1) << 8));
5190 Reads 32-bit data form the memory address.
5192 @param VmPtr A pointer to VM context.
5193 @param Addr The memory address.
5195 @return The 32-bit value from the memory address.
5200 IN VM_CONTEXT
*VmPtr
,
5207 // Convert the address if it's in the stack gap
5209 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5211 // Read direct if aligned
5213 if (IS_ALIGNED (Addr
, sizeof (UINT32
))) {
5214 return * (UINT32
*) Addr
;
5217 // Return unaligned data
5219 Data
= (UINT32
) VmReadMem16 (VmPtr
, Addr
);
5220 Data
|= (VmReadMem16 (VmPtr
, Addr
+ 2) << 16);
5225 Reads 64-bit data form the memory address.
5227 @param VmPtr A pointer to VM context.
5228 @param Addr The memory address.
5230 @return The 64-bit value from the memory address.
5235 IN VM_CONTEXT
*VmPtr
,
5243 // Convert the address if it's in the stack gap
5245 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5248 // Read direct if aligned
5250 if (IS_ALIGNED (Addr
, sizeof (UINT64
))) {
5251 return * (UINT64
*) Addr
;
5254 // Return unaligned data. Assume little endian.
5256 Data32
= VmReadMem32 (VmPtr
, Addr
);
5257 Data
= (UINT64
) VmReadMem32 (VmPtr
, Addr
+ sizeof (UINT32
));
5258 Data
= LShiftU64 (Data
, 32) | Data32
;
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]
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.
5275 @param VmPtr A Pointer to VM context.
5276 @param Addr Address of interest
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.
5284 IN VM_CONTEXT
*VmPtr
,
5288 ASSERT(((Addr
< VmPtr
->LowStackTop
) || (Addr
> VmPtr
->HighStackBottom
)));
5294 Read a natural value from memory. May or may not be aligned.
5296 @param VmPtr current VM context
5297 @param Addr the address to read from
5299 @return The natural value at address Addr.
5304 IN VM_CONTEXT
*VmPtr
,
5309 volatile UINT32 Size
;
5313 // Convert the address if it's in the stack gap
5315 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5317 // Read direct if aligned
5319 if (IS_ALIGNED (Addr
, sizeof (UINTN
))) {
5320 return * (UINTN
*) Addr
;
5323 // Return unaligned data
5326 FromPtr
= (UINT8
*) Addr
;
5327 ToPtr
= (UINT8
*) &Data
;
5329 for (Size
= 0; Size
< sizeof (Data
); Size
++) {
5339 Returns the version of the EBC virtual machine.
5341 @return The 64-bit version of EBC virtual machine.
5349 return (UINT64
) (((VM_MAJOR_VERSION
& 0xFFFF) << 16) | ((VM_MINOR_VERSION
& 0xFFFF)));