2 Contains code that implements the virtual machine.
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "EbcExecute.h"
11 #include "EbcDebuggerHook.h"
15 // Define some useful data size constants to allow switch statements based on
16 // size of operands or data.
18 #define DATA_SIZE_INVALID 0
20 #define DATA_SIZE_16 2
21 #define DATA_SIZE_32 4
22 #define DATA_SIZE_64 8
23 #define DATA_SIZE_N 48 // 4 or 8
25 // Structure we'll use to dispatch opcodes to execute functions.
28 EFI_STATUS (*ExecuteFunction
) (IN VM_CONTEXT
* VmPtr
);
34 (*DATA_MANIP_EXEC_FUNCTION
) (
35 IN VM_CONTEXT
* VmPtr
,
41 Decode a 16-bit index to determine the offset. Given an index value:
44 b14:12 - number of bits in this index assigned to natural units (=a)
45 ba:11 - constant units = ConstUnits
46 b0:a - natural units = NaturalUnits
48 Given this info, the offset can be computed by:
49 offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
51 Max offset is achieved with index = 0x7FFF giving an offset of
52 0x27B (32-bit machine) or 0x477 (64-bit machine).
53 Min offset is achieved with index =
55 @param VmPtr A pointer to VM context.
56 @param CodeOffset Offset from IP of the location of the 16-bit index
59 @return The decoded offset.
69 Decode a 32-bit index to determine the offset.
71 @param VmPtr A pointer to VM context.
72 @param CodeOffset Offset from IP of the location of the 32-bit index
75 @return Converted index per EBC VM specification.
85 Decode a 64-bit index to determine the offset.
87 @param VmPtr A pointer to VM context.s
88 @param CodeOffset Offset from IP of the location of the 64-bit index
91 @return Converted index per EBC VM specification
101 Reads 8-bit data form the memory address.
103 @param VmPtr A pointer to VM context.
104 @param Addr The memory address.
106 @return The 8-bit value from the memory address.
111 IN VM_CONTEXT
*VmPtr
,
116 Reads 16-bit data form the memory address.
118 @param VmPtr A pointer to VM context.
119 @param Addr The memory address.
121 @return The 16-bit value from the memory address.
126 IN VM_CONTEXT
*VmPtr
,
131 Reads 32-bit data form the memory address.
133 @param VmPtr A pointer to VM context.
134 @param Addr The memory address.
136 @return The 32-bit value from the memory address.
141 IN VM_CONTEXT
*VmPtr
,
146 Reads 64-bit data form the memory address.
148 @param VmPtr A pointer to VM context.
149 @param Addr The memory address.
151 @return The 64-bit value from the memory address.
156 IN VM_CONTEXT
*VmPtr
,
161 Read a natural value from memory. May or may not be aligned.
163 @param VmPtr current VM context
164 @param Addr the address to read from
166 @return The natural value at address Addr.
171 IN VM_CONTEXT
*VmPtr
,
176 Writes 8-bit data to memory address.
178 This routine is called by the EBC data
179 movement instructions that write to memory. Since these writes
180 may be to the stack, which looks like (high address on top) this,
182 [EBC entry point arguments]
186 we need to detect all attempts to write to the EBC entry point argument
187 stack area and adjust the address (which will initially point into the
188 VM stack) to point into the EBC entry point arguments.
190 @param VmPtr A pointer to a VM context.
191 @param Addr Address to write to.
192 @param Data Value to write to Addr.
194 @retval EFI_SUCCESS The instruction is executed successfully.
195 @retval Other Some error occurs when writing data to the address.
200 IN VM_CONTEXT
*VmPtr
,
206 Writes 16-bit data to memory address.
208 This routine is called by the EBC data
209 movement instructions that write to memory. Since these writes
210 may be to the stack, which looks like (high address on top) this,
212 [EBC entry point arguments]
216 we need to detect all attempts to write to the EBC entry point argument
217 stack area and adjust the address (which will initially point into the
218 VM stack) to point into the EBC entry point arguments.
220 @param VmPtr A pointer to a VM context.
221 @param Addr Address to write to.
222 @param Data Value to write to Addr.
224 @retval EFI_SUCCESS The instruction is executed successfully.
225 @retval Other Some error occurs when writing data to the address.
230 IN VM_CONTEXT
*VmPtr
,
236 Writes 32-bit data to memory address.
238 This routine is called by the EBC data
239 movement instructions that write to memory. Since these writes
240 may be to the stack, which looks like (high address on top) this,
242 [EBC entry point arguments]
246 we need to detect all attempts to write to the EBC entry point argument
247 stack area and adjust the address (which will initially point into the
248 VM stack) to point into the EBC entry point arguments.
250 @param VmPtr A pointer to a VM context.
251 @param Addr Address to write to.
252 @param Data Value to write to Addr.
254 @retval EFI_SUCCESS The instruction is executed successfully.
255 @retval Other Some error occurs when writing data to the address.
260 IN VM_CONTEXT
*VmPtr
,
266 Reads 16-bit unsigned data from the code stream.
268 This routine provides the ability to read raw unsigned data from the code
271 @param VmPtr A pointer to VM context
272 @param Offset Offset from current IP to the raw data to read.
274 @return The raw unsigned 16-bit value from the code stream.
279 IN VM_CONTEXT
*VmPtr
,
284 Reads 32-bit unsigned data from the code stream.
286 This routine provides the ability to read raw unsigned data from the code
289 @param VmPtr A pointer to VM context
290 @param Offset Offset from current IP to the raw data to read.
292 @return The raw unsigned 32-bit value from the code stream.
297 IN VM_CONTEXT
*VmPtr
,
302 Reads 64-bit unsigned data from the code stream.
304 This routine provides the ability to read raw unsigned data from the code
307 @param VmPtr A pointer to VM context
308 @param Offset Offset from current IP to the raw data to read.
310 @return The raw unsigned 64-bit value from the code stream.
315 IN VM_CONTEXT
*VmPtr
,
320 Reads 8-bit immediate value at the offset.
322 This routine is called by the EBC execute
323 functions to read EBC immediate values from the code stream.
324 Since we can't assume alignment, each tries to read in the biggest
325 chunks size available, but will revert to smaller reads if necessary.
327 @param VmPtr A pointer to a VM context.
328 @param Offset offset from IP of the code bytes to read.
330 @return Signed data of the requested size from the specified address.
335 IN VM_CONTEXT
*VmPtr
,
340 Reads 16-bit immediate value at the offset.
342 This routine is called by the EBC execute
343 functions to read EBC immediate values from the code stream.
344 Since we can't assume alignment, each tries to read in the biggest
345 chunks size available, but will revert to smaller reads if necessary.
347 @param VmPtr A pointer to a VM context.
348 @param Offset offset from IP of the code bytes to read.
350 @return Signed data of the requested size from the specified address.
355 IN VM_CONTEXT
*VmPtr
,
360 Reads 32-bit immediate value at the offset.
362 This routine is called by the EBC execute
363 functions to read EBC immediate values from the code stream.
364 Since we can't assume alignment, each tries to read in the biggest
365 chunks size available, but will revert to smaller reads if necessary.
367 @param VmPtr A pointer to a VM context.
368 @param Offset offset from IP of the code bytes to read.
370 @return Signed data of the requested size from the specified address.
375 IN VM_CONTEXT
*VmPtr
,
380 Reads 64-bit immediate value at the offset.
382 This routine is called by the EBC execute
383 functions to read EBC immediate values from the code stream.
384 Since we can't assume alignment, each tries to read in the biggest
385 chunks size available, but will revert to smaller reads if necessary.
387 @param VmPtr A pointer to a VM context.
388 @param Offset offset from IP of the code bytes to read.
390 @return Signed data of the requested size from the specified address.
395 IN VM_CONTEXT
*VmPtr
,
400 Given an address that EBC is going to read from or write to, return
401 an appropriate address that accounts for a gap in the stack.
402 The stack for this application looks like this (high addr on top)
403 [EBC entry point arguments]
406 The EBC assumes that its arguments are at the top of its stack, which
407 is where the VM stack is really. Therefore if the EBC does memory
408 accesses into the VM stack area, then we need to convert the address
409 to point to the EBC entry point arguments area. Do this here.
411 @param VmPtr A Pointer to VM context.
412 @param Addr Address of interest
414 @return The unchanged address if it's not in the VM stack region. Otherwise,
415 adjust for the stack gap and return the modified address.
420 IN VM_CONTEXT
*VmPtr
,
425 Execute all the EBC data manipulation instructions.
426 Since the EBC data manipulation instructions all have the same basic form,
427 they can share the code that does the fetch of operands and the write-back
428 of the result. This function performs the fetch of the operands (even if
429 both are not needed to be fetched, like NOT instruction), dispatches to the
430 appropriate subfunction, then writes back the returned result.
433 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
435 @param VmPtr A pointer to VM context.
436 @param IsSignedOp Indicates whether the operand is signed or not.
438 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
439 @retval EFI_SUCCESS The instruction is executed successfully.
444 IN VM_CONTEXT
*VmPtr
,
445 IN BOOLEAN IsSignedOp
449 // Functions that execute VM opcodes
452 Execute the EBC BREAK instruction.
454 @param VmPtr A pointer to a VM context.
456 @retval EFI_SUCCESS The instruction is executed successfully.
465 Execute the JMP instruction.
469 JMP32{cs|cc} {@}R1 {Immed32|Index32}
472 b0.7 - immediate data present
473 b0.6 - 1 = 64 bit immediate data
474 0 = 32 bit immediate data
475 b1.7 - 1 = conditional
476 b1.6 1 = CS (condition set)
477 0 = CC (condition clear)
478 b1.4 1 = relative address
480 b1.3 1 = operand1 indirect
483 @param VmPtr A pointer to a VM context.
485 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
486 @retval EFI_SUCCESS The instruction is executed successfully.
495 Execute the EBC JMP8 instruction.
500 @param VmPtr A pointer to a VM context.
502 @retval EFI_SUCCESS The instruction is executed successfully.
511 Implements the EBC CALL instruction.
515 CALL32 {@}R1 {Immed32|Index32}
517 CALLEX16 {@}R1 {Immed32}
519 If Rx == R0, then it's a PC relative call to PC = PC + imm32.
521 @param VmPtr A pointer to a VM context.
523 @retval EFI_SUCCESS The instruction is executed successfully.
532 Execute the EBC RET instruction.
537 @param VmPtr A pointer to a VM context.
539 @retval EFI_SUCCESS The instruction is executed successfully.
548 Execute the EBC CMP instruction.
551 CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
553 @param VmPtr A pointer to a VM context.
555 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
556 @retval EFI_SUCCESS The instruction is executed successfully.
565 Execute the EBC CMPI instruction
568 CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
570 @param VmPtr A pointer to a VM context.
572 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
573 @retval EFI_SUCCESS The instruction is executed successfully.
582 Execute the MOVxx instructions.
586 MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
587 MOVqq {@}R1 {Index64}, {@}R2 {Index64}
589 Copies contents of [R2] -> [R1], zero extending where required.
591 First character indicates the size of the move.
592 Second character indicates the size of the index(s).
594 Invalid to have R1 direct with index.
596 @param VmPtr A pointer to a VM context.
598 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
599 @retval EFI_SUCCESS The instruction is executed successfully.
608 Execute the EBC MOVI.
612 MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
614 First variable character specifies the move size
615 Second variable character specifies size of the immediate data
617 Sign-extend the immediate data to the size of the operation, and zero-extend
618 if storing to a register.
620 Operand1 direct with index/immed is invalid.
622 @param VmPtr A pointer to a VM context.
624 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
625 @retval EFI_SUCCESS The instruction is executed successfully.
634 Execute the EBC MOV immediate natural. This instruction moves an immediate
635 index value into a register or memory location.
639 MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
641 @param VmPtr A pointer to a VM context.
643 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
644 @retval EFI_SUCCESS The instruction is executed successfully.
653 Execute the EBC MOVREL instruction.
658 MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
660 @param VmPtr A pointer to a VM context.
662 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
663 @retval EFI_SUCCESS The instruction is executed successfully.
672 Execute the EBC PUSHn instruction
675 PUSHn {@}R1 {Index16|Immed16}
677 @param VmPtr A pointer to a VM context.
679 @retval EFI_SUCCESS The instruction is executed successfully.
688 Execute the EBC PUSH instruction.
691 PUSH[32|64] {@}R1 {Index16|Immed16}
693 @param VmPtr A pointer to a VM context.
695 @retval EFI_SUCCESS The instruction is executed successfully.
704 Execute the EBC POPn instruction.
707 POPn {@}R1 {Index16|Immed16}
709 @param VmPtr A pointer to a VM context.
711 @retval EFI_SUCCESS The instruction is executed successfully.
720 Execute the EBC POP instruction.
723 POPn {@}R1 {Index16|Immed16}
725 @param VmPtr A pointer to a VM context.
727 @retval EFI_SUCCESS The instruction is executed successfully.
736 Execute all the EBC signed data manipulation instructions.
737 Since the EBC data manipulation instructions all have the same basic form,
738 they can share the code that does the fetch of operands and the write-back
739 of the result. This function performs the fetch of the operands (even if
740 both are not needed to be fetched, like NOT instruction), dispatches to the
741 appropriate subfunction, then writes back the returned result.
744 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
746 @param VmPtr A pointer to VM context.
748 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
749 @retval EFI_SUCCESS The instruction is executed successfully.
753 ExecuteSignedDataManip (
758 Execute all the EBC unsigned data manipulation instructions.
759 Since the EBC data manipulation instructions all have the same basic form,
760 they can share the code that does the fetch of operands and the write-back
761 of the result. This function performs the fetch of the operands (even if
762 both are not needed to be fetched, like NOT instruction), dispatches to the
763 appropriate subfunction, then writes back the returned result.
766 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
768 @param VmPtr A pointer to VM context.
770 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
771 @retval EFI_SUCCESS The instruction is executed successfully.
775 ExecuteUnsignedDataManip (
780 Execute the EBC LOADSP instruction.
785 @param VmPtr A pointer to a VM context.
787 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
788 @retval EFI_SUCCESS The instruction is executed successfully.
797 Execute the EBC STORESP instruction.
802 @param VmPtr A pointer to a VM context.
804 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
805 @retval EFI_SUCCESS The instruction is executed successfully.
814 Execute the EBC MOVsnw instruction. This instruction loads a signed
815 natural value from memory or register to another memory or register. On
816 32-bit machines, the value gets sign-extended to 64 bits if the destination
821 MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
823 0:7 1=>operand1 index present
824 0:6 1=>operand2 index present
826 @param VmPtr A pointer to a VM context.
828 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
829 @retval EFI_SUCCESS The instruction is executed successfully.
838 Execute the EBC MOVsnw instruction. This instruction loads a signed
839 natural value from memory or register to another memory or register. On
840 32-bit machines, the value gets sign-extended to 64 bits if the destination
845 MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
847 0:7 1=>operand1 index present
848 0:6 1=>operand2 index present
850 @param VmPtr A pointer to a VM context.
852 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
853 @retval EFI_SUCCESS The instruction is executed successfully.
862 // Data manipulation subfunctions
865 Execute the EBC NOT instruction.s
868 NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
870 @param VmPtr A pointer to a VM context.
871 @param Op1 Operand 1 from the instruction
872 @param Op2 Operand 2 from the instruction
879 IN VM_CONTEXT
*VmPtr
,
885 Execute the EBC NEG instruction.
888 NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
890 @param VmPtr A pointer to a VM context.
891 @param Op1 Operand 1 from the instruction
892 @param Op2 Operand 2 from the instruction
899 IN VM_CONTEXT
*VmPtr
,
905 Execute the EBC ADD instruction.
908 ADD[32|64] {@}R1, {@}R2 {Index16}
910 @param VmPtr A pointer to a VM context.
911 @param Op1 Operand 1 from the instruction
912 @param Op2 Operand 2 from the instruction
919 IN VM_CONTEXT
*VmPtr
,
925 Execute the EBC SUB instruction.
928 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
930 @param VmPtr A pointer to a VM context.
931 @param Op1 Operand 1 from the instruction
932 @param Op2 Operand 2 from the instruction
939 IN VM_CONTEXT
*VmPtr
,
945 Execute the EBC MUL instruction.
948 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
950 @param VmPtr A pointer to a VM context.
951 @param Op1 Operand 1 from the instruction
952 @param Op2 Operand 2 from the instruction
959 IN VM_CONTEXT
*VmPtr
,
965 Execute the EBC MULU instruction
968 MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
970 @param VmPtr A pointer to a VM context.
971 @param Op1 Operand 1 from the instruction
972 @param Op2 Operand 2 from the instruction
974 @return (unsigned)Op1 * (unsigned)Op2
979 IN VM_CONTEXT
*VmPtr
,
985 Execute the EBC DIV instruction.
988 DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
990 @param VmPtr A pointer to a VM context.
991 @param Op1 Operand 1 from the instruction
992 @param Op2 Operand 2 from the instruction
999 IN VM_CONTEXT
*VmPtr
,
1005 Execute the EBC DIVU instruction
1008 DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
1010 @param VmPtr A pointer to a VM context.
1011 @param Op1 Operand 1 from the instruction
1012 @param Op2 Operand 2 from the instruction
1014 @return (unsigned)Op1 / (unsigned)Op2
1019 IN VM_CONTEXT
*VmPtr
,
1025 Execute the EBC MOD instruction.
1028 MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
1030 @param VmPtr A pointer to a VM context.
1031 @param Op1 Operand 1 from the instruction
1032 @param Op2 Operand 2 from the instruction
1034 @return Op1 MODULUS Op2
1039 IN VM_CONTEXT
*VmPtr
,
1045 Execute the EBC MODU instruction.
1048 MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
1050 @param VmPtr A pointer to a VM context.
1051 @param Op1 Operand 1 from the instruction
1052 @param Op2 Operand 2 from the instruction
1054 @return Op1 UNSIGNED_MODULUS Op2
1059 IN VM_CONTEXT
*VmPtr
,
1065 Execute the EBC AND instruction.
1068 AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
1070 @param VmPtr A pointer to a VM context.
1071 @param Op1 Operand 1 from the instruction
1072 @param Op2 Operand 2 from the instruction
1079 IN VM_CONTEXT
*VmPtr
,
1085 Execute the EBC OR instruction.
1088 OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1090 @param VmPtr A pointer to a VM context.
1091 @param Op1 Operand 1 from the instruction
1092 @param Op2 Operand 2 from the instruction
1099 IN VM_CONTEXT
*VmPtr
,
1105 Execute the EBC XOR instruction.
1108 XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1110 @param VmPtr A pointer to a VM context.
1111 @param Op1 Operand 1 from the instruction
1112 @param Op2 Operand 2 from the instruction
1119 IN VM_CONTEXT
*VmPtr
,
1125 Execute the EBC SHL shift left instruction.
1128 SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
1130 @param VmPtr A pointer to a VM context.
1131 @param Op1 Operand 1 from the instruction
1132 @param Op2 Operand 2 from the instruction
1139 IN VM_CONTEXT
*VmPtr
,
1145 Execute the EBC SHR instruction.
1148 SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1150 @param VmPtr A pointer to a VM context.
1151 @param Op1 Operand 1 from the instruction
1152 @param Op2 Operand 2 from the instruction
1154 @return Op1 >> Op2 (unsigned operands)
1159 IN VM_CONTEXT
*VmPtr
,
1165 Execute the EBC ASHR instruction.
1168 ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1170 @param VmPtr A pointer to a VM context.
1171 @param Op1 Operand 1 from the instruction
1172 @param Op2 Operand 2 from the instruction
1174 @return Op1 >> Op2 (signed)
1179 IN VM_CONTEXT
*VmPtr
,
1185 Execute the EBC EXTNDB instruction to sign-extend a byte value.
1188 EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
1190 @param VmPtr A pointer to a VM context.
1191 @param Op1 Operand 1 from the instruction
1192 @param Op2 Operand 2 from the instruction
1194 @return (INT64)(INT8)Op2
1199 IN VM_CONTEXT
*VmPtr
,
1205 Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
1208 EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
1210 @param VmPtr A pointer to a VM context.
1211 @param Op1 Operand 1 from the instruction
1212 @param Op2 Operand 2 from the instruction
1214 @return (INT64)(INT16)Op2
1219 IN VM_CONTEXT
*VmPtr
,
1225 Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
1228 EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
1230 @param VmPtr A pointer to a VM context.
1231 @param Op1 Operand 1 from the instruction
1232 @param Op2 Operand 2 from the instruction
1234 @return (INT64)(INT32)Op2
1239 IN VM_CONTEXT
*VmPtr
,
1245 // Once we retrieve the operands for the data manipulation instructions,
1246 // call these functions to perform the operation.
1248 CONST DATA_MANIP_EXEC_FUNCTION mDataManipDispatchTable
[] = {
1270 CONST VM_TABLE_ENTRY mVmOpcodeTable
[] = {
1271 { ExecuteBREAK
}, // opcode 0x00
1272 { ExecuteJMP
}, // opcode 0x01
1273 { ExecuteJMP8
}, // opcode 0x02
1274 { ExecuteCALL
}, // opcode 0x03
1275 { ExecuteRET
}, // opcode 0x04
1276 { ExecuteCMP
}, // opcode 0x05 CMPeq
1277 { ExecuteCMP
}, // opcode 0x06 CMPlte
1278 { ExecuteCMP
}, // opcode 0x07 CMPgte
1279 { ExecuteCMP
}, // opcode 0x08 CMPulte
1280 { ExecuteCMP
}, // opcode 0x09 CMPugte
1281 { ExecuteUnsignedDataManip
}, // opcode 0x0A NOT
1282 { ExecuteSignedDataManip
}, // opcode 0x0B NEG
1283 { ExecuteSignedDataManip
}, // opcode 0x0C ADD
1284 { ExecuteSignedDataManip
}, // opcode 0x0D SUB
1285 { ExecuteSignedDataManip
}, // opcode 0x0E MUL
1286 { ExecuteUnsignedDataManip
}, // opcode 0x0F MULU
1287 { ExecuteSignedDataManip
}, // opcode 0x10 DIV
1288 { ExecuteUnsignedDataManip
}, // opcode 0x11 DIVU
1289 { ExecuteSignedDataManip
}, // opcode 0x12 MOD
1290 { ExecuteUnsignedDataManip
}, // opcode 0x13 MODU
1291 { ExecuteUnsignedDataManip
}, // opcode 0x14 AND
1292 { ExecuteUnsignedDataManip
}, // opcode 0x15 OR
1293 { ExecuteUnsignedDataManip
}, // opcode 0x16 XOR
1294 { ExecuteUnsignedDataManip
}, // opcode 0x17 SHL
1295 { ExecuteUnsignedDataManip
}, // opcode 0x18 SHR
1296 { ExecuteSignedDataManip
}, // opcode 0x19 ASHR
1297 { ExecuteUnsignedDataManip
}, // opcode 0x1A EXTNDB
1298 { ExecuteUnsignedDataManip
}, // opcode 0x1B EXTNDW
1299 { ExecuteUnsignedDataManip
}, // opcode 0x1C EXTNDD
1300 { ExecuteMOVxx
}, // opcode 0x1D MOVBW
1301 { ExecuteMOVxx
}, // opcode 0x1E MOVWW
1302 { ExecuteMOVxx
}, // opcode 0x1F MOVDW
1303 { ExecuteMOVxx
}, // opcode 0x20 MOVQW
1304 { ExecuteMOVxx
}, // opcode 0x21 MOVBD
1305 { ExecuteMOVxx
}, // opcode 0x22 MOVWD
1306 { ExecuteMOVxx
}, // opcode 0x23 MOVDD
1307 { ExecuteMOVxx
}, // opcode 0x24 MOVQD
1308 { ExecuteMOVsnw
}, // opcode 0x25 MOVsnw
1309 { ExecuteMOVsnd
}, // opcode 0x26 MOVsnd
1310 { NULL
}, // opcode 0x27
1311 { ExecuteMOVxx
}, // opcode 0x28 MOVqq
1312 { ExecuteLOADSP
}, // opcode 0x29 LOADSP SP1, R2
1313 { ExecuteSTORESP
}, // opcode 0x2A STORESP R1, SP2
1314 { ExecutePUSH
}, // opcode 0x2B PUSH {@}R1 [imm16]
1315 { ExecutePOP
}, // opcode 0x2C POP {@}R1 [imm16]
1316 { ExecuteCMPI
}, // opcode 0x2D CMPIEQ
1317 { ExecuteCMPI
}, // opcode 0x2E CMPILTE
1318 { ExecuteCMPI
}, // opcode 0x2F CMPIGTE
1319 { ExecuteCMPI
}, // opcode 0x30 CMPIULTE
1320 { ExecuteCMPI
}, // opcode 0x31 CMPIUGTE
1321 { ExecuteMOVxx
}, // opcode 0x32 MOVN
1322 { ExecuteMOVxx
}, // opcode 0x33 MOVND
1323 { NULL
}, // opcode 0x34
1324 { ExecutePUSHn
}, // opcode 0x35
1325 { ExecutePOPn
}, // opcode 0x36
1326 { ExecuteMOVI
}, // opcode 0x37 - mov immediate data
1327 { ExecuteMOVIn
}, // opcode 0x38 - mov immediate natural
1328 { ExecuteMOVREL
}, // opcode 0x39 - move data relative to PC
1329 { NULL
}, // opcode 0x3a
1330 { NULL
}, // opcode 0x3b
1331 { NULL
}, // opcode 0x3c
1332 { NULL
}, // opcode 0x3d
1333 { NULL
}, // opcode 0x3e
1334 { NULL
} // opcode 0x3f
1338 // Length of JMP instructions, depending on upper two bits of opcode.
1340 CONST UINT8 mJMPLen
[] = { 2, 2, 6, 10 };
1343 Given a pointer to a new VM context, execute one or more instructions. This
1344 function is only used for test purposes via the EBC VM test protocol.
1346 @param This A pointer to the EFI_EBC_VM_TEST_PROTOCOL structure.
1347 @param VmPtr A pointer to a VM context.
1348 @param InstructionCount A pointer to a UINTN value holding the number of
1349 instructions to execute. If it holds value of 0,
1350 then the instruction to be executed is 1.
1352 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
1353 @retval EFI_SUCCESS All of the instructions are executed successfully.
1358 EbcExecuteInstructions (
1359 IN EFI_EBC_VM_TEST_PROTOCOL
*This
,
1360 IN VM_CONTEXT
*VmPtr
,
1361 IN OUT UINTN
*InstructionCount
1366 UINTN InstructionsLeft
;
1367 UINTN SavedInstructionCount
;
1369 Status
= EFI_SUCCESS
;
1371 if (*InstructionCount
== 0) {
1372 InstructionsLeft
= 1;
1374 InstructionsLeft
= *InstructionCount
;
1377 SavedInstructionCount
= *InstructionCount
;
1378 *InstructionCount
= 0;
1381 // Index into the opcode table using the opcode byte for this instruction.
1382 // This gives you the execute function, which we first test for null, then
1383 // call it if it's not null.
1385 while (InstructionsLeft
!= 0) {
1386 ExecFunc
= (UINTN
) mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction
;
1387 if (ExecFunc
== (UINTN
) NULL
) {
1388 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1389 return EFI_UNSUPPORTED
;
1391 mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction (VmPtr
);
1392 *InstructionCount
= *InstructionCount
+ 1;
1396 // Decrement counter if applicable
1398 if (SavedInstructionCount
!= 0) {
1408 Execute an EBC image from an entry point or from a published protocol.
1410 @param VmPtr A pointer to a VM context.
1412 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
1413 @retval EFI_SUCCESS All of the instructions are executed successfully.
1418 IN VM_CONTEXT
*VmPtr
1422 UINT8 StackCorrupted
;
1424 EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL
*EbcSimpleDebugger
;
1427 EbcSimpleDebugger
= NULL
;
1428 Status
= EFI_SUCCESS
;
1432 // Make sure the magic value has been put on the stack before we got here.
1434 if (*VmPtr
->StackMagicPtr
!= (UINTN
) VM_STACK_KEY_VALUE
) {
1438 VmPtr
->FramePtr
= (VOID
*) ((UINT8
*) (UINTN
) VmPtr
->Gpr
[0] + 8);
1441 // Try to get the debug support for EBC
1443 DEBUG_CODE_BEGIN ();
1444 Status
= gBS
->LocateProtocol (
1445 &gEfiEbcSimpleDebuggerProtocolGuid
,
1447 (VOID
**) &EbcSimpleDebugger
1449 if (EFI_ERROR (Status
)) {
1450 EbcSimpleDebugger
= NULL
;
1455 // Save the start IP for debug. For example, if we take an exception we
1456 // can print out the location of the exception relative to the entry point,
1457 // which could then be used in a disassembly listing to find the problem.
1459 VmPtr
->EntryPoint
= (VOID
*) VmPtr
->Ip
;
1462 // We'll wait for this flag to know when we're done. The RET
1463 // instruction sets it if it runs out of stack.
1465 VmPtr
->StopFlags
= 0;
1466 while ((VmPtr
->StopFlags
& STOPFLAG_APP_DONE
) == 0) {
1468 // If we've found a simple debugger protocol, call it
1470 DEBUG_CODE_BEGIN ();
1471 if (EbcSimpleDebugger
!= NULL
) {
1472 EbcSimpleDebugger
->Debugger (EbcSimpleDebugger
, VmPtr
);
1477 // Use the opcode bits to index into the opcode dispatch table. If the
1478 // function pointer is null then generate an exception.
1480 ExecFunc
= (UINTN
) mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction
;
1481 if (ExecFunc
== (UINTN
) NULL
) {
1482 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1483 Status
= EFI_UNSUPPORTED
;
1487 EbcDebuggerHookExecuteStart (VmPtr
);
1490 // The EBC VM is a strongly ordered processor, so perform a fence operation before
1491 // and after each instruction is executed.
1495 mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction (VmPtr
);
1499 EbcDebuggerHookExecuteEnd (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
) {
1979 EbcDebuggerHookJMPStart (VmPtr
);
1981 EbcDebuggerHookJMPEnd (VmPtr
);
1986 // Check for 64-bit form and do it right away since it's the most
1987 // straight-forward form.
1989 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
1991 // Double check for immediate-data, which is required. If not there,
1992 // then signal an exception
1994 if ((Opcode
& OPCODE_M_IMMDATA
) == 0) {
1995 EbcDebugSignalException (
1996 EXCEPT_EBC_INSTRUCTION_ENCODING
,
1997 EXCEPTION_FLAG_ERROR
,
2000 return EFI_UNSUPPORTED
;
2003 // 64-bit immediate data is full address. Read the immediate data,
2004 // check for alignment, and jump absolute.
2006 Data64
= (UINT64
) VmReadImmed64 (VmPtr
, 2);
2007 if (!IS_ALIGNED ((UINTN
) Data64
, sizeof (UINT16
))) {
2008 EbcDebugSignalException (
2009 EXCEPT_EBC_ALIGNMENT_CHECK
,
2010 EXCEPTION_FLAG_FATAL
,
2014 return EFI_UNSUPPORTED
;
2018 // Take jump -- relative or absolute
2020 EbcDebuggerHookJMPStart (VmPtr
);
2021 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2022 VmPtr
->Ip
+= (UINTN
) Data64
+ Size
;
2024 VmPtr
->Ip
= (VMIP
) (UINTN
) Data64
;
2026 EbcDebuggerHookJMPEnd (VmPtr
);
2032 // Get the index if there is one. May be either an index, or an immediate
2033 // offset depending on indirect operand.
2034 // JMP32 @R1 Index32 -- immediate data is an index
2035 // JMP32 R1 Immed32 -- immedate data is an offset
2037 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
2038 if (OPERAND1_INDIRECT (Operand
)) {
2039 Index32
= VmReadIndex32 (VmPtr
, 2);
2041 Index32
= VmReadImmed32 (VmPtr
, 2);
2047 // Get the register data. If R == 0, then special case where it's ignored.
2049 if (OPERAND1_REGNUM (Operand
) == 0) {
2052 Data64
= (UINT64
) OPERAND1_REGDATA (VmPtr
, Operand
);
2057 if (OPERAND1_INDIRECT (Operand
)) {
2059 // Form: JMP32 @Rx {Index32}
2061 Addr
= VmReadMemN (VmPtr
, (UINTN
) Data64
+ Index32
);
2062 if (!IS_ALIGNED ((UINTN
) Addr
, sizeof (UINT16
))) {
2063 EbcDebugSignalException (
2064 EXCEPT_EBC_ALIGNMENT_CHECK
,
2065 EXCEPTION_FLAG_FATAL
,
2069 return EFI_UNSUPPORTED
;
2072 EbcDebuggerHookJMPStart (VmPtr
);
2073 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2074 VmPtr
->Ip
+= (UINTN
) Addr
+ Size
;
2076 VmPtr
->Ip
= (VMIP
) Addr
;
2078 EbcDebuggerHookJMPEnd (VmPtr
);
2082 // Form: JMP32 Rx {Immed32}
2084 Addr
= (UINTN
) (Data64
+ Index32
);
2085 if (!IS_ALIGNED ((UINTN
) Addr
, sizeof (UINT16
))) {
2086 EbcDebugSignalException (
2087 EXCEPT_EBC_ALIGNMENT_CHECK
,
2088 EXCEPTION_FLAG_FATAL
,
2092 return EFI_UNSUPPORTED
;
2095 EbcDebuggerHookJMPStart (VmPtr
);
2096 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2097 VmPtr
->Ip
+= (UINTN
) Addr
+ Size
;
2099 VmPtr
->Ip
= (VMIP
) Addr
;
2101 EbcDebuggerHookJMPEnd (VmPtr
);
2110 Execute the EBC JMP8 instruction.
2113 JMP8{cs|cc} Offset/2
2115 @param VmPtr A pointer to a VM context.
2117 @retval EFI_SUCCESS The instruction is executed successfully.
2122 IN VM_CONTEXT
*VmPtr
2126 UINT8 ConditionFlag
;
2131 // Decode instruction.
2133 Opcode
= GETOPCODE (VmPtr
);
2134 CompareSet
= (UINT8
) (((Opcode
& JMP_M_CS
) != 0) ? 1 : 0);
2135 ConditionFlag
= (UINT8
) VMFLAG_ISSET (VmPtr
, VMFLAGS_CC
);
2138 // If we haven't met the condition, then simply advance the IP and return
2140 if ((Opcode
& CONDITION_M_CONDITIONAL
) != 0) {
2141 if (CompareSet
!= ConditionFlag
) {
2142 EbcDebuggerHookJMP8Start (VmPtr
);
2144 EbcDebuggerHookJMP8End (VmPtr
);
2149 // Get the offset from the instruction stream. It's relative to the
2150 // following instruction, and divided by 2.
2152 Offset
= VmReadImmed8 (VmPtr
, 1);
2154 // Want to check for offset == -2 and then raise an exception?
2156 EbcDebuggerHookJMP8Start (VmPtr
);
2157 VmPtr
->Ip
+= (Offset
* 2) + 2;
2158 EbcDebuggerHookJMP8End (VmPtr
);
2164 Execute the EBC MOVI.
2168 MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
2170 First variable character specifies the move size
2171 Second variable character specifies size of the immediate data
2173 Sign-extend the immediate data to the size of the operation, and zero-extend
2174 if storing to a register.
2176 Operand1 direct with index/immed is invalid.
2178 @param VmPtr A pointer to a VM context.
2180 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2181 @retval EFI_SUCCESS The instruction is executed successfully.
2186 IN VM_CONTEXT
*VmPtr
2198 // Get the opcode and operands byte so we can get R1 and R2
2200 Opcode
= GETOPCODE (VmPtr
);
2201 Operands
= GETOPERANDS (VmPtr
);
2204 // Get the index (16-bit) if present
2206 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2207 Index16
= VmReadIndex16 (VmPtr
, 2);
2214 // Extract the immediate data. Sign-extend always.
2216 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2217 ImmData64
= (INT64
) (INT16
) VmReadImmed16 (VmPtr
, Size
);
2219 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2220 ImmData64
= (INT64
) (INT32
) VmReadImmed32 (VmPtr
, Size
);
2222 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2223 ImmData64
= (INT64
) VmReadImmed64 (VmPtr
, Size
);
2229 EbcDebugSignalException (
2230 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2231 EXCEPTION_FLAG_FATAL
,
2234 return EFI_UNSUPPORTED
;
2237 // Now write back the result
2239 if (!OPERAND1_INDIRECT (Operands
)) {
2241 // Operand1 direct. Make sure it didn't have an index.
2243 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2244 EbcDebugSignalException (
2245 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2246 EXCEPTION_FLAG_FATAL
,
2249 return EFI_UNSUPPORTED
;
2252 // Writing directly to a register. Clear unused bits.
2254 if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH8
) {
2255 Mask64
= 0x000000FF;
2256 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH16
) {
2257 Mask64
= 0x0000FFFF;
2258 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH32
) {
2259 Mask64
= 0x00000000FFFFFFFF;
2261 Mask64
= (UINT64
)~0;
2264 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = ImmData64
& Mask64
;
2267 // Get the address then write back based on size of the move
2269 Op1
= (UINT64
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
;
2270 if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH8
) {
2271 VmWriteMem8 (VmPtr
, (UINTN
) Op1
, (UINT8
) ImmData64
);
2272 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH16
) {
2273 VmWriteMem16 (VmPtr
, (UINTN
) Op1
, (UINT16
) ImmData64
);
2274 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH32
) {
2275 VmWriteMem32 (VmPtr
, (UINTN
) Op1
, (UINT32
) ImmData64
);
2277 VmWriteMem64 (VmPtr
, (UINTN
) Op1
, (UINT64
) ImmData64
);
2281 // Advance the instruction pointer
2289 Execute the EBC MOV immediate natural. This instruction moves an immediate
2290 index value into a register or memory location.
2294 MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
2296 @param VmPtr A pointer to a VM context.
2298 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2299 @retval EFI_SUCCESS The instruction is executed successfully.
2304 IN VM_CONTEXT
*VmPtr
2317 // Get the opcode and operands byte so we can get R1 and R2
2319 Opcode
= GETOPCODE (VmPtr
);
2320 Operands
= GETOPERANDS (VmPtr
);
2323 // Get the operand1 index (16-bit) if present
2325 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2326 Index16
= VmReadIndex16 (VmPtr
, 2);
2333 // Extract the immediate data and convert to a 64-bit index.
2335 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2336 ImmedIndex16
= VmReadIndex16 (VmPtr
, Size
);
2337 ImmedIndex64
= (INT64
) ImmedIndex16
;
2339 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2340 ImmedIndex32
= VmReadIndex32 (VmPtr
, Size
);
2341 ImmedIndex64
= (INT64
) ImmedIndex32
;
2343 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2344 ImmedIndex64
= VmReadIndex64 (VmPtr
, Size
);
2350 EbcDebugSignalException (
2351 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2352 EXCEPTION_FLAG_FATAL
,
2355 return EFI_UNSUPPORTED
;
2358 // Now write back the result
2360 if (!OPERAND1_INDIRECT (Operands
)) {
2362 // Check for MOVIn R1 Index16, Immed (not indirect, with index), which
2365 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2366 EbcDebugSignalException (
2367 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2368 EXCEPTION_FLAG_FATAL
,
2371 return EFI_UNSUPPORTED
;
2374 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = ImmedIndex64
;
2379 Op1
= (UINT64
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
;
2380 VmWriteMemN (VmPtr
, (UINTN
) Op1
, (UINTN
)(INTN
) ImmedIndex64
);
2383 // Advance the instruction pointer
2391 Execute the EBC MOVREL instruction.
2392 Dest <- Ip + ImmData
2396 MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
2398 @param VmPtr A pointer to a VM context.
2400 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2401 @retval EFI_SUCCESS The instruction is executed successfully.
2406 IN VM_CONTEXT
*VmPtr
2418 // Get the opcode and operands byte so we can get R1 and R2
2420 Opcode
= GETOPCODE (VmPtr
);
2421 Operands
= GETOPERANDS (VmPtr
);
2424 // Get the Operand 1 index (16-bit) if present
2426 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2427 Index16
= VmReadIndex16 (VmPtr
, 2);
2434 // Get the immediate data.
2436 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2437 ImmData64
= (INT64
) VmReadImmed16 (VmPtr
, Size
);
2439 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2440 ImmData64
= (INT64
) VmReadImmed32 (VmPtr
, Size
);
2442 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2443 ImmData64
= VmReadImmed64 (VmPtr
, Size
);
2449 EbcDebugSignalException (
2450 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2451 EXCEPTION_FLAG_FATAL
,
2454 return EFI_UNSUPPORTED
;
2457 // Compute the value and write back the result
2459 Op2
= (UINT64
) ((INT64
) ((UINT64
) (UINTN
) VmPtr
->Ip
) + (INT64
) ImmData64
+ Size
);
2460 if (!OPERAND1_INDIRECT (Operands
)) {
2462 // Check for illegal combination of operand1 direct with immediate data
2464 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2465 EbcDebugSignalException (
2466 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2467 EXCEPTION_FLAG_FATAL
,
2470 return EFI_UNSUPPORTED
;
2473 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (VM_REGISTER
) Op2
;
2476 // Get the address = [Rx] + Index16
2477 // Write back the result. Always a natural size write, since
2478 // we're talking addresses here.
2480 Op1
= (UINT64
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
;
2481 VmWriteMemN (VmPtr
, (UINTN
) Op1
, (UINTN
) Op2
);
2484 // Advance the instruction pointer
2492 Execute the EBC MOVsnw instruction. This instruction loads a signed
2493 natural value from memory or register to another memory or register. On
2494 32-bit machines, the value gets sign-extended to 64 bits if the destination
2499 MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
2501 0:7 1=>operand1 index present
2502 0:6 1=>operand2 index present
2504 @param VmPtr A pointer to a VM context.
2506 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2507 @retval EFI_SUCCESS The instruction is executed successfully.
2512 IN VM_CONTEXT
*VmPtr
2523 // Get the opcode and operand bytes
2525 Opcode
= GETOPCODE (VmPtr
);
2526 Operands
= GETOPERANDS (VmPtr
);
2528 Op1Index
= Op2Index
= 0;
2531 // Get the indexes if present.
2534 if ((Opcode
& OPCODE_M_IMMED_OP1
) !=0) {
2535 if (OPERAND1_INDIRECT (Operands
)) {
2536 Op1Index
= VmReadIndex16 (VmPtr
, 2);
2539 // Illegal form operand1 direct with index: MOVsnw R1 Index16, {@}R2
2541 EbcDebugSignalException (
2542 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2543 EXCEPTION_FLAG_FATAL
,
2546 return EFI_UNSUPPORTED
;
2549 Size
+= sizeof (UINT16
);
2552 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
2553 if (OPERAND2_INDIRECT (Operands
)) {
2554 Op2Index
= VmReadIndex16 (VmPtr
, Size
);
2556 Op2Index
= VmReadImmed16 (VmPtr
, Size
);
2559 Size
+= sizeof (UINT16
);
2562 // Get the data from the source.
2564 Op2
= (UINT64
)(INT64
)(INTN
)(VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Op2Index
);
2565 if (OPERAND2_INDIRECT (Operands
)) {
2566 Op2
= (UINT64
)(INT64
)(INTN
)VmReadMemN (VmPtr
, (UINTN
) Op2
);
2569 // Now write back the result.
2571 if (!OPERAND1_INDIRECT (Operands
)) {
2572 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = Op2
;
2574 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Op1Index
), (UINTN
) Op2
);
2577 // Advance the instruction pointer
2585 Execute the EBC MOVsnw instruction. This instruction loads a signed
2586 natural value from memory or register to another memory or register. On
2587 32-bit machines, the value gets sign-extended to 64 bits if the destination
2592 MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
2594 0:7 1=>operand1 index present
2595 0:6 1=>operand2 index present
2597 @param VmPtr A pointer to a VM context.
2599 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2600 @retval EFI_SUCCESS The instruction is executed successfully.
2605 IN VM_CONTEXT
*VmPtr
2616 // Get the opcode and operand bytes
2618 Opcode
= GETOPCODE (VmPtr
);
2619 Operands
= GETOPERANDS (VmPtr
);
2621 Op1Index
= Op2Index
= 0;
2624 // Get the indexes if present.
2627 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
2628 if (OPERAND1_INDIRECT (Operands
)) {
2629 Op1Index
= VmReadIndex32 (VmPtr
, 2);
2632 // Illegal form operand1 direct with index: MOVsnd R1 Index16,..
2634 EbcDebugSignalException (
2635 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2636 EXCEPTION_FLAG_FATAL
,
2639 return EFI_UNSUPPORTED
;
2642 Size
+= sizeof (UINT32
);
2645 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
2646 if (OPERAND2_INDIRECT (Operands
)) {
2647 Op2Index
= VmReadIndex32 (VmPtr
, Size
);
2649 Op2Index
= VmReadImmed32 (VmPtr
, Size
);
2652 Size
+= sizeof (UINT32
);
2655 // Get the data from the source.
2657 Op2
= (UINT64
)(INT64
)(INTN
)(INT64
)(VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Op2Index
);
2658 if (OPERAND2_INDIRECT (Operands
)) {
2659 Op2
= (UINT64
)(INT64
)(INTN
)(INT64
)VmReadMemN (VmPtr
, (UINTN
) Op2
);
2662 // Now write back the result.
2664 if (!OPERAND1_INDIRECT (Operands
)) {
2665 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = Op2
;
2667 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Op1Index
), (UINTN
) Op2
);
2670 // Advance the instruction pointer
2678 Execute the EBC PUSHn instruction
2681 PUSHn {@}R1 {Index16|Immed16}
2683 @param VmPtr A pointer to a VM context.
2685 @retval EFI_SUCCESS The instruction is executed successfully.
2690 IN VM_CONTEXT
*VmPtr
2699 // Get opcode and operands
2701 Opcode
= GETOPCODE (VmPtr
);
2702 Operands
= GETOPERANDS (VmPtr
);
2705 // Get index if present
2707 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2708 if (OPERAND1_INDIRECT (Operands
)) {
2709 Index16
= VmReadIndex16 (VmPtr
, 2);
2711 Index16
= VmReadImmed16 (VmPtr
, 2);
2720 // Get the data to push
2722 if (OPERAND1_INDIRECT (Operands
)) {
2723 DataN
= VmReadMemN (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
));
2725 DataN
= (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
);
2728 // Adjust the stack down.
2730 VmPtr
->Gpr
[0] -= sizeof (UINTN
);
2731 VmWriteMemN (VmPtr
, (UINTN
) VmPtr
->Gpr
[0], DataN
);
2737 Execute the EBC PUSH instruction.
2740 PUSH[32|64] {@}R1 {Index16|Immed16}
2742 @param VmPtr A pointer to a VM context.
2744 @retval EFI_SUCCESS The instruction is executed successfully.
2749 IN VM_CONTEXT
*VmPtr
2759 // Get opcode and operands
2761 Opcode
= GETOPCODE (VmPtr
);
2762 Operands
= GETOPERANDS (VmPtr
);
2764 // Get immediate index if present, then advance the IP.
2766 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2767 if (OPERAND1_INDIRECT (Operands
)) {
2768 Index16
= VmReadIndex16 (VmPtr
, 2);
2770 Index16
= VmReadImmed16 (VmPtr
, 2);
2779 // Get the data to push
2781 if ((Opcode
& PUSHPOP_M_64
) != 0) {
2782 if (OPERAND1_INDIRECT (Operands
)) {
2783 Data64
= VmReadMem64 (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
));
2785 Data64
= (UINT64
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
;
2788 // Adjust the stack down, then write back the data
2790 VmPtr
->Gpr
[0] -= sizeof (UINT64
);
2791 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->Gpr
[0], Data64
);
2796 if (OPERAND1_INDIRECT (Operands
)) {
2797 Data32
= VmReadMem32 (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
));
2799 Data32
= (UINT32
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
;
2802 // Adjust the stack down and write the data
2804 VmPtr
->Gpr
[0] -= sizeof (UINT32
);
2805 VmWriteMem32 (VmPtr
, (UINTN
) VmPtr
->Gpr
[0], Data32
);
2813 Execute the EBC POPn instruction.
2816 POPn {@}R1 {Index16|Immed16}
2818 @param VmPtr A pointer to a VM context.
2820 @retval EFI_SUCCESS The instruction is executed successfully.
2825 IN VM_CONTEXT
*VmPtr
2834 // Get opcode and operands
2836 Opcode
= GETOPCODE (VmPtr
);
2837 Operands
= GETOPERANDS (VmPtr
);
2839 // Get immediate data if present, and advance the IP
2841 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2842 if (OPERAND1_INDIRECT (Operands
)) {
2843 Index16
= VmReadIndex16 (VmPtr
, 2);
2845 Index16
= VmReadImmed16 (VmPtr
, 2);
2854 // Read the data off the stack, then adjust the stack pointer
2856 DataN
= VmReadMemN (VmPtr
, (UINTN
) VmPtr
->Gpr
[0]);
2857 VmPtr
->Gpr
[0] += sizeof (UINTN
);
2859 // Do the write-back
2861 if (OPERAND1_INDIRECT (Operands
)) {
2862 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
), DataN
);
2864 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (INT64
) (UINT64
) (UINTN
) (DataN
+ Index16
);
2872 Execute the EBC POP instruction.
2875 POPn {@}R1 {Index16|Immed16}
2877 @param VmPtr A pointer to a VM context.
2879 @retval EFI_SUCCESS The instruction is executed successfully.
2884 IN VM_CONTEXT
*VmPtr
2894 // Get opcode and operands
2896 Opcode
= GETOPCODE (VmPtr
);
2897 Operands
= GETOPERANDS (VmPtr
);
2899 // Get immediate data if present, and advance the IP.
2901 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2902 if (OPERAND1_INDIRECT (Operands
)) {
2903 Index16
= VmReadIndex16 (VmPtr
, 2);
2905 Index16
= VmReadImmed16 (VmPtr
, 2);
2914 // Get the data off the stack, then write it to the appropriate location
2916 if ((Opcode
& PUSHPOP_M_64
) != 0) {
2918 // Read the data off the stack, then adjust the stack pointer
2920 Data64
= VmReadMem64 (VmPtr
, (UINTN
) VmPtr
->Gpr
[0]);
2921 VmPtr
->Gpr
[0] += sizeof (UINT64
);
2923 // Do the write-back
2925 if (OPERAND1_INDIRECT (Operands
)) {
2926 VmWriteMem64 (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
), Data64
);
2928 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = Data64
+ Index16
;
2932 // 32-bit pop. Read it off the stack and adjust the stack pointer
2934 Data32
= (INT32
) VmReadMem32 (VmPtr
, (UINTN
) VmPtr
->Gpr
[0]);
2935 VmPtr
->Gpr
[0] += sizeof (UINT32
);
2937 // Do the write-back
2939 if (OPERAND1_INDIRECT (Operands
)) {
2940 VmWriteMem32 (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
), Data32
);
2942 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (INT64
) Data32
+ Index16
;
2951 Implements the EBC CALL instruction.
2955 CALL32 {@}R1 {Immed32|Index32}
2957 CALLEX16 {@}R1 {Immed32}
2959 If Rx == R0, then it's a PC relative call to PC = PC + imm32.
2961 @param VmPtr A pointer to a VM context.
2963 @retval EFI_SUCCESS The instruction is executed successfully.
2968 IN VM_CONTEXT
*VmPtr
2979 // Get opcode and operands
2981 Opcode
= GETOPCODE (VmPtr
);
2982 Operands
= GETOPERANDS (VmPtr
);
2984 if ((Operands
& OPERAND_M_NATIVE_CALL
) != 0) {
2985 EbcDebuggerHookCALLEXStart (VmPtr
);
2987 EbcDebuggerHookCALLStart (VmPtr
);
2991 // Assign these as well to avoid compiler warnings
2996 FramePtr
= VmPtr
->FramePtr
;
2998 // Determine the instruction size, and get immediate data if present
3000 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
3001 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
3002 Immed64
= VmReadImmed64 (VmPtr
, 2);
3006 // If register operand is indirect, then the immediate data is an index
3008 if (OPERAND1_INDIRECT (Operands
)) {
3009 Immed32
= VmReadIndex32 (VmPtr
, 2);
3011 Immed32
= VmReadImmed32 (VmPtr
, 2);
3020 // If it's a call to EBC, adjust the stack pointer down 16 bytes and
3021 // put our return address and frame pointer on the VM stack.
3023 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3025 VmWriteMemN (VmPtr
, (UINTN
) VmPtr
->Gpr
[0], (UINTN
) FramePtr
);
3026 VmPtr
->FramePtr
= (VOID
*) (UINTN
) VmPtr
->Gpr
[0];
3028 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->Gpr
[0], (UINT64
) (UINTN
) (VmPtr
->Ip
+ Size
));
3031 // If 64-bit data, then absolute jump only
3033 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
3035 // Native or EBC call?
3037 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3038 VmPtr
->Ip
= (VMIP
) (UINTN
) Immed64
;
3041 // Call external function, get the return value, and advance the IP
3043 EbcLLCALLEX (VmPtr
, (UINTN
) Immed64
, (UINTN
) VmPtr
->Gpr
[0], FramePtr
, Size
);
3047 // Get the register data. If operand1 == 0, then ignore register and
3048 // take immediate data as relative or absolute address.
3049 // Compiler should take care of upper bits if 32-bit machine.
3051 if (OPERAND1_REGNUM (Operands
) != 0) {
3052 Immed64
= (UINT64
) (UINTN
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)];
3055 // Get final address
3057 if (OPERAND1_INDIRECT (Operands
)) {
3058 Immed64
= (INT64
) (UINT64
) (UINTN
) VmReadMemN (VmPtr
, (UINTN
) (Immed64
+ Immed32
));
3063 // Now determine if external call, and then if relative or absolute
3065 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3067 // EBC call. Relative or absolute? If relative, then it's relative to the
3068 // start of the next instruction.
3070 if ((Operands
& OPERAND_M_RELATIVE_ADDR
) != 0) {
3071 VmPtr
->Ip
+= Immed64
+ Size
;
3073 VmPtr
->Ip
= (VMIP
) (UINTN
) Immed64
;
3077 // Native call. Relative or absolute?
3079 if ((Operands
& OPERAND_M_RELATIVE_ADDR
) != 0) {
3080 EbcLLCALLEX (VmPtr
, (UINTN
) (Immed64
+ VmPtr
->Ip
+ Size
), (UINTN
) VmPtr
->Gpr
[0], FramePtr
, Size
);
3082 if ((VmPtr
->StopFlags
& STOPFLAG_BREAK_ON_CALLEX
) != 0) {
3086 EbcLLCALLEX (VmPtr
, (UINTN
) Immed64
, (UINTN
) VmPtr
->Gpr
[0], FramePtr
, Size
);
3091 if ((Operands
& OPERAND_M_NATIVE_CALL
) != 0) {
3092 EbcDebuggerHookCALLEXEnd (VmPtr
);
3094 EbcDebuggerHookCALLEnd (VmPtr
);
3102 Execute the EBC RET instruction.
3107 @param VmPtr A pointer to a VM context.
3109 @retval EFI_SUCCESS The instruction is executed successfully.
3114 IN VM_CONTEXT
*VmPtr
3118 EbcDebuggerHookRETStart (VmPtr
);
3121 // If we're at the top of the stack, then simply set the done
3124 if (VmPtr
->StackRetAddr
== (UINT64
) VmPtr
->Gpr
[0]) {
3125 VmPtr
->StopFlags
|= STOPFLAG_APP_DONE
;
3128 // Pull the return address off the VM app's stack and set the IP
3131 if (!IS_ALIGNED ((UINTN
) VmPtr
->Gpr
[0], sizeof (UINT16
))) {
3132 EbcDebugSignalException (
3133 EXCEPT_EBC_ALIGNMENT_CHECK
,
3134 EXCEPTION_FLAG_FATAL
,
3139 // Restore the IP and frame pointer from the stack
3141 VmPtr
->Ip
= (VMIP
) (UINTN
) VmReadMem64 (VmPtr
, (UINTN
) VmPtr
->Gpr
[0]);
3143 VmPtr
->FramePtr
= (VOID
*) VmReadMemN (VmPtr
, (UINTN
) VmPtr
->Gpr
[0]);
3148 EbcDebuggerHookRETEnd (VmPtr
);
3155 Execute the EBC CMP instruction.
3158 CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
3160 @param VmPtr A pointer to a VM context.
3162 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
3163 @retval EFI_SUCCESS The instruction is executed successfully.
3168 IN VM_CONTEXT
*VmPtr
3180 // Get opcode and operands
3182 Opcode
= GETOPCODE (VmPtr
);
3183 Operands
= GETOPERANDS (VmPtr
);
3185 // Get the register data we're going to compare to
3187 Op1
= VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)];
3189 // Get immediate data
3191 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
3192 if (OPERAND2_INDIRECT (Operands
)) {
3193 Index16
= VmReadIndex16 (VmPtr
, 2);
3195 Index16
= VmReadImmed16 (VmPtr
, 2);
3206 if (OPERAND2_INDIRECT (Operands
)) {
3207 if ((Opcode
& OPCODE_M_64BIT
) != 0) {
3208 Op2
= (INT64
) VmReadMem64 (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index16
));
3211 // 32-bit operations. 0-extend the values for all cases.
3213 Op2
= (INT64
) (UINT64
) ((UINT32
) VmReadMem32 (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index16
)));
3216 Op2
= VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index16
;
3219 // Now do the compare
3222 if ((Opcode
& OPCODE_M_64BIT
) != 0) {
3226 switch (Opcode
& OPCODE_M_OPCODE
) {
3245 case OPCODE_CMPULTE
:
3246 if ((UINT64
) Op1
<= (UINT64
) Op2
) {
3251 case OPCODE_CMPUGTE
:
3252 if ((UINT64
) Op1
>= (UINT64
) Op2
) {
3264 switch (Opcode
& OPCODE_M_OPCODE
) {
3266 if ((INT32
) Op1
== (INT32
) Op2
) {
3272 if ((INT32
) Op1
<= (INT32
) Op2
) {
3278 if ((INT32
) Op1
>= (INT32
) Op2
) {
3283 case OPCODE_CMPULTE
:
3284 if ((UINT32
) Op1
<= (UINT32
) Op2
) {
3289 case OPCODE_CMPUGTE
:
3290 if ((UINT32
) Op1
>= (UINT32
) Op2
) {
3300 // Now set the flag accordingly for the comparison
3303 VMFLAG_SET (VmPtr
, VMFLAGS_CC
);
3305 VMFLAG_CLEAR (VmPtr
, (UINT64
)VMFLAGS_CC
);
3316 Execute the EBC CMPI instruction
3319 CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
3321 @param VmPtr A pointer to a VM context.
3323 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
3324 @retval EFI_SUCCESS The instruction is executed successfully.
3329 IN VM_CONTEXT
*VmPtr
3341 // Get opcode and operands
3343 Opcode
= GETOPCODE (VmPtr
);
3344 Operands
= GETOPERANDS (VmPtr
);
3347 // Get operand1 index if present
3350 if ((Operands
& OPERAND_M_CMPI_INDEX
) != 0) {
3351 Index16
= VmReadIndex16 (VmPtr
, 2);
3357 // Get operand1 data we're going to compare to
3359 Op1
= (INT64
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)];
3360 if (OPERAND1_INDIRECT (Operands
)) {
3362 // Indirect operand1. Fetch 32 or 64-bit value based on compare size.
3364 if ((Opcode
& OPCODE_M_CMPI64
) != 0) {
3365 Op1
= (INT64
) VmReadMem64 (VmPtr
, (UINTN
) Op1
+ Index16
);
3367 Op1
= (INT64
) VmReadMem32 (VmPtr
, (UINTN
) Op1
+ Index16
);
3371 // Better not have been an index with direct. That is, CMPI R1 Index,...
3374 if ((Operands
& OPERAND_M_CMPI_INDEX
) != 0) {
3375 EbcDebugSignalException (
3376 EXCEPT_EBC_INSTRUCTION_ENCODING
,
3377 EXCEPTION_FLAG_ERROR
,
3381 return EFI_UNSUPPORTED
;
3385 // Get immediate data -- 16- or 32-bit sign extended
3387 if ((Opcode
& OPCODE_M_CMPI32_DATA
) != 0) {
3388 Op2
= (INT64
) VmReadImmed32 (VmPtr
, Size
);
3392 // 16-bit immediate data. Sign extend always.
3394 Op2
= (INT64
) ((INT16
) VmReadImmed16 (VmPtr
, Size
));
3398 // Now do the compare
3401 if ((Opcode
& OPCODE_M_CMPI64
) != 0) {
3403 // 64 bit comparison
3405 switch (Opcode
& OPCODE_M_OPCODE
) {
3407 if (Op1
== (INT64
) Op2
) {
3412 case OPCODE_CMPILTE
:
3413 if (Op1
<= (INT64
) Op2
) {
3418 case OPCODE_CMPIGTE
:
3419 if (Op1
>= (INT64
) Op2
) {
3424 case OPCODE_CMPIULTE
:
3425 if ((UINT64
) Op1
<= (UINT64
) ((UINT32
) Op2
)) {
3430 case OPCODE_CMPIUGTE
:
3431 if ((UINT64
) Op1
>= (UINT64
) ((UINT32
) Op2
)) {
3441 // 32-bit comparisons
3443 switch (Opcode
& OPCODE_M_OPCODE
) {
3445 if ((INT32
) Op1
== Op2
) {
3450 case OPCODE_CMPILTE
:
3451 if ((INT32
) Op1
<= Op2
) {
3456 case OPCODE_CMPIGTE
:
3457 if ((INT32
) Op1
>= Op2
) {
3462 case OPCODE_CMPIULTE
:
3463 if ((UINT32
) Op1
<= (UINT32
) Op2
) {
3468 case OPCODE_CMPIUGTE
:
3469 if ((UINT32
) Op1
>= (UINT32
) Op2
) {
3479 // Now set the flag accordingly for the comparison
3482 VMFLAG_SET (VmPtr
, VMFLAGS_CC
);
3484 VMFLAG_CLEAR (VmPtr
, (UINT64
)VMFLAGS_CC
);
3495 Execute the EBC NOT instruction.s
3498 NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
3500 @param VmPtr A pointer to a VM context.
3501 @param Op1 Operand 1 from the instruction
3502 @param Op2 Operand 2 from the instruction
3509 IN VM_CONTEXT
*VmPtr
,
3519 Execute the EBC NEG instruction.
3522 NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
3524 @param VmPtr A pointer to a VM context.
3525 @param Op1 Operand 1 from the instruction
3526 @param Op2 Operand 2 from the instruction
3533 IN VM_CONTEXT
*VmPtr
,
3543 Execute the EBC ADD instruction.
3546 ADD[32|64] {@}R1, {@}R2 {Index16}
3548 @param VmPtr A pointer to a VM context.
3549 @param Op1 Operand 1 from the instruction
3550 @param Op2 Operand 2 from the instruction
3557 IN VM_CONTEXT
*VmPtr
,
3567 Execute the EBC SUB instruction.
3570 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3572 @param VmPtr A pointer to a VM context.
3573 @param Op1 Operand 1 from the instruction
3574 @param Op2 Operand 2 from the instruction
3581 IN VM_CONTEXT
*VmPtr
,
3586 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3587 return (UINT64
) ((INT64
) ((INT64
) Op1
- (INT64
) Op2
));
3589 return (UINT64
) ((INT64
) ((INT32
) ((INT32
) Op1
- (INT32
) Op2
)));
3595 Execute the EBC MUL instruction.
3598 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3600 @param VmPtr A pointer to a VM context.
3601 @param Op1 Operand 1 from the instruction
3602 @param Op2 Operand 2 from the instruction
3609 IN VM_CONTEXT
*VmPtr
,
3614 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3615 return MultS64x64 ((INT64
)Op1
, (INT64
)Op2
);
3617 return (UINT64
) ((INT64
) ((INT32
) ((INT32
) Op1
* (INT32
) Op2
)));
3623 Execute the EBC MULU instruction
3626 MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3628 @param VmPtr A pointer to a VM context.
3629 @param Op1 Operand 1 from the instruction
3630 @param Op2 Operand 2 from the instruction
3632 @return (unsigned)Op1 * (unsigned)Op2
3637 IN VM_CONTEXT
*VmPtr
,
3642 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3643 return MultU64x64 (Op1
, Op2
);
3645 return (UINT64
) ((UINT32
) ((UINT32
) Op1
* (UINT32
) Op2
));
3651 Execute the EBC DIV instruction.
3654 DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
3656 @param VmPtr A pointer to a VM context.
3657 @param Op1 Operand 1 from the instruction
3658 @param Op2 Operand 2 from the instruction
3665 IN VM_CONTEXT
*VmPtr
,
3673 // Check for divide-by-0
3676 EbcDebugSignalException (
3677 EXCEPT_EBC_DIVIDE_ERROR
,
3678 EXCEPTION_FLAG_FATAL
,
3684 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3685 return (UINT64
) (DivS64x64Remainder (Op1
, Op2
, &Remainder
));
3687 return (UINT64
) ((INT64
) ((INT32
) Op1
/ (INT32
) Op2
));
3694 Execute the EBC DIVU instruction
3697 DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3699 @param VmPtr A pointer to a VM context.
3700 @param Op1 Operand 1 from the instruction
3701 @param Op2 Operand 2 from the instruction
3703 @return (unsigned)Op1 / (unsigned)Op2
3708 IN VM_CONTEXT
*VmPtr
,
3716 // Check for divide-by-0
3719 EbcDebugSignalException (
3720 EXCEPT_EBC_DIVIDE_ERROR
,
3721 EXCEPTION_FLAG_FATAL
,
3727 // Get the destination register
3729 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3730 return (UINT64
) (DivU64x64Remainder (Op1
, Op2
, &Remainder
));
3732 return (UINT64
) ((UINT32
) Op1
/ (UINT32
) Op2
);
3739 Execute the EBC MOD instruction.
3742 MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
3744 @param VmPtr A pointer to a VM context.
3745 @param Op1 Operand 1 from the instruction
3746 @param Op2 Operand 2 from the instruction
3748 @return Op1 MODULUS Op2
3753 IN VM_CONTEXT
*VmPtr
,
3761 // Check for divide-by-0
3764 EbcDebugSignalException (
3765 EXCEPT_EBC_DIVIDE_ERROR
,
3766 EXCEPTION_FLAG_FATAL
,
3771 DivS64x64Remainder ((INT64
)Op1
, (INT64
)Op2
, &Remainder
);
3778 Execute the EBC MODU instruction.
3781 MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3783 @param VmPtr A pointer to a VM context.
3784 @param Op1 Operand 1 from the instruction
3785 @param Op2 Operand 2 from the instruction
3787 @return Op1 UNSIGNED_MODULUS Op2
3792 IN VM_CONTEXT
*VmPtr
,
3800 // Check for divide-by-0
3803 EbcDebugSignalException (
3804 EXCEPT_EBC_DIVIDE_ERROR
,
3805 EXCEPTION_FLAG_FATAL
,
3810 DivU64x64Remainder (Op1
, Op2
, &Remainder
);
3817 Execute the EBC AND instruction.
3820 AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
3822 @param VmPtr A pointer to a VM context.
3823 @param Op1 Operand 1 from the instruction
3824 @param Op2 Operand 2 from the instruction
3831 IN VM_CONTEXT
*VmPtr
,
3841 Execute the EBC OR instruction.
3844 OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3846 @param VmPtr A pointer to a VM context.
3847 @param Op1 Operand 1 from the instruction
3848 @param Op2 Operand 2 from the instruction
3855 IN VM_CONTEXT
*VmPtr
,
3865 Execute the EBC XOR instruction.
3868 XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3870 @param VmPtr A pointer to a VM context.
3871 @param Op1 Operand 1 from the instruction
3872 @param Op2 Operand 2 from the instruction
3879 IN VM_CONTEXT
*VmPtr
,
3889 Execute the EBC SHL shift left instruction.
3892 SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
3894 @param VmPtr A pointer to a VM context.
3895 @param Op1 Operand 1 from the instruction
3896 @param Op2 Operand 2 from the instruction
3903 IN VM_CONTEXT
*VmPtr
,
3908 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3909 return LShiftU64 (Op1
, (UINTN
)Op2
);
3911 return (UINT64
) ((UINT32
) ((UINT32
) Op1
<< (UINT32
) Op2
));
3917 Execute the EBC SHR instruction.
3920 SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3922 @param VmPtr A pointer to a VM context.
3923 @param Op1 Operand 1 from the instruction
3924 @param Op2 Operand 2 from the instruction
3926 @return Op1 >> Op2 (unsigned operands)
3931 IN VM_CONTEXT
*VmPtr
,
3936 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3937 return RShiftU64 (Op1
, (UINTN
)Op2
);
3939 return (UINT64
) ((UINT32
) Op1
>> (UINT32
) Op2
);
3945 Execute the EBC ASHR instruction.
3948 ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3950 @param VmPtr A pointer to a VM context.
3951 @param Op1 Operand 1 from the instruction
3952 @param Op2 Operand 2 from the instruction
3954 @return Op1 >> Op2 (signed)
3959 IN VM_CONTEXT
*VmPtr
,
3964 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3965 return ARShiftU64 (Op1
, (UINTN
)Op2
);
3967 return (UINT64
) ((INT64
) ((INT32
) Op1
>> (UINT32
) Op2
));
3973 Execute the EBC EXTNDB instruction to sign-extend a byte value.
3976 EXTNDB[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)(INT8)Op2
3987 IN VM_CONTEXT
*VmPtr
,
3995 // Convert to byte, then return as 64-bit signed value to let compiler
3996 // sign-extend the value
3999 Data64
= (INT64
) Data8
;
4001 return (UINT64
) Data64
;
4006 Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
4009 EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
4011 @param VmPtr A pointer to a VM context.
4012 @param Op1 Operand 1 from the instruction
4013 @param Op2 Operand 2 from the instruction
4015 @return (INT64)(INT16)Op2
4020 IN VM_CONTEXT
*VmPtr
,
4028 // Convert to word, then return as 64-bit signed value to let compiler
4029 // sign-extend the value
4031 Data16
= (INT16
) Op2
;
4032 Data64
= (INT64
) Data16
;
4034 return (UINT64
) Data64
;
4037 // Execute the EBC EXTNDD instruction.
4039 // Format: EXTNDD {@}Rx, {@}Ry [Index16|Immed16]
4040 // EXTNDD Dest, Source
4042 // Operation: Dest <- SignExtended((DWORD)Source))
4046 Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
4049 EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
4051 @param VmPtr A pointer to a VM context.
4052 @param Op1 Operand 1 from the instruction
4053 @param Op2 Operand 2 from the instruction
4055 @return (INT64)(INT32)Op2
4060 IN VM_CONTEXT
*VmPtr
,
4068 // Convert to 32-bit value, then return as 64-bit signed value to let compiler
4069 // sign-extend the value
4071 Data32
= (INT32
) Op2
;
4072 Data64
= (INT64
) Data32
;
4074 return (UINT64
) Data64
;
4079 Execute all the EBC signed data manipulation instructions.
4080 Since the EBC data manipulation instructions all have the same basic form,
4081 they can share the code that does the fetch of operands and the write-back
4082 of the result. This function performs the fetch of the operands (even if
4083 both are not needed to be fetched, like NOT instruction), dispatches to the
4084 appropriate subfunction, then writes back the returned result.
4087 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4089 @param VmPtr A pointer to VM context.
4091 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4092 @retval EFI_SUCCESS The instruction is executed successfully.
4096 ExecuteSignedDataManip (
4097 IN VM_CONTEXT
*VmPtr
4101 // Just call the data manipulation function with a flag indicating this
4102 // is a signed operation.
4104 return ExecuteDataManip (VmPtr
, TRUE
);
4109 Execute all the EBC unsigned data manipulation instructions.
4110 Since the EBC data manipulation instructions all have the same basic form,
4111 they can share the code that does the fetch of operands and the write-back
4112 of the result. This function performs the fetch of the operands (even if
4113 both are not needed to be fetched, like NOT instruction), dispatches to the
4114 appropriate subfunction, then writes back the returned result.
4117 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4119 @param VmPtr A pointer to VM context.
4121 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4122 @retval EFI_SUCCESS The instruction is executed successfully.
4126 ExecuteUnsignedDataManip (
4127 IN VM_CONTEXT
*VmPtr
4131 // Just call the data manipulation function with a flag indicating this
4132 // is not a signed operation.
4134 return ExecuteDataManip (VmPtr
, FALSE
);
4139 Execute all the EBC data manipulation instructions.
4140 Since the EBC data manipulation instructions all have the same basic form,
4141 they can share the code that does the fetch of operands and the write-back
4142 of the result. This function performs the fetch of the operands (even if
4143 both are not needed to be fetched, like NOT instruction), dispatches to the
4144 appropriate subfunction, then writes back the returned result.
4147 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4149 @param VmPtr A pointer to VM context.
4150 @param IsSignedOp Indicates whether the operand is signed or not.
4152 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4153 @retval EFI_SUCCESS The instruction is executed successfully.
4158 IN VM_CONTEXT
*VmPtr
,
4159 IN BOOLEAN IsSignedOp
4168 INTN DataManipDispatchTableIndex
;
4171 // Get opcode and operands
4173 Opcode
= GETOPCODE (VmPtr
);
4174 Operands
= GETOPERANDS (VmPtr
);
4177 // Determine if we have immediate data by the opcode
4179 if ((Opcode
& DATAMANIP_M_IMMDATA
) != 0) {
4181 // Index16 if Ry is indirect, or Immed16 if Ry direct.
4183 if (OPERAND2_INDIRECT (Operands
)) {
4184 Index16
= VmReadIndex16 (VmPtr
, 2);
4186 Index16
= VmReadImmed16 (VmPtr
, 2);
4195 // Now get operand2 (source). It's of format {@}R2 {Index16|Immed16}
4197 Op2
= (UINT64
) VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index16
;
4198 if (OPERAND2_INDIRECT (Operands
)) {
4200 // Indirect form: @R2 Index16. Fetch as 32- or 64-bit data
4202 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4203 Op2
= VmReadMem64 (VmPtr
, (UINTN
) Op2
);
4206 // Read as signed value where appropriate.
4209 Op2
= (UINT64
) (INT64
) ((INT32
) VmReadMem32 (VmPtr
, (UINTN
) Op2
));
4211 Op2
= (UINT64
) VmReadMem32 (VmPtr
, (UINTN
) Op2
);
4215 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4217 Op2
= (UINT64
) (INT64
) ((INT32
) Op2
);
4219 Op2
= (UINT64
) ((UINT32
) Op2
);
4224 // Get operand1 (destination and sometimes also an actual operand)
4227 Op1
= (UINT64
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)];
4228 if (OPERAND1_INDIRECT (Operands
)) {
4229 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4230 Op1
= VmReadMem64 (VmPtr
, (UINTN
) Op1
);
4233 Op1
= (UINT64
) (INT64
) ((INT32
) VmReadMem32 (VmPtr
, (UINTN
) Op1
));
4235 Op1
= (UINT64
) VmReadMem32 (VmPtr
, (UINTN
) Op1
);
4239 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4241 Op1
= (UINT64
) (INT64
) ((INT32
) Op1
);
4243 Op1
= (UINT64
) ((UINT32
) Op1
);
4248 // Dispatch to the computation function
4250 DataManipDispatchTableIndex
= (Opcode
& OPCODE_M_OPCODE
) - OPCODE_NOT
;
4251 if ((DataManipDispatchTableIndex
< 0) ||
4252 (DataManipDispatchTableIndex
>= ARRAY_SIZE (mDataManipDispatchTable
))) {
4253 EbcDebugSignalException (
4254 EXCEPT_EBC_INVALID_OPCODE
,
4255 EXCEPTION_FLAG_ERROR
,
4259 // Advance and return
4262 return EFI_UNSUPPORTED
;
4264 Op2
= mDataManipDispatchTable
[DataManipDispatchTableIndex
](VmPtr
, Op1
, Op2
);
4267 // Write back the result.
4269 if (OPERAND1_INDIRECT (Operands
)) {
4270 Op1
= (UINT64
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)];
4271 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4272 VmWriteMem64 (VmPtr
, (UINTN
) Op1
, Op2
);
4274 VmWriteMem32 (VmPtr
, (UINTN
) Op1
, (UINT32
) Op2
);
4278 // Storage back to a register. Write back, clearing upper bits (as per
4279 // the specification) if 32-bit operation.
4281 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = Op2
;
4282 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4283 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] &= 0xFFFFFFFF;
4287 // Advance the instruction pointer
4295 Execute the EBC LOADSP instruction.
4300 @param VmPtr A pointer to a VM context.
4302 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4303 @retval EFI_SUCCESS The instruction is executed successfully.
4308 IN VM_CONTEXT
*VmPtr
4316 Operands
= GETOPERANDS (VmPtr
);
4321 switch (OPERAND1_REGNUM (Operands
)) {
4327 // Spec states that this instruction will not modify reserved bits in
4328 // the flags register.
4330 VmPtr
->Flags
= (VmPtr
->Flags
&~VMFLAGS_ALL_VALID
) | (VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] & VMFLAGS_ALL_VALID
);
4334 EbcDebugSignalException (
4335 EXCEPT_EBC_INSTRUCTION_ENCODING
,
4336 EXCEPTION_FLAG_WARNING
,
4340 return EFI_UNSUPPORTED
;
4349 Execute the EBC STORESP instruction.
4352 STORESP Rx, FLAGS|IP
4354 @param VmPtr A pointer to a VM context.
4356 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4357 @retval EFI_SUCCESS The instruction is executed successfully.
4362 IN VM_CONTEXT
*VmPtr
4370 Operands
= GETOPERANDS (VmPtr
);
4375 switch (OPERAND2_REGNUM (Operands
)) {
4381 // Retrieve the value in the flags register, then clear reserved bits
4383 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (UINT64
) (VmPtr
->Flags
& VMFLAGS_ALL_VALID
);
4387 // Get IP -- address of following instruction
4390 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (UINT64
) (UINTN
) VmPtr
->Ip
+ 2;
4394 EbcDebugSignalException (
4395 EXCEPT_EBC_INSTRUCTION_ENCODING
,
4396 EXCEPTION_FLAG_WARNING
,
4400 return EFI_UNSUPPORTED
;
4410 Decode a 16-bit index to determine the offset. Given an index value:
4413 b14:12 - number of bits in this index assigned to natural units (=a)
4414 ba:11 - constant units = ConstUnits
4415 b0:a - natural units = NaturalUnits
4417 Given this info, the offset can be computed by:
4418 offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
4420 Max offset is achieved with index = 0x7FFF giving an offset of
4421 0x27B (32-bit machine) or 0x477 (64-bit machine).
4422 Min offset is achieved with index =
4424 @param VmPtr A pointer to VM context.
4425 @param CodeOffset Offset from IP of the location of the 16-bit index
4428 @return The decoded offset.
4433 IN VM_CONTEXT
*VmPtr
,
4434 IN UINT32 CodeOffset
4445 // First read the index from the code stream
4447 Index
= VmReadCode16 (VmPtr
, CodeOffset
);
4450 // Get the mask for NaturalUnits. First get the number of bits from the index.
4452 NBits
= (INT16
) ((Index
& 0x7000) >> 12);
4455 // Scale it for 16-bit indexes
4460 // Now using the number of bits, create a mask.
4462 Mask
= (INT16
) ((INT16
)~0 << NBits
);
4465 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4467 NaturalUnits
= (INT16
) (Index
&~Mask
);
4470 // Now compute ConstUnits
4472 ConstUnits
= (INT16
) (((Index
&~0xF000) & Mask
) >> NBits
);
4474 Offset
= (INT16
) (NaturalUnits
* sizeof (UINTN
) + ConstUnits
);
4479 if ((Index
& 0x8000) != 0) {
4481 // Do it the hard way to work around a bogus compiler warning
4483 // Offset = -1 * Offset;
4485 Offset
= (INT16
) ((INT32
) Offset
* -1);
4493 Decode a 32-bit index to determine the offset.
4495 @param VmPtr A pointer to VM context.
4496 @param CodeOffset Offset from IP of the location of the 32-bit index
4499 @return Converted index per EBC VM specification.
4504 IN VM_CONTEXT
*VmPtr
,
4505 IN UINT32 CodeOffset
4515 Index
= VmReadImmed32 (VmPtr
, CodeOffset
);
4518 // Get the mask for NaturalUnits. First get the number of bits from the index.
4520 NBits
= (Index
& 0x70000000) >> 28;
4523 // Scale it for 32-bit indexes
4528 // Now using the number of bits, create a mask.
4530 Mask
= (INT32
)~0 << NBits
;
4533 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4535 NaturalUnits
= Index
&~Mask
;
4538 // Now compute ConstUnits
4540 ConstUnits
= ((Index
&~0xF0000000) & Mask
) >> NBits
;
4542 Offset
= NaturalUnits
* sizeof (UINTN
) + ConstUnits
;
4547 if ((Index
& 0x80000000) != 0) {
4548 Offset
= Offset
* -1;
4556 Decode a 64-bit index to determine the offset.
4558 @param VmPtr A pointer to VM context.s
4559 @param CodeOffset Offset from IP of the location of the 64-bit index
4562 @return Converted index per EBC VM specification
4567 IN VM_CONTEXT
*VmPtr
,
4568 IN UINT32 CodeOffset
4578 Index
= VmReadCode64 (VmPtr
, CodeOffset
);
4581 // Get the mask for NaturalUnits. First get the number of bits from the index.
4583 NBits
= RShiftU64 ((Index
& 0x7000000000000000ULL
), 60);
4586 // Scale it for 64-bit indexes (multiply by 8 by shifting left 3)
4588 NBits
= LShiftU64 ((UINT64
)NBits
, 3);
4591 // Now using the number of bits, create a mask.
4593 Mask
= (LShiftU64 ((UINT64
)~0, (UINTN
)NBits
));
4596 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4598 NaturalUnits
= Index
&~Mask
;
4601 // Now compute ConstUnits
4603 ConstUnits
= ARShiftU64 (((Index
&~0xF000000000000000ULL
) & Mask
), (UINTN
)NBits
);
4605 Offset
= MultU64x64 ((UINT64
) NaturalUnits
, sizeof (UINTN
)) + ConstUnits
;
4610 if ((Index
& 0x8000000000000000ULL
) != 0) {
4611 Offset
= MultS64x64 (Offset
, -1);
4619 Writes 8-bit data to memory address.
4621 This routine is called by the EBC data
4622 movement instructions that write to memory. Since these writes
4623 may be to the stack, which looks like (high address on top) this,
4625 [EBC entry point arguments]
4629 we need to detect all attempts to write to the EBC entry point argument
4630 stack area and adjust the address (which will initially point into the
4631 VM stack) to point into the EBC entry point arguments.
4633 @param VmPtr A pointer to a VM context.
4634 @param Addr Address to write to.
4635 @param Data Value to write to Addr.
4637 @retval EFI_SUCCESS The instruction is executed successfully.
4638 @retval Other Some error occurs when writing data to the address.
4643 IN VM_CONTEXT
*VmPtr
,
4649 // Convert the address if it's in the stack gap
4651 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4652 *(UINT8
*) Addr
= Data
;
4657 Writes 16-bit data to memory address.
4659 This routine is called by the EBC data
4660 movement instructions that write to memory. Since these writes
4661 may be to the stack, which looks like (high address on top) this,
4663 [EBC entry point arguments]
4667 we need to detect all attempts to write to the EBC entry point argument
4668 stack area and adjust the address (which will initially point into the
4669 VM stack) to point into the EBC entry point arguments.
4671 @param VmPtr A pointer to a VM context.
4672 @param Addr Address to write to.
4673 @param Data Value to write to Addr.
4675 @retval EFI_SUCCESS The instruction is executed successfully.
4676 @retval Other Some error occurs when writing data to the address.
4681 IN VM_CONTEXT
*VmPtr
,
4689 // Convert the address if it's in the stack gap
4691 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4694 // Do a simple write if aligned
4696 if (IS_ALIGNED (Addr
, sizeof (UINT16
))) {
4697 *(UINT16
*) Addr
= Data
;
4700 // Write as two bytes
4703 if ((Status
= VmWriteMem8 (VmPtr
, Addr
, (UINT8
) Data
)) != EFI_SUCCESS
) {
4708 if ((Status
= VmWriteMem8 (VmPtr
, Addr
+ 1, (UINT8
) (Data
>> 8))) != EFI_SUCCESS
) {
4720 Writes 32-bit data to memory address.
4722 This routine is called by the EBC data
4723 movement instructions that write to memory. Since these writes
4724 may be to the stack, which looks like (high address on top) this,
4726 [EBC entry point arguments]
4730 we need to detect all attempts to write to the EBC entry point argument
4731 stack area and adjust the address (which will initially point into the
4732 VM stack) to point into the EBC entry point arguments.
4734 @param VmPtr A pointer to a VM context.
4735 @param Addr Address to write to.
4736 @param Data Value to write to Addr.
4738 @retval EFI_SUCCESS The instruction is executed successfully.
4739 @retval Other Some error occurs when writing data to the address.
4744 IN VM_CONTEXT
*VmPtr
,
4752 // Convert the address if it's in the stack gap
4754 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4757 // Do a simple write if aligned
4759 if (IS_ALIGNED (Addr
, sizeof (UINT32
))) {
4760 *(UINT32
*) Addr
= Data
;
4763 // Write as two words
4766 if ((Status
= VmWriteMem16 (VmPtr
, Addr
, (UINT16
) Data
)) != EFI_SUCCESS
) {
4771 if ((Status
= VmWriteMem16 (VmPtr
, Addr
+ sizeof (UINT16
), (UINT16
) (Data
>> 16))) != EFI_SUCCESS
) {
4783 Writes 64-bit data to memory address.
4785 This routine is called by the EBC data
4786 movement instructions that write to memory. Since these writes
4787 may be to the stack, which looks like (high address on top) this,
4789 [EBC entry point arguments]
4793 we need to detect all attempts to write to the EBC entry point argument
4794 stack area and adjust the address (which will initially point into the
4795 VM stack) to point into the EBC entry point arguments.
4797 @param VmPtr A pointer to a VM context.
4798 @param Addr Address to write to.
4799 @param Data Value to write to Addr.
4801 @retval EFI_SUCCESS The instruction is executed successfully.
4802 @retval Other Some error occurs when writing data to the address.
4807 IN VM_CONTEXT
*VmPtr
,
4815 // Convert the address if it's in the stack gap
4817 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4820 // Do a simple write if aligned
4822 if (IS_ALIGNED (Addr
, sizeof (UINT64
))) {
4823 *(UINT64
*) Addr
= Data
;
4826 // Write as two 32-bit words
4829 if ((Status
= VmWriteMem32 (VmPtr
, Addr
, (UINT32
) Data
)) != EFI_SUCCESS
) {
4834 if ((Status
= VmWriteMem32 (VmPtr
, Addr
+ sizeof (UINT32
), (UINT32
) RShiftU64(Data
, 32))) != EFI_SUCCESS
) {
4846 Writes UINTN data to memory address.
4848 This routine is called by the EBC data
4849 movement instructions that write to memory. Since these writes
4850 may be to the stack, which looks like (high address on top) this,
4852 [EBC entry point arguments]
4856 we need to detect all attempts to write to the EBC entry point argument
4857 stack area and adjust the address (which will initially point into the
4858 VM stack) to point into the EBC entry point arguments.
4860 @param VmPtr A pointer to a VM context.
4861 @param Addr Address to write to.
4862 @param Data Value to write to Addr.
4864 @retval EFI_SUCCESS The instruction is executed successfully.
4865 @retval Other Some error occurs when writing data to the address.
4870 IN VM_CONTEXT
*VmPtr
,
4878 Status
= EFI_SUCCESS
;
4881 // Convert the address if it's in the stack gap
4883 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4886 // Do a simple write if aligned
4888 if (IS_ALIGNED (Addr
, sizeof (UINTN
))) {
4889 *(UINTN
*) Addr
= Data
;
4891 for (Index
= 0; Index
< sizeof (UINTN
) / sizeof (UINT32
); Index
++) {
4893 Status
= VmWriteMem32 (VmPtr
, Addr
+ Index
* sizeof (UINT32
), (UINT32
) Data
);
4895 Data
= (UINTN
) RShiftU64 ((UINT64
)Data
, 32);
4904 Reads 8-bit immediate value at the offset.
4906 This routine is called by the EBC execute
4907 functions to read EBC immediate values from the code stream.
4908 Since we can't assume alignment, each tries to read in the biggest
4909 chunks size available, but will revert to smaller reads if necessary.
4911 @param VmPtr A pointer to a VM context.
4912 @param Offset offset from IP of the code bytes to read.
4914 @return Signed data of the requested size from the specified address.
4919 IN VM_CONTEXT
*VmPtr
,
4924 // Simply return the data in flat memory space
4926 return * (INT8
*) (VmPtr
->Ip
+ Offset
);
4930 Reads 16-bit immediate value at the offset.
4932 This routine is called by the EBC execute
4933 functions to read EBC immediate values from the code stream.
4934 Since we can't assume alignment, each tries to read in the biggest
4935 chunks size available, but will revert to smaller reads if necessary.
4937 @param VmPtr A pointer to a VM context.
4938 @param Offset offset from IP of the code bytes to read.
4940 @return Signed data of the requested size from the specified address.
4945 IN VM_CONTEXT
*VmPtr
,
4950 // Read direct if aligned
4952 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (INT16
))) {
4953 return * (INT16
*) (VmPtr
->Ip
+ Offset
);
4956 // All code word reads should be aligned
4958 EbcDebugSignalException (
4959 EXCEPT_EBC_ALIGNMENT_CHECK
,
4960 EXCEPTION_FLAG_WARNING
,
4965 // Return unaligned data
4967 return (INT16
) (*(UINT8
*) (VmPtr
->Ip
+ Offset
) + (*(UINT8
*) (VmPtr
->Ip
+ Offset
+ 1) << 8));
4972 Reads 32-bit immediate value at the offset.
4974 This routine is called by the EBC execute
4975 functions to read EBC immediate values from the code stream.
4976 Since we can't assume alignment, each tries to read in the biggest
4977 chunks size available, but will revert to smaller reads if necessary.
4979 @param VmPtr A pointer to a VM context.
4980 @param Offset offset from IP of the code bytes to read.
4982 @return Signed data of the requested size from the specified address.
4987 IN VM_CONTEXT
*VmPtr
,
4994 // Read direct if aligned
4996 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT32
))) {
4997 return * (INT32
*) (VmPtr
->Ip
+ Offset
);
5000 // Return unaligned data
5002 Data
= (UINT32
) VmReadCode16 (VmPtr
, Offset
);
5003 Data
|= (UINT32
)(VmReadCode16 (VmPtr
, Offset
+ 2) << 16);
5009 Reads 64-bit immediate value at the offset.
5011 This routine is called by the EBC execute
5012 functions to read EBC immediate values from the code stream.
5013 Since we can't assume alignment, each tries to read in the biggest
5014 chunks size available, but will revert to smaller reads if necessary.
5016 @param VmPtr A pointer to a VM context.
5017 @param Offset offset from IP of the code bytes to read.
5019 @return Signed data of the requested size from the specified address.
5024 IN VM_CONTEXT
*VmPtr
,
5033 // Read direct if aligned
5035 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT64
))) {
5036 return * (UINT64
*) (VmPtr
->Ip
+ Offset
);
5039 // Return unaligned data.
5041 Ptr
= (UINT8
*) &Data64
;
5042 Data32
= VmReadCode32 (VmPtr
, Offset
);
5043 *(UINT32
*) Ptr
= Data32
;
5044 Ptr
+= sizeof (Data32
);
5045 Data32
= VmReadCode32 (VmPtr
, Offset
+ sizeof (UINT32
));
5046 *(UINT32
*) Ptr
= Data32
;
5052 Reads 16-bit unsigned data from the code stream.
5054 This routine provides the ability to read raw unsigned data from the code
5057 @param VmPtr A pointer to VM context
5058 @param Offset Offset from current IP to the raw data to read.
5060 @return The raw unsigned 16-bit value from the code stream.
5065 IN VM_CONTEXT
*VmPtr
,
5070 // Read direct if aligned
5072 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT16
))) {
5073 return * (UINT16
*) (VmPtr
->Ip
+ Offset
);
5076 // All code word reads should be aligned
5078 EbcDebugSignalException (
5079 EXCEPT_EBC_ALIGNMENT_CHECK
,
5080 EXCEPTION_FLAG_WARNING
,
5085 // Return unaligned data
5087 return (UINT16
) (*(UINT8
*) (VmPtr
->Ip
+ Offset
) + (*(UINT8
*) (VmPtr
->Ip
+ Offset
+ 1) << 8));
5092 Reads 32-bit unsigned data from the code stream.
5094 This routine provides the ability to read raw unsigned data from the code
5097 @param VmPtr A pointer to VM context
5098 @param Offset Offset from current IP to the raw data to read.
5100 @return The raw unsigned 32-bit value from the code stream.
5105 IN VM_CONTEXT
*VmPtr
,
5111 // Read direct if aligned
5113 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT32
))) {
5114 return * (UINT32
*) (VmPtr
->Ip
+ Offset
);
5117 // Return unaligned data
5119 Data
= (UINT32
) VmReadCode16 (VmPtr
, Offset
);
5120 Data
|= (VmReadCode16 (VmPtr
, Offset
+ 2) << 16);
5126 Reads 64-bit unsigned data from the code stream.
5128 This routine provides the ability to read raw unsigned data from the code
5131 @param VmPtr A pointer to VM context
5132 @param Offset Offset from current IP to the raw data to read.
5134 @return The raw unsigned 64-bit value from the code stream.
5139 IN VM_CONTEXT
*VmPtr
,
5148 // Read direct if aligned
5150 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT64
))) {
5151 return * (UINT64
*) (VmPtr
->Ip
+ Offset
);
5154 // Return unaligned data.
5156 Ptr
= (UINT8
*) &Data64
;
5157 Data32
= VmReadCode32 (VmPtr
, Offset
);
5158 *(UINT32
*) Ptr
= Data32
;
5159 Ptr
+= sizeof (Data32
);
5160 Data32
= VmReadCode32 (VmPtr
, Offset
+ sizeof (UINT32
));
5161 *(UINT32
*) Ptr
= Data32
;
5167 Reads 8-bit data form the memory address.
5169 @param VmPtr A pointer to VM context.
5170 @param Addr The memory address.
5172 @return The 8-bit value from the memory address.
5177 IN VM_CONTEXT
*VmPtr
,
5182 // Convert the address if it's in the stack gap
5184 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5186 // Simply return the data in flat memory space
5188 return * (UINT8
*) Addr
;
5192 Reads 16-bit data form the memory address.
5194 @param VmPtr A pointer to VM context.
5195 @param Addr The memory address.
5197 @return The 16-bit value from the memory address.
5202 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 (UINT16
))) {
5214 return * (UINT16
*) Addr
;
5217 // Return unaligned data
5219 return (UINT16
) (*(UINT8
*) Addr
+ (*(UINT8
*) (Addr
+ 1) << 8));
5223 Reads 32-bit data form the memory address.
5225 @param VmPtr A pointer to VM context.
5226 @param Addr The memory address.
5228 @return The 32-bit value from the memory address.
5233 IN VM_CONTEXT
*VmPtr
,
5240 // Convert the address if it's in the stack gap
5242 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5244 // Read direct if aligned
5246 if (IS_ALIGNED (Addr
, sizeof (UINT32
))) {
5247 return * (UINT32
*) Addr
;
5250 // Return unaligned data
5252 Data
= (UINT32
) VmReadMem16 (VmPtr
, Addr
);
5253 Data
|= (VmReadMem16 (VmPtr
, Addr
+ 2) << 16);
5258 Reads 64-bit data form the memory address.
5260 @param VmPtr A pointer to VM context.
5261 @param Addr The memory address.
5263 @return The 64-bit value from the memory address.
5268 IN VM_CONTEXT
*VmPtr
,
5276 // Convert the address if it's in the stack gap
5278 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5281 // Read direct if aligned
5283 if (IS_ALIGNED (Addr
, sizeof (UINT64
))) {
5284 return * (UINT64
*) Addr
;
5287 // Return unaligned data. Assume little endian.
5289 Data32
= VmReadMem32 (VmPtr
, Addr
);
5290 Data
= (UINT64
) VmReadMem32 (VmPtr
, Addr
+ sizeof (UINT32
));
5291 Data
= LShiftU64 (Data
, 32) | Data32
;
5297 Given an address that EBC is going to read from or write to, return
5298 an appropriate address that accounts for a gap in the stack.
5299 The stack for this application looks like this (high addr on top)
5300 [EBC entry point arguments]
5303 The EBC assumes that its arguments are at the top of its stack, which
5304 is where the VM stack is really. Therefore if the EBC does memory
5305 accesses into the VM stack area, then we need to convert the address
5306 to point to the EBC entry point arguments area. Do this here.
5308 @param VmPtr A Pointer to VM context.
5309 @param Addr Address of interest
5311 @return The unchanged address if it's not in the VM stack region. Otherwise,
5312 adjust for the stack gap and return the modified address.
5317 IN VM_CONTEXT
*VmPtr
,
5321 ASSERT(((Addr
< VmPtr
->LowStackTop
) || (Addr
> VmPtr
->HighStackBottom
)));
5327 Read a natural value from memory. May or may not be aligned.
5329 @param VmPtr current VM context
5330 @param Addr the address to read from
5332 @return The natural value at address Addr.
5337 IN VM_CONTEXT
*VmPtr
,
5342 volatile UINT32 Size
;
5346 // Convert the address if it's in the stack gap
5348 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5350 // Read direct if aligned
5352 if (IS_ALIGNED (Addr
, sizeof (UINTN
))) {
5353 return * (UINTN
*) Addr
;
5356 // Return unaligned data
5359 FromPtr
= (UINT8
*) Addr
;
5360 ToPtr
= (UINT8
*) &Data
;
5362 for (Size
= 0; Size
< sizeof (Data
); Size
++) {
5372 Returns the version of the EBC virtual machine.
5374 @return The 64-bit version of EBC virtual machine.
5382 return (UINT64
) (((VM_MAJOR_VERSION
& 0xFFFF) << 16) | ((VM_MINOR_VERSION
& 0xFFFF)));