2 Contains code that implements the virtual machine.
4 Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "EbcExecute.h"
17 #include "EbcDebuggerHook.h"
21 // Define some useful data size constants to allow switch statements based on
22 // size of operands or data.
24 #define DATA_SIZE_INVALID 0
26 #define DATA_SIZE_16 2
27 #define DATA_SIZE_32 4
28 #define DATA_SIZE_64 8
29 #define DATA_SIZE_N 48 // 4 or 8
31 // Structure we'll use to dispatch opcodes to execute functions.
34 EFI_STATUS (*ExecuteFunction
) (IN VM_CONTEXT
* VmPtr
);
40 (*DATA_MANIP_EXEC_FUNCTION
) (
41 IN VM_CONTEXT
* VmPtr
,
47 Decode a 16-bit index to determine the offset. Given an index value:
50 b14:12 - number of bits in this index assigned to natural units (=a)
51 ba:11 - constant units = ConstUnits
52 b0:a - natural units = NaturalUnits
54 Given this info, the offset can be computed by:
55 offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
57 Max offset is achieved with index = 0x7FFF giving an offset of
58 0x27B (32-bit machine) or 0x477 (64-bit machine).
59 Min offset is achieved with index =
61 @param VmPtr A pointer to VM context.
62 @param CodeOffset Offset from IP of the location of the 16-bit index
65 @return The decoded offset.
75 Decode a 32-bit index to determine the offset.
77 @param VmPtr A pointer to VM context.
78 @param CodeOffset Offset from IP of the location of the 32-bit index
81 @return Converted index per EBC VM specification.
91 Decode a 64-bit index to determine the offset.
93 @param VmPtr A pointer to VM context.s
94 @param CodeOffset Offset from IP of the location of the 64-bit index
97 @return Converted index per EBC VM specification
102 IN VM_CONTEXT
*VmPtr
,
107 Reads 8-bit data form the memory address.
109 @param VmPtr A pointer to VM context.
110 @param Addr The memory address.
112 @return The 8-bit value from the memory address.
117 IN VM_CONTEXT
*VmPtr
,
122 Reads 16-bit data form the memory address.
124 @param VmPtr A pointer to VM context.
125 @param Addr The memory address.
127 @return The 16-bit value from the memory address.
132 IN VM_CONTEXT
*VmPtr
,
137 Reads 32-bit data form the memory address.
139 @param VmPtr A pointer to VM context.
140 @param Addr The memory address.
142 @return The 32-bit value from the memory address.
147 IN VM_CONTEXT
*VmPtr
,
152 Reads 64-bit data form the memory address.
154 @param VmPtr A pointer to VM context.
155 @param Addr The memory address.
157 @return The 64-bit value from the memory address.
162 IN VM_CONTEXT
*VmPtr
,
167 Read a natural value from memory. May or may not be aligned.
169 @param VmPtr current VM context
170 @param Addr the address to read from
172 @return The natural value at address Addr.
177 IN VM_CONTEXT
*VmPtr
,
182 Writes 8-bit data to memory address.
184 This routine is called by the EBC data
185 movement instructions that write to memory. Since these writes
186 may be to the stack, which looks like (high address on top) this,
188 [EBC entry point arguments]
192 we need to detect all attempts to write to the EBC entry point argument
193 stack area and adjust the address (which will initially point into the
194 VM stack) to point into the EBC entry point arguments.
196 @param VmPtr A pointer to a VM context.
197 @param Addr Address to write to.
198 @param Data Value to write to Addr.
200 @retval EFI_SUCCESS The instruction is executed successfully.
201 @retval Other Some error occurs when writing data to the address.
206 IN VM_CONTEXT
*VmPtr
,
212 Writes 16-bit data to memory address.
214 This routine is called by the EBC data
215 movement instructions that write to memory. Since these writes
216 may be to the stack, which looks like (high address on top) this,
218 [EBC entry point arguments]
222 we need to detect all attempts to write to the EBC entry point argument
223 stack area and adjust the address (which will initially point into the
224 VM stack) to point into the EBC entry point arguments.
226 @param VmPtr A pointer to a VM context.
227 @param Addr Address to write to.
228 @param Data Value to write to Addr.
230 @retval EFI_SUCCESS The instruction is executed successfully.
231 @retval Other Some error occurs when writing data to the address.
236 IN VM_CONTEXT
*VmPtr
,
242 Writes 32-bit data to memory address.
244 This routine is called by the EBC data
245 movement instructions that write to memory. Since these writes
246 may be to the stack, which looks like (high address on top) this,
248 [EBC entry point arguments]
252 we need to detect all attempts to write to the EBC entry point argument
253 stack area and adjust the address (which will initially point into the
254 VM stack) to point into the EBC entry point arguments.
256 @param VmPtr A pointer to a VM context.
257 @param Addr Address to write to.
258 @param Data Value to write to Addr.
260 @retval EFI_SUCCESS The instruction is executed successfully.
261 @retval Other Some error occurs when writing data to the address.
266 IN VM_CONTEXT
*VmPtr
,
272 Reads 16-bit unsigned data from the code stream.
274 This routine provides the ability to read raw unsigned data from the code
277 @param VmPtr A pointer to VM context
278 @param Offset Offset from current IP to the raw data to read.
280 @return The raw unsigned 16-bit value from the code stream.
285 IN VM_CONTEXT
*VmPtr
,
290 Reads 32-bit unsigned data from the code stream.
292 This routine provides the ability to read raw unsigned data from the code
295 @param VmPtr A pointer to VM context
296 @param Offset Offset from current IP to the raw data to read.
298 @return The raw unsigned 32-bit value from the code stream.
303 IN VM_CONTEXT
*VmPtr
,
308 Reads 64-bit unsigned data from the code stream.
310 This routine provides the ability to read raw unsigned data from the code
313 @param VmPtr A pointer to VM context
314 @param Offset Offset from current IP to the raw data to read.
316 @return The raw unsigned 64-bit value from the code stream.
321 IN VM_CONTEXT
*VmPtr
,
326 Reads 8-bit immediate value at the offset.
328 This routine is called by the EBC execute
329 functions to read EBC immediate values from the code stream.
330 Since we can't assume alignment, each tries to read in the biggest
331 chunks size available, but will revert to smaller reads if necessary.
333 @param VmPtr A pointer to a VM context.
334 @param Offset offset from IP of the code bytes to read.
336 @return Signed data of the requested size from the specified address.
341 IN VM_CONTEXT
*VmPtr
,
346 Reads 16-bit immediate value at the offset.
348 This routine is called by the EBC execute
349 functions to read EBC immediate values from the code stream.
350 Since we can't assume alignment, each tries to read in the biggest
351 chunks size available, but will revert to smaller reads if necessary.
353 @param VmPtr A pointer to a VM context.
354 @param Offset offset from IP of the code bytes to read.
356 @return Signed data of the requested size from the specified address.
361 IN VM_CONTEXT
*VmPtr
,
366 Reads 32-bit immediate value at the offset.
368 This routine is called by the EBC execute
369 functions to read EBC immediate values from the code stream.
370 Since we can't assume alignment, each tries to read in the biggest
371 chunks size available, but will revert to smaller reads if necessary.
373 @param VmPtr A pointer to a VM context.
374 @param Offset offset from IP of the code bytes to read.
376 @return Signed data of the requested size from the specified address.
381 IN VM_CONTEXT
*VmPtr
,
386 Reads 64-bit immediate value at the offset.
388 This routine is called by the EBC execute
389 functions to read EBC immediate values from the code stream.
390 Since we can't assume alignment, each tries to read in the biggest
391 chunks size available, but will revert to smaller reads if necessary.
393 @param VmPtr A pointer to a VM context.
394 @param Offset offset from IP of the code bytes to read.
396 @return Signed data of the requested size from the specified address.
401 IN VM_CONTEXT
*VmPtr
,
406 Given an address that EBC is going to read from or write to, return
407 an appropriate address that accounts for a gap in the stack.
408 The stack for this application looks like this (high addr on top)
409 [EBC entry point arguments]
412 The EBC assumes that its arguments are at the top of its stack, which
413 is where the VM stack is really. Therefore if the EBC does memory
414 accesses into the VM stack area, then we need to convert the address
415 to point to the EBC entry point arguments area. Do this here.
417 @param VmPtr A Pointer to VM context.
418 @param Addr Address of interest
420 @return The unchanged address if it's not in the VM stack region. Otherwise,
421 adjust for the stack gap and return the modified address.
426 IN VM_CONTEXT
*VmPtr
,
431 Execute all the EBC data manipulation instructions.
432 Since the EBC data manipulation instructions all have the same basic form,
433 they can share the code that does the fetch of operands and the write-back
434 of the result. This function performs the fetch of the operands (even if
435 both are not needed to be fetched, like NOT instruction), dispatches to the
436 appropriate subfunction, then writes back the returned result.
439 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
441 @param VmPtr A pointer to VM context.
442 @param IsSignedOp Indicates whether the operand is signed or not.
444 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
445 @retval EFI_SUCCESS The instruction is executed successfully.
450 IN VM_CONTEXT
*VmPtr
,
451 IN BOOLEAN IsSignedOp
455 // Functions that execute VM opcodes
458 Execute the EBC BREAK instruction.
460 @param VmPtr A pointer to a VM context.
462 @retval EFI_SUCCESS The instruction is executed successfully.
471 Execute the JMP instruction.
475 JMP32{cs|cc} {@}R1 {Immed32|Index32}
478 b0.7 - immediate data present
479 b0.6 - 1 = 64 bit immediate data
480 0 = 32 bit immediate data
481 b1.7 - 1 = conditional
482 b1.6 1 = CS (condition set)
483 0 = CC (condition clear)
484 b1.4 1 = relative address
486 b1.3 1 = operand1 indirect
489 @param VmPtr A pointer to a VM context.
491 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
492 @retval EFI_SUCCESS The instruction is executed successfully.
501 Execute the EBC JMP8 instruction.
506 @param VmPtr A pointer to a VM context.
508 @retval EFI_SUCCESS The instruction is executed successfully.
517 Implements the EBC CALL instruction.
521 CALL32 {@}R1 {Immed32|Index32}
523 CALLEX16 {@}R1 {Immed32}
525 If Rx == R0, then it's a PC relative call to PC = PC + imm32.
527 @param VmPtr A pointer to a VM context.
529 @retval EFI_SUCCESS The instruction is executed successfully.
538 Execute the EBC RET instruction.
543 @param VmPtr A pointer to a VM context.
545 @retval EFI_SUCCESS The instruction is executed successfully.
554 Execute the EBC CMP instruction.
557 CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
559 @param VmPtr A pointer to a VM context.
561 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
562 @retval EFI_SUCCESS The instruction is executed successfully.
571 Execute the EBC CMPI instruction
574 CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
576 @param VmPtr A pointer to a VM context.
578 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
579 @retval EFI_SUCCESS The instruction is executed successfully.
588 Execute the MOVxx instructions.
592 MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
593 MOVqq {@}R1 {Index64}, {@}R2 {Index64}
595 Copies contents of [R2] -> [R1], zero extending where required.
597 First character indicates the size of the move.
598 Second character indicates the size of the index(s).
600 Invalid to have R1 direct with index.
602 @param VmPtr A pointer to a VM context.
604 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
605 @retval EFI_SUCCESS The instruction is executed successfully.
614 Execute the EBC MOVI.
618 MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
620 First variable character specifies the move size
621 Second variable character specifies size of the immediate data
623 Sign-extend the immediate data to the size of the operation, and zero-extend
624 if storing to a register.
626 Operand1 direct with index/immed is invalid.
628 @param VmPtr A pointer to a VM context.
630 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
631 @retval EFI_SUCCESS The instruction is executed successfully.
640 Execute the EBC MOV immediate natural. This instruction moves an immediate
641 index value into a register or memory location.
645 MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
647 @param VmPtr A pointer to a VM context.
649 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
650 @retval EFI_SUCCESS The instruction is executed successfully.
659 Execute the EBC MOVREL instruction.
664 MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
666 @param VmPtr A pointer to a VM context.
668 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
669 @retval EFI_SUCCESS The instruction is executed successfully.
678 Execute the EBC PUSHn instruction
681 PUSHn {@}R1 {Index16|Immed16}
683 @param VmPtr A pointer to a VM context.
685 @retval EFI_SUCCESS The instruction is executed successfully.
694 Execute the EBC PUSH instruction.
697 PUSH[32|64] {@}R1 {Index16|Immed16}
699 @param VmPtr A pointer to a VM context.
701 @retval EFI_SUCCESS The instruction is executed successfully.
710 Execute the EBC POPn instruction.
713 POPn {@}R1 {Index16|Immed16}
715 @param VmPtr A pointer to a VM context.
717 @retval EFI_SUCCESS The instruction is executed successfully.
726 Execute the EBC POP instruction.
729 POPn {@}R1 {Index16|Immed16}
731 @param VmPtr A pointer to a VM context.
733 @retval EFI_SUCCESS The instruction is executed successfully.
742 Execute all the EBC signed data manipulation instructions.
743 Since the EBC data manipulation instructions all have the same basic form,
744 they can share the code that does the fetch of operands and the write-back
745 of the result. This function performs the fetch of the operands (even if
746 both are not needed to be fetched, like NOT instruction), dispatches to the
747 appropriate subfunction, then writes back the returned result.
750 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
752 @param VmPtr A pointer to VM context.
754 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
755 @retval EFI_SUCCESS The instruction is executed successfully.
759 ExecuteSignedDataManip (
764 Execute all the EBC unsigned data manipulation instructions.
765 Since the EBC data manipulation instructions all have the same basic form,
766 they can share the code that does the fetch of operands and the write-back
767 of the result. This function performs the fetch of the operands (even if
768 both are not needed to be fetched, like NOT instruction), dispatches to the
769 appropriate subfunction, then writes back the returned result.
772 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
774 @param VmPtr A pointer to VM context.
776 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
777 @retval EFI_SUCCESS The instruction is executed successfully.
781 ExecuteUnsignedDataManip (
786 Execute the EBC LOADSP instruction.
791 @param VmPtr A pointer to a VM context.
793 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
794 @retval EFI_SUCCESS The instruction is executed successfully.
803 Execute the EBC STORESP instruction.
808 @param VmPtr A pointer to a VM context.
810 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
811 @retval EFI_SUCCESS The instruction is executed successfully.
820 Execute the EBC MOVsnw instruction. This instruction loads a signed
821 natural value from memory or register to another memory or register. On
822 32-bit machines, the value gets sign-extended to 64 bits if the destination
827 MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
829 0:7 1=>operand1 index present
830 0:6 1=>operand2 index present
832 @param VmPtr A pointer to a VM context.
834 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
835 @retval EFI_SUCCESS The instruction is executed successfully.
844 Execute the EBC MOVsnw instruction. This instruction loads a signed
845 natural value from memory or register to another memory or register. On
846 32-bit machines, the value gets sign-extended to 64 bits if the destination
851 MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
853 0:7 1=>operand1 index present
854 0:6 1=>operand2 index present
856 @param VmPtr A pointer to a VM context.
858 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
859 @retval EFI_SUCCESS The instruction is executed successfully.
868 // Data manipulation subfunctions
871 Execute the EBC NOT instruction.s
874 NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
876 @param VmPtr A pointer to a VM context.
877 @param Op1 Operand 1 from the instruction
878 @param Op2 Operand 2 from the instruction
885 IN VM_CONTEXT
*VmPtr
,
891 Execute the EBC NEG instruction.
894 NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
896 @param VmPtr A pointer to a VM context.
897 @param Op1 Operand 1 from the instruction
898 @param Op2 Operand 2 from the instruction
905 IN VM_CONTEXT
*VmPtr
,
911 Execute the EBC ADD instruction.
914 ADD[32|64] {@}R1, {@}R2 {Index16}
916 @param VmPtr A pointer to a VM context.
917 @param Op1 Operand 1 from the instruction
918 @param Op2 Operand 2 from the instruction
925 IN VM_CONTEXT
*VmPtr
,
931 Execute the EBC SUB instruction.
934 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
936 @param VmPtr A pointer to a VM context.
937 @param Op1 Operand 1 from the instruction
938 @param Op2 Operand 2 from the instruction
945 IN VM_CONTEXT
*VmPtr
,
951 Execute the EBC MUL instruction.
954 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
956 @param VmPtr A pointer to a VM context.
957 @param Op1 Operand 1 from the instruction
958 @param Op2 Operand 2 from the instruction
965 IN VM_CONTEXT
*VmPtr
,
971 Execute the EBC MULU instruction
974 MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
976 @param VmPtr A pointer to a VM context.
977 @param Op1 Operand 1 from the instruction
978 @param Op2 Operand 2 from the instruction
980 @return (unsigned)Op1 * (unsigned)Op2
985 IN VM_CONTEXT
*VmPtr
,
991 Execute the EBC DIV instruction.
994 DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
996 @param VmPtr A pointer to a VM context.
997 @param Op1 Operand 1 from the instruction
998 @param Op2 Operand 2 from the instruction
1005 IN VM_CONTEXT
*VmPtr
,
1011 Execute the EBC DIVU instruction
1014 DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
1016 @param VmPtr A pointer to a VM context.
1017 @param Op1 Operand 1 from the instruction
1018 @param Op2 Operand 2 from the instruction
1020 @return (unsigned)Op1 / (unsigned)Op2
1025 IN VM_CONTEXT
*VmPtr
,
1031 Execute the EBC MOD instruction.
1034 MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
1036 @param VmPtr A pointer to a VM context.
1037 @param Op1 Operand 1 from the instruction
1038 @param Op2 Operand 2 from the instruction
1040 @return Op1 MODULUS Op2
1045 IN VM_CONTEXT
*VmPtr
,
1051 Execute the EBC MODU instruction.
1054 MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
1056 @param VmPtr A pointer to a VM context.
1057 @param Op1 Operand 1 from the instruction
1058 @param Op2 Operand 2 from the instruction
1060 @return Op1 UNSIGNED_MODULUS Op2
1065 IN VM_CONTEXT
*VmPtr
,
1071 Execute the EBC AND instruction.
1074 AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
1076 @param VmPtr A pointer to a VM context.
1077 @param Op1 Operand 1 from the instruction
1078 @param Op2 Operand 2 from the instruction
1085 IN VM_CONTEXT
*VmPtr
,
1091 Execute the EBC OR instruction.
1094 OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1096 @param VmPtr A pointer to a VM context.
1097 @param Op1 Operand 1 from the instruction
1098 @param Op2 Operand 2 from the instruction
1105 IN VM_CONTEXT
*VmPtr
,
1111 Execute the EBC XOR instruction.
1114 XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1116 @param VmPtr A pointer to a VM context.
1117 @param Op1 Operand 1 from the instruction
1118 @param Op2 Operand 2 from the instruction
1125 IN VM_CONTEXT
*VmPtr
,
1131 Execute the EBC SHL shift left instruction.
1134 SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
1136 @param VmPtr A pointer to a VM context.
1137 @param Op1 Operand 1 from the instruction
1138 @param Op2 Operand 2 from the instruction
1145 IN VM_CONTEXT
*VmPtr
,
1151 Execute the EBC SHR instruction.
1154 SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1156 @param VmPtr A pointer to a VM context.
1157 @param Op1 Operand 1 from the instruction
1158 @param Op2 Operand 2 from the instruction
1160 @return Op1 >> Op2 (unsigned operands)
1165 IN VM_CONTEXT
*VmPtr
,
1171 Execute the EBC ASHR instruction.
1174 ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1176 @param VmPtr A pointer to a VM context.
1177 @param Op1 Operand 1 from the instruction
1178 @param Op2 Operand 2 from the instruction
1180 @return Op1 >> Op2 (signed)
1185 IN VM_CONTEXT
*VmPtr
,
1191 Execute the EBC EXTNDB instruction to sign-extend a byte value.
1194 EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
1196 @param VmPtr A pointer to a VM context.
1197 @param Op1 Operand 1 from the instruction
1198 @param Op2 Operand 2 from the instruction
1200 @return (INT64)(INT8)Op2
1205 IN VM_CONTEXT
*VmPtr
,
1211 Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
1214 EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
1216 @param VmPtr A pointer to a VM context.
1217 @param Op1 Operand 1 from the instruction
1218 @param Op2 Operand 2 from the instruction
1220 @return (INT64)(INT16)Op2
1225 IN VM_CONTEXT
*VmPtr
,
1231 Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
1234 EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
1236 @param VmPtr A pointer to a VM context.
1237 @param Op1 Operand 1 from the instruction
1238 @param Op2 Operand 2 from the instruction
1240 @return (INT64)(INT32)Op2
1245 IN VM_CONTEXT
*VmPtr
,
1251 // Once we retrieve the operands for the data manipulation instructions,
1252 // call these functions to perform the operation.
1254 CONST DATA_MANIP_EXEC_FUNCTION mDataManipDispatchTable
[] = {
1276 CONST VM_TABLE_ENTRY mVmOpcodeTable
[] = {
1277 { ExecuteBREAK
}, // opcode 0x00
1278 { ExecuteJMP
}, // opcode 0x01
1279 { ExecuteJMP8
}, // opcode 0x02
1280 { ExecuteCALL
}, // opcode 0x03
1281 { ExecuteRET
}, // opcode 0x04
1282 { ExecuteCMP
}, // opcode 0x05 CMPeq
1283 { ExecuteCMP
}, // opcode 0x06 CMPlte
1284 { ExecuteCMP
}, // opcode 0x07 CMPgte
1285 { ExecuteCMP
}, // opcode 0x08 CMPulte
1286 { ExecuteCMP
}, // opcode 0x09 CMPugte
1287 { ExecuteUnsignedDataManip
}, // opcode 0x0A NOT
1288 { ExecuteSignedDataManip
}, // opcode 0x0B NEG
1289 { ExecuteSignedDataManip
}, // opcode 0x0C ADD
1290 { ExecuteSignedDataManip
}, // opcode 0x0D SUB
1291 { ExecuteSignedDataManip
}, // opcode 0x0E MUL
1292 { ExecuteUnsignedDataManip
}, // opcode 0x0F MULU
1293 { ExecuteSignedDataManip
}, // opcode 0x10 DIV
1294 { ExecuteUnsignedDataManip
}, // opcode 0x11 DIVU
1295 { ExecuteSignedDataManip
}, // opcode 0x12 MOD
1296 { ExecuteUnsignedDataManip
}, // opcode 0x13 MODU
1297 { ExecuteUnsignedDataManip
}, // opcode 0x14 AND
1298 { ExecuteUnsignedDataManip
}, // opcode 0x15 OR
1299 { ExecuteUnsignedDataManip
}, // opcode 0x16 XOR
1300 { ExecuteUnsignedDataManip
}, // opcode 0x17 SHL
1301 { ExecuteUnsignedDataManip
}, // opcode 0x18 SHR
1302 { ExecuteSignedDataManip
}, // opcode 0x19 ASHR
1303 { ExecuteUnsignedDataManip
}, // opcode 0x1A EXTNDB
1304 { ExecuteUnsignedDataManip
}, // opcode 0x1B EXTNDW
1305 { ExecuteUnsignedDataManip
}, // opcode 0x1C EXTNDD
1306 { ExecuteMOVxx
}, // opcode 0x1D MOVBW
1307 { ExecuteMOVxx
}, // opcode 0x1E MOVWW
1308 { ExecuteMOVxx
}, // opcode 0x1F MOVDW
1309 { ExecuteMOVxx
}, // opcode 0x20 MOVQW
1310 { ExecuteMOVxx
}, // opcode 0x21 MOVBD
1311 { ExecuteMOVxx
}, // opcode 0x22 MOVWD
1312 { ExecuteMOVxx
}, // opcode 0x23 MOVDD
1313 { ExecuteMOVxx
}, // opcode 0x24 MOVQD
1314 { ExecuteMOVsnw
}, // opcode 0x25 MOVsnw
1315 { ExecuteMOVsnd
}, // opcode 0x26 MOVsnd
1316 { NULL
}, // opcode 0x27
1317 { ExecuteMOVxx
}, // opcode 0x28 MOVqq
1318 { ExecuteLOADSP
}, // opcode 0x29 LOADSP SP1, R2
1319 { ExecuteSTORESP
}, // opcode 0x2A STORESP R1, SP2
1320 { ExecutePUSH
}, // opcode 0x2B PUSH {@}R1 [imm16]
1321 { ExecutePOP
}, // opcode 0x2C POP {@}R1 [imm16]
1322 { ExecuteCMPI
}, // opcode 0x2D CMPIEQ
1323 { ExecuteCMPI
}, // opcode 0x2E CMPILTE
1324 { ExecuteCMPI
}, // opcode 0x2F CMPIGTE
1325 { ExecuteCMPI
}, // opcode 0x30 CMPIULTE
1326 { ExecuteCMPI
}, // opcode 0x31 CMPIUGTE
1327 { ExecuteMOVxx
}, // opcode 0x32 MOVN
1328 { ExecuteMOVxx
}, // opcode 0x33 MOVND
1329 { NULL
}, // opcode 0x34
1330 { ExecutePUSHn
}, // opcode 0x35
1331 { ExecutePOPn
}, // opcode 0x36
1332 { ExecuteMOVI
}, // opcode 0x37 - mov immediate data
1333 { ExecuteMOVIn
}, // opcode 0x38 - mov immediate natural
1334 { ExecuteMOVREL
}, // opcode 0x39 - move data relative to PC
1335 { NULL
}, // opcode 0x3a
1336 { NULL
}, // opcode 0x3b
1337 { NULL
}, // opcode 0x3c
1338 { NULL
}, // opcode 0x3d
1339 { NULL
}, // opcode 0x3e
1340 { NULL
} // opcode 0x3f
1344 // Length of JMP instructions, depending on upper two bits of opcode.
1346 CONST UINT8 mJMPLen
[] = { 2, 2, 6, 10 };
1349 Given a pointer to a new VM context, execute one or more instructions. This
1350 function is only used for test purposes via the EBC VM test protocol.
1352 @param This A pointer to the EFI_EBC_VM_TEST_PROTOCOL structure.
1353 @param VmPtr A pointer to a VM context.
1354 @param InstructionCount A pointer to a UINTN value holding the number of
1355 instructions to execute. If it holds value of 0,
1356 then the instruction to be executed is 1.
1358 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
1359 @retval EFI_SUCCESS All of the instructions are executed successfully.
1364 EbcExecuteInstructions (
1365 IN EFI_EBC_VM_TEST_PROTOCOL
*This
,
1366 IN VM_CONTEXT
*VmPtr
,
1367 IN OUT UINTN
*InstructionCount
1372 UINTN InstructionsLeft
;
1373 UINTN SavedInstructionCount
;
1375 Status
= EFI_SUCCESS
;
1377 if (*InstructionCount
== 0) {
1378 InstructionsLeft
= 1;
1380 InstructionsLeft
= *InstructionCount
;
1383 SavedInstructionCount
= *InstructionCount
;
1384 *InstructionCount
= 0;
1387 // Index into the opcode table using the opcode byte for this instruction.
1388 // This gives you the execute function, which we first test for null, then
1389 // call it if it's not null.
1391 while (InstructionsLeft
!= 0) {
1392 ExecFunc
= (UINTN
) mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction
;
1393 if (ExecFunc
== (UINTN
) NULL
) {
1394 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1395 return EFI_UNSUPPORTED
;
1397 mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction (VmPtr
);
1398 *InstructionCount
= *InstructionCount
+ 1;
1402 // Decrement counter if applicable
1404 if (SavedInstructionCount
!= 0) {
1414 Execute an EBC image from an entry point or from a published protocol.
1416 @param VmPtr A pointer to a VM context.
1418 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
1419 @retval EFI_SUCCESS All of the instructions are executed successfully.
1424 IN VM_CONTEXT
*VmPtr
1428 UINT8 StackCorrupted
;
1430 EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL
*EbcSimpleDebugger
;
1433 EbcSimpleDebugger
= NULL
;
1434 Status
= EFI_SUCCESS
;
1438 // Make sure the magic value has been put on the stack before we got here.
1440 if (*VmPtr
->StackMagicPtr
!= (UINTN
) VM_STACK_KEY_VALUE
) {
1444 VmPtr
->FramePtr
= (VOID
*) ((UINT8
*) (UINTN
) VmPtr
->Gpr
[0] + 8);
1447 // Try to get the debug support for EBC
1449 DEBUG_CODE_BEGIN ();
1450 Status
= gBS
->LocateProtocol (
1451 &gEfiEbcSimpleDebuggerProtocolGuid
,
1453 (VOID
**) &EbcSimpleDebugger
1455 if (EFI_ERROR (Status
)) {
1456 EbcSimpleDebugger
= NULL
;
1461 // Save the start IP for debug. For example, if we take an exception we
1462 // can print out the location of the exception relative to the entry point,
1463 // which could then be used in a disassembly listing to find the problem.
1465 VmPtr
->EntryPoint
= (VOID
*) VmPtr
->Ip
;
1468 // We'll wait for this flag to know when we're done. The RET
1469 // instruction sets it if it runs out of stack.
1471 VmPtr
->StopFlags
= 0;
1472 while ((VmPtr
->StopFlags
& STOPFLAG_APP_DONE
) == 0) {
1474 // If we've found a simple debugger protocol, call it
1476 DEBUG_CODE_BEGIN ();
1477 if (EbcSimpleDebugger
!= NULL
) {
1478 EbcSimpleDebugger
->Debugger (EbcSimpleDebugger
, VmPtr
);
1483 // Use the opcode bits to index into the opcode dispatch table. If the
1484 // function pointer is null then generate an exception.
1486 ExecFunc
= (UINTN
) mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction
;
1487 if (ExecFunc
== (UINTN
) NULL
) {
1488 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1489 Status
= EFI_UNSUPPORTED
;
1493 EbcDebuggerHookExecuteStart (VmPtr
);
1496 // The EBC VM is a strongly ordered processor, so perform a fence operation before
1497 // and after each instruction is executed.
1501 mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction (VmPtr
);
1505 EbcDebuggerHookExecuteEnd (VmPtr
);
1508 // If the step flag is set, signal an exception and continue. We don't
1509 // clear it here. Assuming the debugger is responsible for clearing it.
1511 if (VMFLAG_ISSET (VmPtr
, VMFLAGS_STEP
)) {
1512 EbcDebugSignalException (EXCEPT_EBC_STEP
, EXCEPTION_FLAG_NONE
, VmPtr
);
1515 // Make sure stack has not been corrupted. Only report it once though.
1517 if ((StackCorrupted
== 0) && (*VmPtr
->StackMagicPtr
!= (UINTN
) VM_STACK_KEY_VALUE
)) {
1518 EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1521 if ((StackCorrupted
== 0) && ((UINT64
)VmPtr
->Gpr
[0] <= (UINT64
)(UINTN
) VmPtr
->StackTop
)) {
1522 EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1535 Execute the MOVxx instructions.
1539 MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
1540 MOVqq {@}R1 {Index64}, {@}R2 {Index64}
1542 Copies contents of [R2] -> [R1], zero extending where required.
1544 First character indicates the size of the move.
1545 Second character indicates the size of the index(s).
1547 Invalid to have R1 direct with index.
1549 @param VmPtr A pointer to a VM context.
1551 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
1552 @retval EFI_SUCCESS The instruction is executed successfully.
1557 IN VM_CONTEXT
*VmPtr
1573 Opcode
= GETOPCODE (VmPtr
);
1574 OpcMasked
= (UINT8
) (Opcode
& OPCODE_M_OPCODE
);
1577 // Get the operands byte so we can get R1 and R2
1579 Operands
= GETOPERANDS (VmPtr
);
1582 // Assume no indexes
1589 // Determine if we have an index/immediate data. Base instruction size
1590 // is 2 (opcode + operands). Add to this size each index specified.
1593 if ((Opcode
& (OPCODE_M_IMMED_OP1
| OPCODE_M_IMMED_OP2
)) != 0) {
1595 // Determine size of the index from the opcode. Then get it.
1597 if ((OpcMasked
<= OPCODE_MOVQW
) || (OpcMasked
== OPCODE_MOVNW
)) {
1599 // MOVBW, MOVWW, MOVDW, MOVQW, and MOVNW have 16-bit immediate index.
1600 // Get one or both index values.
1602 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1603 Index16
= VmReadIndex16 (VmPtr
, 2);
1604 Index64Op1
= (INT64
) Index16
;
1605 Size
+= sizeof (UINT16
);
1608 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1609 Index16
= VmReadIndex16 (VmPtr
, Size
);
1610 Index64Op2
= (INT64
) Index16
;
1611 Size
+= sizeof (UINT16
);
1613 } else if ((OpcMasked
<= OPCODE_MOVQD
) || (OpcMasked
== OPCODE_MOVND
)) {
1615 // MOVBD, MOVWD, MOVDD, MOVQD, and MOVND have 32-bit immediate index
1617 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1618 Index32
= VmReadIndex32 (VmPtr
, 2);
1619 Index64Op1
= (INT64
) Index32
;
1620 Size
+= sizeof (UINT32
);
1623 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1624 Index32
= VmReadIndex32 (VmPtr
, Size
);
1625 Index64Op2
= (INT64
) Index32
;
1626 Size
+= sizeof (UINT32
);
1628 } else if (OpcMasked
== OPCODE_MOVQQ
) {
1630 // MOVqq -- only form with a 64-bit index
1632 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1633 Index64Op1
= VmReadIndex64 (VmPtr
, 2);
1634 Size
+= sizeof (UINT64
);
1637 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1638 Index64Op2
= VmReadIndex64 (VmPtr
, Size
);
1639 Size
+= sizeof (UINT64
);
1643 // Obsolete MOVBQ, MOVWQ, MOVDQ, and MOVNQ have 64-bit immediate index
1645 EbcDebugSignalException (
1646 EXCEPT_EBC_INSTRUCTION_ENCODING
,
1647 EXCEPTION_FLAG_FATAL
,
1650 return EFI_UNSUPPORTED
;
1654 // Determine the size of the move, and create a mask for it so we can
1655 // clear unused bits.
1657 if ((OpcMasked
== OPCODE_MOVBW
) || (OpcMasked
== OPCODE_MOVBD
)) {
1658 MoveSize
= DATA_SIZE_8
;
1660 } else if ((OpcMasked
== OPCODE_MOVWW
) || (OpcMasked
== OPCODE_MOVWD
)) {
1661 MoveSize
= DATA_SIZE_16
;
1663 } else if ((OpcMasked
== OPCODE_MOVDW
) || (OpcMasked
== OPCODE_MOVDD
)) {
1664 MoveSize
= DATA_SIZE_32
;
1665 DataMask
= 0xFFFFFFFF;
1666 } else if ((OpcMasked
== OPCODE_MOVQW
) || (OpcMasked
== OPCODE_MOVQD
) || (OpcMasked
== OPCODE_MOVQQ
)) {
1667 MoveSize
= DATA_SIZE_64
;
1668 DataMask
= (UINT64
)~0;
1669 } else if ((OpcMasked
== OPCODE_MOVNW
) || (OpcMasked
== OPCODE_MOVND
)) {
1670 MoveSize
= DATA_SIZE_N
;
1671 DataMask
= (UINT64
)~0 >> (64 - 8 * sizeof (UINTN
));
1674 // We were dispatched to this function and we don't recognize the opcode
1676 EbcDebugSignalException (EXCEPT_EBC_UNDEFINED
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1677 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
))
1747 Data64
= (UINT64
) ConvertStackAddr (VmPtr
, (UINTN
) (INT64
) Data64
);
1752 // Now write it back
1754 if (OPERAND1_INDIRECT (Operands
)) {
1756 // Reuse the Source variable to now be dest.
1758 Source
= (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index64Op1
);
1760 // Do the write based on the size
1764 VmWriteMem8 (VmPtr
, Source
, (UINT8
) Data64
);
1768 VmWriteMem16 (VmPtr
, Source
, (UINT16
) Data64
);
1772 VmWriteMem32 (VmPtr
, Source
, (UINT32
) Data64
);
1776 VmWriteMem64 (VmPtr
, Source
, Data64
);
1780 VmWriteMemN (VmPtr
, Source
, (UINTN
) Data64
);
1792 // Make sure we didn't have an index on operand1.
1794 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1795 EbcDebugSignalException (
1796 EXCEPT_EBC_INSTRUCTION_ENCODING
,
1797 EXCEPTION_FLAG_FATAL
,
1800 return EFI_UNSUPPORTED
;
1803 // Direct storage in register. Clear unused bits and store back to
1806 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = Data64
& DataMask
;
1809 // Advance the instruction pointer
1817 Execute the EBC BREAK instruction.
1819 @param VmPtr A pointer to a VM context.
1821 @retval EFI_SUCCESS The instruction is executed successfully.
1826 IN VM_CONTEXT
*VmPtr
1831 VOID
*EbcEntryPoint
;
1833 UINT64 U64EbcEntryPoint
;
1837 Operands
= GETOPERANDS (VmPtr
);
1840 // Runaway program break. Generate an exception and terminate
1843 EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1847 // Get VM version -- return VM revision number in R7
1853 // 16-8 = Major version
1854 // 7-0 = Minor version
1856 VmPtr
->Gpr
[7] = GetVmVersion ();
1860 // Debugger breakpoint
1863 VmPtr
->StopFlags
|= STOPFLAG_BREAKPOINT
;
1865 // See if someone has registered a handler
1867 EbcDebugSignalException (
1868 EXCEPT_EBC_BREAKPOINT
,
1869 EXCEPTION_FLAG_NONE
,
1875 // System call, which there are none, so NOP it.
1881 // Create a thunk for EBC code. R7 points to a 32-bit (in a 64-bit slot)
1882 // "offset from self" pointer to the EBC entry point.
1883 // After we're done, *(UINT64 *)R7 will be the address of the new thunk.
1886 Offset
= (INT32
) VmReadMem32 (VmPtr
, (UINTN
) VmPtr
->Gpr
[7]);
1887 U64EbcEntryPoint
= (UINT64
) (VmPtr
->Gpr
[7] + Offset
+ 4);
1888 EbcEntryPoint
= (VOID
*) (UINTN
) U64EbcEntryPoint
;
1891 // Now create a new thunk
1893 Status
= EbcCreateThunks (VmPtr
->ImageHandle
, EbcEntryPoint
, &Thunk
, 0);
1894 if (EFI_ERROR (Status
)) {
1899 // Finally replace the EBC entry point memory with the thunk address
1901 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->Gpr
[7], (UINT64
) (UINTN
) Thunk
);
1905 // Compiler setting version per value in R7
1908 VmPtr
->CompilerVersion
= (UINT32
) VmPtr
->Gpr
[7];
1910 // Check compiler version against VM version?
1915 // Unhandled break code. Signal exception.
1918 EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1930 Execute the JMP instruction.
1933 JMP64{cs|cc} Immed64
1934 JMP32{cs|cc} {@}R1 {Immed32|Index32}
1937 b0.7 - immediate data present
1938 b0.6 - 1 = 64 bit immediate data
1939 0 = 32 bit immediate data
1940 b1.7 - 1 = conditional
1941 b1.6 1 = CS (condition set)
1942 0 = CC (condition clear)
1943 b1.4 1 = relative address
1944 0 = absolute address
1945 b1.3 1 = operand1 indirect
1948 @param VmPtr A pointer to a VM context.
1950 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
1951 @retval EFI_SUCCESS The instruction is executed successfully.
1956 IN VM_CONTEXT
*VmPtr
1961 UINT8 ConditionFlag
;
1968 Operand
= GETOPERANDS (VmPtr
);
1969 Opcode
= GETOPCODE (VmPtr
);
1972 // Get instruction length from the opcode. The upper two bits are used here
1973 // to index into the length array.
1975 Size
= mJMPLen
[(Opcode
>> 6) & 0x03];
1978 // Decode instruction conditions
1979 // If we haven't met the condition, then simply advance the IP and return.
1981 CompareSet
= (UINT8
) (((Operand
& JMP_M_CS
) != 0) ? 1 : 0);
1982 ConditionFlag
= (UINT8
) VMFLAG_ISSET (VmPtr
, VMFLAGS_CC
);
1983 if ((Operand
& CONDITION_M_CONDITIONAL
) != 0) {
1984 if (CompareSet
!= ConditionFlag
) {
1985 EbcDebuggerHookJMPStart (VmPtr
);
1987 EbcDebuggerHookJMPEnd (VmPtr
);
1992 // Check for 64-bit form and do it right away since it's the most
1993 // straight-forward form.
1995 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
1997 // Double check for immediate-data, which is required. If not there,
1998 // then signal an exception
2000 if ((Opcode
& OPCODE_M_IMMDATA
) == 0) {
2001 EbcDebugSignalException (
2002 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2003 EXCEPTION_FLAG_ERROR
,
2006 return EFI_UNSUPPORTED
;
2009 // 64-bit immediate data is full address. Read the immediate data,
2010 // check for alignment, and jump absolute.
2012 Data64
= (UINT64
) VmReadImmed64 (VmPtr
, 2);
2013 if (!IS_ALIGNED ((UINTN
) Data64
, sizeof (UINT16
))) {
2014 EbcDebugSignalException (
2015 EXCEPT_EBC_ALIGNMENT_CHECK
,
2016 EXCEPTION_FLAG_FATAL
,
2020 return EFI_UNSUPPORTED
;
2024 // Take jump -- relative or absolute
2026 EbcDebuggerHookJMPStart (VmPtr
);
2027 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2028 VmPtr
->Ip
+= (UINTN
) Data64
+ Size
;
2030 VmPtr
->Ip
= (VMIP
) (UINTN
) Data64
;
2032 EbcDebuggerHookJMPEnd (VmPtr
);
2038 // Get the index if there is one. May be either an index, or an immediate
2039 // offset depending on indirect operand.
2040 // JMP32 @R1 Index32 -- immediate data is an index
2041 // JMP32 R1 Immed32 -- immedate data is an offset
2043 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
2044 if (OPERAND1_INDIRECT (Operand
)) {
2045 Index32
= VmReadIndex32 (VmPtr
, 2);
2047 Index32
= VmReadImmed32 (VmPtr
, 2);
2053 // Get the register data. If R == 0, then special case where it's ignored.
2055 if (OPERAND1_REGNUM (Operand
) == 0) {
2058 Data64
= (UINT64
) OPERAND1_REGDATA (VmPtr
, Operand
);
2063 if (OPERAND1_INDIRECT (Operand
)) {
2065 // Form: JMP32 @Rx {Index32}
2067 Addr
= VmReadMemN (VmPtr
, (UINTN
) Data64
+ Index32
);
2068 if (!IS_ALIGNED ((UINTN
) Addr
, sizeof (UINT16
))) {
2069 EbcDebugSignalException (
2070 EXCEPT_EBC_ALIGNMENT_CHECK
,
2071 EXCEPTION_FLAG_FATAL
,
2075 return EFI_UNSUPPORTED
;
2078 EbcDebuggerHookJMPStart (VmPtr
);
2079 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2080 VmPtr
->Ip
+= (UINTN
) Addr
+ Size
;
2082 VmPtr
->Ip
= (VMIP
) Addr
;
2084 EbcDebuggerHookJMPEnd (VmPtr
);
2088 // Form: JMP32 Rx {Immed32}
2090 Addr
= (UINTN
) (Data64
+ Index32
);
2091 if (!IS_ALIGNED ((UINTN
) Addr
, sizeof (UINT16
))) {
2092 EbcDebugSignalException (
2093 EXCEPT_EBC_ALIGNMENT_CHECK
,
2094 EXCEPTION_FLAG_FATAL
,
2098 return EFI_UNSUPPORTED
;
2101 EbcDebuggerHookJMPStart (VmPtr
);
2102 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2103 VmPtr
->Ip
+= (UINTN
) Addr
+ Size
;
2105 VmPtr
->Ip
= (VMIP
) Addr
;
2107 EbcDebuggerHookJMPEnd (VmPtr
);
2116 Execute the EBC JMP8 instruction.
2119 JMP8{cs|cc} Offset/2
2121 @param VmPtr A pointer to a VM context.
2123 @retval EFI_SUCCESS The instruction is executed successfully.
2128 IN VM_CONTEXT
*VmPtr
2132 UINT8 ConditionFlag
;
2137 // Decode instruction.
2139 Opcode
= GETOPCODE (VmPtr
);
2140 CompareSet
= (UINT8
) (((Opcode
& JMP_M_CS
) != 0) ? 1 : 0);
2141 ConditionFlag
= (UINT8
) VMFLAG_ISSET (VmPtr
, VMFLAGS_CC
);
2144 // If we haven't met the condition, then simply advance the IP and return
2146 if ((Opcode
& CONDITION_M_CONDITIONAL
) != 0) {
2147 if (CompareSet
!= ConditionFlag
) {
2148 EbcDebuggerHookJMP8Start (VmPtr
);
2150 EbcDebuggerHookJMP8End (VmPtr
);
2155 // Get the offset from the instruction stream. It's relative to the
2156 // following instruction, and divided by 2.
2158 Offset
= VmReadImmed8 (VmPtr
, 1);
2160 // Want to check for offset == -2 and then raise an exception?
2162 EbcDebuggerHookJMP8Start (VmPtr
);
2163 VmPtr
->Ip
+= (Offset
* 2) + 2;
2164 EbcDebuggerHookJMP8End (VmPtr
);
2170 Execute the EBC MOVI.
2174 MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
2176 First variable character specifies the move size
2177 Second variable character specifies size of the immediate data
2179 Sign-extend the immediate data to the size of the operation, and zero-extend
2180 if storing to a register.
2182 Operand1 direct with index/immed is invalid.
2184 @param VmPtr A pointer to a VM context.
2186 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2187 @retval EFI_SUCCESS The instruction is executed successfully.
2192 IN VM_CONTEXT
*VmPtr
2204 // Get the opcode and operands byte so we can get R1 and R2
2206 Opcode
= GETOPCODE (VmPtr
);
2207 Operands
= GETOPERANDS (VmPtr
);
2210 // Get the index (16-bit) if present
2212 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2213 Index16
= VmReadIndex16 (VmPtr
, 2);
2220 // Extract the immediate data. Sign-extend always.
2222 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2223 ImmData64
= (INT64
) (INT16
) VmReadImmed16 (VmPtr
, Size
);
2225 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2226 ImmData64
= (INT64
) (INT32
) VmReadImmed32 (VmPtr
, Size
);
2228 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2229 ImmData64
= (INT64
) VmReadImmed64 (VmPtr
, Size
);
2235 EbcDebugSignalException (
2236 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2237 EXCEPTION_FLAG_FATAL
,
2240 return EFI_UNSUPPORTED
;
2243 // Now write back the result
2245 if (!OPERAND1_INDIRECT (Operands
)) {
2247 // Operand1 direct. Make sure it didn't have an index.
2249 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2250 EbcDebugSignalException (
2251 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2252 EXCEPTION_FLAG_FATAL
,
2255 return EFI_UNSUPPORTED
;
2258 // Writing directly to a register. Clear unused bits.
2260 if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH8
) {
2261 Mask64
= 0x000000FF;
2262 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH16
) {
2263 Mask64
= 0x0000FFFF;
2264 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH32
) {
2265 Mask64
= 0x00000000FFFFFFFF;
2267 Mask64
= (UINT64
)~0;
2270 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = ImmData64
& Mask64
;
2273 // Get the address then write back based on size of the move
2275 Op1
= (UINT64
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
;
2276 if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH8
) {
2277 VmWriteMem8 (VmPtr
, (UINTN
) Op1
, (UINT8
) ImmData64
);
2278 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH16
) {
2279 VmWriteMem16 (VmPtr
, (UINTN
) Op1
, (UINT16
) ImmData64
);
2280 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH32
) {
2281 VmWriteMem32 (VmPtr
, (UINTN
) Op1
, (UINT32
) ImmData64
);
2283 VmWriteMem64 (VmPtr
, (UINTN
) Op1
, (UINT64
) ImmData64
);
2287 // Advance the instruction pointer
2295 Execute the EBC MOV immediate natural. This instruction moves an immediate
2296 index value into a register or memory location.
2300 MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
2302 @param VmPtr A pointer to a VM context.
2304 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2305 @retval EFI_SUCCESS The instruction is executed successfully.
2310 IN VM_CONTEXT
*VmPtr
2323 // Get the opcode and operands byte so we can get R1 and R2
2325 Opcode
= GETOPCODE (VmPtr
);
2326 Operands
= GETOPERANDS (VmPtr
);
2329 // Get the operand1 index (16-bit) if present
2331 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2332 Index16
= VmReadIndex16 (VmPtr
, 2);
2339 // Extract the immediate data and convert to a 64-bit index.
2341 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2342 ImmedIndex16
= VmReadIndex16 (VmPtr
, Size
);
2343 ImmedIndex64
= (INT64
) ImmedIndex16
;
2345 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2346 ImmedIndex32
= VmReadIndex32 (VmPtr
, Size
);
2347 ImmedIndex64
= (INT64
) ImmedIndex32
;
2349 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2350 ImmedIndex64
= VmReadIndex64 (VmPtr
, Size
);
2356 EbcDebugSignalException (
2357 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2358 EXCEPTION_FLAG_FATAL
,
2361 return EFI_UNSUPPORTED
;
2364 // Now write back the result
2366 if (!OPERAND1_INDIRECT (Operands
)) {
2368 // Check for MOVIn R1 Index16, Immed (not indirect, with index), which
2371 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2372 EbcDebugSignalException (
2373 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2374 EXCEPTION_FLAG_FATAL
,
2377 return EFI_UNSUPPORTED
;
2380 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = ImmedIndex64
;
2385 Op1
= (UINT64
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
;
2386 VmWriteMemN (VmPtr
, (UINTN
) Op1
, (UINTN
)(INTN
) ImmedIndex64
);
2389 // Advance the instruction pointer
2397 Execute the EBC MOVREL instruction.
2398 Dest <- Ip + ImmData
2402 MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
2404 @param VmPtr A pointer to a VM context.
2406 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2407 @retval EFI_SUCCESS The instruction is executed successfully.
2412 IN VM_CONTEXT
*VmPtr
2424 // Get the opcode and operands byte so we can get R1 and R2
2426 Opcode
= GETOPCODE (VmPtr
);
2427 Operands
= GETOPERANDS (VmPtr
);
2430 // Get the Operand 1 index (16-bit) if present
2432 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2433 Index16
= VmReadIndex16 (VmPtr
, 2);
2440 // Get the immediate data.
2442 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2443 ImmData64
= (INT64
) VmReadImmed16 (VmPtr
, Size
);
2445 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2446 ImmData64
= (INT64
) VmReadImmed32 (VmPtr
, Size
);
2448 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2449 ImmData64
= VmReadImmed64 (VmPtr
, Size
);
2455 EbcDebugSignalException (
2456 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2457 EXCEPTION_FLAG_FATAL
,
2460 return EFI_UNSUPPORTED
;
2463 // Compute the value and write back the result
2465 Op2
= (UINT64
) ((INT64
) ((UINT64
) (UINTN
) VmPtr
->Ip
) + (INT64
) ImmData64
+ Size
);
2466 if (!OPERAND1_INDIRECT (Operands
)) {
2468 // Check for illegal combination of operand1 direct with immediate data
2470 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2471 EbcDebugSignalException (
2472 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2473 EXCEPTION_FLAG_FATAL
,
2476 return EFI_UNSUPPORTED
;
2479 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (VM_REGISTER
) Op2
;
2482 // Get the address = [Rx] + Index16
2483 // Write back the result. Always a natural size write, since
2484 // we're talking addresses here.
2486 Op1
= (UINT64
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
;
2487 VmWriteMemN (VmPtr
, (UINTN
) Op1
, (UINTN
) Op2
);
2490 // Advance the instruction pointer
2498 Execute the EBC MOVsnw instruction. This instruction loads a signed
2499 natural value from memory or register to another memory or register. On
2500 32-bit machines, the value gets sign-extended to 64 bits if the destination
2505 MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
2507 0:7 1=>operand1 index present
2508 0:6 1=>operand2 index present
2510 @param VmPtr A pointer to a VM context.
2512 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2513 @retval EFI_SUCCESS The instruction is executed successfully.
2518 IN VM_CONTEXT
*VmPtr
2529 // Get the opcode and operand bytes
2531 Opcode
= GETOPCODE (VmPtr
);
2532 Operands
= GETOPERANDS (VmPtr
);
2534 Op1Index
= Op2Index
= 0;
2537 // Get the indexes if present.
2540 if ((Opcode
& OPCODE_M_IMMED_OP1
) !=0) {
2541 if (OPERAND1_INDIRECT (Operands
)) {
2542 Op1Index
= VmReadIndex16 (VmPtr
, 2);
2545 // Illegal form operand1 direct with index: MOVsnw R1 Index16, {@}R2
2547 EbcDebugSignalException (
2548 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2549 EXCEPTION_FLAG_FATAL
,
2552 return EFI_UNSUPPORTED
;
2555 Size
+= sizeof (UINT16
);
2558 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
2559 if (OPERAND2_INDIRECT (Operands
)) {
2560 Op2Index
= VmReadIndex16 (VmPtr
, Size
);
2562 Op2Index
= VmReadImmed16 (VmPtr
, Size
);
2565 Size
+= sizeof (UINT16
);
2568 // Get the data from the source.
2570 Op2
= (UINT64
)(INT64
)(INTN
)(VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Op2Index
);
2571 if (OPERAND2_INDIRECT (Operands
)) {
2572 Op2
= (UINT64
)(INT64
)(INTN
)VmReadMemN (VmPtr
, (UINTN
) Op2
);
2575 // Now write back the result.
2577 if (!OPERAND1_INDIRECT (Operands
)) {
2578 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = Op2
;
2580 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Op1Index
), (UINTN
) Op2
);
2583 // Advance the instruction pointer
2591 Execute the EBC MOVsnw instruction. This instruction loads a signed
2592 natural value from memory or register to another memory or register. On
2593 32-bit machines, the value gets sign-extended to 64 bits if the destination
2598 MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
2600 0:7 1=>operand1 index present
2601 0:6 1=>operand2 index present
2603 @param VmPtr A pointer to a VM context.
2605 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2606 @retval EFI_SUCCESS The instruction is executed successfully.
2611 IN VM_CONTEXT
*VmPtr
2622 // Get the opcode and operand bytes
2624 Opcode
= GETOPCODE (VmPtr
);
2625 Operands
= GETOPERANDS (VmPtr
);
2627 Op1Index
= Op2Index
= 0;
2630 // Get the indexes if present.
2633 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
2634 if (OPERAND1_INDIRECT (Operands
)) {
2635 Op1Index
= VmReadIndex32 (VmPtr
, 2);
2638 // Illegal form operand1 direct with index: MOVsnd R1 Index16,..
2640 EbcDebugSignalException (
2641 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2642 EXCEPTION_FLAG_FATAL
,
2645 return EFI_UNSUPPORTED
;
2648 Size
+= sizeof (UINT32
);
2651 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
2652 if (OPERAND2_INDIRECT (Operands
)) {
2653 Op2Index
= VmReadIndex32 (VmPtr
, Size
);
2655 Op2Index
= VmReadImmed32 (VmPtr
, Size
);
2658 Size
+= sizeof (UINT32
);
2661 // Get the data from the source.
2663 Op2
= (UINT64
)(INT64
)(INTN
)(INT64
)(VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Op2Index
);
2664 if (OPERAND2_INDIRECT (Operands
)) {
2665 Op2
= (UINT64
)(INT64
)(INTN
)(INT64
)VmReadMemN (VmPtr
, (UINTN
) Op2
);
2668 // Now write back the result.
2670 if (!OPERAND1_INDIRECT (Operands
)) {
2671 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = Op2
;
2673 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Op1Index
), (UINTN
) Op2
);
2676 // Advance the instruction pointer
2684 Execute the EBC PUSHn instruction
2687 PUSHn {@}R1 {Index16|Immed16}
2689 @param VmPtr A pointer to a VM context.
2691 @retval EFI_SUCCESS The instruction is executed successfully.
2696 IN VM_CONTEXT
*VmPtr
2705 // Get opcode and operands
2707 Opcode
= GETOPCODE (VmPtr
);
2708 Operands
= GETOPERANDS (VmPtr
);
2711 // Get index if present
2713 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2714 if (OPERAND1_INDIRECT (Operands
)) {
2715 Index16
= VmReadIndex16 (VmPtr
, 2);
2717 Index16
= VmReadImmed16 (VmPtr
, 2);
2726 // Get the data to push
2728 if (OPERAND1_INDIRECT (Operands
)) {
2729 DataN
= VmReadMemN (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
));
2731 DataN
= (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
);
2734 // Adjust the stack down.
2736 VmPtr
->Gpr
[0] -= sizeof (UINTN
);
2737 VmWriteMemN (VmPtr
, (UINTN
) VmPtr
->Gpr
[0], DataN
);
2743 Execute the EBC PUSH instruction.
2746 PUSH[32|64] {@}R1 {Index16|Immed16}
2748 @param VmPtr A pointer to a VM context.
2750 @retval EFI_SUCCESS The instruction is executed successfully.
2755 IN VM_CONTEXT
*VmPtr
2765 // Get opcode and operands
2767 Opcode
= GETOPCODE (VmPtr
);
2768 Operands
= GETOPERANDS (VmPtr
);
2770 // Get immediate index if present, then advance the IP.
2772 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2773 if (OPERAND1_INDIRECT (Operands
)) {
2774 Index16
= VmReadIndex16 (VmPtr
, 2);
2776 Index16
= VmReadImmed16 (VmPtr
, 2);
2785 // Get the data to push
2787 if ((Opcode
& PUSHPOP_M_64
) != 0) {
2788 if (OPERAND1_INDIRECT (Operands
)) {
2789 Data64
= VmReadMem64 (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
));
2791 Data64
= (UINT64
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
;
2794 // Adjust the stack down, then write back the data
2796 VmPtr
->Gpr
[0] -= sizeof (UINT64
);
2797 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->Gpr
[0], Data64
);
2802 if (OPERAND1_INDIRECT (Operands
)) {
2803 Data32
= VmReadMem32 (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
));
2805 Data32
= (UINT32
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
;
2808 // Adjust the stack down and write the data
2810 VmPtr
->Gpr
[0] -= sizeof (UINT32
);
2811 VmWriteMem32 (VmPtr
, (UINTN
) VmPtr
->Gpr
[0], Data32
);
2819 Execute the EBC POPn instruction.
2822 POPn {@}R1 {Index16|Immed16}
2824 @param VmPtr A pointer to a VM context.
2826 @retval EFI_SUCCESS The instruction is executed successfully.
2831 IN VM_CONTEXT
*VmPtr
2840 // Get opcode and operands
2842 Opcode
= GETOPCODE (VmPtr
);
2843 Operands
= GETOPERANDS (VmPtr
);
2845 // Get immediate data if present, and advance the IP
2847 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2848 if (OPERAND1_INDIRECT (Operands
)) {
2849 Index16
= VmReadIndex16 (VmPtr
, 2);
2851 Index16
= VmReadImmed16 (VmPtr
, 2);
2860 // Read the data off the stack, then adjust the stack pointer
2862 DataN
= VmReadMemN (VmPtr
, (UINTN
) VmPtr
->Gpr
[0]);
2863 VmPtr
->Gpr
[0] += sizeof (UINTN
);
2865 // Do the write-back
2867 if (OPERAND1_INDIRECT (Operands
)) {
2868 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
), DataN
);
2870 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (INT64
) (UINT64
) (UINTN
) (DataN
+ Index16
);
2878 Execute the EBC POP instruction.
2881 POPn {@}R1 {Index16|Immed16}
2883 @param VmPtr A pointer to a VM context.
2885 @retval EFI_SUCCESS The instruction is executed successfully.
2890 IN VM_CONTEXT
*VmPtr
2900 // Get opcode and operands
2902 Opcode
= GETOPCODE (VmPtr
);
2903 Operands
= GETOPERANDS (VmPtr
);
2905 // Get immediate data if present, and advance the IP.
2907 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2908 if (OPERAND1_INDIRECT (Operands
)) {
2909 Index16
= VmReadIndex16 (VmPtr
, 2);
2911 Index16
= VmReadImmed16 (VmPtr
, 2);
2920 // Get the data off the stack, then write it to the appropriate location
2922 if ((Opcode
& PUSHPOP_M_64
) != 0) {
2924 // Read the data off the stack, then adjust the stack pointer
2926 Data64
= VmReadMem64 (VmPtr
, (UINTN
) VmPtr
->Gpr
[0]);
2927 VmPtr
->Gpr
[0] += sizeof (UINT64
);
2929 // Do the write-back
2931 if (OPERAND1_INDIRECT (Operands
)) {
2932 VmWriteMem64 (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
), Data64
);
2934 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = Data64
+ Index16
;
2938 // 32-bit pop. Read it off the stack and adjust the stack pointer
2940 Data32
= (INT32
) VmReadMem32 (VmPtr
, (UINTN
) VmPtr
->Gpr
[0]);
2941 VmPtr
->Gpr
[0] += sizeof (UINT32
);
2943 // Do the write-back
2945 if (OPERAND1_INDIRECT (Operands
)) {
2946 VmWriteMem32 (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] + Index16
), Data32
);
2948 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (INT64
) Data32
+ Index16
;
2957 Implements the EBC CALL instruction.
2961 CALL32 {@}R1 {Immed32|Index32}
2963 CALLEX16 {@}R1 {Immed32}
2965 If Rx == R0, then it's a PC relative call to PC = PC + imm32.
2967 @param VmPtr A pointer to a VM context.
2969 @retval EFI_SUCCESS The instruction is executed successfully.
2974 IN VM_CONTEXT
*VmPtr
2985 // Get opcode and operands
2987 Opcode
= GETOPCODE (VmPtr
);
2988 Operands
= GETOPERANDS (VmPtr
);
2990 if ((Operands
& OPERAND_M_NATIVE_CALL
) != 0) {
2991 EbcDebuggerHookCALLEXStart (VmPtr
);
2993 EbcDebuggerHookCALLStart (VmPtr
);
2997 // Assign these as well to avoid compiler warnings
3002 FramePtr
= VmPtr
->FramePtr
;
3004 // Determine the instruction size, and get immediate data if present
3006 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
3007 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
3008 Immed64
= VmReadImmed64 (VmPtr
, 2);
3012 // If register operand is indirect, then the immediate data is an index
3014 if (OPERAND1_INDIRECT (Operands
)) {
3015 Immed32
= VmReadIndex32 (VmPtr
, 2);
3017 Immed32
= VmReadImmed32 (VmPtr
, 2);
3026 // If it's a call to EBC, adjust the stack pointer down 16 bytes and
3027 // put our return address and frame pointer on the VM stack.
3029 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3031 VmWriteMemN (VmPtr
, (UINTN
) VmPtr
->Gpr
[0], (UINTN
) FramePtr
);
3032 VmPtr
->FramePtr
= (VOID
*) (UINTN
) VmPtr
->Gpr
[0];
3034 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->Gpr
[0], (UINT64
) (UINTN
) (VmPtr
->Ip
+ Size
));
3037 // If 64-bit data, then absolute jump only
3039 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
3041 // Native or EBC call?
3043 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3044 VmPtr
->Ip
= (VMIP
) (UINTN
) Immed64
;
3047 // Call external function, get the return value, and advance the IP
3049 EbcLLCALLEX (VmPtr
, (UINTN
) Immed64
, (UINTN
) VmPtr
->Gpr
[0], FramePtr
, Size
);
3053 // Get the register data. If operand1 == 0, then ignore register and
3054 // take immediate data as relative or absolute address.
3055 // Compiler should take care of upper bits if 32-bit machine.
3057 if (OPERAND1_REGNUM (Operands
) != 0) {
3058 Immed64
= (UINT64
) (UINTN
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)];
3061 // Get final address
3063 if (OPERAND1_INDIRECT (Operands
)) {
3064 Immed64
= (INT64
) (UINT64
) (UINTN
) VmReadMemN (VmPtr
, (UINTN
) (Immed64
+ Immed32
));
3069 // Now determine if external call, and then if relative or absolute
3071 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3073 // EBC call. Relative or absolute? If relative, then it's relative to the
3074 // start of the next instruction.
3076 if ((Operands
& OPERAND_M_RELATIVE_ADDR
) != 0) {
3077 VmPtr
->Ip
+= Immed64
+ Size
;
3079 VmPtr
->Ip
= (VMIP
) (UINTN
) Immed64
;
3083 // Native call. Relative or absolute?
3085 if ((Operands
& OPERAND_M_RELATIVE_ADDR
) != 0) {
3086 EbcLLCALLEX (VmPtr
, (UINTN
) (Immed64
+ VmPtr
->Ip
+ Size
), (UINTN
) VmPtr
->Gpr
[0], FramePtr
, Size
);
3088 if ((VmPtr
->StopFlags
& STOPFLAG_BREAK_ON_CALLEX
) != 0) {
3092 EbcLLCALLEX (VmPtr
, (UINTN
) Immed64
, (UINTN
) VmPtr
->Gpr
[0], FramePtr
, Size
);
3097 if ((Operands
& OPERAND_M_NATIVE_CALL
) != 0) {
3098 EbcDebuggerHookCALLEXEnd (VmPtr
);
3100 EbcDebuggerHookCALLEnd (VmPtr
);
3108 Execute the EBC RET instruction.
3113 @param VmPtr A pointer to a VM context.
3115 @retval EFI_SUCCESS The instruction is executed successfully.
3120 IN VM_CONTEXT
*VmPtr
3124 EbcDebuggerHookRETStart (VmPtr
);
3127 // If we're at the top of the stack, then simply set the done
3130 if (VmPtr
->StackRetAddr
== (UINT64
) VmPtr
->Gpr
[0]) {
3131 VmPtr
->StopFlags
|= STOPFLAG_APP_DONE
;
3134 // Pull the return address off the VM app's stack and set the IP
3137 if (!IS_ALIGNED ((UINTN
) VmPtr
->Gpr
[0], sizeof (UINT16
))) {
3138 EbcDebugSignalException (
3139 EXCEPT_EBC_ALIGNMENT_CHECK
,
3140 EXCEPTION_FLAG_FATAL
,
3145 // Restore the IP and frame pointer from the stack
3147 VmPtr
->Ip
= (VMIP
) (UINTN
) VmReadMem64 (VmPtr
, (UINTN
) VmPtr
->Gpr
[0]);
3149 VmPtr
->FramePtr
= (VOID
*) VmReadMemN (VmPtr
, (UINTN
) VmPtr
->Gpr
[0]);
3154 EbcDebuggerHookRETEnd (VmPtr
);
3161 Execute the EBC CMP instruction.
3164 CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
3166 @param VmPtr A pointer to a VM context.
3168 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
3169 @retval EFI_SUCCESS The instruction is executed successfully.
3174 IN VM_CONTEXT
*VmPtr
3186 // Get opcode and operands
3188 Opcode
= GETOPCODE (VmPtr
);
3189 Operands
= GETOPERANDS (VmPtr
);
3191 // Get the register data we're going to compare to
3193 Op1
= VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)];
3195 // Get immediate data
3197 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
3198 if (OPERAND2_INDIRECT (Operands
)) {
3199 Index16
= VmReadIndex16 (VmPtr
, 2);
3201 Index16
= VmReadImmed16 (VmPtr
, 2);
3212 if (OPERAND2_INDIRECT (Operands
)) {
3213 if ((Opcode
& OPCODE_M_64BIT
) != 0) {
3214 Op2
= (INT64
) VmReadMem64 (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index16
));
3217 // 32-bit operations. 0-extend the values for all cases.
3219 Op2
= (INT64
) (UINT64
) ((UINT32
) VmReadMem32 (VmPtr
, (UINTN
) (VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index16
)));
3222 Op2
= VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index16
;
3225 // Now do the compare
3228 if ((Opcode
& OPCODE_M_64BIT
) != 0) {
3232 switch (Opcode
& OPCODE_M_OPCODE
) {
3251 case OPCODE_CMPULTE
:
3252 if ((UINT64
) Op1
<= (UINT64
) Op2
) {
3257 case OPCODE_CMPUGTE
:
3258 if ((UINT64
) Op1
>= (UINT64
) Op2
) {
3270 switch (Opcode
& OPCODE_M_OPCODE
) {
3272 if ((INT32
) Op1
== (INT32
) Op2
) {
3278 if ((INT32
) Op1
<= (INT32
) Op2
) {
3284 if ((INT32
) Op1
>= (INT32
) Op2
) {
3289 case OPCODE_CMPULTE
:
3290 if ((UINT32
) Op1
<= (UINT32
) Op2
) {
3295 case OPCODE_CMPUGTE
:
3296 if ((UINT32
) Op1
>= (UINT32
) Op2
) {
3306 // Now set the flag accordingly for the comparison
3309 VMFLAG_SET (VmPtr
, VMFLAGS_CC
);
3311 VMFLAG_CLEAR (VmPtr
, (UINT64
)VMFLAGS_CC
);
3322 Execute the EBC CMPI instruction
3325 CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
3327 @param VmPtr A pointer to a VM context.
3329 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
3330 @retval EFI_SUCCESS The instruction is executed successfully.
3335 IN VM_CONTEXT
*VmPtr
3347 // Get opcode and operands
3349 Opcode
= GETOPCODE (VmPtr
);
3350 Operands
= GETOPERANDS (VmPtr
);
3353 // Get operand1 index if present
3356 if ((Operands
& OPERAND_M_CMPI_INDEX
) != 0) {
3357 Index16
= VmReadIndex16 (VmPtr
, 2);
3363 // Get operand1 data we're going to compare to
3365 Op1
= (INT64
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)];
3366 if (OPERAND1_INDIRECT (Operands
)) {
3368 // Indirect operand1. Fetch 32 or 64-bit value based on compare size.
3370 if ((Opcode
& OPCODE_M_CMPI64
) != 0) {
3371 Op1
= (INT64
) VmReadMem64 (VmPtr
, (UINTN
) Op1
+ Index16
);
3373 Op1
= (INT64
) VmReadMem32 (VmPtr
, (UINTN
) Op1
+ Index16
);
3377 // Better not have been an index with direct. That is, CMPI R1 Index,...
3380 if ((Operands
& OPERAND_M_CMPI_INDEX
) != 0) {
3381 EbcDebugSignalException (
3382 EXCEPT_EBC_INSTRUCTION_ENCODING
,
3383 EXCEPTION_FLAG_ERROR
,
3387 return EFI_UNSUPPORTED
;
3391 // Get immediate data -- 16- or 32-bit sign extended
3393 if ((Opcode
& OPCODE_M_CMPI32_DATA
) != 0) {
3394 Op2
= (INT64
) VmReadImmed32 (VmPtr
, Size
);
3398 // 16-bit immediate data. Sign extend always.
3400 Op2
= (INT64
) ((INT16
) VmReadImmed16 (VmPtr
, Size
));
3404 // Now do the compare
3407 if ((Opcode
& OPCODE_M_CMPI64
) != 0) {
3409 // 64 bit comparison
3411 switch (Opcode
& OPCODE_M_OPCODE
) {
3413 if (Op1
== (INT64
) Op2
) {
3418 case OPCODE_CMPILTE
:
3419 if (Op1
<= (INT64
) Op2
) {
3424 case OPCODE_CMPIGTE
:
3425 if (Op1
>= (INT64
) Op2
) {
3430 case OPCODE_CMPIULTE
:
3431 if ((UINT64
) Op1
<= (UINT64
) ((UINT32
) Op2
)) {
3436 case OPCODE_CMPIUGTE
:
3437 if ((UINT64
) Op1
>= (UINT64
) ((UINT32
) Op2
)) {
3447 // 32-bit comparisons
3449 switch (Opcode
& OPCODE_M_OPCODE
) {
3451 if ((INT32
) Op1
== Op2
) {
3456 case OPCODE_CMPILTE
:
3457 if ((INT32
) Op1
<= Op2
) {
3462 case OPCODE_CMPIGTE
:
3463 if ((INT32
) Op1
>= Op2
) {
3468 case OPCODE_CMPIULTE
:
3469 if ((UINT32
) Op1
<= (UINT32
) Op2
) {
3474 case OPCODE_CMPIUGTE
:
3475 if ((UINT32
) Op1
>= (UINT32
) Op2
) {
3485 // Now set the flag accordingly for the comparison
3488 VMFLAG_SET (VmPtr
, VMFLAGS_CC
);
3490 VMFLAG_CLEAR (VmPtr
, (UINT64
)VMFLAGS_CC
);
3501 Execute the EBC NOT instruction.s
3504 NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
3506 @param VmPtr A pointer to a VM context.
3507 @param Op1 Operand 1 from the instruction
3508 @param Op2 Operand 2 from the instruction
3515 IN VM_CONTEXT
*VmPtr
,
3525 Execute the EBC NEG instruction.
3528 NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
3530 @param VmPtr A pointer to a VM context.
3531 @param Op1 Operand 1 from the instruction
3532 @param Op2 Operand 2 from the instruction
3539 IN VM_CONTEXT
*VmPtr
,
3549 Execute the EBC ADD instruction.
3552 ADD[32|64] {@}R1, {@}R2 {Index16}
3554 @param VmPtr A pointer to a VM context.
3555 @param Op1 Operand 1 from the instruction
3556 @param Op2 Operand 2 from the instruction
3563 IN VM_CONTEXT
*VmPtr
,
3573 Execute the EBC SUB instruction.
3576 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3578 @param VmPtr A pointer to a VM context.
3579 @param Op1 Operand 1 from the instruction
3580 @param Op2 Operand 2 from the instruction
3587 IN VM_CONTEXT
*VmPtr
,
3592 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3593 return (UINT64
) ((INT64
) ((INT64
) Op1
- (INT64
) Op2
));
3595 return (UINT64
) ((INT64
) ((INT32
) ((INT32
) Op1
- (INT32
) Op2
)));
3601 Execute the EBC MUL instruction.
3604 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3606 @param VmPtr A pointer to a VM context.
3607 @param Op1 Operand 1 from the instruction
3608 @param Op2 Operand 2 from the instruction
3615 IN VM_CONTEXT
*VmPtr
,
3620 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3621 return MultS64x64 ((INT64
)Op1
, (INT64
)Op2
);
3623 return (UINT64
) ((INT64
) ((INT32
) ((INT32
) Op1
* (INT32
) Op2
)));
3629 Execute the EBC MULU instruction
3632 MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3634 @param VmPtr A pointer to a VM context.
3635 @param Op1 Operand 1 from the instruction
3636 @param Op2 Operand 2 from the instruction
3638 @return (unsigned)Op1 * (unsigned)Op2
3643 IN VM_CONTEXT
*VmPtr
,
3648 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3649 return MultU64x64 (Op1
, Op2
);
3651 return (UINT64
) ((UINT32
) ((UINT32
) Op1
* (UINT32
) Op2
));
3657 Execute the EBC DIV instruction.
3660 DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
3662 @param VmPtr A pointer to a VM context.
3663 @param Op1 Operand 1 from the instruction
3664 @param Op2 Operand 2 from the instruction
3671 IN VM_CONTEXT
*VmPtr
,
3679 // Check for divide-by-0
3682 EbcDebugSignalException (
3683 EXCEPT_EBC_DIVIDE_ERROR
,
3684 EXCEPTION_FLAG_FATAL
,
3690 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3691 return (UINT64
) (DivS64x64Remainder (Op1
, Op2
, &Remainder
));
3693 return (UINT64
) ((INT64
) ((INT32
) Op1
/ (INT32
) Op2
));
3700 Execute the EBC DIVU instruction
3703 DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3705 @param VmPtr A pointer to a VM context.
3706 @param Op1 Operand 1 from the instruction
3707 @param Op2 Operand 2 from the instruction
3709 @return (unsigned)Op1 / (unsigned)Op2
3714 IN VM_CONTEXT
*VmPtr
,
3722 // Check for divide-by-0
3725 EbcDebugSignalException (
3726 EXCEPT_EBC_DIVIDE_ERROR
,
3727 EXCEPTION_FLAG_FATAL
,
3733 // Get the destination register
3735 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3736 return (UINT64
) (DivU64x64Remainder (Op1
, Op2
, &Remainder
));
3738 return (UINT64
) ((UINT32
) Op1
/ (UINT32
) Op2
);
3745 Execute the EBC MOD instruction.
3748 MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
3750 @param VmPtr A pointer to a VM context.
3751 @param Op1 Operand 1 from the instruction
3752 @param Op2 Operand 2 from the instruction
3754 @return Op1 MODULUS Op2
3759 IN VM_CONTEXT
*VmPtr
,
3767 // Check for divide-by-0
3770 EbcDebugSignalException (
3771 EXCEPT_EBC_DIVIDE_ERROR
,
3772 EXCEPTION_FLAG_FATAL
,
3777 DivS64x64Remainder ((INT64
)Op1
, (INT64
)Op2
, &Remainder
);
3784 Execute the EBC MODU instruction.
3787 MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3789 @param VmPtr A pointer to a VM context.
3790 @param Op1 Operand 1 from the instruction
3791 @param Op2 Operand 2 from the instruction
3793 @return Op1 UNSIGNED_MODULUS Op2
3798 IN VM_CONTEXT
*VmPtr
,
3806 // Check for divide-by-0
3809 EbcDebugSignalException (
3810 EXCEPT_EBC_DIVIDE_ERROR
,
3811 EXCEPTION_FLAG_FATAL
,
3816 DivU64x64Remainder (Op1
, Op2
, &Remainder
);
3823 Execute the EBC AND instruction.
3826 AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
3828 @param VmPtr A pointer to a VM context.
3829 @param Op1 Operand 1 from the instruction
3830 @param Op2 Operand 2 from the instruction
3837 IN VM_CONTEXT
*VmPtr
,
3847 Execute the EBC OR instruction.
3850 OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3852 @param VmPtr A pointer to a VM context.
3853 @param Op1 Operand 1 from the instruction
3854 @param Op2 Operand 2 from the instruction
3861 IN VM_CONTEXT
*VmPtr
,
3871 Execute the EBC XOR instruction.
3874 XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3876 @param VmPtr A pointer to a VM context.
3877 @param Op1 Operand 1 from the instruction
3878 @param Op2 Operand 2 from the instruction
3885 IN VM_CONTEXT
*VmPtr
,
3895 Execute the EBC SHL shift left instruction.
3898 SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
3900 @param VmPtr A pointer to a VM context.
3901 @param Op1 Operand 1 from the instruction
3902 @param Op2 Operand 2 from the instruction
3909 IN VM_CONTEXT
*VmPtr
,
3914 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3915 return LShiftU64 (Op1
, (UINTN
)Op2
);
3917 return (UINT64
) ((UINT32
) ((UINT32
) Op1
<< (UINT32
) Op2
));
3923 Execute the EBC SHR instruction.
3926 SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3928 @param VmPtr A pointer to a VM context.
3929 @param Op1 Operand 1 from the instruction
3930 @param Op2 Operand 2 from the instruction
3932 @return Op1 >> Op2 (unsigned operands)
3937 IN VM_CONTEXT
*VmPtr
,
3942 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3943 return RShiftU64 (Op1
, (UINTN
)Op2
);
3945 return (UINT64
) ((UINT32
) Op1
>> (UINT32
) Op2
);
3951 Execute the EBC ASHR instruction.
3954 ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3956 @param VmPtr A pointer to a VM context.
3957 @param Op1 Operand 1 from the instruction
3958 @param Op2 Operand 2 from the instruction
3960 @return Op1 >> Op2 (signed)
3965 IN VM_CONTEXT
*VmPtr
,
3970 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3971 return ARShiftU64 (Op1
, (UINTN
)Op2
);
3973 return (UINT64
) ((INT64
) ((INT32
) Op1
>> (UINT32
) Op2
));
3979 Execute the EBC EXTNDB instruction to sign-extend a byte value.
3982 EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3984 @param VmPtr A pointer to a VM context.
3985 @param Op1 Operand 1 from the instruction
3986 @param Op2 Operand 2 from the instruction
3988 @return (INT64)(INT8)Op2
3993 IN VM_CONTEXT
*VmPtr
,
4001 // Convert to byte, then return as 64-bit signed value to let compiler
4002 // sign-extend the value
4005 Data64
= (INT64
) Data8
;
4007 return (UINT64
) Data64
;
4012 Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
4015 EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
4017 @param VmPtr A pointer to a VM context.
4018 @param Op1 Operand 1 from the instruction
4019 @param Op2 Operand 2 from the instruction
4021 @return (INT64)(INT16)Op2
4026 IN VM_CONTEXT
*VmPtr
,
4034 // Convert to word, then return as 64-bit signed value to let compiler
4035 // sign-extend the value
4037 Data16
= (INT16
) Op2
;
4038 Data64
= (INT64
) Data16
;
4040 return (UINT64
) Data64
;
4043 // Execute the EBC EXTNDD instruction.
4045 // Format: EXTNDD {@}Rx, {@}Ry [Index16|Immed16]
4046 // EXTNDD Dest, Source
4048 // Operation: Dest <- SignExtended((DWORD)Source))
4052 Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
4055 EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
4057 @param VmPtr A pointer to a VM context.
4058 @param Op1 Operand 1 from the instruction
4059 @param Op2 Operand 2 from the instruction
4061 @return (INT64)(INT32)Op2
4066 IN VM_CONTEXT
*VmPtr
,
4074 // Convert to 32-bit value, then return as 64-bit signed value to let compiler
4075 // sign-extend the value
4077 Data32
= (INT32
) Op2
;
4078 Data64
= (INT64
) Data32
;
4080 return (UINT64
) Data64
;
4085 Execute all the EBC signed data manipulation instructions.
4086 Since the EBC data manipulation instructions all have the same basic form,
4087 they can share the code that does the fetch of operands and the write-back
4088 of the result. This function performs the fetch of the operands (even if
4089 both are not needed to be fetched, like NOT instruction), dispatches to the
4090 appropriate subfunction, then writes back the returned result.
4093 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4095 @param VmPtr A pointer to VM context.
4097 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4098 @retval EFI_SUCCESS The instruction is executed successfully.
4102 ExecuteSignedDataManip (
4103 IN VM_CONTEXT
*VmPtr
4107 // Just call the data manipulation function with a flag indicating this
4108 // is a signed operation.
4110 return ExecuteDataManip (VmPtr
, TRUE
);
4115 Execute all the EBC unsigned data manipulation instructions.
4116 Since the EBC data manipulation instructions all have the same basic form,
4117 they can share the code that does the fetch of operands and the write-back
4118 of the result. This function performs the fetch of the operands (even if
4119 both are not needed to be fetched, like NOT instruction), dispatches to the
4120 appropriate subfunction, then writes back the returned result.
4123 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4125 @param VmPtr A pointer to VM context.
4127 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4128 @retval EFI_SUCCESS The instruction is executed successfully.
4132 ExecuteUnsignedDataManip (
4133 IN VM_CONTEXT
*VmPtr
4137 // Just call the data manipulation function with a flag indicating this
4138 // is not a signed operation.
4140 return ExecuteDataManip (VmPtr
, FALSE
);
4145 Execute all the EBC data manipulation instructions.
4146 Since the EBC data manipulation instructions all have the same basic form,
4147 they can share the code that does the fetch of operands and the write-back
4148 of the result. This function performs the fetch of the operands (even if
4149 both are not needed to be fetched, like NOT instruction), dispatches to the
4150 appropriate subfunction, then writes back the returned result.
4153 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4155 @param VmPtr A pointer to VM context.
4156 @param IsSignedOp Indicates whether the operand is signed or not.
4158 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4159 @retval EFI_SUCCESS The instruction is executed successfully.
4164 IN VM_CONTEXT
*VmPtr
,
4165 IN BOOLEAN IsSignedOp
4174 INTN DataManipDispatchTableIndex
;
4177 // Get opcode and operands
4179 Opcode
= GETOPCODE (VmPtr
);
4180 Operands
= GETOPERANDS (VmPtr
);
4183 // Determine if we have immediate data by the opcode
4185 if ((Opcode
& DATAMANIP_M_IMMDATA
) != 0) {
4187 // Index16 if Ry is indirect, or Immed16 if Ry direct.
4189 if (OPERAND2_INDIRECT (Operands
)) {
4190 Index16
= VmReadIndex16 (VmPtr
, 2);
4192 Index16
= VmReadImmed16 (VmPtr
, 2);
4201 // Now get operand2 (source). It's of format {@}R2 {Index16|Immed16}
4203 Op2
= (UINT64
) VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] + Index16
;
4204 if (OPERAND2_INDIRECT (Operands
)) {
4206 // Indirect form: @R2 Index16. Fetch as 32- or 64-bit data
4208 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4209 Op2
= VmReadMem64 (VmPtr
, (UINTN
) Op2
);
4212 // Read as signed value where appropriate.
4215 Op2
= (UINT64
) (INT64
) ((INT32
) VmReadMem32 (VmPtr
, (UINTN
) Op2
));
4217 Op2
= (UINT64
) VmReadMem32 (VmPtr
, (UINTN
) Op2
);
4221 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4223 Op2
= (UINT64
) (INT64
) ((INT32
) Op2
);
4225 Op2
= (UINT64
) ((UINT32
) Op2
);
4230 // Get operand1 (destination and sometimes also an actual operand)
4233 Op1
= (UINT64
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)];
4234 if (OPERAND1_INDIRECT (Operands
)) {
4235 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4236 Op1
= VmReadMem64 (VmPtr
, (UINTN
) Op1
);
4239 Op1
= (UINT64
) (INT64
) ((INT32
) VmReadMem32 (VmPtr
, (UINTN
) Op1
));
4241 Op1
= (UINT64
) VmReadMem32 (VmPtr
, (UINTN
) Op1
);
4245 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4247 Op1
= (UINT64
) (INT64
) ((INT32
) Op1
);
4249 Op1
= (UINT64
) ((UINT32
) Op1
);
4254 // Dispatch to the computation function
4256 DataManipDispatchTableIndex
= (Opcode
& OPCODE_M_OPCODE
) - OPCODE_NOT
;
4257 if ((DataManipDispatchTableIndex
< 0) ||
4258 (DataManipDispatchTableIndex
>= ARRAY_SIZE (mDataManipDispatchTable
))) {
4259 EbcDebugSignalException (
4260 EXCEPT_EBC_INVALID_OPCODE
,
4261 EXCEPTION_FLAG_ERROR
,
4265 // Advance and return
4268 return EFI_UNSUPPORTED
;
4270 Op2
= mDataManipDispatchTable
[DataManipDispatchTableIndex
](VmPtr
, Op1
, Op2
);
4273 // Write back the result.
4275 if (OPERAND1_INDIRECT (Operands
)) {
4276 Op1
= (UINT64
) VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)];
4277 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4278 VmWriteMem64 (VmPtr
, (UINTN
) Op1
, Op2
);
4280 VmWriteMem32 (VmPtr
, (UINTN
) Op1
, (UINT32
) Op2
);
4284 // Storage back to a register. Write back, clearing upper bits (as per
4285 // the specification) if 32-bit operation.
4287 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = Op2
;
4288 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4289 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] &= 0xFFFFFFFF;
4293 // Advance the instruction pointer
4301 Execute the EBC LOADSP instruction.
4306 @param VmPtr A pointer to a VM context.
4308 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4309 @retval EFI_SUCCESS The instruction is executed successfully.
4314 IN VM_CONTEXT
*VmPtr
4322 Operands
= GETOPERANDS (VmPtr
);
4327 switch (OPERAND1_REGNUM (Operands
)) {
4333 // Spec states that this instruction will not modify reserved bits in
4334 // the flags register.
4336 VmPtr
->Flags
= (VmPtr
->Flags
&~VMFLAGS_ALL_VALID
) | (VmPtr
->Gpr
[OPERAND2_REGNUM (Operands
)] & VMFLAGS_ALL_VALID
);
4340 EbcDebugSignalException (
4341 EXCEPT_EBC_INSTRUCTION_ENCODING
,
4342 EXCEPTION_FLAG_WARNING
,
4346 return EFI_UNSUPPORTED
;
4355 Execute the EBC STORESP instruction.
4358 STORESP Rx, FLAGS|IP
4360 @param VmPtr A pointer to a VM context.
4362 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4363 @retval EFI_SUCCESS The instruction is executed successfully.
4368 IN VM_CONTEXT
*VmPtr
4376 Operands
= GETOPERANDS (VmPtr
);
4381 switch (OPERAND2_REGNUM (Operands
)) {
4387 // Retrieve the value in the flags register, then clear reserved bits
4389 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (UINT64
) (VmPtr
->Flags
& VMFLAGS_ALL_VALID
);
4393 // Get IP -- address of following instruction
4396 VmPtr
->Gpr
[OPERAND1_REGNUM (Operands
)] = (UINT64
) (UINTN
) VmPtr
->Ip
+ 2;
4400 EbcDebugSignalException (
4401 EXCEPT_EBC_INSTRUCTION_ENCODING
,
4402 EXCEPTION_FLAG_WARNING
,
4406 return EFI_UNSUPPORTED
;
4416 Decode a 16-bit index to determine the offset. Given an index value:
4419 b14:12 - number of bits in this index assigned to natural units (=a)
4420 ba:11 - constant units = ConstUnits
4421 b0:a - natural units = NaturalUnits
4423 Given this info, the offset can be computed by:
4424 offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
4426 Max offset is achieved with index = 0x7FFF giving an offset of
4427 0x27B (32-bit machine) or 0x477 (64-bit machine).
4428 Min offset is achieved with index =
4430 @param VmPtr A pointer to VM context.
4431 @param CodeOffset Offset from IP of the location of the 16-bit index
4434 @return The decoded offset.
4439 IN VM_CONTEXT
*VmPtr
,
4440 IN UINT32 CodeOffset
4451 // First read the index from the code stream
4453 Index
= VmReadCode16 (VmPtr
, CodeOffset
);
4456 // Get the mask for NaturalUnits. First get the number of bits from the index.
4458 NBits
= (INT16
) ((Index
& 0x7000) >> 12);
4461 // Scale it for 16-bit indexes
4466 // Now using the number of bits, create a mask.
4468 Mask
= (INT16
) ((INT16
)~0 << NBits
);
4471 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4473 NaturalUnits
= (INT16
) (Index
&~Mask
);
4476 // Now compute ConstUnits
4478 ConstUnits
= (INT16
) (((Index
&~0xF000) & Mask
) >> NBits
);
4480 Offset
= (INT16
) (NaturalUnits
* sizeof (UINTN
) + ConstUnits
);
4485 if ((Index
& 0x8000) != 0) {
4487 // Do it the hard way to work around a bogus compiler warning
4489 // Offset = -1 * Offset;
4491 Offset
= (INT16
) ((INT32
) Offset
* -1);
4499 Decode a 32-bit index to determine the offset.
4501 @param VmPtr A pointer to VM context.
4502 @param CodeOffset Offset from IP of the location of the 32-bit index
4505 @return Converted index per EBC VM specification.
4510 IN VM_CONTEXT
*VmPtr
,
4511 IN UINT32 CodeOffset
4521 Index
= VmReadImmed32 (VmPtr
, CodeOffset
);
4524 // Get the mask for NaturalUnits. First get the number of bits from the index.
4526 NBits
= (Index
& 0x70000000) >> 28;
4529 // Scale it for 32-bit indexes
4534 // Now using the number of bits, create a mask.
4536 Mask
= (INT32
)~0 << NBits
;
4539 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4541 NaturalUnits
= Index
&~Mask
;
4544 // Now compute ConstUnits
4546 ConstUnits
= ((Index
&~0xF0000000) & Mask
) >> NBits
;
4548 Offset
= NaturalUnits
* sizeof (UINTN
) + ConstUnits
;
4553 if ((Index
& 0x80000000) != 0) {
4554 Offset
= Offset
* -1;
4562 Decode a 64-bit index to determine the offset.
4564 @param VmPtr A pointer to VM context.s
4565 @param CodeOffset Offset from IP of the location of the 64-bit index
4568 @return Converted index per EBC VM specification
4573 IN VM_CONTEXT
*VmPtr
,
4574 IN UINT32 CodeOffset
4584 Index
= VmReadCode64 (VmPtr
, CodeOffset
);
4587 // Get the mask for NaturalUnits. First get the number of bits from the index.
4589 NBits
= RShiftU64 ((Index
& 0x7000000000000000ULL
), 60);
4592 // Scale it for 64-bit indexes (multiply by 8 by shifting left 3)
4594 NBits
= LShiftU64 ((UINT64
)NBits
, 3);
4597 // Now using the number of bits, create a mask.
4599 Mask
= (LShiftU64 ((UINT64
)~0, (UINTN
)NBits
));
4602 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4604 NaturalUnits
= Index
&~Mask
;
4607 // Now compute ConstUnits
4609 ConstUnits
= ARShiftU64 (((Index
&~0xF000000000000000ULL
) & Mask
), (UINTN
)NBits
);
4611 Offset
= MultU64x64 ((UINT64
) NaturalUnits
, sizeof (UINTN
)) + ConstUnits
;
4616 if ((Index
& 0x8000000000000000ULL
) != 0) {
4617 Offset
= MultS64x64 (Offset
, -1);
4625 Writes 8-bit data to memory address.
4627 This routine is called by the EBC data
4628 movement instructions that write to memory. Since these writes
4629 may be to the stack, which looks like (high address on top) this,
4631 [EBC entry point arguments]
4635 we need to detect all attempts to write to the EBC entry point argument
4636 stack area and adjust the address (which will initially point into the
4637 VM stack) to point into the EBC entry point arguments.
4639 @param VmPtr A pointer to a VM context.
4640 @param Addr Address to write to.
4641 @param Data Value to write to Addr.
4643 @retval EFI_SUCCESS The instruction is executed successfully.
4644 @retval Other Some error occurs when writing data to the address.
4649 IN VM_CONTEXT
*VmPtr
,
4655 // Convert the address if it's in the stack gap
4657 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4658 *(UINT8
*) Addr
= Data
;
4663 Writes 16-bit data to memory address.
4665 This routine is called by the EBC data
4666 movement instructions that write to memory. Since these writes
4667 may be to the stack, which looks like (high address on top) this,
4669 [EBC entry point arguments]
4673 we need to detect all attempts to write to the EBC entry point argument
4674 stack area and adjust the address (which will initially point into the
4675 VM stack) to point into the EBC entry point arguments.
4677 @param VmPtr A pointer to a VM context.
4678 @param Addr Address to write to.
4679 @param Data Value to write to Addr.
4681 @retval EFI_SUCCESS The instruction is executed successfully.
4682 @retval Other Some error occurs when writing data to the address.
4687 IN VM_CONTEXT
*VmPtr
,
4695 // Convert the address if it's in the stack gap
4697 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4700 // Do a simple write if aligned
4702 if (IS_ALIGNED (Addr
, sizeof (UINT16
))) {
4703 *(UINT16
*) Addr
= Data
;
4706 // Write as two bytes
4709 if ((Status
= VmWriteMem8 (VmPtr
, Addr
, (UINT8
) Data
)) != EFI_SUCCESS
) {
4714 if ((Status
= VmWriteMem8 (VmPtr
, Addr
+ 1, (UINT8
) (Data
>> 8))) != EFI_SUCCESS
) {
4726 Writes 32-bit data to memory address.
4728 This routine is called by the EBC data
4729 movement instructions that write to memory. Since these writes
4730 may be to the stack, which looks like (high address on top) this,
4732 [EBC entry point arguments]
4736 we need to detect all attempts to write to the EBC entry point argument
4737 stack area and adjust the address (which will initially point into the
4738 VM stack) to point into the EBC entry point arguments.
4740 @param VmPtr A pointer to a VM context.
4741 @param Addr Address to write to.
4742 @param Data Value to write to Addr.
4744 @retval EFI_SUCCESS The instruction is executed successfully.
4745 @retval Other Some error occurs when writing data to the address.
4750 IN VM_CONTEXT
*VmPtr
,
4758 // Convert the address if it's in the stack gap
4760 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4763 // Do a simple write if aligned
4765 if (IS_ALIGNED (Addr
, sizeof (UINT32
))) {
4766 *(UINT32
*) Addr
= Data
;
4769 // Write as two words
4772 if ((Status
= VmWriteMem16 (VmPtr
, Addr
, (UINT16
) Data
)) != EFI_SUCCESS
) {
4777 if ((Status
= VmWriteMem16 (VmPtr
, Addr
+ sizeof (UINT16
), (UINT16
) (Data
>> 16))) != EFI_SUCCESS
) {
4789 Writes 64-bit data to memory address.
4791 This routine is called by the EBC data
4792 movement instructions that write to memory. Since these writes
4793 may be to the stack, which looks like (high address on top) this,
4795 [EBC entry point arguments]
4799 we need to detect all attempts to write to the EBC entry point argument
4800 stack area and adjust the address (which will initially point into the
4801 VM stack) to point into the EBC entry point arguments.
4803 @param VmPtr A pointer to a VM context.
4804 @param Addr Address to write to.
4805 @param Data Value to write to Addr.
4807 @retval EFI_SUCCESS The instruction is executed successfully.
4808 @retval Other Some error occurs when writing data to the address.
4813 IN VM_CONTEXT
*VmPtr
,
4821 // Convert the address if it's in the stack gap
4823 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4826 // Do a simple write if aligned
4828 if (IS_ALIGNED (Addr
, sizeof (UINT64
))) {
4829 *(UINT64
*) Addr
= Data
;
4832 // Write as two 32-bit words
4835 if ((Status
= VmWriteMem32 (VmPtr
, Addr
, (UINT32
) Data
)) != EFI_SUCCESS
) {
4840 if ((Status
= VmWriteMem32 (VmPtr
, Addr
+ sizeof (UINT32
), (UINT32
) RShiftU64(Data
, 32))) != EFI_SUCCESS
) {
4852 Writes UINTN data to memory address.
4854 This routine is called by the EBC data
4855 movement instructions that write to memory. Since these writes
4856 may be to the stack, which looks like (high address on top) this,
4858 [EBC entry point arguments]
4862 we need to detect all attempts to write to the EBC entry point argument
4863 stack area and adjust the address (which will initially point into the
4864 VM stack) to point into the EBC entry point arguments.
4866 @param VmPtr A pointer to a VM context.
4867 @param Addr Address to write to.
4868 @param Data Value to write to Addr.
4870 @retval EFI_SUCCESS The instruction is executed successfully.
4871 @retval Other Some error occurs when writing data to the address.
4876 IN VM_CONTEXT
*VmPtr
,
4884 Status
= EFI_SUCCESS
;
4887 // Convert the address if it's in the stack gap
4889 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4892 // Do a simple write if aligned
4894 if (IS_ALIGNED (Addr
, sizeof (UINTN
))) {
4895 *(UINTN
*) Addr
= Data
;
4897 for (Index
= 0; Index
< sizeof (UINTN
) / sizeof (UINT32
); Index
++) {
4899 Status
= VmWriteMem32 (VmPtr
, Addr
+ Index
* sizeof (UINT32
), (UINT32
) Data
);
4901 Data
= (UINTN
) RShiftU64 ((UINT64
)Data
, 32);
4910 Reads 8-bit immediate value at the offset.
4912 This routine is called by the EBC execute
4913 functions to read EBC immediate values from the code stream.
4914 Since we can't assume alignment, each tries to read in the biggest
4915 chunks size available, but will revert to smaller reads if necessary.
4917 @param VmPtr A pointer to a VM context.
4918 @param Offset offset from IP of the code bytes to read.
4920 @return Signed data of the requested size from the specified address.
4925 IN VM_CONTEXT
*VmPtr
,
4930 // Simply return the data in flat memory space
4932 return * (INT8
*) (VmPtr
->Ip
+ Offset
);
4936 Reads 16-bit immediate value at the offset.
4938 This routine is called by the EBC execute
4939 functions to read EBC immediate values from the code stream.
4940 Since we can't assume alignment, each tries to read in the biggest
4941 chunks size available, but will revert to smaller reads if necessary.
4943 @param VmPtr A pointer to a VM context.
4944 @param Offset offset from IP of the code bytes to read.
4946 @return Signed data of the requested size from the specified address.
4951 IN VM_CONTEXT
*VmPtr
,
4956 // Read direct if aligned
4958 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (INT16
))) {
4959 return * (INT16
*) (VmPtr
->Ip
+ Offset
);
4962 // All code word reads should be aligned
4964 EbcDebugSignalException (
4965 EXCEPT_EBC_ALIGNMENT_CHECK
,
4966 EXCEPTION_FLAG_WARNING
,
4971 // Return unaligned data
4973 return (INT16
) (*(UINT8
*) (VmPtr
->Ip
+ Offset
) + (*(UINT8
*) (VmPtr
->Ip
+ Offset
+ 1) << 8));
4978 Reads 32-bit immediate value at the offset.
4980 This routine is called by the EBC execute
4981 functions to read EBC immediate values from the code stream.
4982 Since we can't assume alignment, each tries to read in the biggest
4983 chunks size available, but will revert to smaller reads if necessary.
4985 @param VmPtr A pointer to a VM context.
4986 @param Offset offset from IP of the code bytes to read.
4988 @return Signed data of the requested size from the specified address.
4993 IN VM_CONTEXT
*VmPtr
,
5000 // Read direct if aligned
5002 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT32
))) {
5003 return * (INT32
*) (VmPtr
->Ip
+ Offset
);
5006 // Return unaligned data
5008 Data
= (UINT32
) VmReadCode16 (VmPtr
, Offset
);
5009 Data
|= (UINT32
)(VmReadCode16 (VmPtr
, Offset
+ 2) << 16);
5015 Reads 64-bit immediate value at the offset.
5017 This routine is called by the EBC execute
5018 functions to read EBC immediate values from the code stream.
5019 Since we can't assume alignment, each tries to read in the biggest
5020 chunks size available, but will revert to smaller reads if necessary.
5022 @param VmPtr A pointer to a VM context.
5023 @param Offset offset from IP of the code bytes to read.
5025 @return Signed data of the requested size from the specified address.
5030 IN VM_CONTEXT
*VmPtr
,
5039 // Read direct if aligned
5041 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT64
))) {
5042 return * (UINT64
*) (VmPtr
->Ip
+ Offset
);
5045 // Return unaligned data.
5047 Ptr
= (UINT8
*) &Data64
;
5048 Data32
= VmReadCode32 (VmPtr
, Offset
);
5049 *(UINT32
*) Ptr
= Data32
;
5050 Ptr
+= sizeof (Data32
);
5051 Data32
= VmReadCode32 (VmPtr
, Offset
+ sizeof (UINT32
));
5052 *(UINT32
*) Ptr
= Data32
;
5058 Reads 16-bit unsigned data from the code stream.
5060 This routine provides the ability to read raw unsigned data from the code
5063 @param VmPtr A pointer to VM context
5064 @param Offset Offset from current IP to the raw data to read.
5066 @return The raw unsigned 16-bit value from the code stream.
5071 IN VM_CONTEXT
*VmPtr
,
5076 // Read direct if aligned
5078 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT16
))) {
5079 return * (UINT16
*) (VmPtr
->Ip
+ Offset
);
5082 // All code word reads should be aligned
5084 EbcDebugSignalException (
5085 EXCEPT_EBC_ALIGNMENT_CHECK
,
5086 EXCEPTION_FLAG_WARNING
,
5091 // Return unaligned data
5093 return (UINT16
) (*(UINT8
*) (VmPtr
->Ip
+ Offset
) + (*(UINT8
*) (VmPtr
->Ip
+ Offset
+ 1) << 8));
5098 Reads 32-bit unsigned data from the code stream.
5100 This routine provides the ability to read raw unsigned data from the code
5103 @param VmPtr A pointer to VM context
5104 @param Offset Offset from current IP to the raw data to read.
5106 @return The raw unsigned 32-bit value from the code stream.
5111 IN VM_CONTEXT
*VmPtr
,
5117 // Read direct if aligned
5119 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT32
))) {
5120 return * (UINT32
*) (VmPtr
->Ip
+ Offset
);
5123 // Return unaligned data
5125 Data
= (UINT32
) VmReadCode16 (VmPtr
, Offset
);
5126 Data
|= (VmReadCode16 (VmPtr
, Offset
+ 2) << 16);
5132 Reads 64-bit unsigned data from the code stream.
5134 This routine provides the ability to read raw unsigned data from the code
5137 @param VmPtr A pointer to VM context
5138 @param Offset Offset from current IP to the raw data to read.
5140 @return The raw unsigned 64-bit value from the code stream.
5145 IN VM_CONTEXT
*VmPtr
,
5154 // Read direct if aligned
5156 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT64
))) {
5157 return * (UINT64
*) (VmPtr
->Ip
+ Offset
);
5160 // Return unaligned data.
5162 Ptr
= (UINT8
*) &Data64
;
5163 Data32
= VmReadCode32 (VmPtr
, Offset
);
5164 *(UINT32
*) Ptr
= Data32
;
5165 Ptr
+= sizeof (Data32
);
5166 Data32
= VmReadCode32 (VmPtr
, Offset
+ sizeof (UINT32
));
5167 *(UINT32
*) Ptr
= Data32
;
5173 Reads 8-bit data form the memory address.
5175 @param VmPtr A pointer to VM context.
5176 @param Addr The memory address.
5178 @return The 8-bit value from the memory address.
5183 IN VM_CONTEXT
*VmPtr
,
5188 // Convert the address if it's in the stack gap
5190 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5192 // Simply return the data in flat memory space
5194 return * (UINT8
*) Addr
;
5198 Reads 16-bit data form the memory address.
5200 @param VmPtr A pointer to VM context.
5201 @param Addr The memory address.
5203 @return The 16-bit value from the memory address.
5208 IN VM_CONTEXT
*VmPtr
,
5213 // Convert the address if it's in the stack gap
5215 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5217 // Read direct if aligned
5219 if (IS_ALIGNED (Addr
, sizeof (UINT16
))) {
5220 return * (UINT16
*) Addr
;
5223 // Return unaligned data
5225 return (UINT16
) (*(UINT8
*) Addr
+ (*(UINT8
*) (Addr
+ 1) << 8));
5229 Reads 32-bit data form the memory address.
5231 @param VmPtr A pointer to VM context.
5232 @param Addr The memory address.
5234 @return The 32-bit value from the memory address.
5239 IN VM_CONTEXT
*VmPtr
,
5246 // Convert the address if it's in the stack gap
5248 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5250 // Read direct if aligned
5252 if (IS_ALIGNED (Addr
, sizeof (UINT32
))) {
5253 return * (UINT32
*) Addr
;
5256 // Return unaligned data
5258 Data
= (UINT32
) VmReadMem16 (VmPtr
, Addr
);
5259 Data
|= (VmReadMem16 (VmPtr
, Addr
+ 2) << 16);
5264 Reads 64-bit data form the memory address.
5266 @param VmPtr A pointer to VM context.
5267 @param Addr The memory address.
5269 @return The 64-bit value from the memory address.
5274 IN VM_CONTEXT
*VmPtr
,
5282 // Convert the address if it's in the stack gap
5284 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5287 // Read direct if aligned
5289 if (IS_ALIGNED (Addr
, sizeof (UINT64
))) {
5290 return * (UINT64
*) Addr
;
5293 // Return unaligned data. Assume little endian.
5295 Data32
= VmReadMem32 (VmPtr
, Addr
);
5296 Data
= (UINT64
) VmReadMem32 (VmPtr
, Addr
+ sizeof (UINT32
));
5297 Data
= LShiftU64 (Data
, 32) | Data32
;
5303 Given an address that EBC is going to read from or write to, return
5304 an appropriate address that accounts for a gap in the stack.
5305 The stack for this application looks like this (high addr on top)
5306 [EBC entry point arguments]
5309 The EBC assumes that its arguments are at the top of its stack, which
5310 is where the VM stack is really. Therefore if the EBC does memory
5311 accesses into the VM stack area, then we need to convert the address
5312 to point to the EBC entry point arguments area. Do this here.
5314 @param VmPtr A Pointer to VM context.
5315 @param Addr Address of interest
5317 @return The unchanged address if it's not in the VM stack region. Otherwise,
5318 adjust for the stack gap and return the modified address.
5323 IN VM_CONTEXT
*VmPtr
,
5327 ASSERT(((Addr
< VmPtr
->LowStackTop
) || (Addr
> VmPtr
->HighStackBottom
)));
5333 Read a natural value from memory. May or may not be aligned.
5335 @param VmPtr current VM context
5336 @param Addr the address to read from
5338 @return The natural value at address Addr.
5343 IN VM_CONTEXT
*VmPtr
,
5348 volatile UINT32 Size
;
5352 // Convert the address if it's in the stack gap
5354 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5356 // Read direct if aligned
5358 if (IS_ALIGNED (Addr
, sizeof (UINTN
))) {
5359 return * (UINTN
*) Addr
;
5362 // Return unaligned data
5365 FromPtr
= (UINT8
*) Addr
;
5366 ToPtr
= (UINT8
*) &Data
;
5368 for (Size
= 0; Size
< sizeof (Data
); Size
++) {
5378 Returns the version of the EBC virtual machine.
5380 @return The 64-bit version of EBC virtual machine.
5388 return (UINT64
) (((VM_MAJOR_VERSION
& 0xFFFF) << 16) | ((VM_MINOR_VERSION
& 0xFFFF)));