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"
14 // Define some useful data size constants to allow switch statements based on
15 // size of operands or data.
17 #define DATA_SIZE_INVALID 0
19 #define DATA_SIZE_16 2
20 #define DATA_SIZE_32 4
21 #define DATA_SIZE_64 8
22 #define DATA_SIZE_N 48 // 4 or 8
24 // Structure we'll use to dispatch opcodes to execute functions.
27 EFI_STATUS (*ExecuteFunction
)(
34 (*DATA_MANIP_EXEC_FUNCTION
) (
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
453 Execute the EBC BREAK instruction.
455 @param VmPtr A pointer to a VM context.
457 @retval EFI_SUCCESS The instruction is executed successfully.
466 Execute the JMP instruction.
470 JMP32{cs|cc} {@}R1 {Immed32|Index32}
473 b0.7 - immediate data present
474 b0.6 - 1 = 64 bit immediate data
475 0 = 32 bit immediate data
476 b1.7 - 1 = conditional
477 b1.6 1 = CS (condition set)
478 0 = CC (condition clear)
479 b1.4 1 = relative address
481 b1.3 1 = operand1 indirect
484 @param VmPtr A pointer to a VM context.
486 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
487 @retval EFI_SUCCESS The instruction is executed successfully.
496 Execute the EBC JMP8 instruction.
501 @param VmPtr A pointer to a VM context.
503 @retval EFI_SUCCESS The instruction is executed successfully.
512 Implements the EBC CALL instruction.
516 CALL32 {@}R1 {Immed32|Index32}
518 CALLEX16 {@}R1 {Immed32}
520 If Rx == R0, then it's a PC relative call to PC = PC + imm32.
522 @param VmPtr A pointer to a VM context.
524 @retval EFI_SUCCESS The instruction is executed successfully.
533 Execute the EBC RET instruction.
538 @param VmPtr A pointer to a VM context.
540 @retval EFI_SUCCESS The instruction is executed successfully.
549 Execute the EBC CMP instruction.
552 CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
554 @param VmPtr A pointer to a VM context.
556 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
557 @retval EFI_SUCCESS The instruction is executed successfully.
566 Execute the EBC CMPI instruction
569 CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
571 @param VmPtr A pointer to a VM context.
573 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
574 @retval EFI_SUCCESS The instruction is executed successfully.
583 Execute the MOVxx instructions.
587 MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
588 MOVqq {@}R1 {Index64}, {@}R2 {Index64}
590 Copies contents of [R2] -> [R1], zero extending where required.
592 First character indicates the size of the move.
593 Second character indicates the size of the index(s).
595 Invalid to have R1 direct with index.
597 @param VmPtr A pointer to a VM context.
599 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
600 @retval EFI_SUCCESS The instruction is executed successfully.
609 Execute the EBC MOVI.
613 MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
615 First variable character specifies the move size
616 Second variable character specifies size of the immediate data
618 Sign-extend the immediate data to the size of the operation, and zero-extend
619 if storing to a register.
621 Operand1 direct with index/immed is invalid.
623 @param VmPtr A pointer to a VM context.
625 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
626 @retval EFI_SUCCESS The instruction is executed successfully.
635 Execute the EBC MOV immediate natural. This instruction moves an immediate
636 index value into a register or memory location.
640 MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
642 @param VmPtr A pointer to a VM context.
644 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
645 @retval EFI_SUCCESS The instruction is executed successfully.
654 Execute the EBC MOVREL instruction.
659 MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
661 @param VmPtr A pointer to a VM context.
663 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
664 @retval EFI_SUCCESS The instruction is executed successfully.
673 Execute the EBC PUSHn instruction
676 PUSHn {@}R1 {Index16|Immed16}
678 @param VmPtr A pointer to a VM context.
680 @retval EFI_SUCCESS The instruction is executed successfully.
689 Execute the EBC PUSH instruction.
692 PUSH[32|64] {@}R1 {Index16|Immed16}
694 @param VmPtr A pointer to a VM context.
696 @retval EFI_SUCCESS The instruction is executed successfully.
705 Execute the EBC POPn instruction.
708 POPn {@}R1 {Index16|Immed16}
710 @param VmPtr A pointer to a VM context.
712 @retval EFI_SUCCESS The instruction is executed successfully.
721 Execute the EBC POP instruction.
724 POPn {@}R1 {Index16|Immed16}
726 @param VmPtr A pointer to a VM context.
728 @retval EFI_SUCCESS The instruction is executed successfully.
737 Execute all the EBC signed data manipulation instructions.
738 Since the EBC data manipulation instructions all have the same basic form,
739 they can share the code that does the fetch of operands and the write-back
740 of the result. This function performs the fetch of the operands (even if
741 both are not needed to be fetched, like NOT instruction), dispatches to the
742 appropriate subfunction, then writes back the returned result.
745 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
747 @param VmPtr A pointer to VM context.
749 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
750 @retval EFI_SUCCESS The instruction is executed successfully.
754 ExecuteSignedDataManip (
759 Execute all the EBC unsigned data manipulation instructions.
760 Since the EBC data manipulation instructions all have the same basic form,
761 they can share the code that does the fetch of operands and the write-back
762 of the result. This function performs the fetch of the operands (even if
763 both are not needed to be fetched, like NOT instruction), dispatches to the
764 appropriate subfunction, then writes back the returned result.
767 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
769 @param VmPtr A pointer to VM context.
771 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
772 @retval EFI_SUCCESS The instruction is executed successfully.
776 ExecuteUnsignedDataManip (
781 Execute the EBC LOADSP instruction.
786 @param VmPtr A pointer to a VM context.
788 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
789 @retval EFI_SUCCESS The instruction is executed successfully.
798 Execute the EBC STORESP instruction.
803 @param VmPtr A pointer to a VM context.
805 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
806 @retval EFI_SUCCESS The instruction is executed successfully.
815 Execute the EBC MOVsnw instruction. This instruction loads a signed
816 natural value from memory or register to another memory or register. On
817 32-bit machines, the value gets sign-extended to 64 bits if the destination
822 MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
824 0:7 1=>operand1 index present
825 0:6 1=>operand2 index present
827 @param VmPtr A pointer to a VM context.
829 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
830 @retval EFI_SUCCESS The instruction is executed successfully.
839 Execute the EBC MOVsnw instruction. This instruction loads a signed
840 natural value from memory or register to another memory or register. On
841 32-bit machines, the value gets sign-extended to 64 bits if the destination
846 MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
848 0:7 1=>operand1 index present
849 0:6 1=>operand2 index present
851 @param VmPtr A pointer to a VM context.
853 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
854 @retval EFI_SUCCESS The instruction is executed successfully.
863 // Data manipulation subfunctions
867 Execute the EBC NOT instruction.s
870 NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
872 @param VmPtr A pointer to a VM context.
873 @param Op1 Operand 1 from the instruction
874 @param Op2 Operand 2 from the instruction
881 IN VM_CONTEXT
*VmPtr
,
887 Execute the EBC NEG instruction.
890 NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
892 @param VmPtr A pointer to a VM context.
893 @param Op1 Operand 1 from the instruction
894 @param Op2 Operand 2 from the instruction
901 IN VM_CONTEXT
*VmPtr
,
907 Execute the EBC ADD instruction.
910 ADD[32|64] {@}R1, {@}R2 {Index16}
912 @param VmPtr A pointer to a VM context.
913 @param Op1 Operand 1 from the instruction
914 @param Op2 Operand 2 from the instruction
921 IN VM_CONTEXT
*VmPtr
,
927 Execute the EBC SUB instruction.
930 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
932 @param VmPtr A pointer to a VM context.
933 @param Op1 Operand 1 from the instruction
934 @param Op2 Operand 2 from the instruction
941 IN VM_CONTEXT
*VmPtr
,
947 Execute the EBC MUL instruction.
950 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
952 @param VmPtr A pointer to a VM context.
953 @param Op1 Operand 1 from the instruction
954 @param Op2 Operand 2 from the instruction
961 IN VM_CONTEXT
*VmPtr
,
967 Execute the EBC MULU instruction
970 MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
972 @param VmPtr A pointer to a VM context.
973 @param Op1 Operand 1 from the instruction
974 @param Op2 Operand 2 from the instruction
976 @return (unsigned)Op1 * (unsigned)Op2
981 IN VM_CONTEXT
*VmPtr
,
987 Execute the EBC DIV instruction.
990 DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
992 @param VmPtr A pointer to a VM context.
993 @param Op1 Operand 1 from the instruction
994 @param Op2 Operand 2 from the instruction
1001 IN VM_CONTEXT
*VmPtr
,
1007 Execute the EBC DIVU instruction
1010 DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
1012 @param VmPtr A pointer to a VM context.
1013 @param Op1 Operand 1 from the instruction
1014 @param Op2 Operand 2 from the instruction
1016 @return (unsigned)Op1 / (unsigned)Op2
1021 IN VM_CONTEXT
*VmPtr
,
1027 Execute the EBC MOD instruction.
1030 MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
1032 @param VmPtr A pointer to a VM context.
1033 @param Op1 Operand 1 from the instruction
1034 @param Op2 Operand 2 from the instruction
1036 @return Op1 MODULUS Op2
1041 IN VM_CONTEXT
*VmPtr
,
1047 Execute the EBC MODU instruction.
1050 MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
1052 @param VmPtr A pointer to a VM context.
1053 @param Op1 Operand 1 from the instruction
1054 @param Op2 Operand 2 from the instruction
1056 @return Op1 UNSIGNED_MODULUS Op2
1061 IN VM_CONTEXT
*VmPtr
,
1067 Execute the EBC AND instruction.
1070 AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
1072 @param VmPtr A pointer to a VM context.
1073 @param Op1 Operand 1 from the instruction
1074 @param Op2 Operand 2 from the instruction
1081 IN VM_CONTEXT
*VmPtr
,
1087 Execute the EBC OR instruction.
1090 OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1092 @param VmPtr A pointer to a VM context.
1093 @param Op1 Operand 1 from the instruction
1094 @param Op2 Operand 2 from the instruction
1101 IN VM_CONTEXT
*VmPtr
,
1107 Execute the EBC XOR instruction.
1110 XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1112 @param VmPtr A pointer to a VM context.
1113 @param Op1 Operand 1 from the instruction
1114 @param Op2 Operand 2 from the instruction
1121 IN VM_CONTEXT
*VmPtr
,
1127 Execute the EBC SHL shift left instruction.
1130 SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
1132 @param VmPtr A pointer to a VM context.
1133 @param Op1 Operand 1 from the instruction
1134 @param Op2 Operand 2 from the instruction
1141 IN VM_CONTEXT
*VmPtr
,
1147 Execute the EBC SHR instruction.
1150 SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1152 @param VmPtr A pointer to a VM context.
1153 @param Op1 Operand 1 from the instruction
1154 @param Op2 Operand 2 from the instruction
1156 @return Op1 >> Op2 (unsigned operands)
1161 IN VM_CONTEXT
*VmPtr
,
1167 Execute the EBC ASHR instruction.
1170 ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1172 @param VmPtr A pointer to a VM context.
1173 @param Op1 Operand 1 from the instruction
1174 @param Op2 Operand 2 from the instruction
1176 @return Op1 >> Op2 (signed)
1181 IN VM_CONTEXT
*VmPtr
,
1187 Execute the EBC EXTNDB instruction to sign-extend a byte value.
1190 EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
1192 @param VmPtr A pointer to a VM context.
1193 @param Op1 Operand 1 from the instruction
1194 @param Op2 Operand 2 from the instruction
1196 @return (INT64)(INT8)Op2
1201 IN VM_CONTEXT
*VmPtr
,
1207 Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
1210 EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
1212 @param VmPtr A pointer to a VM context.
1213 @param Op1 Operand 1 from the instruction
1214 @param Op2 Operand 2 from the instruction
1216 @return (INT64)(INT16)Op2
1221 IN VM_CONTEXT
*VmPtr
,
1227 Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
1230 EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
1232 @param VmPtr A pointer to a VM context.
1233 @param Op1 Operand 1 from the instruction
1234 @param Op2 Operand 2 from the instruction
1236 @return (INT64)(INT32)Op2
1241 IN VM_CONTEXT
*VmPtr
,
1247 // Once we retrieve the operands for the data manipulation instructions,
1248 // call these functions to perform the operation.
1250 CONST DATA_MANIP_EXEC_FUNCTION mDataManipDispatchTable
[] = {
1272 CONST VM_TABLE_ENTRY mVmOpcodeTable
[] = {
1273 { ExecuteBREAK
}, // opcode 0x00
1274 { ExecuteJMP
}, // opcode 0x01
1275 { ExecuteJMP8
}, // opcode 0x02
1276 { ExecuteCALL
}, // opcode 0x03
1277 { ExecuteRET
}, // opcode 0x04
1278 { ExecuteCMP
}, // opcode 0x05 CMPeq
1279 { ExecuteCMP
}, // opcode 0x06 CMPlte
1280 { ExecuteCMP
}, // opcode 0x07 CMPgte
1281 { ExecuteCMP
}, // opcode 0x08 CMPulte
1282 { ExecuteCMP
}, // opcode 0x09 CMPugte
1283 { ExecuteUnsignedDataManip
}, // opcode 0x0A NOT
1284 { ExecuteSignedDataManip
}, // opcode 0x0B NEG
1285 { ExecuteSignedDataManip
}, // opcode 0x0C ADD
1286 { ExecuteSignedDataManip
}, // opcode 0x0D SUB
1287 { ExecuteSignedDataManip
}, // opcode 0x0E MUL
1288 { ExecuteUnsignedDataManip
}, // opcode 0x0F MULU
1289 { ExecuteSignedDataManip
}, // opcode 0x10 DIV
1290 { ExecuteUnsignedDataManip
}, // opcode 0x11 DIVU
1291 { ExecuteSignedDataManip
}, // opcode 0x12 MOD
1292 { ExecuteUnsignedDataManip
}, // opcode 0x13 MODU
1293 { ExecuteUnsignedDataManip
}, // opcode 0x14 AND
1294 { ExecuteUnsignedDataManip
}, // opcode 0x15 OR
1295 { ExecuteUnsignedDataManip
}, // opcode 0x16 XOR
1296 { ExecuteUnsignedDataManip
}, // opcode 0x17 SHL
1297 { ExecuteUnsignedDataManip
}, // opcode 0x18 SHR
1298 { ExecuteSignedDataManip
}, // opcode 0x19 ASHR
1299 { ExecuteUnsignedDataManip
}, // opcode 0x1A EXTNDB
1300 { ExecuteUnsignedDataManip
}, // opcode 0x1B EXTNDW
1301 { ExecuteUnsignedDataManip
}, // opcode 0x1C EXTNDD
1302 { ExecuteMOVxx
}, // opcode 0x1D MOVBW
1303 { ExecuteMOVxx
}, // opcode 0x1E MOVWW
1304 { ExecuteMOVxx
}, // opcode 0x1F MOVDW
1305 { ExecuteMOVxx
}, // opcode 0x20 MOVQW
1306 { ExecuteMOVxx
}, // opcode 0x21 MOVBD
1307 { ExecuteMOVxx
}, // opcode 0x22 MOVWD
1308 { ExecuteMOVxx
}, // opcode 0x23 MOVDD
1309 { ExecuteMOVxx
}, // opcode 0x24 MOVQD
1310 { ExecuteMOVsnw
}, // opcode 0x25 MOVsnw
1311 { ExecuteMOVsnd
}, // opcode 0x26 MOVsnd
1312 { NULL
}, // opcode 0x27
1313 { ExecuteMOVxx
}, // opcode 0x28 MOVqq
1314 { ExecuteLOADSP
}, // opcode 0x29 LOADSP SP1, R2
1315 { ExecuteSTORESP
}, // opcode 0x2A STORESP R1, SP2
1316 { ExecutePUSH
}, // opcode 0x2B PUSH {@}R1 [imm16]
1317 { ExecutePOP
}, // opcode 0x2C POP {@}R1 [imm16]
1318 { ExecuteCMPI
}, // opcode 0x2D CMPIEQ
1319 { ExecuteCMPI
}, // opcode 0x2E CMPILTE
1320 { ExecuteCMPI
}, // opcode 0x2F CMPIGTE
1321 { ExecuteCMPI
}, // opcode 0x30 CMPIULTE
1322 { ExecuteCMPI
}, // opcode 0x31 CMPIUGTE
1323 { ExecuteMOVxx
}, // opcode 0x32 MOVN
1324 { ExecuteMOVxx
}, // opcode 0x33 MOVND
1325 { NULL
}, // opcode 0x34
1326 { ExecutePUSHn
}, // opcode 0x35
1327 { ExecutePOPn
}, // opcode 0x36
1328 { ExecuteMOVI
}, // opcode 0x37 - mov immediate data
1329 { ExecuteMOVIn
}, // opcode 0x38 - mov immediate natural
1330 { ExecuteMOVREL
}, // opcode 0x39 - move data relative to PC
1331 { NULL
}, // opcode 0x3a
1332 { NULL
}, // opcode 0x3b
1333 { NULL
}, // opcode 0x3c
1334 { NULL
}, // opcode 0x3d
1335 { NULL
}, // opcode 0x3e
1336 { NULL
} // opcode 0x3f
1340 // Length of JMP instructions, depending on upper two bits of opcode.
1342 CONST UINT8 mJMPLen
[] = { 2, 2, 6, 10 };
1345 Given a pointer to a new VM context, execute one or more instructions. This
1346 function is only used for test purposes via the EBC VM test protocol.
1348 @param This A pointer to the EFI_EBC_VM_TEST_PROTOCOL structure.
1349 @param VmPtr A pointer to a VM context.
1350 @param InstructionCount A pointer to a UINTN value holding the number of
1351 instructions to execute. If it holds value of 0,
1352 then the instruction to be executed is 1.
1354 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
1355 @retval EFI_SUCCESS All of the instructions are executed successfully.
1360 EbcExecuteInstructions (
1361 IN EFI_EBC_VM_TEST_PROTOCOL
*This
,
1362 IN VM_CONTEXT
*VmPtr
,
1363 IN OUT UINTN
*InstructionCount
1368 UINTN InstructionsLeft
;
1369 UINTN SavedInstructionCount
;
1371 Status
= EFI_SUCCESS
;
1373 if (*InstructionCount
== 0) {
1374 InstructionsLeft
= 1;
1376 InstructionsLeft
= *InstructionCount
;
1379 SavedInstructionCount
= *InstructionCount
;
1380 *InstructionCount
= 0;
1383 // Index into the opcode table using the opcode byte for this instruction.
1384 // This gives you the execute function, which we first test for null, then
1385 // call it if it's not null.
1387 while (InstructionsLeft
!= 0) {
1388 ExecFunc
= (UINTN
)mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction
;
1389 if (ExecFunc
== (UINTN
)NULL
) {
1390 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1391 return EFI_UNSUPPORTED
;
1393 mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction (VmPtr
);
1394 *InstructionCount
= *InstructionCount
+ 1;
1398 // Decrement counter if applicable
1400 if (SavedInstructionCount
!= 0) {
1409 Execute an EBC image from an entry point or from a published protocol.
1411 @param VmPtr A pointer to a VM context.
1413 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
1414 @retval EFI_SUCCESS All of the instructions are executed successfully.
1419 IN VM_CONTEXT
*VmPtr
1423 UINT8 StackCorrupted
;
1425 EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL
*EbcSimpleDebugger
;
1428 EbcSimpleDebugger
= NULL
;
1429 Status
= EFI_SUCCESS
;
1433 // Make sure the magic value has been put on the stack before we got here.
1435 if (*VmPtr
->StackMagicPtr
!= (UINTN
)VM_STACK_KEY_VALUE
) {
1439 VmPtr
->FramePtr
= (VOID
*)((UINT8
*)(UINTN
)VmPtr
->Gpr
[0] + 8);
1442 // Try to get the debug support for EBC
1444 DEBUG_CODE_BEGIN ();
1445 Status
= gBS
->LocateProtocol (
1446 &gEfiEbcSimpleDebuggerProtocolGuid
,
1448 (VOID
**)&EbcSimpleDebugger
1450 if (EFI_ERROR (Status
)) {
1451 EbcSimpleDebugger
= NULL
;
1457 // Save the start IP for debug. For example, if we take an exception we
1458 // can print out the location of the exception relative to the entry point,
1459 // which could then be used in a disassembly listing to find the problem.
1461 VmPtr
->EntryPoint
= (VOID
*)VmPtr
->Ip
;
1464 // We'll wait for this flag to know when we're done. The RET
1465 // instruction sets it if it runs out of stack.
1467 VmPtr
->StopFlags
= 0;
1468 while ((VmPtr
->StopFlags
& STOPFLAG_APP_DONE
) == 0) {
1470 // If we've found a simple debugger protocol, call it
1472 DEBUG_CODE_BEGIN ();
1473 if (EbcSimpleDebugger
!= NULL
) {
1474 EbcSimpleDebugger
->Debugger (EbcSimpleDebugger
, VmPtr
);
1480 // Use the opcode bits to index into the opcode dispatch table. If the
1481 // function pointer is null then generate an exception.
1483 ExecFunc
= (UINTN
)mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction
;
1484 if (ExecFunc
== (UINTN
)NULL
) {
1485 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1486 Status
= EFI_UNSUPPORTED
;
1490 EbcDebuggerHookExecuteStart (VmPtr
);
1493 // The EBC VM is a strongly ordered processor, so perform a fence operation before
1494 // and after each instruction is executed.
1498 mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction (VmPtr
);
1502 EbcDebuggerHookExecuteEnd (VmPtr
);
1505 // If the step flag is set, signal an exception and continue. We don't
1506 // clear it here. Assuming the debugger is responsible for clearing it.
1508 if (VMFLAG_ISSET (VmPtr
, VMFLAGS_STEP
)) {
1509 EbcDebugSignalException (EXCEPT_EBC_STEP
, EXCEPTION_FLAG_NONE
, VmPtr
);
1513 // Make sure stack has not been corrupted. Only report it once though.
1515 if ((StackCorrupted
== 0) && (*VmPtr
->StackMagicPtr
!= (UINTN
)VM_STACK_KEY_VALUE
)) {
1516 EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1520 if ((StackCorrupted
== 0) && ((UINT64
)VmPtr
->Gpr
[0] <= (UINT64
)(UINTN
)VmPtr
->StackTop
)) {
1521 EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1533 Execute the MOVxx instructions.
1537 MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
1538 MOVqq {@}R1 {Index64}, {@}R2 {Index64}
1540 Copies contents of [R2] -> [R1], zero extending where required.
1542 First character indicates the size of the move.
1543 Second character indicates the size of the index(s).
1545 Invalid to have R1 direct with index.
1547 @param VmPtr A pointer to a VM context.
1549 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
1550 @retval EFI_SUCCESS The instruction is executed successfully.
1555 IN VM_CONTEXT
*VmPtr
1571 Opcode
= GETOPCODE (VmPtr
);
1572 OpcMasked
= (UINT8
)(Opcode
& OPCODE_M_OPCODE
);
1575 // Get the operands byte so we can get R1 and R2
1577 Operands
= GETOPERANDS (VmPtr
);
1580 // Assume no indexes
1587 // Determine if we have an index/immediate data. Base instruction size
1588 // is 2 (opcode + operands). Add to this size each index specified.
1591 if ((Opcode
& (OPCODE_M_IMMED_OP1
| OPCODE_M_IMMED_OP2
)) != 0) {
1593 // Determine size of the index from the opcode. Then get it.
1595 if ((OpcMasked
<= OPCODE_MOVQW
) || (OpcMasked
== OPCODE_MOVNW
)) {
1597 // MOVBW, MOVWW, MOVDW, MOVQW, and MOVNW have 16-bit immediate index.
1598 // Get one or both index values.
1600 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1601 Index16
= VmReadIndex16 (VmPtr
, 2);
1602 Index64Op1
= (INT64
)Index16
;
1603 Size
+= sizeof (UINT16
);
1606 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1607 Index16
= VmReadIndex16 (VmPtr
, Size
);
1608 Index64Op2
= (INT64
)Index16
;
1609 Size
+= sizeof (UINT16
);
1611 } else if ((OpcMasked
<= OPCODE_MOVQD
) || (OpcMasked
== OPCODE_MOVND
)) {
1613 // MOVBD, MOVWD, MOVDD, MOVQD, and MOVND have 32-bit immediate index
1615 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1616 Index32
= VmReadIndex32 (VmPtr
, 2);
1617 Index64Op1
= (INT64
)Index32
;
1618 Size
+= sizeof (UINT32
);
1621 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1622 Index32
= VmReadIndex32 (VmPtr
, Size
);
1623 Index64Op2
= (INT64
)Index32
;
1624 Size
+= sizeof (UINT32
);
1626 } else if (OpcMasked
== OPCODE_MOVQQ
) {
1628 // MOVqq -- only form with a 64-bit index
1630 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1631 Index64Op1
= VmReadIndex64 (VmPtr
, 2);
1632 Size
+= sizeof (UINT64
);
1635 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1636 Index64Op2
= VmReadIndex64 (VmPtr
, Size
);
1637 Size
+= sizeof (UINT64
);
1641 // Obsolete MOVBQ, MOVWQ, MOVDQ, and MOVNQ have 64-bit immediate index
1643 EbcDebugSignalException (
1644 EXCEPT_EBC_INSTRUCTION_ENCODING
,
1645 EXCEPTION_FLAG_FATAL
,
1648 return EFI_UNSUPPORTED
;
1653 // Determine the size of the move, and create a mask for it so we can
1654 // clear unused bits.
1656 if ((OpcMasked
== OPCODE_MOVBW
) || (OpcMasked
== OPCODE_MOVBD
)) {
1657 MoveSize
= DATA_SIZE_8
;
1659 } else if ((OpcMasked
== OPCODE_MOVWW
) || (OpcMasked
== OPCODE_MOVWD
)) {
1660 MoveSize
= DATA_SIZE_16
;
1662 } else if ((OpcMasked
== OPCODE_MOVDW
) || (OpcMasked
== OPCODE_MOVDD
)) {
1663 MoveSize
= DATA_SIZE_32
;
1664 DataMask
= 0xFFFFFFFF;
1665 } else if ((OpcMasked
== OPCODE_MOVQW
) || (OpcMasked
== OPCODE_MOVQD
) || (OpcMasked
== OPCODE_MOVQQ
)) {
1666 MoveSize
= DATA_SIZE_64
;
1667 DataMask
= (UINT64
) ~0;
1668 } else if ((OpcMasked
== OPCODE_MOVNW
) || (OpcMasked
== OPCODE_MOVND
)) {
1669 MoveSize
= DATA_SIZE_N
;
1670 DataMask
= (UINT64
) ~0 >> (64 - 8 * sizeof (UINTN
));
1673 // We were dispatched to this function and we don't recognize the opcode
1675 EbcDebugSignalException (EXCEPT_EBC_UNDEFINED
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1676 return EFI_UNSUPPORTED
;
1680 // Now get the source address
1682 if (OPERAND2_INDIRECT (Operands
)) {
1684 // Indirect form @R2. Compute address of operand2
1686 Source
= (UINTN
)(VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index64Op2
);
1688 // Now get the data from the source. Always 0-extend and let the compiler
1689 // sign-extend where required.
1693 Data64
= (UINT64
)(UINT8
)VmReadMem8 (VmPtr
, Source
);
1697 Data64
= (UINT64
)(UINT16
)VmReadMem16 (VmPtr
, Source
);
1701 Data64
= (UINT64
)(UINT32
)VmReadMem32 (VmPtr
, Source
);
1705 Data64
= (UINT64
)VmReadMem64 (VmPtr
, Source
);
1709 Data64
= (UINT64
)(UINTN
)VmReadMemN (VmPtr
, Source
);
1720 // Not indirect source: MOVxx {@}Rx, Ry [Index]
1722 Data64
= (UINT64
)(VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index64Op2
);
1724 // Did Operand2 have an index? If so, treat as two signed values since
1725 // indexes are signed values.
1727 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1729 // NOTE: need to find a way to fix this, most likely by changing the VM
1730 // implementation to remove the stack gap. To do that, we'd need to
1731 // allocate stack space for the VM and actually set the system
1732 // stack pointer to the allocated buffer when the VM starts.
1734 // Special case -- if someone took the address of a function parameter
1735 // then we need to make sure it's not in the stack gap. We can identify
1736 // this situation if (Operand2 register == 0) && (Operand2 is direct)
1737 // && (Index applies to Operand2) && (Index > 0) && (Operand1 register != 0)
1738 // Situations that to be aware of:
1739 // * stack adjustments at beginning and end of functions R0 = R0 += stacksize
1741 if ((OPERAND2_REGNUM (Operands
) == 0) &&
1742 (!OPERAND2_INDIRECT (Operands
)) &&
1744 (OPERAND1_REGNUM (Operands
) == 0) &&
1745 (OPERAND1_INDIRECT (Operands
))
1748 Data64
= (UINT64
)ConvertStackAddr (VmPtr
, (UINTN
)(INT64
)Data64
);
1754 // Now write it back
1756 if (OPERAND1_INDIRECT (Operands
)) {
1758 // Reuse the Source variable to now be dest.
1760 Source
= (UINTN
)(VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index64Op1
);
1762 // Do the write based on the size
1766 VmWriteMem8 (VmPtr
, Source
, (UINT8
)Data64
);
1770 VmWriteMem16 (VmPtr
, Source
, (UINT16
)Data64
);
1774 VmWriteMem32 (VmPtr
, Source
, (UINT32
)Data64
);
1778 VmWriteMem64 (VmPtr
, Source
, Data64
);
1782 VmWriteMemN (VmPtr
, Source
, (UINTN
)Data64
);
1794 // Make sure we didn't have an index on operand1.
1796 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1797 EbcDebugSignalException (
1798 EXCEPT_EBC_INSTRUCTION_ENCODING
,
1799 EXCEPTION_FLAG_FATAL
,
1802 return EFI_UNSUPPORTED
;
1806 // Direct storage in register. Clear unused bits and store back to
1809 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = Data64
& DataMask
;
1813 // Advance the instruction pointer
1820 Execute the EBC BREAK instruction.
1822 @param VmPtr A pointer to a VM context.
1824 @retval EFI_SUCCESS The instruction is executed successfully.
1829 IN VM_CONTEXT
*VmPtr
1834 VOID
*EbcEntryPoint
;
1836 UINT64 U64EbcEntryPoint
;
1840 Operands
= GETOPERANDS (VmPtr
);
1843 // Runaway program break. Generate an exception and terminate
1846 EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1850 // Get VM version -- return VM revision number in R7
1856 // 16-8 = Major version
1857 // 7-0 = Minor version
1859 VmPtr
->Gpr
[7] = GetVmVersion ();
1863 // Debugger breakpoint
1866 VmPtr
->StopFlags
|= STOPFLAG_BREAKPOINT
;
1868 // See if someone has registered a handler
1870 EbcDebugSignalException (
1871 EXCEPT_EBC_BREAKPOINT
,
1872 EXCEPTION_FLAG_NONE
,
1878 // System call, which there are none, so NOP it.
1884 // Create a thunk for EBC code. R7 points to a 32-bit (in a 64-bit slot)
1885 // "offset from self" pointer to the EBC entry point.
1886 // After we're done, *(UINT64 *)R7 will be the address of the new thunk.
1889 Offset
= (INT32
)VmReadMem32 (VmPtr
, (UINTN
)VmPtr
->Gpr
[7]);
1890 U64EbcEntryPoint
= (UINT64
)(VmPtr
->Gpr
[7] + Offset
+ 4);
1891 EbcEntryPoint
= (VOID
*)(UINTN
)U64EbcEntryPoint
;
1894 // Now create a new thunk
1896 Status
= EbcCreateThunks (VmPtr
->ImageHandle
, EbcEntryPoint
, &Thunk
, 0);
1897 if (EFI_ERROR (Status
)) {
1902 // Finally replace the EBC entry point memory with the thunk address
1904 VmWriteMem64 (VmPtr
, (UINTN
)VmPtr
->Gpr
[7], (UINT64
)(UINTN
)Thunk
);
1908 // Compiler setting version per value in R7
1911 VmPtr
->CompilerVersion
= (UINT32
)VmPtr
->Gpr
[7];
1913 // Check compiler version against VM version?
1918 // Unhandled break code. Signal exception.
1921 EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1933 Execute the JMP instruction.
1936 JMP64{cs|cc} Immed64
1937 JMP32{cs|cc} {@}R1 {Immed32|Index32}
1940 b0.7 - immediate data present
1941 b0.6 - 1 = 64 bit immediate data
1942 0 = 32 bit immediate data
1943 b1.7 - 1 = conditional
1944 b1.6 1 = CS (condition set)
1945 0 = CC (condition clear)
1946 b1.4 1 = relative address
1947 0 = absolute address
1948 b1.3 1 = operand1 indirect
1951 @param VmPtr A pointer to a VM context.
1953 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
1954 @retval EFI_SUCCESS The instruction is executed successfully.
1959 IN VM_CONTEXT
*VmPtr
1964 UINT8 ConditionFlag
;
1971 Operand
= GETOPERANDS (VmPtr
);
1972 Opcode
= GETOPCODE (VmPtr
);
1975 // Get instruction length from the opcode. The upper two bits are used here
1976 // to index into the length array.
1978 Size
= mJMPLen
[(Opcode
>> 6) & 0x03];
1981 // Decode instruction conditions
1982 // If we haven't met the condition, then simply advance the IP and return.
1984 CompareSet
= (UINT8
)(((Operand
& JMP_M_CS
) != 0) ? 1 : 0);
1985 ConditionFlag
= (UINT8
)VMFLAG_ISSET (VmPtr
, VMFLAGS_CC
);
1986 if ((Operand
& CONDITION_M_CONDITIONAL
) != 0) {
1987 if (CompareSet
!= ConditionFlag
) {
1988 EbcDebuggerHookJMPStart (VmPtr
);
1990 EbcDebuggerHookJMPEnd (VmPtr
);
1996 // Check for 64-bit form and do it right away since it's the most
1997 // straight-forward form.
1999 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
2001 // Double check for immediate-data, which is required. If not there,
2002 // then signal an exception
2004 if ((Opcode
& OPCODE_M_IMMDATA
) == 0) {
2005 EbcDebugSignalException (
2006 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2007 EXCEPTION_FLAG_ERROR
,
2010 return EFI_UNSUPPORTED
;
2014 // 64-bit immediate data is full address. Read the immediate data,
2015 // check for alignment, and jump absolute.
2017 Data64
= (UINT64
)VmReadImmed64 (VmPtr
, 2);
2018 if (!IS_ALIGNED ((UINTN
)Data64
, sizeof (UINT16
))) {
2019 EbcDebugSignalException (
2020 EXCEPT_EBC_ALIGNMENT_CHECK
,
2021 EXCEPTION_FLAG_FATAL
,
2025 return EFI_UNSUPPORTED
;
2029 // Take jump -- relative or absolute
2031 EbcDebuggerHookJMPStart (VmPtr
);
2032 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2033 VmPtr
->Ip
+= (UINTN
)Data64
+ Size
;
2035 VmPtr
->Ip
= (VMIP
)(UINTN
)Data64
;
2038 EbcDebuggerHookJMPEnd (VmPtr
);
2045 // Get the index if there is one. May be either an index, or an immediate
2046 // offset depending on indirect operand.
2047 // JMP32 @R1 Index32 -- immediate data is an index
2048 // JMP32 R1 Immed32 -- immedate data is an offset
2050 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
2051 if (OPERAND1_INDIRECT (Operand
)) {
2052 Index32
= VmReadIndex32 (VmPtr
, 2);
2054 Index32
= VmReadImmed32 (VmPtr
, 2);
2061 // Get the register data. If R == 0, then special case where it's ignored.
2063 if (OPERAND1_REGNUM (Operand
) == 0) {
2066 Data64
= (UINT64
)OPERAND1_REGDATA (VmPtr
, Operand
);
2072 if (OPERAND1_INDIRECT (Operand
)) {
2074 // Form: JMP32 @Rx {Index32}
2076 Addr
= VmReadMemN (VmPtr
, (UINTN
)Data64
+ Index32
);
2077 if (!IS_ALIGNED ((UINTN
)Addr
, sizeof (UINT16
))) {
2078 EbcDebugSignalException (
2079 EXCEPT_EBC_ALIGNMENT_CHECK
,
2080 EXCEPTION_FLAG_FATAL
,
2084 return EFI_UNSUPPORTED
;
2087 EbcDebuggerHookJMPStart (VmPtr
);
2088 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2089 VmPtr
->Ip
+= (UINTN
)Addr
+ Size
;
2091 VmPtr
->Ip
= (VMIP
)Addr
;
2094 EbcDebuggerHookJMPEnd (VmPtr
);
2097 // Form: JMP32 Rx {Immed32}
2099 Addr
= (UINTN
)(Data64
+ Index32
);
2100 if (!IS_ALIGNED ((UINTN
)Addr
, sizeof (UINT16
))) {
2101 EbcDebugSignalException (
2102 EXCEPT_EBC_ALIGNMENT_CHECK
,
2103 EXCEPTION_FLAG_FATAL
,
2107 return EFI_UNSUPPORTED
;
2110 EbcDebuggerHookJMPStart (VmPtr
);
2111 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2112 VmPtr
->Ip
+= (UINTN
)Addr
+ Size
;
2114 VmPtr
->Ip
= (VMIP
)Addr
;
2117 EbcDebuggerHookJMPEnd (VmPtr
);
2124 Execute the EBC JMP8 instruction.
2127 JMP8{cs|cc} Offset/2
2129 @param VmPtr A pointer to a VM context.
2131 @retval EFI_SUCCESS The instruction is executed successfully.
2136 IN VM_CONTEXT
*VmPtr
2140 UINT8 ConditionFlag
;
2145 // Decode instruction.
2147 Opcode
= GETOPCODE (VmPtr
);
2148 CompareSet
= (UINT8
)(((Opcode
& JMP_M_CS
) != 0) ? 1 : 0);
2149 ConditionFlag
= (UINT8
)VMFLAG_ISSET (VmPtr
, VMFLAGS_CC
);
2152 // If we haven't met the condition, then simply advance the IP and return
2154 if ((Opcode
& CONDITION_M_CONDITIONAL
) != 0) {
2155 if (CompareSet
!= ConditionFlag
) {
2156 EbcDebuggerHookJMP8Start (VmPtr
);
2158 EbcDebuggerHookJMP8End (VmPtr
);
2164 // Get the offset from the instruction stream. It's relative to the
2165 // following instruction, and divided by 2.
2167 Offset
= VmReadImmed8 (VmPtr
, 1);
2169 // Want to check for offset == -2 and then raise an exception?
2171 EbcDebuggerHookJMP8Start (VmPtr
);
2172 VmPtr
->Ip
+= (Offset
* 2) + 2;
2173 EbcDebuggerHookJMP8End (VmPtr
);
2178 Execute the EBC MOVI.
2182 MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
2184 First variable character specifies the move size
2185 Second variable character specifies size of the immediate data
2187 Sign-extend the immediate data to the size of the operation, and zero-extend
2188 if storing to a register.
2190 Operand1 direct with index/immed is invalid.
2192 @param VmPtr A pointer to a VM context.
2194 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2195 @retval EFI_SUCCESS The instruction is executed successfully.
2200 IN VM_CONTEXT
*VmPtr
2212 // Get the opcode and operands byte so we can get R1 and R2
2214 Opcode
= GETOPCODE (VmPtr
);
2215 Operands
= GETOPERANDS (VmPtr
);
2218 // Get the index (16-bit) if present
2220 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2221 Index16
= VmReadIndex16 (VmPtr
, 2);
2229 // Extract the immediate data. Sign-extend always.
2231 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2232 ImmData64
= (INT64
)(INT16
)VmReadImmed16 (VmPtr
, Size
);
2234 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2235 ImmData64
= (INT64
)(INT32
)VmReadImmed32 (VmPtr
, Size
);
2237 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2238 ImmData64
= (INT64
)VmReadImmed64 (VmPtr
, Size
);
2244 EbcDebugSignalException (
2245 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2246 EXCEPTION_FLAG_FATAL
,
2249 return EFI_UNSUPPORTED
;
2253 // Now write back the result
2255 if (!OPERAND1_INDIRECT (Operands
)) {
2257 // Operand1 direct. Make sure it didn't have an index.
2259 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2260 EbcDebugSignalException (
2261 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2262 EXCEPTION_FLAG_FATAL
,
2265 return EFI_UNSUPPORTED
;
2269 // Writing directly to a register. Clear unused bits.
2271 if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH8
) {
2272 Mask64
= 0x000000FF;
2273 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH16
) {
2274 Mask64
= 0x0000FFFF;
2275 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH32
) {
2276 Mask64
= 0x00000000FFFFFFFF;
2278 Mask64
= (UINT64
) ~0;
2281 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = ImmData64
& Mask64
;
2284 // Get the address then write back based on size of the move
2286 Op1
= (UINT64
)VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
;
2287 if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH8
) {
2288 VmWriteMem8 (VmPtr
, (UINTN
)Op1
, (UINT8
)ImmData64
);
2289 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH16
) {
2290 VmWriteMem16 (VmPtr
, (UINTN
)Op1
, (UINT16
)ImmData64
);
2291 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH32
) {
2292 VmWriteMem32 (VmPtr
, (UINTN
)Op1
, (UINT32
)ImmData64
);
2294 VmWriteMem64 (VmPtr
, (UINTN
)Op1
, (UINT64
)ImmData64
);
2299 // Advance the instruction pointer
2306 Execute the EBC MOV immediate natural. This instruction moves an immediate
2307 index value into a register or memory location.
2311 MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
2313 @param VmPtr A pointer to a VM context.
2315 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2316 @retval EFI_SUCCESS The instruction is executed successfully.
2321 IN VM_CONTEXT
*VmPtr
2334 // Get the opcode and operands byte so we can get R1 and R2
2336 Opcode
= GETOPCODE (VmPtr
);
2337 Operands
= GETOPERANDS (VmPtr
);
2340 // Get the operand1 index (16-bit) if present
2342 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2343 Index16
= VmReadIndex16 (VmPtr
, 2);
2351 // Extract the immediate data and convert to a 64-bit index.
2353 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2354 ImmedIndex16
= VmReadIndex16 (VmPtr
, Size
);
2355 ImmedIndex64
= (INT64
)ImmedIndex16
;
2357 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2358 ImmedIndex32
= VmReadIndex32 (VmPtr
, Size
);
2359 ImmedIndex64
= (INT64
)ImmedIndex32
;
2361 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2362 ImmedIndex64
= VmReadIndex64 (VmPtr
, Size
);
2368 EbcDebugSignalException (
2369 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2370 EXCEPTION_FLAG_FATAL
,
2373 return EFI_UNSUPPORTED
;
2377 // Now write back the result
2379 if (!OPERAND1_INDIRECT (Operands
)) {
2381 // Check for MOVIn R1 Index16, Immed (not indirect, with index), which
2384 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2385 EbcDebugSignalException (
2386 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2387 EXCEPTION_FLAG_FATAL
,
2390 return EFI_UNSUPPORTED
;
2393 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = ImmedIndex64
;
2398 Op1
= (UINT64
)VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
;
2399 VmWriteMemN (VmPtr
, (UINTN
)Op1
, (UINTN
)(INTN
)ImmedIndex64
);
2403 // Advance the instruction pointer
2410 Execute the EBC MOVREL instruction.
2411 Dest <- Ip + ImmData
2415 MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
2417 @param VmPtr A pointer to a VM context.
2419 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2420 @retval EFI_SUCCESS The instruction is executed successfully.
2425 IN VM_CONTEXT
*VmPtr
2437 // Get the opcode and operands byte so we can get R1 and R2
2439 Opcode
= GETOPCODE (VmPtr
);
2440 Operands
= GETOPERANDS (VmPtr
);
2443 // Get the Operand 1 index (16-bit) if present
2445 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2446 Index16
= VmReadIndex16 (VmPtr
, 2);
2454 // Get the immediate data.
2456 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2457 ImmData64
= (INT64
)VmReadImmed16 (VmPtr
, Size
);
2459 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2460 ImmData64
= (INT64
)VmReadImmed32 (VmPtr
, Size
);
2462 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2463 ImmData64
= VmReadImmed64 (VmPtr
, Size
);
2469 EbcDebugSignalException (
2470 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2471 EXCEPTION_FLAG_FATAL
,
2474 return EFI_UNSUPPORTED
;
2478 // Compute the value and write back the result
2480 Op2
= (UINT64
)((INT64
)((UINT64
)(UINTN
)VmPtr
->Ip
) + (INT64
)ImmData64
+ Size
);
2481 if (!OPERAND1_INDIRECT (Operands
)) {
2483 // Check for illegal combination of operand1 direct with immediate data
2485 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2486 EbcDebugSignalException (
2487 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2488 EXCEPTION_FLAG_FATAL
,
2491 return EFI_UNSUPPORTED
;
2494 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (VM_REGISTER
)Op2
;
2497 // Get the address = [Rx] + Index16
2498 // Write back the result. Always a natural size write, since
2499 // we're talking addresses here.
2501 Op1
= (UINT64
)VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
;
2502 VmWriteMemN (VmPtr
, (UINTN
)Op1
, (UINTN
)Op2
);
2506 // Advance the instruction pointer
2513 Execute the EBC MOVsnw instruction. This instruction loads a signed
2514 natural value from memory or register to another memory or register. On
2515 32-bit machines, the value gets sign-extended to 64 bits if the destination
2520 MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
2522 0:7 1=>operand1 index present
2523 0:6 1=>operand2 index present
2525 @param VmPtr A pointer to a VM context.
2527 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2528 @retval EFI_SUCCESS The instruction is executed successfully.
2533 IN VM_CONTEXT
*VmPtr
2544 // Get the opcode and operand bytes
2546 Opcode
= GETOPCODE (VmPtr
);
2547 Operands
= GETOPERANDS (VmPtr
);
2549 Op1Index
= Op2Index
= 0;
2552 // Get the indexes if present.
2555 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
2556 if (OPERAND1_INDIRECT (Operands
)) {
2557 Op1Index
= VmReadIndex16 (VmPtr
, 2);
2560 // Illegal form operand1 direct with index: MOVsnw R1 Index16, {@}R2
2562 EbcDebugSignalException (
2563 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2564 EXCEPTION_FLAG_FATAL
,
2567 return EFI_UNSUPPORTED
;
2570 Size
+= sizeof (UINT16
);
2573 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
2574 if (OPERAND2_INDIRECT (Operands
)) {
2575 Op2Index
= VmReadIndex16 (VmPtr
, Size
);
2577 Op2Index
= VmReadImmed16 (VmPtr
, Size
);
2580 Size
+= sizeof (UINT16
);
2584 // Get the data from the source.
2586 Op2
= (UINT64
)(INT64
)(INTN
)(VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Op2Index
);
2587 if (OPERAND2_INDIRECT (Operands
)) {
2588 Op2
= (UINT64
)(INT64
)(INTN
)VmReadMemN (VmPtr
, (UINTN
)Op2
);
2592 // Now write back the result.
2594 if (!OPERAND1_INDIRECT (Operands
)) {
2595 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = Op2
;
2597 VmWriteMemN (VmPtr
, (UINTN
)(VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Op1Index
), (UINTN
)Op2
);
2601 // Advance the instruction pointer
2608 Execute the EBC MOVsnw instruction. This instruction loads a signed
2609 natural value from memory or register to another memory or register. On
2610 32-bit machines, the value gets sign-extended to 64 bits if the destination
2615 MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
2617 0:7 1=>operand1 index present
2618 0:6 1=>operand2 index present
2620 @param VmPtr A pointer to a VM context.
2622 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2623 @retval EFI_SUCCESS The instruction is executed successfully.
2628 IN VM_CONTEXT
*VmPtr
2639 // Get the opcode and operand bytes
2641 Opcode
= GETOPCODE (VmPtr
);
2642 Operands
= GETOPERANDS (VmPtr
);
2644 Op1Index
= Op2Index
= 0;
2647 // Get the indexes if present.
2650 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
2651 if (OPERAND1_INDIRECT (Operands
)) {
2652 Op1Index
= VmReadIndex32 (VmPtr
, 2);
2655 // Illegal form operand1 direct with index: MOVsnd R1 Index16,..
2657 EbcDebugSignalException (
2658 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2659 EXCEPTION_FLAG_FATAL
,
2662 return EFI_UNSUPPORTED
;
2665 Size
+= sizeof (UINT32
);
2668 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
2669 if (OPERAND2_INDIRECT (Operands
)) {
2670 Op2Index
= VmReadIndex32 (VmPtr
, Size
);
2672 Op2Index
= VmReadImmed32 (VmPtr
, Size
);
2675 Size
+= sizeof (UINT32
);
2679 // Get the data from the source.
2681 Op2
= (UINT64
)(INT64
)(INTN
)(INT64
)(VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Op2Index
);
2682 if (OPERAND2_INDIRECT (Operands
)) {
2683 Op2
= (UINT64
)(INT64
)(INTN
)(INT64
)VmReadMemN (VmPtr
, (UINTN
)Op2
);
2687 // Now write back the result.
2689 if (!OPERAND1_INDIRECT (Operands
)) {
2690 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = Op2
;
2692 VmWriteMemN (VmPtr
, (UINTN
)(VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Op1Index
), (UINTN
)Op2
);
2696 // Advance the instruction pointer
2703 Execute the EBC PUSHn instruction
2706 PUSHn {@}R1 {Index16|Immed16}
2708 @param VmPtr A pointer to a VM context.
2710 @retval EFI_SUCCESS The instruction is executed successfully.
2715 IN VM_CONTEXT
*VmPtr
2724 // Get opcode and operands
2726 Opcode
= GETOPCODE (VmPtr
);
2727 Operands
= GETOPERANDS (VmPtr
);
2730 // Get index if present
2732 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2733 if (OPERAND1_INDIRECT (Operands
)) {
2734 Index16
= VmReadIndex16 (VmPtr
, 2);
2736 Index16
= VmReadImmed16 (VmPtr
, 2);
2746 // Get the data to push
2748 if (OPERAND1_INDIRECT (Operands
)) {
2749 DataN
= VmReadMemN (VmPtr
, (UINTN
)(VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
));
2751 DataN
= (UINTN
)(VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
);
2755 // Adjust the stack down.
2757 VmPtr
->Gpr
[0] -= sizeof (UINTN
);
2758 VmWriteMemN (VmPtr
, (UINTN
)VmPtr
->Gpr
[0], DataN
);
2763 Execute the EBC PUSH instruction.
2766 PUSH[32|64] {@}R1 {Index16|Immed16}
2768 @param VmPtr A pointer to a VM context.
2770 @retval EFI_SUCCESS The instruction is executed successfully.
2775 IN VM_CONTEXT
*VmPtr
2785 // Get opcode and operands
2787 Opcode
= GETOPCODE (VmPtr
);
2788 Operands
= GETOPERANDS (VmPtr
);
2790 // Get immediate index if present, then advance the IP.
2792 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2793 if (OPERAND1_INDIRECT (Operands
)) {
2794 Index16
= VmReadIndex16 (VmPtr
, 2);
2796 Index16
= VmReadImmed16 (VmPtr
, 2);
2806 // Get the data to push
2808 if ((Opcode
& PUSHPOP_M_64
) != 0) {
2809 if (OPERAND1_INDIRECT (Operands
)) {
2810 Data64
= VmReadMem64 (VmPtr
, (UINTN
)(VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
));
2812 Data64
= (UINT64
)VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
;
2816 // Adjust the stack down, then write back the data
2818 VmPtr
->Gpr
[0] -= sizeof (UINT64
);
2819 VmWriteMem64 (VmPtr
, (UINTN
)VmPtr
->Gpr
[0], Data64
);
2824 if (OPERAND1_INDIRECT (Operands
)) {
2825 Data32
= VmReadMem32 (VmPtr
, (UINTN
)(VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
));
2827 Data32
= (UINT32
)VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
;
2831 // Adjust the stack down and write the data
2833 VmPtr
->Gpr
[0] -= sizeof (UINT32
);
2834 VmWriteMem32 (VmPtr
, (UINTN
)VmPtr
->Gpr
[0], Data32
);
2841 Execute the EBC POPn instruction.
2844 POPn {@}R1 {Index16|Immed16}
2846 @param VmPtr A pointer to a VM context.
2848 @retval EFI_SUCCESS The instruction is executed successfully.
2853 IN VM_CONTEXT
*VmPtr
2862 // Get opcode and operands
2864 Opcode
= GETOPCODE (VmPtr
);
2865 Operands
= GETOPERANDS (VmPtr
);
2867 // Get immediate data if present, and advance the IP
2869 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2870 if (OPERAND1_INDIRECT (Operands
)) {
2871 Index16
= VmReadIndex16 (VmPtr
, 2);
2873 Index16
= VmReadImmed16 (VmPtr
, 2);
2883 // Read the data off the stack, then adjust the stack pointer
2885 DataN
= VmReadMemN (VmPtr
, (UINTN
)VmPtr
->Gpr
[0]);
2886 VmPtr
->Gpr
[0] += sizeof (UINTN
);
2888 // Do the write-back
2890 if (OPERAND1_INDIRECT (Operands
)) {
2891 VmWriteMemN (VmPtr
, (UINTN
)(VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
), DataN
);
2893 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (INT64
)(UINT64
)(UINTN
)(DataN
+ Index16
);
2900 Execute the EBC POP instruction.
2903 POPn {@}R1 {Index16|Immed16}
2905 @param VmPtr A pointer to a VM context.
2907 @retval EFI_SUCCESS The instruction is executed successfully.
2912 IN VM_CONTEXT
*VmPtr
2922 // Get opcode and operands
2924 Opcode
= GETOPCODE (VmPtr
);
2925 Operands
= GETOPERANDS (VmPtr
);
2927 // Get immediate data if present, and advance the IP.
2929 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2930 if (OPERAND1_INDIRECT (Operands
)) {
2931 Index16
= VmReadIndex16 (VmPtr
, 2);
2933 Index16
= VmReadImmed16 (VmPtr
, 2);
2943 // Get the data off the stack, then write it to the appropriate location
2945 if ((Opcode
& PUSHPOP_M_64
) != 0) {
2947 // Read the data off the stack, then adjust the stack pointer
2949 Data64
= VmReadMem64 (VmPtr
, (UINTN
)VmPtr
->Gpr
[0]);
2950 VmPtr
->Gpr
[0] += sizeof (UINT64
);
2952 // Do the write-back
2954 if (OPERAND1_INDIRECT (Operands
)) {
2955 VmWriteMem64 (VmPtr
, (UINTN
)(VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
), Data64
);
2957 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = Data64
+ Index16
;
2961 // 32-bit pop. Read it off the stack and adjust the stack pointer
2963 Data32
= (INT32
)VmReadMem32 (VmPtr
, (UINTN
)VmPtr
->Gpr
[0]);
2964 VmPtr
->Gpr
[0] += sizeof (UINT32
);
2966 // Do the write-back
2968 if (OPERAND1_INDIRECT (Operands
)) {
2969 VmWriteMem32 (VmPtr
, (UINTN
)(VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
), Data32
);
2971 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (INT64
)Data32
+ Index16
;
2979 Implements the EBC CALL instruction.
2983 CALL32 {@}R1 {Immed32|Index32}
2985 CALLEX16 {@}R1 {Immed32}
2987 If Rx == R0, then it's a PC relative call to PC = PC + imm32.
2989 @param VmPtr A pointer to a VM context.
2991 @retval EFI_SUCCESS The instruction is executed successfully.
2996 IN VM_CONTEXT
*VmPtr
3007 // Get opcode and operands
3009 Opcode
= GETOPCODE (VmPtr
);
3010 Operands
= GETOPERANDS (VmPtr
);
3012 if ((Operands
& OPERAND_M_NATIVE_CALL
) != 0) {
3013 EbcDebuggerHookCALLEXStart (VmPtr
);
3015 EbcDebuggerHookCALLStart (VmPtr
);
3019 // Assign these as well to avoid compiler warnings
3024 FramePtr
= VmPtr
->FramePtr
;
3026 // Determine the instruction size, and get immediate data if present
3028 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
3029 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
3030 Immed64
= VmReadImmed64 (VmPtr
, 2);
3034 // If register operand is indirect, then the immediate data is an index
3036 if (OPERAND1_INDIRECT (Operands
)) {
3037 Immed32
= VmReadIndex32 (VmPtr
, 2);
3039 Immed32
= VmReadImmed32 (VmPtr
, 2);
3049 // If it's a call to EBC, adjust the stack pointer down 16 bytes and
3050 // put our return address and frame pointer on the VM stack.
3052 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3054 VmWriteMemN (VmPtr
, (UINTN
)VmPtr
->Gpr
[0], (UINTN
)FramePtr
);
3055 VmPtr
->FramePtr
= (VOID
*)(UINTN
)VmPtr
->Gpr
[0];
3057 VmWriteMem64 (VmPtr
, (UINTN
)VmPtr
->Gpr
[0], (UINT64
)(UINTN
)(VmPtr
->Ip
+ Size
));
3061 // If 64-bit data, then absolute jump only
3063 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
3065 // Native or EBC call?
3067 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3068 VmPtr
->Ip
= (VMIP
)(UINTN
)Immed64
;
3071 // Call external function, get the return value, and advance the IP
3073 EbcLLCALLEX (VmPtr
, (UINTN
)Immed64
, (UINTN
)VmPtr
->Gpr
[0], FramePtr
, Size
);
3077 // Get the register data. If operand1 == 0, then ignore register and
3078 // take immediate data as relative or absolute address.
3079 // Compiler should take care of upper bits if 32-bit machine.
3081 if (OPERAND1_REGNUM (Operands
) != 0) {
3082 Immed64
= (UINT64
)(UINTN
)VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)];
3086 // Get final address
3088 if (OPERAND1_INDIRECT (Operands
)) {
3089 Immed64
= (INT64
)(UINT64
)(UINTN
)VmReadMemN (VmPtr
, (UINTN
)(Immed64
+ Immed32
));
3095 // Now determine if external call, and then if relative or absolute
3097 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3099 // EBC call. Relative or absolute? If relative, then it's relative to the
3100 // start of the next instruction.
3102 if ((Operands
& OPERAND_M_RELATIVE_ADDR
) != 0) {
3103 VmPtr
->Ip
+= Immed64
+ Size
;
3105 VmPtr
->Ip
= (VMIP
)(UINTN
)Immed64
;
3109 // Native call. Relative or absolute?
3111 if ((Operands
& OPERAND_M_RELATIVE_ADDR
) != 0) {
3112 EbcLLCALLEX (VmPtr
, (UINTN
)(Immed64
+ VmPtr
->Ip
+ Size
), (UINTN
)VmPtr
->Gpr
[0], FramePtr
, Size
);
3114 if ((VmPtr
->StopFlags
& STOPFLAG_BREAK_ON_CALLEX
) != 0) {
3118 EbcLLCALLEX (VmPtr
, (UINTN
)Immed64
, (UINTN
)VmPtr
->Gpr
[0], FramePtr
, Size
);
3123 if ((Operands
& OPERAND_M_NATIVE_CALL
) != 0) {
3124 EbcDebuggerHookCALLEXEnd (VmPtr
);
3126 EbcDebuggerHookCALLEnd (VmPtr
);
3133 Execute the EBC RET instruction.
3138 @param VmPtr A pointer to a VM context.
3140 @retval EFI_SUCCESS The instruction is executed successfully.
3145 IN VM_CONTEXT
*VmPtr
3148 EbcDebuggerHookRETStart (VmPtr
);
3151 // If we're at the top of the stack, then simply set the done
3154 if (VmPtr
->StackRetAddr
== (UINT64
)VmPtr
->Gpr
[0]) {
3155 VmPtr
->StopFlags
|= STOPFLAG_APP_DONE
;
3158 // Pull the return address off the VM app's stack and set the IP
3161 if (!IS_ALIGNED ((UINTN
)VmPtr
->Gpr
[0], sizeof (UINT16
))) {
3162 EbcDebugSignalException (
3163 EXCEPT_EBC_ALIGNMENT_CHECK
,
3164 EXCEPTION_FLAG_FATAL
,
3170 // Restore the IP and frame pointer from the stack
3172 VmPtr
->Ip
= (VMIP
)(UINTN
)VmReadMem64 (VmPtr
, (UINTN
)VmPtr
->Gpr
[0]);
3174 VmPtr
->FramePtr
= (VOID
*)VmReadMemN (VmPtr
, (UINTN
)VmPtr
->Gpr
[0]);
3178 EbcDebuggerHookRETEnd (VmPtr
);
3184 Execute the EBC CMP instruction.
3187 CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
3189 @param VmPtr A pointer to a VM context.
3191 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
3192 @retval EFI_SUCCESS The instruction is executed successfully.
3197 IN VM_CONTEXT
*VmPtr
3209 // Get opcode and operands
3211 Opcode
= GETOPCODE (VmPtr
);
3212 Operands
= GETOPERANDS (VmPtr
);
3214 // Get the register data we're going to compare to
3216 Op1
= VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)];
3218 // Get immediate data
3220 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
3221 if (OPERAND2_INDIRECT (Operands
)) {
3222 Index16
= VmReadIndex16 (VmPtr
, 2);
3224 Index16
= VmReadImmed16 (VmPtr
, 2);
3236 if (OPERAND2_INDIRECT (Operands
)) {
3237 if ((Opcode
& OPCODE_M_64BIT
) != 0) {
3238 Op2
= (INT64
)VmReadMem64 (VmPtr
, (UINTN
)(VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index16
));
3241 // 32-bit operations. 0-extend the values for all cases.
3243 Op2
= (INT64
)(UINT64
)((UINT32
)VmReadMem32 (VmPtr
, (UINTN
)(VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index16
)));
3246 Op2
= VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index16
;
3250 // Now do the compare
3253 if ((Opcode
& OPCODE_M_64BIT
) != 0) {
3257 switch (Opcode
& OPCODE_M_OPCODE
) {
3279 case OPCODE_CMPULTE
:
3280 if ((UINT64
)Op1
<= (UINT64
)Op2
) {
3286 case OPCODE_CMPUGTE
:
3287 if ((UINT64
)Op1
>= (UINT64
)Op2
) {
3300 switch (Opcode
& OPCODE_M_OPCODE
) {
3302 if ((INT32
)Op1
== (INT32
)Op2
) {
3309 if ((INT32
)Op1
<= (INT32
)Op2
) {
3316 if ((INT32
)Op1
>= (INT32
)Op2
) {
3322 case OPCODE_CMPULTE
:
3323 if ((UINT32
)Op1
<= (UINT32
)Op2
) {
3329 case OPCODE_CMPUGTE
:
3330 if ((UINT32
)Op1
>= (UINT32
)Op2
) {
3342 // Now set the flag accordingly for the comparison
3345 VMFLAG_SET (VmPtr
, VMFLAGS_CC
);
3347 VMFLAG_CLEAR (VmPtr
, (UINT64
)VMFLAGS_CC
);
3358 Execute the EBC CMPI instruction
3361 CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
3363 @param VmPtr A pointer to a VM context.
3365 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
3366 @retval EFI_SUCCESS The instruction is executed successfully.
3371 IN VM_CONTEXT
*VmPtr
3383 // Get opcode and operands
3385 Opcode
= GETOPCODE (VmPtr
);
3386 Operands
= GETOPERANDS (VmPtr
);
3389 // Get operand1 index if present
3392 if ((Operands
& OPERAND_M_CMPI_INDEX
) != 0) {
3393 Index16
= VmReadIndex16 (VmPtr
, 2);
3400 // Get operand1 data we're going to compare to
3402 Op1
= (INT64
)VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)];
3403 if (OPERAND1_INDIRECT (Operands
)) {
3405 // Indirect operand1. Fetch 32 or 64-bit value based on compare size.
3407 if ((Opcode
& OPCODE_M_CMPI64
) != 0) {
3408 Op1
= (INT64
)VmReadMem64 (VmPtr
, (UINTN
)Op1
+ Index16
);
3410 Op1
= (INT64
)VmReadMem32 (VmPtr
, (UINTN
)Op1
+ Index16
);
3414 // Better not have been an index with direct. That is, CMPI R1 Index,...
3417 if ((Operands
& OPERAND_M_CMPI_INDEX
) != 0) {
3418 EbcDebugSignalException (
3419 EXCEPT_EBC_INSTRUCTION_ENCODING
,
3420 EXCEPTION_FLAG_ERROR
,
3424 return EFI_UNSUPPORTED
;
3429 // Get immediate data -- 16- or 32-bit sign extended
3431 if ((Opcode
& OPCODE_M_CMPI32_DATA
) != 0) {
3432 Op2
= (INT64
)VmReadImmed32 (VmPtr
, Size
);
3436 // 16-bit immediate data. Sign extend always.
3438 Op2
= (INT64
)((INT16
)VmReadImmed16 (VmPtr
, Size
));
3443 // Now do the compare
3446 if ((Opcode
& OPCODE_M_CMPI64
) != 0) {
3448 // 64 bit comparison
3450 switch (Opcode
& OPCODE_M_OPCODE
) {
3452 if (Op1
== (INT64
)Op2
) {
3458 case OPCODE_CMPILTE
:
3459 if (Op1
<= (INT64
)Op2
) {
3465 case OPCODE_CMPIGTE
:
3466 if (Op1
>= (INT64
)Op2
) {
3472 case OPCODE_CMPIULTE
:
3473 if ((UINT64
)Op1
<= (UINT64
)((UINT32
)Op2
)) {
3479 case OPCODE_CMPIUGTE
:
3480 if ((UINT64
)Op1
>= (UINT64
)((UINT32
)Op2
)) {
3491 // 32-bit comparisons
3493 switch (Opcode
& OPCODE_M_OPCODE
) {
3495 if ((INT32
)Op1
== Op2
) {
3501 case OPCODE_CMPILTE
:
3502 if ((INT32
)Op1
<= Op2
) {
3508 case OPCODE_CMPIGTE
:
3509 if ((INT32
)Op1
>= Op2
) {
3515 case OPCODE_CMPIULTE
:
3516 if ((UINT32
)Op1
<= (UINT32
)Op2
) {
3522 case OPCODE_CMPIUGTE
:
3523 if ((UINT32
)Op1
>= (UINT32
)Op2
) {
3535 // Now set the flag accordingly for the comparison
3538 VMFLAG_SET (VmPtr
, VMFLAGS_CC
);
3540 VMFLAG_CLEAR (VmPtr
, (UINT64
)VMFLAGS_CC
);
3551 Execute the EBC NOT instruction.s
3554 NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
3556 @param VmPtr A pointer to a VM context.
3557 @param Op1 Operand 1 from the instruction
3558 @param Op2 Operand 2 from the instruction
3565 IN VM_CONTEXT
*VmPtr
,
3574 Execute the EBC NEG instruction.
3577 NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
3579 @param VmPtr A pointer to a VM context.
3580 @param Op1 Operand 1 from the instruction
3581 @param Op2 Operand 2 from the instruction
3588 IN VM_CONTEXT
*VmPtr
,
3597 Execute the EBC ADD instruction.
3600 ADD[32|64] {@}R1, {@}R2 {Index16}
3602 @param VmPtr A pointer to a VM context.
3603 @param Op1 Operand 1 from the instruction
3604 @param Op2 Operand 2 from the instruction
3611 IN VM_CONTEXT
*VmPtr
,
3620 Execute the EBC SUB instruction.
3623 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3625 @param VmPtr A pointer to a VM context.
3626 @param Op1 Operand 1 from the instruction
3627 @param Op2 Operand 2 from the instruction
3634 IN VM_CONTEXT
*VmPtr
,
3639 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3640 return (UINT64
)((INT64
)((INT64
)Op1
- (INT64
)Op2
));
3642 return (UINT64
)((INT64
)((INT32
)((INT32
)Op1
- (INT32
)Op2
)));
3647 Execute the EBC MUL instruction.
3650 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3652 @param VmPtr A pointer to a VM context.
3653 @param Op1 Operand 1 from the instruction
3654 @param Op2 Operand 2 from the instruction
3661 IN VM_CONTEXT
*VmPtr
,
3666 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3667 return MultS64x64 ((INT64
)Op1
, (INT64
)Op2
);
3669 return (UINT64
)((INT64
)((INT32
)((INT32
)Op1
* (INT32
)Op2
)));
3674 Execute the EBC MULU instruction
3677 MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3679 @param VmPtr A pointer to a VM context.
3680 @param Op1 Operand 1 from the instruction
3681 @param Op2 Operand 2 from the instruction
3683 @return (unsigned)Op1 * (unsigned)Op2
3688 IN VM_CONTEXT
*VmPtr
,
3693 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3694 return MultU64x64 (Op1
, Op2
);
3696 return (UINT64
)((UINT32
)((UINT32
)Op1
* (UINT32
)Op2
));
3701 Execute the EBC DIV instruction.
3704 DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
3706 @param VmPtr A pointer to a VM context.
3707 @param Op1 Operand 1 from the instruction
3708 @param Op2 Operand 2 from the instruction
3715 IN VM_CONTEXT
*VmPtr
,
3723 // Check for divide-by-0
3726 EbcDebugSignalException (
3727 EXCEPT_EBC_DIVIDE_ERROR
,
3728 EXCEPTION_FLAG_FATAL
,
3734 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3735 return (UINT64
)(DivS64x64Remainder (Op1
, Op2
, &Remainder
));
3737 return (UINT64
)((INT64
)((INT32
)Op1
/ (INT32
)Op2
));
3743 Execute the EBC DIVU instruction
3746 DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3748 @param VmPtr A pointer to a VM context.
3749 @param Op1 Operand 1 from the instruction
3750 @param Op2 Operand 2 from the instruction
3752 @return (unsigned)Op1 / (unsigned)Op2
3757 IN VM_CONTEXT
*VmPtr
,
3765 // Check for divide-by-0
3768 EbcDebugSignalException (
3769 EXCEPT_EBC_DIVIDE_ERROR
,
3770 EXCEPTION_FLAG_FATAL
,
3776 // Get the destination register
3778 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3779 return (UINT64
)(DivU64x64Remainder (Op1
, Op2
, &Remainder
));
3781 return (UINT64
)((UINT32
)Op1
/ (UINT32
)Op2
);
3787 Execute the EBC MOD instruction.
3790 MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
3792 @param VmPtr A pointer to a VM context.
3793 @param Op1 Operand 1 from the instruction
3794 @param Op2 Operand 2 from the instruction
3796 @return Op1 MODULUS Op2
3801 IN VM_CONTEXT
*VmPtr
,
3809 // Check for divide-by-0
3812 EbcDebugSignalException (
3813 EXCEPT_EBC_DIVIDE_ERROR
,
3814 EXCEPTION_FLAG_FATAL
,
3819 DivS64x64Remainder ((INT64
)Op1
, (INT64
)Op2
, &Remainder
);
3825 Execute the EBC MODU instruction.
3828 MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3830 @param VmPtr A pointer to a VM context.
3831 @param Op1 Operand 1 from the instruction
3832 @param Op2 Operand 2 from the instruction
3834 @return Op1 UNSIGNED_MODULUS Op2
3839 IN VM_CONTEXT
*VmPtr
,
3847 // Check for divide-by-0
3850 EbcDebugSignalException (
3851 EXCEPT_EBC_DIVIDE_ERROR
,
3852 EXCEPTION_FLAG_FATAL
,
3857 DivU64x64Remainder (Op1
, Op2
, &Remainder
);
3863 Execute the EBC AND instruction.
3866 AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
3868 @param VmPtr A pointer to a VM context.
3869 @param Op1 Operand 1 from the instruction
3870 @param Op2 Operand 2 from the instruction
3877 IN VM_CONTEXT
*VmPtr
,
3886 Execute the EBC OR instruction.
3889 OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3891 @param VmPtr A pointer to a VM context.
3892 @param Op1 Operand 1 from the instruction
3893 @param Op2 Operand 2 from the instruction
3900 IN VM_CONTEXT
*VmPtr
,
3909 Execute the EBC XOR instruction.
3912 XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3914 @param VmPtr A pointer to a VM context.
3915 @param Op1 Operand 1 from the instruction
3916 @param Op2 Operand 2 from the instruction
3923 IN VM_CONTEXT
*VmPtr
,
3932 Execute the EBC SHL shift left instruction.
3935 SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
3937 @param VmPtr A pointer to a VM context.
3938 @param Op1 Operand 1 from the instruction
3939 @param Op2 Operand 2 from the instruction
3946 IN VM_CONTEXT
*VmPtr
,
3951 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3952 return LShiftU64 (Op1
, (UINTN
)Op2
);
3954 return (UINT64
)((UINT32
)((UINT32
)Op1
<< (UINT32
)Op2
));
3959 Execute the EBC SHR instruction.
3962 SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3964 @param VmPtr A pointer to a VM context.
3965 @param Op1 Operand 1 from the instruction
3966 @param Op2 Operand 2 from the instruction
3968 @return Op1 >> Op2 (unsigned operands)
3973 IN VM_CONTEXT
*VmPtr
,
3978 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3979 return RShiftU64 (Op1
, (UINTN
)Op2
);
3981 return (UINT64
)((UINT32
)Op1
>> (UINT32
)Op2
);
3986 Execute the EBC ASHR instruction.
3989 ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3991 @param VmPtr A pointer to a VM context.
3992 @param Op1 Operand 1 from the instruction
3993 @param Op2 Operand 2 from the instruction
3995 @return Op1 >> Op2 (signed)
4000 IN VM_CONTEXT
*VmPtr
,
4005 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
4006 return ARShiftU64 (Op1
, (UINTN
)Op2
);
4008 return (UINT64
)((INT64
)((INT32
)Op1
>> (UINT32
)Op2
));
4013 Execute the EBC EXTNDB instruction to sign-extend a byte value.
4016 EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
4018 @param VmPtr A pointer to a VM context.
4019 @param Op1 Operand 1 from the instruction
4020 @param Op2 Operand 2 from the instruction
4022 @return (INT64)(INT8)Op2
4027 IN VM_CONTEXT
*VmPtr
,
4036 // Convert to byte, then return as 64-bit signed value to let compiler
4037 // sign-extend the value
4040 Data64
= (INT64
)Data8
;
4042 return (UINT64
)Data64
;
4046 Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
4049 EXTNDW[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)(INT16)Op2
4060 IN VM_CONTEXT
*VmPtr
,
4069 // Convert to word, then return as 64-bit signed value to let compiler
4070 // sign-extend the value
4072 Data16
= (INT16
)Op2
;
4073 Data64
= (INT64
)Data16
;
4075 return (UINT64
)Data64
;
4079 // Execute the EBC EXTNDD instruction.
4081 // Format: EXTNDD {@}Rx, {@}Ry [Index16|Immed16]
4082 // EXTNDD Dest, Source
4084 // Operation: Dest <- SignExtended((DWORD)Source))
4088 Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
4091 EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
4093 @param VmPtr A pointer to a VM context.
4094 @param Op1 Operand 1 from the instruction
4095 @param Op2 Operand 2 from the instruction
4097 @return (INT64)(INT32)Op2
4102 IN VM_CONTEXT
*VmPtr
,
4111 // Convert to 32-bit value, then return as 64-bit signed value to let compiler
4112 // sign-extend the value
4114 Data32
= (INT32
)Op2
;
4115 Data64
= (INT64
)Data32
;
4117 return (UINT64
)Data64
;
4121 Execute all the EBC signed data manipulation instructions.
4122 Since the EBC data manipulation instructions all have the same basic form,
4123 they can share the code that does the fetch of operands and the write-back
4124 of the result. This function performs the fetch of the operands (even if
4125 both are not needed to be fetched, like NOT instruction), dispatches to the
4126 appropriate subfunction, then writes back the returned result.
4129 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4131 @param VmPtr A pointer to VM context.
4133 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4134 @retval EFI_SUCCESS The instruction is executed successfully.
4138 ExecuteSignedDataManip (
4139 IN VM_CONTEXT
*VmPtr
4143 // Just call the data manipulation function with a flag indicating this
4144 // is a signed operation.
4146 return ExecuteDataManip (VmPtr
, TRUE
);
4150 Execute all the EBC unsigned data manipulation instructions.
4151 Since the EBC data manipulation instructions all have the same basic form,
4152 they can share the code that does the fetch of operands and the write-back
4153 of the result. This function performs the fetch of the operands (even if
4154 both are not needed to be fetched, like NOT instruction), dispatches to the
4155 appropriate subfunction, then writes back the returned result.
4158 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4160 @param VmPtr A pointer to VM context.
4162 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4163 @retval EFI_SUCCESS The instruction is executed successfully.
4167 ExecuteUnsignedDataManip (
4168 IN VM_CONTEXT
*VmPtr
4172 // Just call the data manipulation function with a flag indicating this
4173 // is not a signed operation.
4175 return ExecuteDataManip (VmPtr
, FALSE
);
4179 Execute all the EBC data manipulation instructions.
4180 Since the EBC data manipulation instructions all have the same basic form,
4181 they can share the code that does the fetch of operands and the write-back
4182 of the result. This function performs the fetch of the operands (even if
4183 both are not needed to be fetched, like NOT instruction), dispatches to the
4184 appropriate subfunction, then writes back the returned result.
4187 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4189 @param VmPtr A pointer to VM context.
4190 @param IsSignedOp Indicates whether the operand is signed or not.
4192 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4193 @retval EFI_SUCCESS The instruction is executed successfully.
4198 IN VM_CONTEXT
*VmPtr
,
4199 IN BOOLEAN IsSignedOp
4208 INTN DataManipDispatchTableIndex
;
4211 // Get opcode and operands
4213 Opcode
= GETOPCODE (VmPtr
);
4214 Operands
= GETOPERANDS (VmPtr
);
4217 // Determine if we have immediate data by the opcode
4219 if ((Opcode
& DATAMANIP_M_IMMDATA
) != 0) {
4221 // Index16 if Ry is indirect, or Immed16 if Ry direct.
4223 if (OPERAND2_INDIRECT (Operands
)) {
4224 Index16
= VmReadIndex16 (VmPtr
, 2);
4226 Index16
= VmReadImmed16 (VmPtr
, 2);
4236 // Now get operand2 (source). It's of format {@}R2 {Index16|Immed16}
4238 Op2
= (UINT64
)VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index16
;
4239 if (OPERAND2_INDIRECT (Operands
)) {
4241 // Indirect form: @R2 Index16. Fetch as 32- or 64-bit data
4243 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4244 Op2
= VmReadMem64 (VmPtr
, (UINTN
)Op2
);
4247 // Read as signed value where appropriate.
4250 Op2
= (UINT64
)(INT64
)((INT32
)VmReadMem32 (VmPtr
, (UINTN
)Op2
));
4252 Op2
= (UINT64
)VmReadMem32 (VmPtr
, (UINTN
)Op2
);
4256 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4258 Op2
= (UINT64
)(INT64
)((INT32
)Op2
);
4260 Op2
= (UINT64
)((UINT32
)Op2
);
4266 // Get operand1 (destination and sometimes also an actual operand)
4269 Op1
= (UINT64
)VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)];
4270 if (OPERAND1_INDIRECT (Operands
)) {
4271 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4272 Op1
= VmReadMem64 (VmPtr
, (UINTN
)Op1
);
4275 Op1
= (UINT64
)(INT64
)((INT32
)VmReadMem32 (VmPtr
, (UINTN
)Op1
));
4277 Op1
= (UINT64
)VmReadMem32 (VmPtr
, (UINTN
)Op1
);
4281 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4283 Op1
= (UINT64
)(INT64
)((INT32
)Op1
);
4285 Op1
= (UINT64
)((UINT32
)Op1
);
4291 // Dispatch to the computation function
4293 DataManipDispatchTableIndex
= (Opcode
& OPCODE_M_OPCODE
) - OPCODE_NOT
;
4294 if ((DataManipDispatchTableIndex
< 0) ||
4295 (DataManipDispatchTableIndex
>= ARRAY_SIZE (mDataManipDispatchTable
)))
4297 EbcDebugSignalException (
4298 EXCEPT_EBC_INVALID_OPCODE
,
4299 EXCEPTION_FLAG_ERROR
,
4303 // Advance and return
4306 return EFI_UNSUPPORTED
;
4308 Op2
= mDataManipDispatchTable
[DataManipDispatchTableIndex
](VmPtr
, Op1
, Op2
);
4312 // Write back the result.
4314 if (OPERAND1_INDIRECT (Operands
)) {
4315 Op1
= (UINT64
)VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)];
4316 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4317 VmWriteMem64 (VmPtr
, (UINTN
)Op1
, Op2
);
4319 VmWriteMem32 (VmPtr
, (UINTN
)Op1
, (UINT32
)Op2
);
4323 // Storage back to a register. Write back, clearing upper bits (as per
4324 // the specification) if 32-bit operation.
4326 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = Op2
;
4327 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4328 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] &= 0xFFFFFFFF;
4333 // Advance the instruction pointer
4340 Execute the EBC LOADSP instruction.
4345 @param VmPtr A pointer to a VM context.
4347 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4348 @retval EFI_SUCCESS The instruction is executed successfully.
4353 IN VM_CONTEXT
*VmPtr
4361 Operands
= GETOPERANDS (VmPtr
);
4366 switch (OPERAND1_REGNUM (Operands
)) {
4372 // Spec states that this instruction will not modify reserved bits in
4373 // the flags register.
4375 VmPtr
->Flags
= (VmPtr
->Flags
&~VMFLAGS_ALL_VALID
) | (VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] & VMFLAGS_ALL_VALID
);
4379 EbcDebugSignalException (
4380 EXCEPT_EBC_INSTRUCTION_ENCODING
,
4381 EXCEPTION_FLAG_WARNING
,
4385 return EFI_UNSUPPORTED
;
4393 Execute the EBC STORESP instruction.
4396 STORESP Rx, FLAGS|IP
4398 @param VmPtr A pointer to a VM context.
4400 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4401 @retval EFI_SUCCESS The instruction is executed successfully.
4406 IN VM_CONTEXT
*VmPtr
4414 Operands
= GETOPERANDS (VmPtr
);
4419 switch (OPERAND2_REGNUM (Operands
)) {
4425 // Retrieve the value in the flags register, then clear reserved bits
4427 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (UINT64
)(VmPtr
->Flags
& VMFLAGS_ALL_VALID
);
4431 // Get IP -- address of following instruction
4434 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (UINT64
)(UINTN
)VmPtr
->Ip
+ 2;
4438 EbcDebugSignalException (
4439 EXCEPT_EBC_INSTRUCTION_ENCODING
,
4440 EXCEPTION_FLAG_WARNING
,
4444 return EFI_UNSUPPORTED
;
4453 Decode a 16-bit index to determine the offset. Given an index value:
4456 b14:12 - number of bits in this index assigned to natural units (=a)
4457 ba:11 - constant units = ConstUnits
4458 b0:a - natural units = NaturalUnits
4460 Given this info, the offset can be computed by:
4461 offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
4463 Max offset is achieved with index = 0x7FFF giving an offset of
4464 0x27B (32-bit machine) or 0x477 (64-bit machine).
4465 Min offset is achieved with index =
4467 @param VmPtr A pointer to VM context.
4468 @param CodeOffset Offset from IP of the location of the 16-bit index
4471 @return The decoded offset.
4476 IN VM_CONTEXT
*VmPtr
,
4477 IN UINT32 CodeOffset
4488 // First read the index from the code stream
4490 Index
= VmReadCode16 (VmPtr
, CodeOffset
);
4493 // Get the mask for NaturalUnits. First get the number of bits from the index.
4495 NBits
= (INT16
)((Index
& 0x7000) >> 12);
4498 // Scale it for 16-bit indexes
4503 // Now using the number of bits, create a mask.
4505 Mask
= (INT16
)((INT16
) ~0 << NBits
);
4508 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4510 NaturalUnits
= (INT16
)(Index
&~Mask
);
4513 // Now compute ConstUnits
4515 ConstUnits
= (INT16
)(((Index
&~0xF000) & Mask
) >> NBits
);
4517 Offset
= (INT16
)(NaturalUnits
* sizeof (UINTN
) + ConstUnits
);
4522 if ((Index
& 0x8000) != 0) {
4524 // Do it the hard way to work around a bogus compiler warning
4526 // Offset = -1 * Offset;
4528 Offset
= (INT16
)((INT32
)Offset
* -1);
4535 Decode a 32-bit index to determine the offset.
4537 @param VmPtr A pointer to VM context.
4538 @param CodeOffset Offset from IP of the location of the 32-bit index
4541 @return Converted index per EBC VM specification.
4546 IN VM_CONTEXT
*VmPtr
,
4547 IN UINT32 CodeOffset
4557 Index
= VmReadImmed32 (VmPtr
, CodeOffset
);
4560 // Get the mask for NaturalUnits. First get the number of bits from the index.
4562 NBits
= (Index
& 0x70000000) >> 28;
4565 // Scale it for 32-bit indexes
4570 // Now using the number of bits, create a mask.
4572 Mask
= (INT32
) ~0 << NBits
;
4575 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4577 NaturalUnits
= Index
&~Mask
;
4580 // Now compute ConstUnits
4582 ConstUnits
= ((Index
&~0xF0000000) & Mask
) >> NBits
;
4584 Offset
= NaturalUnits
* sizeof (UINTN
) + ConstUnits
;
4589 if ((Index
& 0x80000000) != 0) {
4590 Offset
= Offset
* -1;
4597 Decode a 64-bit index to determine the offset.
4599 @param VmPtr A pointer to VM context.s
4600 @param CodeOffset Offset from IP of the location of the 64-bit index
4603 @return Converted index per EBC VM specification
4608 IN VM_CONTEXT
*VmPtr
,
4609 IN UINT32 CodeOffset
4619 Index
= VmReadCode64 (VmPtr
, CodeOffset
);
4622 // Get the mask for NaturalUnits. First get the number of bits from the index.
4624 NBits
= RShiftU64 ((Index
& 0x7000000000000000ULL
), 60);
4627 // Scale it for 64-bit indexes (multiply by 8 by shifting left 3)
4629 NBits
= LShiftU64 ((UINT64
)NBits
, 3);
4632 // Now using the number of bits, create a mask.
4634 Mask
= (LShiftU64 ((UINT64
) ~0, (UINTN
)NBits
));
4637 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4639 NaturalUnits
= Index
&~Mask
;
4642 // Now compute ConstUnits
4644 ConstUnits
= ARShiftU64 (((Index
&~0xF000000000000000ULL
) & Mask
), (UINTN
)NBits
);
4646 Offset
= MultU64x64 ((UINT64
)NaturalUnits
, sizeof (UINTN
)) + ConstUnits
;
4651 if ((Index
& 0x8000000000000000ULL
) != 0) {
4652 Offset
= MultS64x64 (Offset
, -1);
4659 Writes 8-bit data to memory address.
4661 This routine is called by the EBC data
4662 movement instructions that write to memory. Since these writes
4663 may be to the stack, which looks like (high address on top) this,
4665 [EBC entry point arguments]
4669 we need to detect all attempts to write to the EBC entry point argument
4670 stack area and adjust the address (which will initially point into the
4671 VM stack) to point into the EBC entry point arguments.
4673 @param VmPtr A pointer to a VM context.
4674 @param Addr Address to write to.
4675 @param Data Value to write to Addr.
4677 @retval EFI_SUCCESS The instruction is executed successfully.
4678 @retval Other Some error occurs when writing data to the address.
4683 IN VM_CONTEXT
*VmPtr
,
4689 // Convert the address if it's in the stack gap
4691 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4692 *(UINT8
*)Addr
= Data
;
4697 Writes 16-bit data to memory address.
4699 This routine is called by the EBC data
4700 movement instructions that write to memory. Since these writes
4701 may be to the stack, which looks like (high address on top) this,
4703 [EBC entry point arguments]
4707 we need to detect all attempts to write to the EBC entry point argument
4708 stack area and adjust the address (which will initially point into the
4709 VM stack) to point into the EBC entry point arguments.
4711 @param VmPtr A pointer to a VM context.
4712 @param Addr Address to write to.
4713 @param Data Value to write to Addr.
4715 @retval EFI_SUCCESS The instruction is executed successfully.
4716 @retval Other Some error occurs when writing data to the address.
4721 IN VM_CONTEXT
*VmPtr
,
4729 // Convert the address if it's in the stack gap
4731 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4734 // Do a simple write if aligned
4736 if (IS_ALIGNED (Addr
, sizeof (UINT16
))) {
4737 *(UINT16
*)Addr
= Data
;
4740 // Write as two bytes
4743 if ((Status
= VmWriteMem8 (VmPtr
, Addr
, (UINT8
)Data
)) != EFI_SUCCESS
) {
4748 if ((Status
= VmWriteMem8 (VmPtr
, Addr
+ 1, (UINT8
)(Data
>> 8))) != EFI_SUCCESS
) {
4759 Writes 32-bit data to memory address.
4761 This routine is called by the EBC data
4762 movement instructions that write to memory. Since these writes
4763 may be to the stack, which looks like (high address on top) this,
4765 [EBC entry point arguments]
4769 we need to detect all attempts to write to the EBC entry point argument
4770 stack area and adjust the address (which will initially point into the
4771 VM stack) to point into the EBC entry point arguments.
4773 @param VmPtr A pointer to a VM context.
4774 @param Addr Address to write to.
4775 @param Data Value to write to Addr.
4777 @retval EFI_SUCCESS The instruction is executed successfully.
4778 @retval Other Some error occurs when writing data to the address.
4783 IN VM_CONTEXT
*VmPtr
,
4791 // Convert the address if it's in the stack gap
4793 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4796 // Do a simple write if aligned
4798 if (IS_ALIGNED (Addr
, sizeof (UINT32
))) {
4799 *(UINT32
*)Addr
= Data
;
4802 // Write as two words
4805 if ((Status
= VmWriteMem16 (VmPtr
, Addr
, (UINT16
)Data
)) != EFI_SUCCESS
) {
4810 if ((Status
= VmWriteMem16 (VmPtr
, Addr
+ sizeof (UINT16
), (UINT16
)(Data
>> 16))) != EFI_SUCCESS
) {
4821 Writes 64-bit data to memory address.
4823 This routine is called by the EBC data
4824 movement instructions that write to memory. Since these writes
4825 may be to the stack, which looks like (high address on top) this,
4827 [EBC entry point arguments]
4831 we need to detect all attempts to write to the EBC entry point argument
4832 stack area and adjust the address (which will initially point into the
4833 VM stack) to point into the EBC entry point arguments.
4835 @param VmPtr A pointer to a VM context.
4836 @param Addr Address to write to.
4837 @param Data Value to write to Addr.
4839 @retval EFI_SUCCESS The instruction is executed successfully.
4840 @retval Other Some error occurs when writing data to the address.
4845 IN VM_CONTEXT
*VmPtr
,
4853 // Convert the address if it's in the stack gap
4855 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4858 // Do a simple write if aligned
4860 if (IS_ALIGNED (Addr
, sizeof (UINT64
))) {
4861 *(UINT64
*)Addr
= Data
;
4864 // Write as two 32-bit words
4867 if ((Status
= VmWriteMem32 (VmPtr
, Addr
, (UINT32
)Data
)) != EFI_SUCCESS
) {
4872 if ((Status
= VmWriteMem32 (VmPtr
, Addr
+ sizeof (UINT32
), (UINT32
)RShiftU64 (Data
, 32))) != EFI_SUCCESS
) {
4883 Writes UINTN data to memory address.
4885 This routine is called by the EBC data
4886 movement instructions that write to memory. Since these writes
4887 may be to the stack, which looks like (high address on top) this,
4889 [EBC entry point arguments]
4893 we need to detect all attempts to write to the EBC entry point argument
4894 stack area and adjust the address (which will initially point into the
4895 VM stack) to point into the EBC entry point arguments.
4897 @param VmPtr A pointer to a VM context.
4898 @param Addr Address to write to.
4899 @param Data Value to write to Addr.
4901 @retval EFI_SUCCESS The instruction is executed successfully.
4902 @retval Other Some error occurs when writing data to the address.
4907 IN VM_CONTEXT
*VmPtr
,
4915 Status
= EFI_SUCCESS
;
4918 // Convert the address if it's in the stack gap
4920 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4923 // Do a simple write if aligned
4925 if (IS_ALIGNED (Addr
, sizeof (UINTN
))) {
4926 *(UINTN
*)Addr
= Data
;
4928 for (Index
= 0; Index
< sizeof (UINTN
) / sizeof (UINT32
); Index
++) {
4930 Status
= VmWriteMem32 (VmPtr
, Addr
+ Index
* sizeof (UINT32
), (UINT32
)Data
);
4932 Data
= (UINTN
)RShiftU64 ((UINT64
)Data
, 32);
4940 Reads 8-bit immediate value at the offset.
4942 This routine is called by the EBC execute
4943 functions to read EBC immediate values from the code stream.
4944 Since we can't assume alignment, each tries to read in the biggest
4945 chunks size available, but will revert to smaller reads if necessary.
4947 @param VmPtr A pointer to a VM context.
4948 @param Offset offset from IP of the code bytes to read.
4950 @return Signed data of the requested size from the specified address.
4955 IN VM_CONTEXT
*VmPtr
,
4960 // Simply return the data in flat memory space
4962 return *(INT8
*)(VmPtr
->Ip
+ Offset
);
4966 Reads 16-bit immediate value at the offset.
4968 This routine is called by the EBC execute
4969 functions to read EBC immediate values from the code stream.
4970 Since we can't assume alignment, each tries to read in the biggest
4971 chunks size available, but will revert to smaller reads if necessary.
4973 @param VmPtr A pointer to a VM context.
4974 @param Offset offset from IP of the code bytes to read.
4976 @return Signed data of the requested size from the specified address.
4981 IN VM_CONTEXT
*VmPtr
,
4986 // Read direct if aligned
4988 if (IS_ALIGNED ((UINTN
)VmPtr
->Ip
+ Offset
, sizeof (INT16
))) {
4989 return *(INT16
*)(VmPtr
->Ip
+ Offset
);
4992 // All code word reads should be aligned
4994 EbcDebugSignalException (
4995 EXCEPT_EBC_ALIGNMENT_CHECK
,
4996 EXCEPTION_FLAG_WARNING
,
5002 // Return unaligned data
5004 return (INT16
)(*(UINT8
*)(VmPtr
->Ip
+ Offset
) + (*(UINT8
*)(VmPtr
->Ip
+ Offset
+ 1) << 8));
5008 Reads 32-bit immediate value at the offset.
5010 This routine is called by the EBC execute
5011 functions to read EBC immediate values from the code stream.
5012 Since we can't assume alignment, each tries to read in the biggest
5013 chunks size available, but will revert to smaller reads if necessary.
5015 @param VmPtr A pointer to a VM context.
5016 @param Offset offset from IP of the code bytes to read.
5018 @return Signed data of the requested size from the specified address.
5023 IN VM_CONTEXT
*VmPtr
,
5030 // Read direct if aligned
5032 if (IS_ALIGNED ((UINTN
)VmPtr
->Ip
+ Offset
, sizeof (UINT32
))) {
5033 return *(INT32
*)(VmPtr
->Ip
+ Offset
);
5037 // Return unaligned data
5039 Data
= (UINT32
)VmReadCode16 (VmPtr
, Offset
);
5040 Data
|= (UINT32
)(VmReadCode16 (VmPtr
, Offset
+ 2) << 16);
5045 Reads 64-bit immediate value at the offset.
5047 This routine is called by the EBC execute
5048 functions to read EBC immediate values from the code stream.
5049 Since we can't assume alignment, each tries to read in the biggest
5050 chunks size available, but will revert to smaller reads if necessary.
5052 @param VmPtr A pointer to a VM context.
5053 @param Offset offset from IP of the code bytes to read.
5055 @return Signed data of the requested size from the specified address.
5060 IN VM_CONTEXT
*VmPtr
,
5069 // Read direct if aligned
5071 if (IS_ALIGNED ((UINTN
)VmPtr
->Ip
+ Offset
, sizeof (UINT64
))) {
5072 return *(UINT64
*)(VmPtr
->Ip
+ Offset
);
5076 // Return unaligned data.
5078 Ptr
= (UINT8
*)&Data64
;
5079 Data32
= VmReadCode32 (VmPtr
, Offset
);
5080 *(UINT32
*)Ptr
= Data32
;
5081 Ptr
+= sizeof (Data32
);
5082 Data32
= VmReadCode32 (VmPtr
, Offset
+ sizeof (UINT32
));
5083 *(UINT32
*)Ptr
= Data32
;
5088 Reads 16-bit unsigned data from the code stream.
5090 This routine provides the ability to read raw unsigned data from the code
5093 @param VmPtr A pointer to VM context
5094 @param Offset Offset from current IP to the raw data to read.
5096 @return The raw unsigned 16-bit value from the code stream.
5101 IN VM_CONTEXT
*VmPtr
,
5106 // Read direct if aligned
5108 if (IS_ALIGNED ((UINTN
)VmPtr
->Ip
+ Offset
, sizeof (UINT16
))) {
5109 return *(UINT16
*)(VmPtr
->Ip
+ Offset
);
5112 // All code word reads should be aligned
5114 EbcDebugSignalException (
5115 EXCEPT_EBC_ALIGNMENT_CHECK
,
5116 EXCEPTION_FLAG_WARNING
,
5122 // Return unaligned data
5124 return (UINT16
)(*(UINT8
*)(VmPtr
->Ip
+ Offset
) + (*(UINT8
*)(VmPtr
->Ip
+ Offset
+ 1) << 8));
5128 Reads 32-bit unsigned data from the code stream.
5130 This routine provides the ability to read raw unsigned data from the code
5133 @param VmPtr A pointer to VM context
5134 @param Offset Offset from current IP to the raw data to read.
5136 @return The raw unsigned 32-bit value from the code stream.
5141 IN VM_CONTEXT
*VmPtr
,
5148 // Read direct if aligned
5150 if (IS_ALIGNED ((UINTN
)VmPtr
->Ip
+ Offset
, sizeof (UINT32
))) {
5151 return *(UINT32
*)(VmPtr
->Ip
+ Offset
);
5155 // Return unaligned data
5157 Data
= (UINT32
)VmReadCode16 (VmPtr
, Offset
);
5158 Data
|= (VmReadCode16 (VmPtr
, Offset
+ 2) << 16);
5163 Reads 64-bit unsigned data from the code stream.
5165 This routine provides the ability to read raw unsigned data from the code
5168 @param VmPtr A pointer to VM context
5169 @param Offset Offset from current IP to the raw data to read.
5171 @return The raw unsigned 64-bit value from the code stream.
5176 IN VM_CONTEXT
*VmPtr
,
5185 // Read direct if aligned
5187 if (IS_ALIGNED ((UINTN
)VmPtr
->Ip
+ Offset
, sizeof (UINT64
))) {
5188 return *(UINT64
*)(VmPtr
->Ip
+ Offset
);
5192 // Return unaligned data.
5194 Ptr
= (UINT8
*)&Data64
;
5195 Data32
= VmReadCode32 (VmPtr
, Offset
);
5196 *(UINT32
*)Ptr
= Data32
;
5197 Ptr
+= sizeof (Data32
);
5198 Data32
= VmReadCode32 (VmPtr
, Offset
+ sizeof (UINT32
));
5199 *(UINT32
*)Ptr
= Data32
;
5204 Reads 8-bit data form the memory address.
5206 @param VmPtr A pointer to VM context.
5207 @param Addr The memory address.
5209 @return The 8-bit value from the memory address.
5214 IN VM_CONTEXT
*VmPtr
,
5219 // Convert the address if it's in the stack gap
5221 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5223 // Simply return the data in flat memory space
5225 return *(UINT8
*)Addr
;
5229 Reads 16-bit data form the memory address.
5231 @param VmPtr A pointer to VM context.
5232 @param Addr The memory address.
5234 @return The 16-bit value from the memory address.
5239 IN VM_CONTEXT
*VmPtr
,
5244 // Convert the address if it's in the stack gap
5246 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5248 // Read direct if aligned
5250 if (IS_ALIGNED (Addr
, sizeof (UINT16
))) {
5251 return *(UINT16
*)Addr
;
5255 // Return unaligned data
5257 return (UINT16
)(*(UINT8
*)Addr
+ (*(UINT8
*)(Addr
+ 1) << 8));
5261 Reads 32-bit data form the memory address.
5263 @param VmPtr A pointer to VM context.
5264 @param Addr The memory address.
5266 @return The 32-bit value from the memory address.
5271 IN VM_CONTEXT
*VmPtr
,
5278 // Convert the address if it's in the stack gap
5280 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5282 // Read direct if aligned
5284 if (IS_ALIGNED (Addr
, sizeof (UINT32
))) {
5285 return *(UINT32
*)Addr
;
5289 // Return unaligned data
5291 Data
= (UINT32
)VmReadMem16 (VmPtr
, Addr
);
5292 Data
|= (VmReadMem16 (VmPtr
, Addr
+ 2) << 16);
5297 Reads 64-bit data form the memory address.
5299 @param VmPtr A pointer to VM context.
5300 @param Addr The memory address.
5302 @return The 64-bit value from the memory address.
5307 IN VM_CONTEXT
*VmPtr
,
5315 // Convert the address if it's in the stack gap
5317 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5320 // Read direct if aligned
5322 if (IS_ALIGNED (Addr
, sizeof (UINT64
))) {
5323 return *(UINT64
*)Addr
;
5327 // Return unaligned data. Assume little endian.
5329 Data32
= VmReadMem32 (VmPtr
, Addr
);
5330 Data
= (UINT64
)VmReadMem32 (VmPtr
, Addr
+ sizeof (UINT32
));
5331 Data
= LShiftU64 (Data
, 32) | Data32
;
5336 Given an address that EBC is going to read from or write to, return
5337 an appropriate address that accounts for a gap in the stack.
5338 The stack for this application looks like this (high addr on top)
5339 [EBC entry point arguments]
5342 The EBC assumes that its arguments are at the top of its stack, which
5343 is where the VM stack is really. Therefore if the EBC does memory
5344 accesses into the VM stack area, then we need to convert the address
5345 to point to the EBC entry point arguments area. Do this here.
5347 @param VmPtr A Pointer to VM context.
5348 @param Addr Address of interest
5350 @return The unchanged address if it's not in the VM stack region. Otherwise,
5351 adjust for the stack gap and return the modified address.
5356 IN VM_CONTEXT
*VmPtr
,
5360 ASSERT (((Addr
< VmPtr
->LowStackTop
) || (Addr
> VmPtr
->HighStackBottom
)));
5365 Read a natural value from memory. May or may not be aligned.
5367 @param VmPtr current VM context
5368 @param Addr the address to read from
5370 @return The natural value at address Addr.
5375 IN VM_CONTEXT
*VmPtr
,
5380 volatile UINT32 Size
;
5385 // Convert the address if it's in the stack gap
5387 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5389 // Read direct if aligned
5391 if (IS_ALIGNED (Addr
, sizeof (UINTN
))) {
5392 return *(UINTN
*)Addr
;
5396 // Return unaligned data
5399 FromPtr
= (UINT8
*)Addr
;
5400 ToPtr
= (UINT8
*)&Data
;
5402 for (Size
= 0; Size
< sizeof (Data
); Size
++) {
5412 Returns the version of the EBC virtual machine.
5414 @return The 64-bit version of EBC virtual machine.
5422 return (UINT64
)(((VM_MAJOR_VERSION
& 0xFFFF) << 16) | ((VM_MINOR_VERSION
& 0xFFFF)));