2 Contains code that implements the virtual machine.
4 Copyright (c) 2006 - 2008, Intel Corporation. <BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "EbcExecute.h"
20 // Define some useful data size constants to allow switch statements based on
21 // size of operands or data.
23 #define DATA_SIZE_INVALID 0
25 #define DATA_SIZE_16 2
26 #define DATA_SIZE_32 4
27 #define DATA_SIZE_64 8
28 #define DATA_SIZE_N 48 // 4 or 8
30 // Structure we'll use to dispatch opcodes to execute functions.
33 EFI_STATUS (*ExecuteFunction
) (IN VM_CONTEXT
* VmPtr
);
39 (*DATA_MANIP_EXEC_FUNCTION
) (
40 IN VM_CONTEXT
* VmPtr
,
46 Decode a 16-bit index to determine the offset. Given an index value:
49 b14:12 - number of bits in this index assigned to natural units (=a)
50 ba:11 - constant units = ConstUnits
51 b0:a - natural units = NaturalUnits
53 Given this info, the offset can be computed by:
54 offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
56 Max offset is achieved with index = 0x7FFF giving an offset of
57 0x27B (32-bit machine) or 0x477 (64-bit machine).
58 Min offset is achieved with index =
60 @param VmPtr A pointer to VM context.
61 @param CodeOffset Offset from IP of the location of the 16-bit index
64 @return The decoded offset.
74 Decode a 32-bit index to determine the offset.
76 @param VmPtr A pointer to VM context.
77 @param CodeOffset Offset from IP of the location of the 32-bit index
80 @return Converted index per EBC VM specification.
90 Decode a 64-bit index to determine the offset.
92 @param VmPtr A pointer to VM context.s
93 @param CodeOffset Offset from IP of the location of the 64-bit index
96 @return Converted index per EBC VM specification
101 IN VM_CONTEXT
*VmPtr
,
106 Reads 8-bit data form the memory address.
108 @param VmPtr A pointer to VM context.
109 @param Addr The memory address.
111 @return The 8-bit value from the memory address.
116 IN VM_CONTEXT
*VmPtr
,
121 Reads 16-bit data form the memory address.
123 @param VmPtr A pointer to VM context.
124 @param Addr The memory address.
126 @return The 16-bit value from the memory address.
131 IN VM_CONTEXT
*VmPtr
,
136 Reads 32-bit data form the memory address.
138 @param VmPtr A pointer to VM context.
139 @param Addr The memory address.
141 @return The 32-bit value from the memory address.
146 IN VM_CONTEXT
*VmPtr
,
151 Reads 64-bit data form the memory address.
153 @param VmPtr A pointer to VM context.
154 @param Addr The memory address.
156 @return The 64-bit value from the memory address.
161 IN VM_CONTEXT
*VmPtr
,
166 Read a natural value from memory. May or may not be aligned.
168 @param VmPtr current VM context
169 @param Addr the address to read from
171 @return The natural value at address Addr.
176 IN VM_CONTEXT
*VmPtr
,
181 Writes 8-bit data to memory address.
183 This routine is called by the EBC data
184 movement instructions that write to memory. Since these writes
185 may be to the stack, which looks like (high address on top) this,
187 [EBC entry point arguments]
191 we need to detect all attempts to write to the EBC entry point argument
192 stack area and adjust the address (which will initially point into the
193 VM stack) to point into the EBC entry point arguments.
195 @param VmPtr A pointer to a VM context.
196 @param Addr Address to write to.
197 @param Data Value to write to Addr.
199 @retval EFI_SUCCESS The instruction is executed successfully.
200 @retval Other Some error occurs when writing data to the address.
205 IN VM_CONTEXT
*VmPtr
,
211 Writes 16-bit data to memory address.
213 This routine is called by the EBC data
214 movement instructions that write to memory. Since these writes
215 may be to the stack, which looks like (high address on top) this,
217 [EBC entry point arguments]
221 we need to detect all attempts to write to the EBC entry point argument
222 stack area and adjust the address (which will initially point into the
223 VM stack) to point into the EBC entry point arguments.
225 @param VmPtr A pointer to a VM context.
226 @param Addr Address to write to.
227 @param Data Value to write to Addr.
229 @retval EFI_SUCCESS The instruction is executed successfully.
230 @retval Other Some error occurs when writing data to the address.
235 IN VM_CONTEXT
*VmPtr
,
241 Writes 32-bit data to memory address.
243 This routine is called by the EBC data
244 movement instructions that write to memory. Since these writes
245 may be to the stack, which looks like (high address on top) this,
247 [EBC entry point arguments]
251 we need to detect all attempts to write to the EBC entry point argument
252 stack area and adjust the address (which will initially point into the
253 VM stack) to point into the EBC entry point arguments.
255 @param VmPtr A pointer to a VM context.
256 @param Addr Address to write to.
257 @param Data Value to write to Addr.
259 @retval EFI_SUCCESS The instruction is executed successfully.
260 @retval Other Some error occurs when writing data to the address.
265 IN VM_CONTEXT
*VmPtr
,
271 Reads 16-bit unsigned data from the code stream.
273 This routine provides the ability to read raw unsigned data from the code
276 @param VmPtr A pointer to VM context
277 @param Offset Offset from current IP to the raw data to read.
279 @return The raw unsigned 16-bit value from the code stream.
284 IN VM_CONTEXT
*VmPtr
,
289 Reads 32-bit unsigned data from the code stream.
291 This routine provides the ability to read raw unsigned data from the code
294 @param VmPtr A pointer to VM context
295 @param Offset Offset from current IP to the raw data to read.
297 @return The raw unsigned 32-bit value from the code stream.
302 IN VM_CONTEXT
*VmPtr
,
307 Reads 64-bit unsigned data from the code stream.
309 This routine provides the ability to read raw unsigned data from the code
312 @param VmPtr A pointer to VM context
313 @param Offset Offset from current IP to the raw data to read.
315 @return The raw unsigned 64-bit value from the code stream.
320 IN VM_CONTEXT
*VmPtr
,
325 Reads 8-bit immediate value at the offset.
327 This routine is called by the EBC execute
328 functions to read EBC immediate values from the code stream.
329 Since we can't assume alignment, each tries to read in the biggest
330 chunks size available, but will revert to smaller reads if necessary.
332 @param VmPtr A pointer to a VM context.
333 @param Offset offset from IP of the code bytes to read.
335 @return Signed data of the requested size from the specified address.
340 IN VM_CONTEXT
*VmPtr
,
345 Reads 16-bit immediate value at the offset.
347 This routine is called by the EBC execute
348 functions to read EBC immediate values from the code stream.
349 Since we can't assume alignment, each tries to read in the biggest
350 chunks size available, but will revert to smaller reads if necessary.
352 @param VmPtr A pointer to a VM context.
353 @param Offset offset from IP of the code bytes to read.
355 @return Signed data of the requested size from the specified address.
360 IN VM_CONTEXT
*VmPtr
,
365 Reads 32-bit immediate value at the offset.
367 This routine is called by the EBC execute
368 functions to read EBC immediate values from the code stream.
369 Since we can't assume alignment, each tries to read in the biggest
370 chunks size available, but will revert to smaller reads if necessary.
372 @param VmPtr A pointer to a VM context.
373 @param Offset offset from IP of the code bytes to read.
375 @return Signed data of the requested size from the specified address.
380 IN VM_CONTEXT
*VmPtr
,
385 Reads 64-bit immediate value at the offset.
387 This routine is called by the EBC execute
388 functions to read EBC immediate values from the code stream.
389 Since we can't assume alignment, each tries to read in the biggest
390 chunks size available, but will revert to smaller reads if necessary.
392 @param VmPtr A pointer to a VM context.
393 @param Offset offset from IP of the code bytes to read.
395 @return Signed data of the requested size from the specified address.
400 IN VM_CONTEXT
*VmPtr
,
405 Given an address that EBC is going to read from or write to, return
406 an appropriate address that accounts for a gap in the stack.
407 The stack for this application looks like this (high addr on top)
408 [EBC entry point arguments]
411 The EBC assumes that its arguments are at the top of its stack, which
412 is where the VM stack is really. Therefore if the EBC does memory
413 accesses into the VM stack area, then we need to convert the address
414 to point to the EBC entry point arguments area. Do this here.
416 @param VmPtr A Pointer to VM context.
417 @param Addr Address of interest
419 @return The unchanged address if it's not in the VM stack region. Otherwise,
420 adjust for the stack gap and return the modified address.
425 IN VM_CONTEXT
*VmPtr
,
430 Execute all the EBC data manipulation instructions.
431 Since the EBC data manipulation instructions all have the same basic form,
432 they can share the code that does the fetch of operands and the write-back
433 of the result. This function performs the fetch of the operands (even if
434 both are not needed to be fetched, like NOT instruction), dispatches to the
435 appropriate subfunction, then writes back the returned result.
438 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
440 @param VmPtr A pointer to VM context.
441 @param IsSignedOp Indicates whether the operand is signed or not.
443 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
444 @retval EFI_SUCCESS The instruction is executed successfully.
449 IN VM_CONTEXT
*VmPtr
,
450 IN BOOLEAN IsSignedOp
454 // Functions that execute VM opcodes
457 Execute the EBC BREAK instruction.
459 @param VmPtr A pointer to a VM context.
461 @retval EFI_SUCCESS The instruction is executed successfully.
470 Execute the JMP instruction.
474 JMP32{cs|cc} {@}R1 {Immed32|Index32}
477 b0.7 - immediate data present
478 b0.6 - 1 = 64 bit immediate data
479 0 = 32 bit immediate data
480 b1.7 - 1 = conditional
481 b1.6 1 = CS (condition set)
482 0 = CC (condition clear)
483 b1.4 1 = relative address
485 b1.3 1 = operand1 indirect
488 @param VmPtr A pointer to a VM context.
490 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
491 @retval EFI_SUCCESS The instruction is executed successfully.
500 Execute the EBC JMP8 instruction.
505 @param VmPtr A pointer to a VM context.
507 @retval EFI_SUCCESS The instruction is executed successfully.
516 Implements the EBC CALL instruction.
520 CALL32 {@}R1 {Immed32|Index32}
522 CALLEX16 {@}R1 {Immed32}
524 If Rx == R0, then it's a PC relative call to PC = PC + imm32.
526 @param VmPtr A pointer to a VM context.
528 @retval EFI_SUCCESS The instruction is executed successfully.
537 Execute the EBC RET instruction.
542 @param VmPtr A pointer to a VM context.
544 @retval EFI_SUCCESS The instruction is executed successfully.
553 Execute the EBC CMP instruction.
556 CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
558 @param VmPtr A pointer to a VM context.
560 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
561 @retval EFI_SUCCESS The instruction is executed successfully.
570 Execute the EBC CMPI instruction
573 CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
575 @param VmPtr A pointer to a VM context.
577 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
578 @retval EFI_SUCCESS The instruction is executed successfully.
587 Execute the MOVxx instructions.
591 MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
592 MOVqq {@}R1 {Index64}, {@}R2 {Index64}
594 Copies contents of [R2] -> [R1], zero extending where required.
596 First character indicates the size of the move.
597 Second character indicates the size of the index(s).
599 Invalid to have R1 direct with index.
601 @param VmPtr A pointer to a VM context.
603 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
604 @retval EFI_SUCCESS The instruction is executed successfully.
613 Execute the EBC MOVI.
617 MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
619 First variable character specifies the move size
620 Second variable character specifies size of the immediate data
622 Sign-extend the immediate data to the size of the operation, and zero-extend
623 if storing to a register.
625 Operand1 direct with index/immed is invalid.
627 @param VmPtr A pointer to a VM context.
629 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
630 @retval EFI_SUCCESS The instruction is executed successfully.
639 Execute the EBC MOV immediate natural. This instruction moves an immediate
640 index value into a register or memory location.
644 MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
646 @param VmPtr A pointer to a VM context.
648 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
649 @retval EFI_SUCCESS The instruction is executed successfully.
658 Execute the EBC MOVREL instruction.
663 MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
665 @param VmPtr A pointer to a VM context.
667 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
668 @retval EFI_SUCCESS The instruction is executed successfully.
677 Execute the EBC PUSHn instruction
680 PUSHn {@}R1 {Index16|Immed16}
682 @param VmPtr A pointer to a VM context.
684 @retval EFI_SUCCESS The instruction is executed successfully.
693 Execute the EBC PUSH instruction.
696 PUSH[32|64] {@}R1 {Index16|Immed16}
698 @param VmPtr A pointer to a VM context.
700 @retval EFI_SUCCESS The instruction is executed successfully.
709 Execute the EBC POPn instruction.
712 POPn {@}R1 {Index16|Immed16}
714 @param VmPtr A pointer to a VM context.
716 @retval EFI_SUCCESS The instruction is executed successfully.
725 Execute the EBC POP instruction.
728 POPn {@}R1 {Index16|Immed16}
730 @param VmPtr A pointer to a VM context.
732 @retval EFI_SUCCESS The instruction is executed successfully.
741 Execute all the EBC signed data manipulation instructions.
742 Since the EBC data manipulation instructions all have the same basic form,
743 they can share the code that does the fetch of operands and the write-back
744 of the result. This function performs the fetch of the operands (even if
745 both are not needed to be fetched, like NOT instruction), dispatches to the
746 appropriate subfunction, then writes back the returned result.
749 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
751 @param VmPtr A pointer to VM context.
753 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
754 @retval EFI_SUCCESS The instruction is executed successfully.
758 ExecuteSignedDataManip (
763 Execute all the EBC unsigned data manipulation instructions.
764 Since the EBC data manipulation instructions all have the same basic form,
765 they can share the code that does the fetch of operands and the write-back
766 of the result. This function performs the fetch of the operands (even if
767 both are not needed to be fetched, like NOT instruction), dispatches to the
768 appropriate subfunction, then writes back the returned result.
771 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
773 @param VmPtr A pointer to VM context.
775 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
776 @retval EFI_SUCCESS The instruction is executed successfully.
780 ExecuteUnsignedDataManip (
785 Execute the EBC LOADSP instruction.
790 @param VmPtr A pointer to a VM context.
792 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
793 @retval EFI_SUCCESS The instruction is executed successfully.
802 Execute the EBC STORESP instruction.
807 @param VmPtr A pointer to a VM context.
809 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
810 @retval EFI_SUCCESS The instruction is executed successfully.
819 Execute the EBC MOVsnw instruction. This instruction loads a signed
820 natural value from memory or register to another memory or register. On
821 32-bit machines, the value gets sign-extended to 64 bits if the destination
826 MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
828 0:7 1=>operand1 index present
829 0:6 1=>operand2 index present
831 @param VmPtr A pointer to a VM context.
833 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
834 @retval EFI_SUCCESS The instruction is executed successfully.
843 Execute the EBC MOVsnw instruction. This instruction loads a signed
844 natural value from memory or register to another memory or register. On
845 32-bit machines, the value gets sign-extended to 64 bits if the destination
850 MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
852 0:7 1=>operand1 index present
853 0:6 1=>operand2 index present
855 @param VmPtr A pointer to a VM context.
857 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
858 @retval EFI_SUCCESS The instruction is executed successfully.
867 // Data manipulation subfunctions
870 Execute the EBC NOT instruction.s
873 NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
875 @param VmPtr A pointer to a VM context.
876 @param Op1 Operand 1 from the instruction
877 @param Op2 Operand 2 from the instruction
884 IN VM_CONTEXT
*VmPtr
,
890 Execute the EBC NEG instruction.
893 NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
895 @param VmPtr A pointer to a VM context.
896 @param Op1 Operand 1 from the instruction
897 @param Op2 Operand 2 from the instruction
904 IN VM_CONTEXT
*VmPtr
,
910 Execute the EBC ADD instruction.
913 ADD[32|64] {@}R1, {@}R2 {Index16}
915 @param VmPtr A pointer to a VM context.
916 @param Op1 Operand 1 from the instruction
917 @param Op2 Operand 2 from the instruction
924 IN VM_CONTEXT
*VmPtr
,
930 Execute the EBC SUB instruction.
933 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
935 @param VmPtr A pointer to a VM context.
936 @param Op1 Operand 1 from the instruction
937 @param Op2 Operand 2 from the instruction
944 IN VM_CONTEXT
*VmPtr
,
950 Execute the EBC MUL instruction.
953 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
955 @param VmPtr A pointer to a VM context.
956 @param Op1 Operand 1 from the instruction
957 @param Op2 Operand 2 from the instruction
964 IN VM_CONTEXT
*VmPtr
,
970 Execute the EBC MULU instruction
973 MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
975 @param VmPtr A pointer to a VM context.
976 @param Op1 Operand 1 from the instruction
977 @param Op2 Operand 2 from the instruction
979 @return (unsigned)Op1 * (unsigned)Op2
984 IN VM_CONTEXT
*VmPtr
,
990 Execute the EBC DIV instruction.
993 DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
995 @param VmPtr A pointer to a VM context.
996 @param Op1 Operand 1 from the instruction
997 @param Op2 Operand 2 from the instruction
1004 IN VM_CONTEXT
*VmPtr
,
1010 Execute the EBC DIVU instruction
1013 DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
1015 @param VmPtr A pointer to a VM context.
1016 @param Op1 Operand 1 from the instruction
1017 @param Op2 Operand 2 from the instruction
1019 @return (unsigned)Op1 / (unsigned)Op2
1024 IN VM_CONTEXT
*VmPtr
,
1030 Execute the EBC MOD instruction.
1033 MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
1035 @param VmPtr A pointer to a VM context.
1036 @param Op1 Operand 1 from the instruction
1037 @param Op2 Operand 2 from the instruction
1039 @return Op1 MODULUS Op2
1044 IN VM_CONTEXT
*VmPtr
,
1050 Execute the EBC MODU instruction.
1053 MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
1055 @param VmPtr A pointer to a VM context.
1056 @param Op1 Operand 1 from the instruction
1057 @param Op2 Operand 2 from the instruction
1059 @return Op1 UNSIGNED_MODULUS Op2
1064 IN VM_CONTEXT
*VmPtr
,
1070 Execute the EBC AND instruction.
1073 AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
1075 @param VmPtr A pointer to a VM context.
1076 @param Op1 Operand 1 from the instruction
1077 @param Op2 Operand 2 from the instruction
1084 IN VM_CONTEXT
*VmPtr
,
1090 Execute the EBC OR instruction.
1093 OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1095 @param VmPtr A pointer to a VM context.
1096 @param Op1 Operand 1 from the instruction
1097 @param Op2 Operand 2 from the instruction
1104 IN VM_CONTEXT
*VmPtr
,
1110 Execute the EBC XOR instruction.
1113 XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1115 @param VmPtr A pointer to a VM context.
1116 @param Op1 Operand 1 from the instruction
1117 @param Op2 Operand 2 from the instruction
1124 IN VM_CONTEXT
*VmPtr
,
1130 Execute the EBC SHL shift left instruction.
1133 SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
1135 @param VmPtr A pointer to a VM context.
1136 @param Op1 Operand 1 from the instruction
1137 @param Op2 Operand 2 from the instruction
1144 IN VM_CONTEXT
*VmPtr
,
1150 Execute the EBC SHR instruction.
1153 SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1155 @param VmPtr A pointer to a VM context.
1156 @param Op1 Operand 1 from the instruction
1157 @param Op2 Operand 2 from the instruction
1159 @return Op1 >> Op2 (unsigned operands)
1164 IN VM_CONTEXT
*VmPtr
,
1170 Execute the EBC ASHR instruction.
1173 ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1175 @param VmPtr A pointer to a VM context.
1176 @param Op1 Operand 1 from the instruction
1177 @param Op2 Operand 2 from the instruction
1179 @return Op1 >> Op2 (signed)
1184 IN VM_CONTEXT
*VmPtr
,
1190 Execute the EBC EXTNDB instruction to sign-extend a byte value.
1193 EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
1195 @param VmPtr A pointer to a VM context.
1196 @param Op1 Operand 1 from the instruction
1197 @param Op2 Operand 2 from the instruction
1199 @return (INT64)(INT8)Op2
1204 IN VM_CONTEXT
*VmPtr
,
1210 Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
1213 EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
1215 @param VmPtr A pointer to a VM context.
1216 @param Op1 Operand 1 from the instruction
1217 @param Op2 Operand 2 from the instruction
1219 @return (INT64)(INT16)Op2
1224 IN VM_CONTEXT
*VmPtr
,
1230 Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
1233 EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
1235 @param VmPtr A pointer to a VM context.
1236 @param Op1 Operand 1 from the instruction
1237 @param Op2 Operand 2 from the instruction
1239 @return (INT64)(INT32)Op2
1244 IN VM_CONTEXT
*VmPtr
,
1250 // Once we retrieve the operands for the data manipulation instructions,
1251 // call these functions to perform the operation.
1253 CONST DATA_MANIP_EXEC_FUNCTION mDataManipDispatchTable
[] = {
1275 CONST VM_TABLE_ENTRY mVmOpcodeTable
[] = {
1276 { ExecuteBREAK
}, // opcode 0x00
1277 { ExecuteJMP
}, // opcode 0x01
1278 { ExecuteJMP8
}, // opcode 0x02
1279 { ExecuteCALL
}, // opcode 0x03
1280 { ExecuteRET
}, // opcode 0x04
1281 { ExecuteCMP
}, // opcode 0x05 CMPeq
1282 { ExecuteCMP
}, // opcode 0x06 CMPlte
1283 { ExecuteCMP
}, // opcode 0x07 CMPgte
1284 { ExecuteCMP
}, // opcode 0x08 CMPulte
1285 { ExecuteCMP
}, // opcode 0x09 CMPugte
1286 { ExecuteUnsignedDataManip
}, // opcode 0x0A NOT
1287 { ExecuteSignedDataManip
}, // opcode 0x0B NEG
1288 { ExecuteSignedDataManip
}, // opcode 0x0C ADD
1289 { ExecuteSignedDataManip
}, // opcode 0x0D SUB
1290 { ExecuteSignedDataManip
}, // opcode 0x0E MUL
1291 { ExecuteUnsignedDataManip
}, // opcode 0x0F MULU
1292 { ExecuteSignedDataManip
}, // opcode 0x10 DIV
1293 { ExecuteUnsignedDataManip
}, // opcode 0x11 DIVU
1294 { ExecuteSignedDataManip
}, // opcode 0x12 MOD
1295 { ExecuteUnsignedDataManip
}, // opcode 0x13 MODU
1296 { ExecuteUnsignedDataManip
}, // opcode 0x14 AND
1297 { ExecuteUnsignedDataManip
}, // opcode 0x15 OR
1298 { ExecuteUnsignedDataManip
}, // opcode 0x16 XOR
1299 { ExecuteUnsignedDataManip
}, // opcode 0x17 SHL
1300 { ExecuteUnsignedDataManip
}, // opcode 0x18 SHR
1301 { ExecuteSignedDataManip
}, // opcode 0x19 ASHR
1302 { ExecuteUnsignedDataManip
}, // opcode 0x1A EXTNDB
1303 { ExecuteUnsignedDataManip
}, // opcode 0x1B EXTNDW
1304 { ExecuteUnsignedDataManip
}, // opcode 0x1C EXTNDD
1305 { ExecuteMOVxx
}, // opcode 0x1D MOVBW
1306 { ExecuteMOVxx
}, // opcode 0x1E MOVWW
1307 { ExecuteMOVxx
}, // opcode 0x1F MOVDW
1308 { ExecuteMOVxx
}, // opcode 0x20 MOVQW
1309 { ExecuteMOVxx
}, // opcode 0x21 MOVBD
1310 { ExecuteMOVxx
}, // opcode 0x22 MOVWD
1311 { ExecuteMOVxx
}, // opcode 0x23 MOVDD
1312 { ExecuteMOVxx
}, // opcode 0x24 MOVQD
1313 { ExecuteMOVsnw
}, // opcode 0x25 MOVsnw
1314 { ExecuteMOVsnd
}, // opcode 0x26 MOVsnd
1315 { NULL
}, // opcode 0x27
1316 { ExecuteMOVxx
}, // opcode 0x28 MOVqq
1317 { ExecuteLOADSP
}, // opcode 0x29 LOADSP SP1, R2
1318 { ExecuteSTORESP
}, // opcode 0x2A STORESP R1, SP2
1319 { ExecutePUSH
}, // opcode 0x2B PUSH {@}R1 [imm16]
1320 { ExecutePOP
}, // opcode 0x2C POP {@}R1 [imm16]
1321 { ExecuteCMPI
}, // opcode 0x2D CMPIEQ
1322 { ExecuteCMPI
}, // opcode 0x2E CMPILTE
1323 { ExecuteCMPI
}, // opcode 0x2F CMPIGTE
1324 { ExecuteCMPI
}, // opcode 0x30 CMPIULTE
1325 { ExecuteCMPI
}, // opcode 0x31 CMPIUGTE
1326 { ExecuteMOVxx
}, // opcode 0x32 MOVN
1327 { ExecuteMOVxx
}, // opcode 0x33 MOVND
1328 { NULL
}, // opcode 0x34
1329 { ExecutePUSHn
}, // opcode 0x35
1330 { ExecutePOPn
}, // opcode 0x36
1331 { ExecuteMOVI
}, // opcode 0x37 - mov immediate data
1332 { ExecuteMOVIn
}, // opcode 0x38 - mov immediate natural
1333 { ExecuteMOVREL
} // opcode 0x39 - move data relative to PC
1337 // Length of JMP instructions, depending on upper two bits of opcode.
1339 CONST UINT8 mJMPLen
[] = { 2, 2, 6, 10 };
1342 // Simple Debugger Protocol GUID
1344 EFI_GUID mEbcSimpleDebuggerProtocolGuid
= EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL_GUID
;
1348 Given a pointer to a new VM context, execute one or more instructions. This
1349 function is only used for test purposes via the EBC VM test protocol.
1351 @param This A pointer to the EFI_EBC_VM_TEST_PROTOCOL structure.
1352 @param VmPtr A pointer to a VM context.
1353 @param InstructionCount A pointer to a UINTN value holding the number of
1354 instructions to execute. If it holds value of 0,
1355 then the instruction to be executed is 1.
1357 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
1358 @retval EFI_SUCCESS All of the instructions are executed successfully.
1362 EbcExecuteInstructions (
1363 IN EFI_EBC_VM_TEST_PROTOCOL
*This
,
1364 IN VM_CONTEXT
*VmPtr
,
1365 IN OUT UINTN
*InstructionCount
1370 UINTN InstructionsLeft
;
1371 UINTN SavedInstructionCount
;
1373 if ((*VmPtr
->Ip
& 0x3F) >= sizeof(mVmOpcodeTable
)) {
1374 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1375 return EFI_UNSUPPORTED
;
1378 Status
= EFI_SUCCESS
;
1380 if (*InstructionCount
== 0) {
1381 InstructionsLeft
= 1;
1383 InstructionsLeft
= *InstructionCount
;
1386 SavedInstructionCount
= *InstructionCount
;
1387 *InstructionCount
= 0;
1390 // Index into the opcode table using the opcode byte for this instruction.
1391 // This gives you the execute function, which we first test for null, then
1392 // call it if it's not null.
1394 while (InstructionsLeft
!= 0) {
1395 ExecFunc
= (UINTN
) mVmOpcodeTable
[(*VmPtr
->Ip
& 0x3F)].ExecuteFunction
;
1396 if (ExecFunc
== (UINTN
) NULL
) {
1397 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1398 return EFI_UNSUPPORTED
;
1400 mVmOpcodeTable
[(*VmPtr
->Ip
& 0x3F)].ExecuteFunction (VmPtr
);
1401 *InstructionCount
= *InstructionCount
+ 1;
1405 // Decrement counter if applicable
1407 if (SavedInstructionCount
!= 0) {
1417 Execute an EBC image from an entry point or from a published protocol.
1419 @param VmPtr A pointer to a VM context.
1421 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
1422 @retval EFI_SUCCESS All of the instructions are executed successfully.
1427 IN VM_CONTEXT
*VmPtr
1431 UINT8 StackCorrupted
;
1433 EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL
*EbcSimpleDebugger
;
1436 EbcSimpleDebugger
= NULL
;
1437 Status
= EFI_SUCCESS
;
1441 // Make sure the magic value has been put on the stack before we got here.
1443 if (*VmPtr
->StackMagicPtr
!= (UINTN
) VM_STACK_KEY_VALUE
) {
1447 VmPtr
->FramePtr
= (VOID
*) ((UINT8
*) (UINTN
) VmPtr
->R
[0] + 8);
1450 // Try to get the debug support for EBC
1452 DEBUG_CODE_BEGIN ();
1453 Status
= gBS
->LocateProtocol (
1454 &mEbcSimpleDebuggerProtocolGuid
,
1456 (VOID
**) &EbcSimpleDebugger
1458 if (EFI_ERROR (Status
)) {
1459 EbcSimpleDebugger
= NULL
;
1464 // Save the start IP for debug. For example, if we take an exception we
1465 // can print out the location of the exception relative to the entry point,
1466 // which could then be used in a disassembly listing to find the problem.
1468 VmPtr
->EntryPoint
= (VOID
*) VmPtr
->Ip
;
1471 // We'll wait for this flag to know when we're done. The RET
1472 // instruction sets it if it runs out of stack.
1474 VmPtr
->StopFlags
= 0;
1475 while ((VmPtr
->StopFlags
& STOPFLAG_APP_DONE
) == 0) {
1477 // If we've found a simple debugger protocol, call it
1479 DEBUG_CODE_BEGIN ();
1480 if (EbcSimpleDebugger
!= NULL
) {
1481 EbcSimpleDebugger
->Debugger (EbcSimpleDebugger
, VmPtr
);
1486 // Verify the opcode is in range. Otherwise generate an exception.
1488 if ((*VmPtr
->Ip
& OPCODE_M_OPCODE
) >= (sizeof (mVmOpcodeTable
) / sizeof (mVmOpcodeTable
[0]))) {
1489 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1490 Status
= EFI_UNSUPPORTED
;
1494 // Use the opcode bits to index into the opcode dispatch table. If the
1495 // function pointer is null then generate an exception.
1497 ExecFunc
= (UINTN
) mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction
;
1498 if (ExecFunc
== (UINTN
) NULL
) {
1499 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1500 Status
= EFI_UNSUPPORTED
;
1504 // The EBC VM is a strongly ordered processor, so perform a fence operation before
1505 // and after each instruction is executed.
1509 mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction (VmPtr
);
1514 // If the step flag is set, signal an exception and continue. We don't
1515 // clear it here. Assuming the debugger is responsible for clearing it.
1517 if (VMFLAG_ISSET (VmPtr
, VMFLAGS_STEP
)) {
1518 EbcDebugSignalException (EXCEPT_EBC_STEP
, EXCEPTION_FLAG_NONE
, VmPtr
);
1521 // Make sure stack has not been corrupted. Only report it once though.
1523 if ((StackCorrupted
== 0) && (*VmPtr
->StackMagicPtr
!= (UINTN
) VM_STACK_KEY_VALUE
)) {
1524 EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1527 if ((StackCorrupted
== 0) && ((UINT64
)VmPtr
->R
[0] <= (UINT64
)(UINTN
) VmPtr
->StackTop
)) {
1528 EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1541 Execute the MOVxx instructions.
1545 MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
1546 MOVqq {@}R1 {Index64}, {@}R2 {Index64}
1548 Copies contents of [R2] -> [R1], zero extending where required.
1550 First character indicates the size of the move.
1551 Second character indicates the size of the index(s).
1553 Invalid to have R1 direct with index.
1555 @param VmPtr A pointer to a VM context.
1557 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
1558 @retval EFI_SUCCESS The instruction is executed successfully.
1563 IN VM_CONTEXT
*VmPtr
1579 Opcode
= GETOPCODE (VmPtr
);
1580 OpcMasked
= (UINT8
) (Opcode
& OPCODE_M_OPCODE
);
1583 // Get the operands byte so we can get R1 and R2
1585 Operands
= GETOPERANDS (VmPtr
);
1588 // Assume no indexes
1595 // Determine if we have an index/immediate data. Base instruction size
1596 // is 2 (opcode + operands). Add to this size each index specified.
1599 if ((Opcode
& (OPCODE_M_IMMED_OP1
| OPCODE_M_IMMED_OP2
)) != 0) {
1601 // Determine size of the index from the opcode. Then get it.
1603 if ((OpcMasked
<= OPCODE_MOVQW
) || (OpcMasked
== OPCODE_MOVNW
)) {
1605 // MOVBW, MOVWW, MOVDW, MOVQW, and MOVNW have 16-bit immediate index.
1606 // Get one or both index values.
1608 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1609 Index16
= VmReadIndex16 (VmPtr
, 2);
1610 Index64Op1
= (INT64
) Index16
;
1611 Size
+= sizeof (UINT16
);
1614 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1615 Index16
= VmReadIndex16 (VmPtr
, Size
);
1616 Index64Op2
= (INT64
) Index16
;
1617 Size
+= sizeof (UINT16
);
1619 } else if ((OpcMasked
<= OPCODE_MOVQD
) || (OpcMasked
== OPCODE_MOVND
)) {
1621 // MOVBD, MOVWD, MOVDD, MOVQD, and MOVND have 32-bit immediate index
1623 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1624 Index32
= VmReadIndex32 (VmPtr
, 2);
1625 Index64Op1
= (INT64
) Index32
;
1626 Size
+= sizeof (UINT32
);
1629 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1630 Index32
= VmReadIndex32 (VmPtr
, Size
);
1631 Index64Op2
= (INT64
) Index32
;
1632 Size
+= sizeof (UINT32
);
1634 } else if (OpcMasked
== OPCODE_MOVQQ
) {
1636 // MOVqq -- only form with a 64-bit index
1638 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1639 Index64Op1
= VmReadIndex64 (VmPtr
, 2);
1640 Size
+= sizeof (UINT64
);
1643 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1644 Index64Op2
= VmReadIndex64 (VmPtr
, Size
);
1645 Size
+= sizeof (UINT64
);
1649 // Obsolete MOVBQ, MOVWQ, MOVDQ, and MOVNQ have 64-bit immediate index
1651 EbcDebugSignalException (
1652 EXCEPT_EBC_INSTRUCTION_ENCODING
,
1653 EXCEPTION_FLAG_FATAL
,
1656 return EFI_UNSUPPORTED
;
1660 // Determine the size of the move, and create a mask for it so we can
1661 // clear unused bits.
1663 if ((OpcMasked
== OPCODE_MOVBW
) || (OpcMasked
== OPCODE_MOVBD
)) {
1664 MoveSize
= DATA_SIZE_8
;
1666 } else if ((OpcMasked
== OPCODE_MOVWW
) || (OpcMasked
== OPCODE_MOVWD
)) {
1667 MoveSize
= DATA_SIZE_16
;
1669 } else if ((OpcMasked
== OPCODE_MOVDW
) || (OpcMasked
== OPCODE_MOVDD
)) {
1670 MoveSize
= DATA_SIZE_32
;
1671 DataMask
= 0xFFFFFFFF;
1672 } else if ((OpcMasked
== OPCODE_MOVQW
) || (OpcMasked
== OPCODE_MOVQD
) || (OpcMasked
== OPCODE_MOVQQ
)) {
1673 MoveSize
= DATA_SIZE_64
;
1674 DataMask
= (UINT64
)~0;
1675 } else if ((OpcMasked
== OPCODE_MOVNW
) || (OpcMasked
== OPCODE_MOVND
)) {
1676 MoveSize
= DATA_SIZE_N
;
1677 DataMask
= (UINT64
)~0 >> (64 - 8 * sizeof (UINTN
));
1680 // We were dispatched to this function and we don't recognize the opcode
1682 EbcDebugSignalException (EXCEPT_EBC_UNDEFINED
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1683 return EFI_UNSUPPORTED
;
1686 // Now get the source address
1688 if (OPERAND2_INDIRECT (Operands
)) {
1690 // Indirect form @R2. Compute address of operand2
1692 Source
= (UINTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index64Op2
);
1694 // Now get the data from the source. Always 0-extend and let the compiler
1695 // sign-extend where required.
1699 Data64
= (UINT64
) (UINT8
) VmReadMem8 (VmPtr
, Source
);
1703 Data64
= (UINT64
) (UINT16
) VmReadMem16 (VmPtr
, Source
);
1707 Data64
= (UINT64
) (UINT32
) VmReadMem32 (VmPtr
, Source
);
1711 Data64
= (UINT64
) VmReadMem64 (VmPtr
, Source
);
1715 Data64
= (UINT64
) (UINTN
) VmReadMemN (VmPtr
, Source
);
1726 // Not indirect source: MOVxx {@}Rx, Ry [Index]
1728 Data64
= VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index64Op2
;
1730 // Did Operand2 have an index? If so, treat as two signed values since
1731 // indexes are signed values.
1733 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1735 // NOTE: need to find a way to fix this, most likely by changing the VM
1736 // implementation to remove the stack gap. To do that, we'd need to
1737 // allocate stack space for the VM and actually set the system
1738 // stack pointer to the allocated buffer when the VM starts.
1740 // Special case -- if someone took the address of a function parameter
1741 // then we need to make sure it's not in the stack gap. We can identify
1742 // this situation if (Operand2 register == 0) && (Operand2 is direct)
1743 // && (Index applies to Operand2) && (Index > 0) && (Operand1 register != 0)
1744 // Situations that to be aware of:
1745 // * stack adjustments at beginning and end of functions R0 = R0 += stacksize
1747 if ((OPERAND2_REGNUM (Operands
) == 0) &&
1748 (!OPERAND2_INDIRECT (Operands
)) &&
1750 (OPERAND1_REGNUM (Operands
) == 0) &&
1751 (OPERAND1_INDIRECT (Operands
))
1753 Data64
= (UINT64
) ConvertStackAddr (VmPtr
, (UINTN
) (INT64
) Data64
);
1758 // Now write it back
1760 if (OPERAND1_INDIRECT (Operands
)) {
1762 // Reuse the Source variable to now be dest.
1764 Source
= (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index64Op1
);
1766 // Do the write based on the size
1770 VmWriteMem8 (VmPtr
, Source
, (UINT8
) Data64
);
1774 VmWriteMem16 (VmPtr
, Source
, (UINT16
) Data64
);
1778 VmWriteMem32 (VmPtr
, Source
, (UINT32
) Data64
);
1782 VmWriteMem64 (VmPtr
, Source
, Data64
);
1786 VmWriteMemN (VmPtr
, Source
, (UINTN
) Data64
);
1798 // Make sure we didn't have an index on operand1.
1800 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1801 EbcDebugSignalException (
1802 EXCEPT_EBC_INSTRUCTION_ENCODING
,
1803 EXCEPTION_FLAG_FATAL
,
1806 return EFI_UNSUPPORTED
;
1809 // Direct storage in register. Clear unused bits and store back to
1812 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Data64
& DataMask
;
1815 // Advance the instruction pointer
1823 Execute the EBC BREAK instruction.
1825 @param VmPtr A pointer to a VM context.
1827 @retval EFI_SUCCESS The instruction is executed successfully.
1832 IN VM_CONTEXT
*VmPtr
1836 VOID
*EbcEntryPoint
;
1838 UINT64 U64EbcEntryPoint
;
1841 Operands
= GETOPERANDS (VmPtr
);
1844 // Runaway program break. Generate an exception and terminate
1847 EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1851 // Get VM version -- return VM revision number in R7
1857 // 16-8 = Major version
1858 // 7-0 = Minor version
1860 VmPtr
->R
[7] = GetVmVersion ();
1864 // Debugger breakpoint
1867 VmPtr
->StopFlags
|= STOPFLAG_BREAKPOINT
;
1869 // See if someone has registered a handler
1871 EbcDebugSignalException (
1872 EXCEPT_EBC_BREAKPOINT
,
1873 EXCEPTION_FLAG_NONE
,
1879 // System call, which there are none, so NOP it.
1885 // Create a thunk for EBC code. R7 points to a 32-bit (in a 64-bit slot)
1886 // "offset from self" pointer to the EBC entry point.
1887 // After we're done, *(UINT64 *)R7 will be the address of the new thunk.
1890 Offset
= (INT32
) VmReadMem32 (VmPtr
, (UINTN
) VmPtr
->R
[7]);
1891 U64EbcEntryPoint
= (UINT64
) (VmPtr
->R
[7] + Offset
+ 4);
1892 EbcEntryPoint
= (VOID
*) (UINTN
) U64EbcEntryPoint
;
1895 // Now create a new thunk
1897 EbcCreateThunks (VmPtr
->ImageHandle
, EbcEntryPoint
, &Thunk
, 0);
1900 // Finally replace the EBC entry point memory with the thunk address
1902 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->R
[7], (UINT64
) (UINTN
) Thunk
);
1906 // Compiler setting version per value in R7
1909 VmPtr
->CompilerVersion
= (UINT32
) VmPtr
->R
[7];
1911 // Check compiler version against VM version?
1916 // Unhandled break code. Signal exception.
1919 EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1931 Execute the JMP instruction.
1934 JMP64{cs|cc} Immed64
1935 JMP32{cs|cc} {@}R1 {Immed32|Index32}
1938 b0.7 - immediate data present
1939 b0.6 - 1 = 64 bit immediate data
1940 0 = 32 bit immediate data
1941 b1.7 - 1 = conditional
1942 b1.6 1 = CS (condition set)
1943 0 = CC (condition clear)
1944 b1.4 1 = relative address
1945 0 = absolute address
1946 b1.3 1 = operand1 indirect
1949 @param VmPtr A pointer to a VM context.
1951 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
1952 @retval EFI_SUCCESS The instruction is executed successfully.
1957 IN VM_CONTEXT
*VmPtr
1962 UINT8 ConditionFlag
;
1969 Operand
= GETOPERANDS (VmPtr
);
1970 Opcode
= GETOPCODE (VmPtr
);
1973 // Get instruction length from the opcode. The upper two bits are used here
1974 // to index into the length array.
1976 Size
= mJMPLen
[(Opcode
>> 6) & 0x03];
1979 // Decode instruction conditions
1980 // If we haven't met the condition, then simply advance the IP and return.
1982 CompareSet
= (UINT8
) (((Operand
& JMP_M_CS
) != 0) ? 1 : 0);
1983 ConditionFlag
= (UINT8
) VMFLAG_ISSET (VmPtr
, VMFLAGS_CC
);
1984 if ((Operand
& CONDITION_M_CONDITIONAL
) != 0) {
1985 if (CompareSet
!= ConditionFlag
) {
1991 // Check for 64-bit form and do it right away since it's the most
1992 // straight-forward form.
1994 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
1996 // Double check for immediate-data, which is required. If not there,
1997 // then signal an exception
1999 if ((Opcode
& OPCODE_M_IMMDATA
) == 0) {
2000 EbcDebugSignalException (
2001 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2002 EXCEPTION_FLAG_ERROR
,
2005 return EFI_UNSUPPORTED
;
2008 // 64-bit immediate data is full address. Read the immediate data,
2009 // check for alignment, and jump absolute.
2011 Data64
= VmReadImmed64 (VmPtr
, 2);
2012 if (!IS_ALIGNED ((UINTN
) Data64
, sizeof (UINT16
))) {
2013 EbcDebugSignalException (
2014 EXCEPT_EBC_ALIGNMENT_CHECK
,
2015 EXCEPTION_FLAG_FATAL
,
2019 return EFI_UNSUPPORTED
;
2023 // Take jump -- relative or absolute
2025 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2026 VmPtr
->Ip
+= (UINTN
) Data64
+ Size
;
2028 VmPtr
->Ip
= (VMIP
) (UINTN
) Data64
;
2035 // Get the index if there is one. May be either an index, or an immediate
2036 // offset depending on indirect operand.
2037 // JMP32 @R1 Index32 -- immediate data is an index
2038 // JMP32 R1 Immed32 -- immedate data is an offset
2040 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
2041 if (OPERAND1_INDIRECT (Operand
)) {
2042 Index32
= VmReadIndex32 (VmPtr
, 2);
2044 Index32
= VmReadImmed32 (VmPtr
, 2);
2050 // Get the register data. If R == 0, then special case where it's ignored.
2052 if (OPERAND1_REGNUM (Operand
) == 0) {
2055 Data64
= OPERAND1_REGDATA (VmPtr
, Operand
);
2060 if (OPERAND1_INDIRECT (Operand
)) {
2062 // Form: JMP32 @Rx {Index32}
2064 Addr
= VmReadMemN (VmPtr
, (UINTN
) Data64
+ Index32
);
2065 if (!IS_ALIGNED ((UINTN
) Addr
, sizeof (UINT16
))) {
2066 EbcDebugSignalException (
2067 EXCEPT_EBC_ALIGNMENT_CHECK
,
2068 EXCEPTION_FLAG_FATAL
,
2072 return EFI_UNSUPPORTED
;
2075 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2076 VmPtr
->Ip
+= (UINTN
) Addr
+ Size
;
2078 VmPtr
->Ip
= (VMIP
) Addr
;
2082 // Form: JMP32 Rx {Immed32}
2084 Addr
= (UINTN
) (Data64
+ Index32
);
2085 if (!IS_ALIGNED ((UINTN
) Addr
, sizeof (UINT16
))) {
2086 EbcDebugSignalException (
2087 EXCEPT_EBC_ALIGNMENT_CHECK
,
2088 EXCEPTION_FLAG_FATAL
,
2092 return EFI_UNSUPPORTED
;
2095 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2096 VmPtr
->Ip
+= (UINTN
) Addr
+ Size
;
2098 VmPtr
->Ip
= (VMIP
) Addr
;
2107 Execute the EBC JMP8 instruction.
2110 JMP8{cs|cc} Offset/2
2112 @param VmPtr A pointer to a VM context.
2114 @retval EFI_SUCCESS The instruction is executed successfully.
2119 IN VM_CONTEXT
*VmPtr
2123 UINT8 ConditionFlag
;
2128 // Decode instruction.
2130 Opcode
= GETOPCODE (VmPtr
);
2131 CompareSet
= (UINT8
) (((Opcode
& JMP_M_CS
) != 0) ? 1 : 0);
2132 ConditionFlag
= (UINT8
) VMFLAG_ISSET (VmPtr
, VMFLAGS_CC
);
2135 // If we haven't met the condition, then simply advance the IP and return
2137 if ((Opcode
& CONDITION_M_CONDITIONAL
) != 0) {
2138 if (CompareSet
!= ConditionFlag
) {
2144 // Get the offset from the instruction stream. It's relative to the
2145 // following instruction, and divided by 2.
2147 Offset
= VmReadImmed8 (VmPtr
, 1);
2149 // Want to check for offset == -2 and then raise an exception?
2151 VmPtr
->Ip
+= (Offset
* 2) + 2;
2157 Execute the EBC MOVI.
2161 MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
2163 First variable character specifies the move size
2164 Second variable character specifies size of the immediate data
2166 Sign-extend the immediate data to the size of the operation, and zero-extend
2167 if storing to a register.
2169 Operand1 direct with index/immed is invalid.
2171 @param VmPtr A pointer to a VM context.
2173 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2174 @retval EFI_SUCCESS The instruction is executed successfully.
2179 IN VM_CONTEXT
*VmPtr
2191 // Get the opcode and operands byte so we can get R1 and R2
2193 Opcode
= GETOPCODE (VmPtr
);
2194 Operands
= GETOPERANDS (VmPtr
);
2197 // Get the index (16-bit) if present
2199 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2200 Index16
= VmReadIndex16 (VmPtr
, 2);
2207 // Extract the immediate data. Sign-extend always.
2209 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2210 ImmData64
= (INT64
) (INT16
) VmReadImmed16 (VmPtr
, Size
);
2212 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2213 ImmData64
= (INT64
) (INT32
) VmReadImmed32 (VmPtr
, Size
);
2215 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2216 ImmData64
= (INT64
) VmReadImmed64 (VmPtr
, Size
);
2222 EbcDebugSignalException (
2223 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2224 EXCEPTION_FLAG_FATAL
,
2227 return EFI_UNSUPPORTED
;
2230 // Now write back the result
2232 if (!OPERAND1_INDIRECT (Operands
)) {
2234 // Operand1 direct. Make sure it didn't have an index.
2236 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2237 EbcDebugSignalException (
2238 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2239 EXCEPTION_FLAG_FATAL
,
2242 return EFI_UNSUPPORTED
;
2245 // Writing directly to a register. Clear unused bits.
2247 if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH8
) {
2248 Mask64
= 0x000000FF;
2249 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH16
) {
2250 Mask64
= 0x0000FFFF;
2251 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH32
) {
2252 Mask64
= 0x00000000FFFFFFFF;
2254 Mask64
= (UINT64
)~0;
2257 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = ImmData64
& Mask64
;
2260 // Get the address then write back based on size of the move
2262 Op1
= (UINT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2263 if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH8
) {
2264 VmWriteMem8 (VmPtr
, (UINTN
) Op1
, (UINT8
) ImmData64
);
2265 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH16
) {
2266 VmWriteMem16 (VmPtr
, (UINTN
) Op1
, (UINT16
) ImmData64
);
2267 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH32
) {
2268 VmWriteMem32 (VmPtr
, (UINTN
) Op1
, (UINT32
) ImmData64
);
2270 VmWriteMem64 (VmPtr
, (UINTN
) Op1
, ImmData64
);
2274 // Advance the instruction pointer
2282 Execute the EBC MOV immediate natural. This instruction moves an immediate
2283 index value into a register or memory location.
2287 MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
2289 @param VmPtr A pointer to a VM context.
2291 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2292 @retval EFI_SUCCESS The instruction is executed successfully.
2297 IN VM_CONTEXT
*VmPtr
2310 // Get the opcode and operands byte so we can get R1 and R2
2312 Opcode
= GETOPCODE (VmPtr
);
2313 Operands
= GETOPERANDS (VmPtr
);
2316 // Get the operand1 index (16-bit) if present
2318 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2319 Index16
= VmReadIndex16 (VmPtr
, 2);
2326 // Extract the immediate data and convert to a 64-bit index.
2328 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2329 ImmedIndex16
= VmReadIndex16 (VmPtr
, Size
);
2330 ImmedIndex64
= (INT64
) ImmedIndex16
;
2332 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2333 ImmedIndex32
= VmReadIndex32 (VmPtr
, Size
);
2334 ImmedIndex64
= (INT64
) ImmedIndex32
;
2336 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2337 ImmedIndex64
= VmReadIndex64 (VmPtr
, Size
);
2343 EbcDebugSignalException (
2344 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2345 EXCEPTION_FLAG_FATAL
,
2348 return EFI_UNSUPPORTED
;
2351 // Now write back the result
2353 if (!OPERAND1_INDIRECT (Operands
)) {
2355 // Check for MOVIn R1 Index16, Immed (not indirect, with index), which
2358 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2359 EbcDebugSignalException (
2360 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2361 EXCEPTION_FLAG_FATAL
,
2364 return EFI_UNSUPPORTED
;
2367 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = ImmedIndex64
;
2372 Op1
= (UINT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2373 VmWriteMemN (VmPtr
, (UINTN
) Op1
, (INTN
) ImmedIndex64
);
2376 // Advance the instruction pointer
2384 Execute the EBC MOVREL instruction.
2385 Dest <- Ip + ImmData
2389 MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
2391 @param VmPtr A pointer to a VM context.
2393 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2394 @retval EFI_SUCCESS The instruction is executed successfully.
2399 IN VM_CONTEXT
*VmPtr
2411 // Get the opcode and operands byte so we can get R1 and R2
2413 Opcode
= GETOPCODE (VmPtr
);
2414 Operands
= GETOPERANDS (VmPtr
);
2417 // Get the Operand 1 index (16-bit) if present
2419 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2420 Index16
= VmReadIndex16 (VmPtr
, 2);
2427 // Get the immediate data.
2429 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2430 ImmData64
= (INT64
) VmReadImmed16 (VmPtr
, Size
);
2432 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2433 ImmData64
= (INT64
) VmReadImmed32 (VmPtr
, Size
);
2435 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2436 ImmData64
= VmReadImmed64 (VmPtr
, Size
);
2442 EbcDebugSignalException (
2443 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2444 EXCEPTION_FLAG_FATAL
,
2447 return EFI_UNSUPPORTED
;
2450 // Compute the value and write back the result
2452 Op2
= (UINT64
) ((INT64
) ((UINT64
) (UINTN
) VmPtr
->Ip
) + (INT64
) ImmData64
+ Size
);
2453 if (!OPERAND1_INDIRECT (Operands
)) {
2455 // Check for illegal combination of operand1 direct with immediate data
2457 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2458 EbcDebugSignalException (
2459 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2460 EXCEPTION_FLAG_FATAL
,
2463 return EFI_UNSUPPORTED
;
2466 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (VM_REGISTER
) Op2
;
2469 // Get the address = [Rx] + Index16
2470 // Write back the result. Always a natural size write, since
2471 // we're talking addresses here.
2473 Op1
= (UINT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2474 VmWriteMemN (VmPtr
, (UINTN
) Op1
, (UINTN
) Op2
);
2477 // Advance the instruction pointer
2485 Execute the EBC MOVsnw instruction. This instruction loads a signed
2486 natural value from memory or register to another memory or register. On
2487 32-bit machines, the value gets sign-extended to 64 bits if the destination
2492 MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
2494 0:7 1=>operand1 index present
2495 0:6 1=>operand2 index present
2497 @param VmPtr A pointer to a VM context.
2499 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2500 @retval EFI_SUCCESS The instruction is executed successfully.
2505 IN VM_CONTEXT
*VmPtr
2516 // Get the opcode and operand bytes
2518 Opcode
= GETOPCODE (VmPtr
);
2519 Operands
= GETOPERANDS (VmPtr
);
2521 Op1Index
= Op2Index
= 0;
2524 // Get the indexes if present.
2527 if ((Opcode
& OPCODE_M_IMMED_OP1
) !=0) {
2528 if (OPERAND1_INDIRECT (Operands
)) {
2529 Op1Index
= VmReadIndex16 (VmPtr
, 2);
2532 // Illegal form operand1 direct with index: MOVsnw R1 Index16, {@}R2
2534 EbcDebugSignalException (
2535 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2536 EXCEPTION_FLAG_FATAL
,
2539 return EFI_UNSUPPORTED
;
2542 Size
+= sizeof (UINT16
);
2545 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
2546 if (OPERAND2_INDIRECT (Operands
)) {
2547 Op2Index
= VmReadIndex16 (VmPtr
, Size
);
2549 Op2Index
= VmReadImmed16 (VmPtr
, Size
);
2552 Size
+= sizeof (UINT16
);
2555 // Get the data from the source.
2557 Op2
= (INT64
) ((INTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Op2Index
));
2558 if (OPERAND2_INDIRECT (Operands
)) {
2559 Op2
= (INT64
) (INTN
) VmReadMemN (VmPtr
, (UINTN
) Op2
);
2562 // Now write back the result.
2564 if (!OPERAND1_INDIRECT (Operands
)) {
2565 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Op2
;
2567 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Op1Index
), (UINTN
) Op2
);
2570 // Advance the instruction pointer
2578 Execute the EBC MOVsnw instruction. This instruction loads a signed
2579 natural value from memory or register to another memory or register. On
2580 32-bit machines, the value gets sign-extended to 64 bits if the destination
2585 MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
2587 0:7 1=>operand1 index present
2588 0:6 1=>operand2 index present
2590 @param VmPtr A pointer to a VM context.
2592 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2593 @retval EFI_SUCCESS The instruction is executed successfully.
2598 IN VM_CONTEXT
*VmPtr
2609 // Get the opcode and operand bytes
2611 Opcode
= GETOPCODE (VmPtr
);
2612 Operands
= GETOPERANDS (VmPtr
);
2614 Op1Index
= Op2Index
= 0;
2617 // Get the indexes if present.
2620 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
2621 if (OPERAND1_INDIRECT (Operands
)) {
2622 Op1Index
= VmReadIndex32 (VmPtr
, 2);
2625 // Illegal form operand1 direct with index: MOVsnd R1 Index16,..
2627 EbcDebugSignalException (
2628 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2629 EXCEPTION_FLAG_FATAL
,
2632 return EFI_UNSUPPORTED
;
2635 Size
+= sizeof (UINT32
);
2638 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
2639 if (OPERAND2_INDIRECT (Operands
)) {
2640 Op2Index
= VmReadIndex32 (VmPtr
, Size
);
2642 Op2Index
= VmReadImmed32 (VmPtr
, Size
);
2645 Size
+= sizeof (UINT32
);
2648 // Get the data from the source.
2650 Op2
= (INT64
) ((INTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Op2Index
));
2651 if (OPERAND2_INDIRECT (Operands
)) {
2652 Op2
= (INT64
) (INTN
) VmReadMemN (VmPtr
, (UINTN
) Op2
);
2655 // Now write back the result.
2657 if (!OPERAND1_INDIRECT (Operands
)) {
2658 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Op2
;
2660 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Op1Index
), (UINTN
) Op2
);
2663 // Advance the instruction pointer
2671 Execute the EBC PUSHn instruction
2674 PUSHn {@}R1 {Index16|Immed16}
2676 @param VmPtr A pointer to a VM context.
2678 @retval EFI_SUCCESS The instruction is executed successfully.
2683 IN VM_CONTEXT
*VmPtr
2692 // Get opcode and operands
2694 Opcode
= GETOPCODE (VmPtr
);
2695 Operands
= GETOPERANDS (VmPtr
);
2698 // Get index if present
2700 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2701 if (OPERAND1_INDIRECT (Operands
)) {
2702 Index16
= VmReadIndex16 (VmPtr
, 2);
2704 Index16
= VmReadImmed16 (VmPtr
, 2);
2713 // Get the data to push
2715 if (OPERAND1_INDIRECT (Operands
)) {
2716 DataN
= VmReadMemN (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
));
2718 DataN
= (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
);
2721 // Adjust the stack down.
2723 VmPtr
->R
[0] -= sizeof (UINTN
);
2724 VmWriteMemN (VmPtr
, (UINTN
) VmPtr
->R
[0], DataN
);
2730 Execute the EBC PUSH instruction.
2733 PUSH[32|64] {@}R1 {Index16|Immed16}
2735 @param VmPtr A pointer to a VM context.
2737 @retval EFI_SUCCESS The instruction is executed successfully.
2742 IN VM_CONTEXT
*VmPtr
2752 // Get opcode and operands
2754 Opcode
= GETOPCODE (VmPtr
);
2755 Operands
= GETOPERANDS (VmPtr
);
2757 // Get immediate index if present, then advance the IP.
2759 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2760 if (OPERAND1_INDIRECT (Operands
)) {
2761 Index16
= VmReadIndex16 (VmPtr
, 2);
2763 Index16
= VmReadImmed16 (VmPtr
, 2);
2772 // Get the data to push
2774 if ((Opcode
& PUSHPOP_M_64
) != 0) {
2775 if (OPERAND1_INDIRECT (Operands
)) {
2776 Data64
= VmReadMem64 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
));
2778 Data64
= (UINT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2781 // Adjust the stack down, then write back the data
2783 VmPtr
->R
[0] -= sizeof (UINT64
);
2784 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->R
[0], Data64
);
2789 if (OPERAND1_INDIRECT (Operands
)) {
2790 Data32
= VmReadMem32 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
));
2792 Data32
= (UINT32
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2795 // Adjust the stack down and write the data
2797 VmPtr
->R
[0] -= sizeof (UINT32
);
2798 VmWriteMem32 (VmPtr
, (UINTN
) VmPtr
->R
[0], Data32
);
2806 Execute the EBC POPn instruction.
2809 POPn {@}R1 {Index16|Immed16}
2811 @param VmPtr A pointer to a VM context.
2813 @retval EFI_SUCCESS The instruction is executed successfully.
2818 IN VM_CONTEXT
*VmPtr
2827 // Get opcode and operands
2829 Opcode
= GETOPCODE (VmPtr
);
2830 Operands
= GETOPERANDS (VmPtr
);
2832 // Get immediate data if present, and advance the IP
2834 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2835 if (OPERAND1_INDIRECT (Operands
)) {
2836 Index16
= VmReadIndex16 (VmPtr
, 2);
2838 Index16
= VmReadImmed16 (VmPtr
, 2);
2847 // Read the data off the stack, then adjust the stack pointer
2849 DataN
= VmReadMemN (VmPtr
, (UINTN
) VmPtr
->R
[0]);
2850 VmPtr
->R
[0] += sizeof (UINTN
);
2852 // Do the write-back
2854 if (OPERAND1_INDIRECT (Operands
)) {
2855 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
), DataN
);
2857 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (INT64
) (UINT64
) ((UINTN
) DataN
+ Index16
);
2865 Execute the EBC POP instruction.
2868 POPn {@}R1 {Index16|Immed16}
2870 @param VmPtr A pointer to a VM context.
2872 @retval EFI_SUCCESS The instruction is executed successfully.
2877 IN VM_CONTEXT
*VmPtr
2887 // Get opcode and operands
2889 Opcode
= GETOPCODE (VmPtr
);
2890 Operands
= GETOPERANDS (VmPtr
);
2892 // Get immediate data if present, and advance the IP.
2894 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2895 if (OPERAND1_INDIRECT (Operands
)) {
2896 Index16
= VmReadIndex16 (VmPtr
, 2);
2898 Index16
= VmReadImmed16 (VmPtr
, 2);
2907 // Get the data off the stack, then write it to the appropriate location
2909 if ((Opcode
& PUSHPOP_M_64
) != 0) {
2911 // Read the data off the stack, then adjust the stack pointer
2913 Data64
= VmReadMem64 (VmPtr
, (UINTN
) VmPtr
->R
[0]);
2914 VmPtr
->R
[0] += sizeof (UINT64
);
2916 // Do the write-back
2918 if (OPERAND1_INDIRECT (Operands
)) {
2919 VmWriteMem64 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
), Data64
);
2921 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Data64
+ Index16
;
2925 // 32-bit pop. Read it off the stack and adjust the stack pointer
2927 Data32
= (INT32
) VmReadMem32 (VmPtr
, (UINTN
) VmPtr
->R
[0]);
2928 VmPtr
->R
[0] += sizeof (UINT32
);
2930 // Do the write-back
2932 if (OPERAND1_INDIRECT (Operands
)) {
2933 VmWriteMem32 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
), Data32
);
2935 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (INT64
) Data32
+ Index16
;
2944 Implements the EBC CALL instruction.
2948 CALL32 {@}R1 {Immed32|Index32}
2950 CALLEX16 {@}R1 {Immed32}
2952 If Rx == R0, then it's a PC relative call to PC = PC + imm32.
2954 @param VmPtr A pointer to a VM context.
2956 @retval EFI_SUCCESS The instruction is executed successfully.
2961 IN VM_CONTEXT
*VmPtr
2972 // Get opcode and operands
2974 Opcode
= GETOPCODE (VmPtr
);
2975 Operands
= GETOPERANDS (VmPtr
);
2977 // Assign these as well to avoid compiler warnings
2982 FramePtr
= VmPtr
->FramePtr
;
2984 // Determine the instruction size, and get immediate data if present
2986 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
2987 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
2988 Immed64
= VmReadImmed64 (VmPtr
, 2);
2992 // If register operand is indirect, then the immediate data is an index
2994 if (OPERAND1_INDIRECT (Operands
)) {
2995 Immed32
= VmReadIndex32 (VmPtr
, 2);
2997 Immed32
= VmReadImmed32 (VmPtr
, 2);
3006 // If it's a call to EBC, adjust the stack pointer down 16 bytes and
3007 // put our return address and frame pointer on the VM stack.
3009 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3011 VmWriteMemN (VmPtr
, (UINTN
) VmPtr
->R
[0], (UINTN
) FramePtr
);
3012 VmPtr
->FramePtr
= (VOID
*) (UINTN
) VmPtr
->R
[0];
3014 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->R
[0], (UINT64
) (UINTN
) (VmPtr
->Ip
+ Size
));
3017 // If 64-bit data, then absolute jump only
3019 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
3021 // Native or EBC call?
3023 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3024 VmPtr
->Ip
= (VMIP
) (UINTN
) Immed64
;
3027 // Call external function, get the return value, and advance the IP
3029 EbcLLCALLEX (VmPtr
, (UINTN
) Immed64
, (UINTN
) VmPtr
->R
[0], FramePtr
, Size
);
3033 // Get the register data. If operand1 == 0, then ignore register and
3034 // take immediate data as relative or absolute address.
3035 // Compiler should take care of upper bits if 32-bit machine.
3037 if (OPERAND1_REGNUM (Operands
) != 0) {
3038 Immed64
= (UINT64
) (UINTN
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
3041 // Get final address
3043 if (OPERAND1_INDIRECT (Operands
)) {
3044 Immed64
= (INT64
) (UINT64
) (UINTN
) VmReadMemN (VmPtr
, (UINTN
) (Immed64
+ Immed32
));
3049 // Now determine if external call, and then if relative or absolute
3051 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3053 // EBC call. Relative or absolute? If relative, then it's relative to the
3054 // start of the next instruction.
3056 if ((Operands
& OPERAND_M_RELATIVE_ADDR
) != 0) {
3057 VmPtr
->Ip
+= Immed64
+ Size
;
3059 VmPtr
->Ip
= (VMIP
) (UINTN
) Immed64
;
3063 // Native call. Relative or absolute?
3065 if ((Operands
& OPERAND_M_RELATIVE_ADDR
) != 0) {
3066 EbcLLCALLEX (VmPtr
, (UINTN
) (Immed64
+ VmPtr
->Ip
+ Size
), (UINTN
) VmPtr
->R
[0], FramePtr
, Size
);
3068 if ((VmPtr
->StopFlags
& STOPFLAG_BREAK_ON_CALLEX
) != 0) {
3072 EbcLLCALLEX (VmPtr
, (UINTN
) Immed64
, (UINTN
) VmPtr
->R
[0], FramePtr
, Size
);
3082 Execute the EBC RET instruction.
3087 @param VmPtr A pointer to a VM context.
3089 @retval EFI_SUCCESS The instruction is executed successfully.
3094 IN VM_CONTEXT
*VmPtr
3098 // If we're at the top of the stack, then simply set the done
3101 if (VmPtr
->StackRetAddr
== (UINT64
) VmPtr
->R
[0]) {
3102 VmPtr
->StopFlags
|= STOPFLAG_APP_DONE
;
3105 // Pull the return address off the VM app's stack and set the IP
3108 if (!IS_ALIGNED ((UINTN
) VmPtr
->R
[0], sizeof (UINT16
))) {
3109 EbcDebugSignalException (
3110 EXCEPT_EBC_ALIGNMENT_CHECK
,
3111 EXCEPTION_FLAG_FATAL
,
3116 // Restore the IP and frame pointer from the stack
3118 VmPtr
->Ip
= (VMIP
) (UINTN
) VmReadMem64 (VmPtr
, (UINTN
) VmPtr
->R
[0]);
3120 VmPtr
->FramePtr
= (VOID
*) VmReadMemN (VmPtr
, (UINTN
) VmPtr
->R
[0]);
3129 Execute the EBC CMP instruction.
3132 CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
3134 @param VmPtr A pointer to a VM context.
3136 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
3137 @retval EFI_SUCCESS The instruction is executed successfully.
3142 IN VM_CONTEXT
*VmPtr
3154 // Get opcode and operands
3156 Opcode
= GETOPCODE (VmPtr
);
3157 Operands
= GETOPERANDS (VmPtr
);
3159 // Get the register data we're going to compare to
3161 Op1
= VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
3163 // Get immediate data
3165 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
3166 if (OPERAND2_INDIRECT (Operands
)) {
3167 Index16
= VmReadIndex16 (VmPtr
, 2);
3169 Index16
= VmReadImmed16 (VmPtr
, 2);
3180 if (OPERAND2_INDIRECT (Operands
)) {
3181 if ((Opcode
& OPCODE_M_64BIT
) != 0) {
3182 Op2
= (INT64
) VmReadMem64 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index16
));
3185 // 32-bit operations. 0-extend the values for all cases.
3187 Op2
= (INT64
) (UINT64
) ((UINT32
) VmReadMem32 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index16
)));
3190 Op2
= VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index16
;
3193 // Now do the compare
3196 if ((Opcode
& OPCODE_M_64BIT
) != 0) {
3200 switch (Opcode
& OPCODE_M_OPCODE
) {
3219 case OPCODE_CMPULTE
:
3220 if ((UINT64
) Op1
<= (UINT64
) Op2
) {
3225 case OPCODE_CMPUGTE
:
3226 if ((UINT64
) Op1
>= (UINT64
) Op2
) {
3238 switch (Opcode
& OPCODE_M_OPCODE
) {
3240 if ((INT32
) Op1
== (INT32
) Op2
) {
3246 if ((INT32
) Op1
<= (INT32
) Op2
) {
3252 if ((INT32
) Op1
>= (INT32
) Op2
) {
3257 case OPCODE_CMPULTE
:
3258 if ((UINT32
) Op1
<= (UINT32
) Op2
) {
3263 case OPCODE_CMPUGTE
:
3264 if ((UINT32
) Op1
>= (UINT32
) Op2
) {
3274 // Now set the flag accordingly for the comparison
3277 VMFLAG_SET (VmPtr
, VMFLAGS_CC
);
3279 VMFLAG_CLEAR (VmPtr
, VMFLAGS_CC
);
3290 Execute the EBC CMPI instruction
3293 CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
3295 @param VmPtr A pointer to a VM context.
3297 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
3298 @retval EFI_SUCCESS The instruction is executed successfully.
3303 IN VM_CONTEXT
*VmPtr
3315 // Get opcode and operands
3317 Opcode
= GETOPCODE (VmPtr
);
3318 Operands
= GETOPERANDS (VmPtr
);
3321 // Get operand1 index if present
3324 if ((Operands
& OPERAND_M_CMPI_INDEX
) != 0) {
3325 Index16
= VmReadIndex16 (VmPtr
, 2);
3331 // Get operand1 data we're going to compare to
3333 Op1
= (INT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
3334 if (OPERAND1_INDIRECT (Operands
)) {
3336 // Indirect operand1. Fetch 32 or 64-bit value based on compare size.
3338 if ((Opcode
& OPCODE_M_CMPI64
) != 0) {
3339 Op1
= (INT64
) VmReadMem64 (VmPtr
, (UINTN
) Op1
+ Index16
);
3341 Op1
= (INT64
) VmReadMem32 (VmPtr
, (UINTN
) Op1
+ Index16
);
3345 // Better not have been an index with direct. That is, CMPI R1 Index,...
3348 if ((Operands
& OPERAND_M_CMPI_INDEX
) != 0) {
3349 EbcDebugSignalException (
3350 EXCEPT_EBC_INSTRUCTION_ENCODING
,
3351 EXCEPTION_FLAG_ERROR
,
3355 return EFI_UNSUPPORTED
;
3359 // Get immediate data -- 16- or 32-bit sign extended
3361 if ((Opcode
& OPCODE_M_CMPI32_DATA
) != 0) {
3362 Op2
= (INT64
) VmReadImmed32 (VmPtr
, Size
);
3366 // 16-bit immediate data. Sign extend always.
3368 Op2
= (INT64
) ((INT16
) VmReadImmed16 (VmPtr
, Size
));
3372 // Now do the compare
3375 if ((Opcode
& OPCODE_M_CMPI64
) != 0) {
3377 // 64 bit comparison
3379 switch (Opcode
& OPCODE_M_OPCODE
) {
3381 if (Op1
== (INT64
) Op2
) {
3386 case OPCODE_CMPILTE
:
3387 if (Op1
<= (INT64
) Op2
) {
3392 case OPCODE_CMPIGTE
:
3393 if (Op1
>= (INT64
) Op2
) {
3398 case OPCODE_CMPIULTE
:
3399 if ((UINT64
) Op1
<= (UINT64
) ((UINT32
) Op2
)) {
3404 case OPCODE_CMPIUGTE
:
3405 if ((UINT64
) Op1
>= (UINT64
) ((UINT32
) Op2
)) {
3415 // 32-bit comparisons
3417 switch (Opcode
& OPCODE_M_OPCODE
) {
3419 if ((INT32
) Op1
== Op2
) {
3424 case OPCODE_CMPILTE
:
3425 if ((INT32
) Op1
<= Op2
) {
3430 case OPCODE_CMPIGTE
:
3431 if ((INT32
) Op1
>= Op2
) {
3436 case OPCODE_CMPIULTE
:
3437 if ((UINT32
) Op1
<= (UINT32
) Op2
) {
3442 case OPCODE_CMPIUGTE
:
3443 if ((UINT32
) Op1
>= (UINT32
) Op2
) {
3453 // Now set the flag accordingly for the comparison
3456 VMFLAG_SET (VmPtr
, VMFLAGS_CC
);
3458 VMFLAG_CLEAR (VmPtr
, VMFLAGS_CC
);
3469 Execute the EBC NOT instruction.s
3472 NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
3474 @param VmPtr A pointer to a VM context.
3475 @param Op1 Operand 1 from the instruction
3476 @param Op2 Operand 2 from the instruction
3483 IN VM_CONTEXT
*VmPtr
,
3493 Execute the EBC NEG instruction.
3496 NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
3498 @param VmPtr A pointer to a VM context.
3499 @param Op1 Operand 1 from the instruction
3500 @param Op2 Operand 2 from the instruction
3507 IN VM_CONTEXT
*VmPtr
,
3517 Execute the EBC ADD instruction.
3520 ADD[32|64] {@}R1, {@}R2 {Index16}
3522 @param VmPtr A pointer to a VM context.
3523 @param Op1 Operand 1 from the instruction
3524 @param Op2 Operand 2 from the instruction
3531 IN VM_CONTEXT
*VmPtr
,
3541 Execute the EBC SUB instruction.
3544 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3546 @param VmPtr A pointer to a VM context.
3547 @param Op1 Operand 1 from the instruction
3548 @param Op2 Operand 2 from the instruction
3555 IN VM_CONTEXT
*VmPtr
,
3560 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3561 return (UINT64
) ((INT64
) ((INT64
) Op1
- (INT64
) Op2
));
3563 return (UINT64
) ((INT64
) ((INT32
) Op1
- (INT32
) Op2
));
3569 Execute the EBC MUL instruction.
3572 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3574 @param VmPtr A pointer to a VM context.
3575 @param Op1 Operand 1 from the instruction
3576 @param Op2 Operand 2 from the instruction
3583 IN VM_CONTEXT
*VmPtr
,
3588 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3589 return MultS64x64 ((INT64
)Op1
, (INT64
)Op2
);
3591 return (UINT64
) ((INT64
) ((INT32
) Op1
* (INT32
) Op2
));
3597 Execute the EBC MULU instruction
3600 MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3602 @param VmPtr A pointer to a VM context.
3603 @param Op1 Operand 1 from the instruction
3604 @param Op2 Operand 2 from the instruction
3606 @return (unsigned)Op1 * (unsigned)Op2
3611 IN VM_CONTEXT
*VmPtr
,
3616 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3617 return MultU64x64 (Op1
, Op2
);
3619 return (UINT64
) ((UINT32
) Op1
* (UINT32
) Op2
);
3625 Execute the EBC DIV instruction.
3628 DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
3630 @param VmPtr A pointer to a VM context.
3631 @param Op1 Operand 1 from the instruction
3632 @param Op2 Operand 2 from the instruction
3639 IN VM_CONTEXT
*VmPtr
,
3647 // Check for divide-by-0
3650 EbcDebugSignalException (
3651 EXCEPT_EBC_DIVIDE_ERROR
,
3652 EXCEPTION_FLAG_FATAL
,
3658 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3659 return (UINT64
) (DivS64x64Remainder (Op1
, Op2
, &Remainder
));
3661 return (UINT64
) ((INT64
) ((INT32
) Op1
/ (INT32
) Op2
));
3668 Execute the EBC DIVU instruction
3671 DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3673 @param VmPtr A pointer to a VM context.
3674 @param Op1 Operand 1 from the instruction
3675 @param Op2 Operand 2 from the instruction
3677 @return (unsigned)Op1 / (unsigned)Op2
3682 IN VM_CONTEXT
*VmPtr
,
3690 // Check for divide-by-0
3693 EbcDebugSignalException (
3694 EXCEPT_EBC_DIVIDE_ERROR
,
3695 EXCEPTION_FLAG_FATAL
,
3701 // Get the destination register
3703 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3704 return (UINT64
) (DivU64x64Remainder ((INT64
)Op1
, (INT64
)Op2
, &Remainder
));
3706 return (UINT64
) ((UINT32
) Op1
/ (UINT32
) Op2
);
3713 Execute the EBC MOD instruction.
3716 MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
3718 @param VmPtr A pointer to a VM context.
3719 @param Op1 Operand 1 from the instruction
3720 @param Op2 Operand 2 from the instruction
3722 @return Op1 MODULUS Op2
3727 IN VM_CONTEXT
*VmPtr
,
3735 // Check for divide-by-0
3738 EbcDebugSignalException (
3739 EXCEPT_EBC_DIVIDE_ERROR
,
3740 EXCEPTION_FLAG_FATAL
,
3745 DivS64x64Remainder ((INT64
)Op1
, (INT64
)Op2
, &Remainder
);
3752 Execute the EBC MODU instruction.
3755 MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3757 @param VmPtr A pointer to a VM context.
3758 @param Op1 Operand 1 from the instruction
3759 @param Op2 Operand 2 from the instruction
3761 @return Op1 UNSIGNED_MODULUS Op2
3766 IN VM_CONTEXT
*VmPtr
,
3774 // Check for divide-by-0
3777 EbcDebugSignalException (
3778 EXCEPT_EBC_DIVIDE_ERROR
,
3779 EXCEPTION_FLAG_FATAL
,
3784 DivU64x64Remainder (Op1
, Op2
, &Remainder
);
3791 Execute the EBC AND instruction.
3794 AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
3796 @param VmPtr A pointer to a VM context.
3797 @param Op1 Operand 1 from the instruction
3798 @param Op2 Operand 2 from the instruction
3805 IN VM_CONTEXT
*VmPtr
,
3815 Execute the EBC OR instruction.
3818 OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3820 @param VmPtr A pointer to a VM context.
3821 @param Op1 Operand 1 from the instruction
3822 @param Op2 Operand 2 from the instruction
3829 IN VM_CONTEXT
*VmPtr
,
3839 Execute the EBC XOR instruction.
3842 XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3844 @param VmPtr A pointer to a VM context.
3845 @param Op1 Operand 1 from the instruction
3846 @param Op2 Operand 2 from the instruction
3853 IN VM_CONTEXT
*VmPtr
,
3863 Execute the EBC SHL shift left instruction.
3866 SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
3868 @param VmPtr A pointer to a VM context.
3869 @param Op1 Operand 1 from the instruction
3870 @param Op2 Operand 2 from the instruction
3877 IN VM_CONTEXT
*VmPtr
,
3882 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3883 return LShiftU64 (Op1
, (UINTN
)Op2
);
3885 return (UINT64
) ((UINT32
) ((UINT32
) Op1
<< (UINT32
) Op2
));
3891 Execute the EBC SHR instruction.
3894 SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3896 @param VmPtr A pointer to a VM context.
3897 @param Op1 Operand 1 from the instruction
3898 @param Op2 Operand 2 from the instruction
3900 @return Op1 >> Op2 (unsigned operands)
3905 IN VM_CONTEXT
*VmPtr
,
3910 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3911 return RShiftU64 (Op1
, (UINTN
)Op2
);
3913 return (UINT64
) ((UINT32
) Op1
>> (UINT32
) Op2
);
3919 Execute the EBC ASHR instruction.
3922 ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3924 @param VmPtr A pointer to a VM context.
3925 @param Op1 Operand 1 from the instruction
3926 @param Op2 Operand 2 from the instruction
3928 @return Op1 >> Op2 (signed)
3933 IN VM_CONTEXT
*VmPtr
,
3938 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3939 return ARShiftU64 (Op1
, (UINTN
)Op2
);
3941 return (UINT64
) ((INT64
) ((INT32
) Op1
>> (UINT32
) Op2
));
3947 Execute the EBC EXTNDB instruction to sign-extend a byte value.
3950 EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3952 @param VmPtr A pointer to a VM context.
3953 @param Op1 Operand 1 from the instruction
3954 @param Op2 Operand 2 from the instruction
3956 @return (INT64)(INT8)Op2
3961 IN VM_CONTEXT
*VmPtr
,
3969 // Convert to byte, then return as 64-bit signed value to let compiler
3970 // sign-extend the value
3973 Data64
= (INT64
) Data8
;
3975 return (UINT64
) Data64
;
3980 Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
3983 EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
3985 @param VmPtr A pointer to a VM context.
3986 @param Op1 Operand 1 from the instruction
3987 @param Op2 Operand 2 from the instruction
3989 @return (INT64)(INT16)Op2
3994 IN VM_CONTEXT
*VmPtr
,
4002 // Convert to word, then return as 64-bit signed value to let compiler
4003 // sign-extend the value
4005 Data16
= (INT16
) Op2
;
4006 Data64
= (INT64
) Data16
;
4008 return (UINT64
) Data64
;
4011 // Execute the EBC EXTNDD instruction.
4013 // Format: EXTNDD {@}Rx, {@}Ry [Index16|Immed16]
4014 // EXTNDD Dest, Source
4016 // Operation: Dest <- SignExtended((DWORD)Source))
4020 Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
4023 EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
4025 @param VmPtr A pointer to a VM context.
4026 @param Op1 Operand 1 from the instruction
4027 @param Op2 Operand 2 from the instruction
4029 @return (INT64)(INT32)Op2
4034 IN VM_CONTEXT
*VmPtr
,
4042 // Convert to 32-bit value, then return as 64-bit signed value to let compiler
4043 // sign-extend the value
4045 Data32
= (INT32
) Op2
;
4046 Data64
= (INT64
) Data32
;
4048 return (UINT64
) Data64
;
4053 Execute all the EBC signed data manipulation instructions.
4054 Since the EBC data manipulation instructions all have the same basic form,
4055 they can share the code that does the fetch of operands and the write-back
4056 of the result. This function performs the fetch of the operands (even if
4057 both are not needed to be fetched, like NOT instruction), dispatches to the
4058 appropriate subfunction, then writes back the returned result.
4061 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4063 @param VmPtr A pointer to VM context.
4065 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4066 @retval EFI_SUCCESS The instruction is executed successfully.
4070 ExecuteSignedDataManip (
4071 IN VM_CONTEXT
*VmPtr
4075 // Just call the data manipulation function with a flag indicating this
4076 // is a signed operation.
4078 return ExecuteDataManip (VmPtr
, TRUE
);
4083 Execute all the EBC unsigned data manipulation instructions.
4084 Since the EBC data manipulation instructions all have the same basic form,
4085 they can share the code that does the fetch of operands and the write-back
4086 of the result. This function performs the fetch of the operands (even if
4087 both are not needed to be fetched, like NOT instruction), dispatches to the
4088 appropriate subfunction, then writes back the returned result.
4091 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4093 @param VmPtr A pointer to VM context.
4095 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4096 @retval EFI_SUCCESS The instruction is executed successfully.
4100 ExecuteUnsignedDataManip (
4101 IN VM_CONTEXT
*VmPtr
4105 // Just call the data manipulation function with a flag indicating this
4106 // is not a signed operation.
4108 return ExecuteDataManip (VmPtr
, FALSE
);
4113 Execute all the EBC data manipulation instructions.
4114 Since the EBC data manipulation instructions all have the same basic form,
4115 they can share the code that does the fetch of operands and the write-back
4116 of the result. This function performs the fetch of the operands (even if
4117 both are not needed to be fetched, like NOT instruction), dispatches to the
4118 appropriate subfunction, then writes back the returned result.
4121 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4123 @param VmPtr A pointer to VM context.
4124 @param IsSignedOp Indicates whether the operand is signed or not.
4126 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4127 @retval EFI_SUCCESS The instruction is executed successfully.
4132 IN VM_CONTEXT
*VmPtr
,
4133 IN BOOLEAN IsSignedOp
4144 // Get opcode and operands
4146 Opcode
= GETOPCODE (VmPtr
);
4147 Operands
= GETOPERANDS (VmPtr
);
4150 // Determine if we have immediate data by the opcode
4152 if ((Opcode
& DATAMANIP_M_IMMDATA
) != 0) {
4154 // Index16 if Ry is indirect, or Immed16 if Ry direct.
4156 if (OPERAND2_INDIRECT (Operands
)) {
4157 Index16
= VmReadIndex16 (VmPtr
, 2);
4159 Index16
= VmReadImmed16 (VmPtr
, 2);
4168 // Now get operand2 (source). It's of format {@}R2 {Index16|Immed16}
4170 Op2
= (UINT64
) VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index16
;
4171 if (OPERAND2_INDIRECT (Operands
)) {
4173 // Indirect form: @R2 Index16. Fetch as 32- or 64-bit data
4175 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4176 Op2
= VmReadMem64 (VmPtr
, (UINTN
) Op2
);
4179 // Read as signed value where appropriate.
4182 Op2
= (UINT64
) (INT64
) ((INT32
) VmReadMem32 (VmPtr
, (UINTN
) Op2
));
4184 Op2
= (UINT64
) VmReadMem32 (VmPtr
, (UINTN
) Op2
);
4188 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4190 Op2
= (UINT64
) (INT64
) ((INT32
) Op2
);
4192 Op2
= (UINT64
) ((UINT32
) Op2
);
4197 // Get operand1 (destination and sometimes also an actual operand)
4200 Op1
= VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
4201 if (OPERAND1_INDIRECT (Operands
)) {
4202 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4203 Op1
= VmReadMem64 (VmPtr
, (UINTN
) Op1
);
4206 Op1
= (UINT64
) (INT64
) ((INT32
) VmReadMem32 (VmPtr
, (UINTN
) Op1
));
4208 Op1
= (UINT64
) VmReadMem32 (VmPtr
, (UINTN
) Op1
);
4212 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4214 Op1
= (UINT64
) (INT64
) ((INT32
) Op1
);
4216 Op1
= (UINT64
) ((UINT32
) Op1
);
4221 // Dispatch to the computation function
4223 if (((Opcode
& OPCODE_M_OPCODE
) - OPCODE_NOT
) >=
4224 (sizeof (mDataManipDispatchTable
) / sizeof (mDataManipDispatchTable
[0]))
4226 EbcDebugSignalException (
4227 EXCEPT_EBC_INVALID_OPCODE
,
4228 EXCEPTION_FLAG_ERROR
,
4232 // Advance and return
4235 return EFI_UNSUPPORTED
;
4237 Op2
= mDataManipDispatchTable
[(Opcode
& OPCODE_M_OPCODE
) - OPCODE_NOT
](VmPtr
, Op1
, Op2
);
4240 // Write back the result.
4242 if (OPERAND1_INDIRECT (Operands
)) {
4243 Op1
= VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
4244 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4245 VmWriteMem64 (VmPtr
, (UINTN
) Op1
, Op2
);
4247 VmWriteMem32 (VmPtr
, (UINTN
) Op1
, (UINT32
) Op2
);
4251 // Storage back to a register. Write back, clearing upper bits (as per
4252 // the specification) if 32-bit operation.
4254 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Op2
;
4255 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4256 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] &= 0xFFFFFFFF;
4260 // Advance the instruction pointer
4268 Execute the EBC LOADSP instruction.
4273 @param VmPtr A pointer to a VM context.
4275 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4276 @retval EFI_SUCCESS The instruction is executed successfully.
4281 IN VM_CONTEXT
*VmPtr
4289 Operands
= GETOPERANDS (VmPtr
);
4294 switch (OPERAND1_REGNUM (Operands
)) {
4300 // Spec states that this instruction will not modify reserved bits in
4301 // the flags register.
4303 VmPtr
->Flags
= (VmPtr
->Flags
&~VMFLAGS_ALL_VALID
) | (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] & VMFLAGS_ALL_VALID
);
4307 EbcDebugSignalException (
4308 EXCEPT_EBC_INSTRUCTION_ENCODING
,
4309 EXCEPTION_FLAG_WARNING
,
4313 return EFI_UNSUPPORTED
;
4322 Execute the EBC STORESP instruction.
4325 STORESP Rx, FLAGS|IP
4327 @param VmPtr A pointer to a VM context.
4329 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4330 @retval EFI_SUCCESS The instruction is executed successfully.
4335 IN VM_CONTEXT
*VmPtr
4343 Operands
= GETOPERANDS (VmPtr
);
4348 switch (OPERAND2_REGNUM (Operands
)) {
4354 // Retrieve the value in the flags register, then clear reserved bits
4356 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (UINT64
) (VmPtr
->Flags
& VMFLAGS_ALL_VALID
);
4360 // Get IP -- address of following instruction
4363 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (UINT64
) (UINTN
) VmPtr
->Ip
+ 2;
4367 EbcDebugSignalException (
4368 EXCEPT_EBC_INSTRUCTION_ENCODING
,
4369 EXCEPTION_FLAG_WARNING
,
4373 return EFI_UNSUPPORTED
;
4383 Decode a 16-bit index to determine the offset. Given an index value:
4386 b14:12 - number of bits in this index assigned to natural units (=a)
4387 ba:11 - constant units = ConstUnits
4388 b0:a - natural units = NaturalUnits
4390 Given this info, the offset can be computed by:
4391 offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
4393 Max offset is achieved with index = 0x7FFF giving an offset of
4394 0x27B (32-bit machine) or 0x477 (64-bit machine).
4395 Min offset is achieved with index =
4397 @param VmPtr A pointer to VM context.
4398 @param CodeOffset Offset from IP of the location of the 16-bit index
4401 @return The decoded offset.
4406 IN VM_CONTEXT
*VmPtr
,
4407 IN UINT32 CodeOffset
4418 // First read the index from the code stream
4420 Index
= VmReadCode16 (VmPtr
, CodeOffset
);
4423 // Get the mask for NaturalUnits. First get the number of bits from the index.
4425 NBits
= (INT16
) ((Index
& 0x7000) >> 12);
4428 // Scale it for 16-bit indexes
4433 // Now using the number of bits, create a mask.
4435 Mask
= (INT16
) ((INT16
)~0 << NBits
);
4438 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4440 NaturalUnits
= (INT16
) (Index
&~Mask
);
4443 // Now compute ConstUnits
4445 ConstUnits
= (INT16
) (((Index
&~0xF000) & Mask
) >> NBits
);
4447 Offset
= (INT16
) (NaturalUnits
* sizeof (UINTN
) + ConstUnits
);
4452 if ((Index
& 0x8000) != 0) {
4454 // Do it the hard way to work around a bogus compiler warning
4456 // Offset = -1 * Offset;
4458 Offset
= (INT16
) ((INT32
) Offset
* -1);
4466 Decode a 32-bit index to determine the offset.
4468 @param VmPtr A pointer to VM context.
4469 @param CodeOffset Offset from IP of the location of the 32-bit index
4472 @return Converted index per EBC VM specification.
4477 IN VM_CONTEXT
*VmPtr
,
4478 IN UINT32 CodeOffset
4488 Index
= VmReadImmed32 (VmPtr
, CodeOffset
);
4491 // Get the mask for NaturalUnits. First get the number of bits from the index.
4493 NBits
= (Index
& 0x70000000) >> 28;
4496 // Scale it for 32-bit indexes
4501 // Now using the number of bits, create a mask.
4503 Mask
= (INT32
)~0 << NBits
;
4506 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4508 NaturalUnits
= Index
&~Mask
;
4511 // Now compute ConstUnits
4513 ConstUnits
= ((Index
&~0xF0000000) & Mask
) >> NBits
;
4515 Offset
= NaturalUnits
* sizeof (UINTN
) + ConstUnits
;
4520 if ((Index
& 0x80000000) != 0) {
4521 Offset
= Offset
* -1;
4529 Decode a 64-bit index to determine the offset.
4531 @param VmPtr A pointer to VM context.s
4532 @param CodeOffset Offset from IP of the location of the 64-bit index
4535 @return Converted index per EBC VM specification
4540 IN VM_CONTEXT
*VmPtr
,
4541 IN UINT32 CodeOffset
4551 Index
= VmReadCode64 (VmPtr
, CodeOffset
);
4554 // Get the mask for NaturalUnits. First get the number of bits from the index.
4556 NBits
= RShiftU64 ((Index
& 0x7000000000000000ULL
), 60);
4559 // Scale it for 64-bit indexes (multiply by 8 by shifting left 3)
4561 NBits
= LShiftU64 ((UINT64
)NBits
, 3);
4564 // Now using the number of bits, create a mask.
4566 Mask
= (LShiftU64 ((UINT64
)~0, (UINTN
)NBits
));
4569 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4571 NaturalUnits
= Index
&~Mask
;
4574 // Now compute ConstUnits
4576 ConstUnits
= ARShiftU64 (((Index
&~0xF000000000000000ULL
) & Mask
), (UINTN
)NBits
);
4578 Offset
= MultU64x64 (NaturalUnits
, sizeof (UINTN
)) + ConstUnits
;
4583 if ((Index
& 0x8000000000000000ULL
) != 0) {
4584 Offset
= MultS64x64 (Offset
, -1);
4592 Writes 8-bit data to memory address.
4594 This routine is called by the EBC data
4595 movement instructions that write to memory. Since these writes
4596 may be to the stack, which looks like (high address on top) this,
4598 [EBC entry point arguments]
4602 we need to detect all attempts to write to the EBC entry point argument
4603 stack area and adjust the address (which will initially point into the
4604 VM stack) to point into the EBC entry point arguments.
4606 @param VmPtr A pointer to a VM context.
4607 @param Addr Address to write to.
4608 @param Data Value to write to Addr.
4610 @retval EFI_SUCCESS The instruction is executed successfully.
4611 @retval Other Some error occurs when writing data to the address.
4616 IN VM_CONTEXT
*VmPtr
,
4622 // Convert the address if it's in the stack gap
4624 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4625 *(UINT8
*) Addr
= Data
;
4630 Writes 16-bit data to memory address.
4632 This routine is called by the EBC data
4633 movement instructions that write to memory. Since these writes
4634 may be to the stack, which looks like (high address on top) this,
4636 [EBC entry point arguments]
4640 we need to detect all attempts to write to the EBC entry point argument
4641 stack area and adjust the address (which will initially point into the
4642 VM stack) to point into the EBC entry point arguments.
4644 @param VmPtr A pointer to a VM context.
4645 @param Addr Address to write to.
4646 @param Data Value to write to Addr.
4648 @retval EFI_SUCCESS The instruction is executed successfully.
4649 @retval Other Some error occurs when writing data to the address.
4654 IN VM_CONTEXT
*VmPtr
,
4662 // Convert the address if it's in the stack gap
4664 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4667 // Do a simple write if aligned
4669 if (IS_ALIGNED (Addr
, sizeof (UINT16
))) {
4670 *(UINT16
*) Addr
= Data
;
4673 // Write as two bytes
4676 if ((Status
= VmWriteMem8 (VmPtr
, Addr
, (UINT8
) Data
)) != EFI_SUCCESS
) {
4681 if ((Status
= VmWriteMem8 (VmPtr
, Addr
+ 1, (UINT8
) (Data
>> 8))) != EFI_SUCCESS
) {
4693 Writes 32-bit data to memory address.
4695 This routine is called by the EBC data
4696 movement instructions that write to memory. Since these writes
4697 may be to the stack, which looks like (high address on top) this,
4699 [EBC entry point arguments]
4703 we need to detect all attempts to write to the EBC entry point argument
4704 stack area and adjust the address (which will initially point into the
4705 VM stack) to point into the EBC entry point arguments.
4707 @param VmPtr A pointer to a VM context.
4708 @param Addr Address to write to.
4709 @param Data Value to write to Addr.
4711 @retval EFI_SUCCESS The instruction is executed successfully.
4712 @retval Other Some error occurs when writing data to the address.
4717 IN VM_CONTEXT
*VmPtr
,
4725 // Convert the address if it's in the stack gap
4727 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4730 // Do a simple write if aligned
4732 if (IS_ALIGNED (Addr
, sizeof (UINT32
))) {
4733 *(UINT32
*) Addr
= Data
;
4736 // Write as two words
4739 if ((Status
= VmWriteMem16 (VmPtr
, Addr
, (UINT16
) Data
)) != EFI_SUCCESS
) {
4744 if ((Status
= VmWriteMem16 (VmPtr
, Addr
+ sizeof (UINT16
), (UINT16
) (Data
>> 16))) != EFI_SUCCESS
) {
4756 Writes 64-bit data to memory address.
4758 This routine is called by the EBC data
4759 movement instructions that write to memory. Since these writes
4760 may be to the stack, which looks like (high address on top) this,
4762 [EBC entry point arguments]
4766 we need to detect all attempts to write to the EBC entry point argument
4767 stack area and adjust the address (which will initially point into the
4768 VM stack) to point into the EBC entry point arguments.
4770 @param VmPtr A pointer to a VM context.
4771 @param Addr Address to write to.
4772 @param Data Value to write to Addr.
4774 @retval EFI_SUCCESS The instruction is executed successfully.
4775 @retval Other Some error occurs when writing data to the address.
4780 IN VM_CONTEXT
*VmPtr
,
4789 // Convert the address if it's in the stack gap
4791 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4794 // Do a simple write if aligned
4796 if (IS_ALIGNED (Addr
, sizeof (UINT64
))) {
4797 *(UINT64
*) Addr
= Data
;
4800 // Write as two 32-bit words
4803 if ((Status
= VmWriteMem32 (VmPtr
, Addr
, (UINT32
) Data
)) != EFI_SUCCESS
) {
4808 Data32
= (UINT32
) (((UINT32
*) &Data
)[1]);
4809 if ((Status
= VmWriteMem32 (VmPtr
, Addr
+ sizeof (UINT32
), Data32
)) != EFI_SUCCESS
) {
4821 Writes UINTN data to memory address.
4823 This routine is called by the EBC data
4824 movement instructions that write to memory. Since these writes
4825 may be to the stack, which looks like (high address on top) this,
4827 [EBC entry point arguments]
4831 we need to detect all attempts to write to the EBC entry point argument
4832 stack area and adjust the address (which will initially point into the
4833 VM stack) to point into the EBC entry point arguments.
4835 @param VmPtr A pointer to a VM context.
4836 @param Addr Address to write to.
4837 @param Data Value to write to Addr.
4839 @retval EFI_SUCCESS The instruction is executed successfully.
4840 @retval Other Some error occurs when writing data to the address.
4845 IN VM_CONTEXT
*VmPtr
,
4853 Status
= EFI_SUCCESS
;
4856 // Convert the address if it's in the stack gap
4858 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4861 // Do a simple write if aligned
4863 if (IS_ALIGNED (Addr
, sizeof (UINTN
))) {
4864 *(UINTN
*) Addr
= Data
;
4866 for (Index
= 0; Index
< sizeof (UINTN
) / sizeof (UINT32
); Index
++) {
4868 Status
= VmWriteMem32 (VmPtr
, Addr
+ Index
* sizeof (UINT32
), (UINT32
) Data
);
4870 Data
= (UINTN
) RShiftU64 ((UINT64
)Data
, 32);
4879 Reads 8-bit immediate value at the offset.
4881 This routine is called by the EBC execute
4882 functions to read EBC immediate values from the code stream.
4883 Since we can't assume alignment, each tries to read in the biggest
4884 chunks size available, but will revert to smaller reads if necessary.
4886 @param VmPtr A pointer to a VM context.
4887 @param Offset offset from IP of the code bytes to read.
4889 @return Signed data of the requested size from the specified address.
4894 IN VM_CONTEXT
*VmPtr
,
4899 // Simply return the data in flat memory space
4901 return * (INT8
*) (VmPtr
->Ip
+ Offset
);
4905 Reads 16-bit immediate value at the offset.
4907 This routine is called by the EBC execute
4908 functions to read EBC immediate values from the code stream.
4909 Since we can't assume alignment, each tries to read in the biggest
4910 chunks size available, but will revert to smaller reads if necessary.
4912 @param VmPtr A pointer to a VM context.
4913 @param Offset offset from IP of the code bytes to read.
4915 @return Signed data of the requested size from the specified address.
4920 IN VM_CONTEXT
*VmPtr
,
4925 // Read direct if aligned
4927 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (INT16
))) {
4928 return * (INT16
*) (VmPtr
->Ip
+ Offset
);
4931 // All code word reads should be aligned
4933 EbcDebugSignalException (
4934 EXCEPT_EBC_ALIGNMENT_CHECK
,
4935 EXCEPTION_FLAG_WARNING
,
4940 // Return unaligned data
4942 return (INT16
) (*(UINT8
*) (VmPtr
->Ip
+ Offset
) + (*(UINT8
*) (VmPtr
->Ip
+ Offset
+ 1) << 8));
4947 Reads 32-bit immediate value at the offset.
4949 This routine is called by the EBC execute
4950 functions to read EBC immediate values from the code stream.
4951 Since we can't assume alignment, each tries to read in the biggest
4952 chunks size available, but will revert to smaller reads if necessary.
4954 @param VmPtr A pointer to a VM context.
4955 @param Offset offset from IP of the code bytes to read.
4957 @return Signed data of the requested size from the specified address.
4962 IN VM_CONTEXT
*VmPtr
,
4969 // Read direct if aligned
4971 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT32
))) {
4972 return * (INT32
*) (VmPtr
->Ip
+ Offset
);
4975 // Return unaligned data
4977 Data
= (UINT32
) VmReadCode16 (VmPtr
, Offset
);
4978 Data
|= (UINT32
)(VmReadCode16 (VmPtr
, Offset
+ 2) << 16);
4984 Reads 64-bit immediate value at the offset.
4986 This routine is called by the EBC execute
4987 functions to read EBC immediate values from the code stream.
4988 Since we can't assume alignment, each tries to read in the biggest
4989 chunks size available, but will revert to smaller reads if necessary.
4991 @param VmPtr A pointer to a VM context.
4992 @param Offset offset from IP of the code bytes to read.
4994 @return Signed data of the requested size from the specified address.
4999 IN VM_CONTEXT
*VmPtr
,
5008 // Read direct if aligned
5010 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT64
))) {
5011 return * (UINT64
*) (VmPtr
->Ip
+ Offset
);
5014 // Return unaligned data.
5016 Ptr
= (UINT8
*) &Data64
;
5017 Data32
= VmReadCode32 (VmPtr
, Offset
);
5018 *(UINT32
*) Ptr
= Data32
;
5019 Ptr
+= sizeof (Data32
);
5020 Data32
= VmReadCode32 (VmPtr
, Offset
+ sizeof (UINT32
));
5021 *(UINT32
*) Ptr
= Data32
;
5027 Reads 16-bit unsigned data from the code stream.
5029 This routine provides the ability to read raw unsigned data from the code
5032 @param VmPtr A pointer to VM context
5033 @param Offset Offset from current IP to the raw data to read.
5035 @return The raw unsigned 16-bit value from the code stream.
5040 IN VM_CONTEXT
*VmPtr
,
5045 // Read direct if aligned
5047 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT16
))) {
5048 return * (UINT16
*) (VmPtr
->Ip
+ Offset
);
5051 // All code word reads should be aligned
5053 EbcDebugSignalException (
5054 EXCEPT_EBC_ALIGNMENT_CHECK
,
5055 EXCEPTION_FLAG_WARNING
,
5060 // Return unaligned data
5062 return (UINT16
) (*(UINT8
*) (VmPtr
->Ip
+ Offset
) + (*(UINT8
*) (VmPtr
->Ip
+ Offset
+ 1) << 8));
5067 Reads 32-bit unsigned data from the code stream.
5069 This routine provides the ability to read raw unsigned data from the code
5072 @param VmPtr A pointer to VM context
5073 @param Offset Offset from current IP to the raw data to read.
5075 @return The raw unsigned 32-bit value from the code stream.
5080 IN VM_CONTEXT
*VmPtr
,
5086 // Read direct if aligned
5088 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT32
))) {
5089 return * (UINT32
*) (VmPtr
->Ip
+ Offset
);
5092 // Return unaligned data
5094 Data
= (UINT32
) VmReadCode16 (VmPtr
, Offset
);
5095 Data
|= (VmReadCode16 (VmPtr
, Offset
+ 2) << 16);
5101 Reads 64-bit unsigned data from the code stream.
5103 This routine provides the ability to read raw unsigned data from the code
5106 @param VmPtr A pointer to VM context
5107 @param Offset Offset from current IP to the raw data to read.
5109 @return The raw unsigned 64-bit value from the code stream.
5114 IN VM_CONTEXT
*VmPtr
,
5123 // Read direct if aligned
5125 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT64
))) {
5126 return * (UINT64
*) (VmPtr
->Ip
+ Offset
);
5129 // Return unaligned data.
5131 Ptr
= (UINT8
*) &Data64
;
5132 Data32
= VmReadCode32 (VmPtr
, Offset
);
5133 *(UINT32
*) Ptr
= Data32
;
5134 Ptr
+= sizeof (Data32
);
5135 Data32
= VmReadCode32 (VmPtr
, Offset
+ sizeof (UINT32
));
5136 *(UINT32
*) Ptr
= Data32
;
5142 Reads 8-bit data form the memory address.
5144 @param VmPtr A pointer to VM context.
5145 @param Addr The memory address.
5147 @return The 8-bit value from the memory address.
5152 IN VM_CONTEXT
*VmPtr
,
5157 // Convert the address if it's in the stack gap
5159 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5161 // Simply return the data in flat memory space
5163 return * (UINT8
*) Addr
;
5167 Reads 16-bit data form the memory address.
5169 @param VmPtr A pointer to VM context.
5170 @param Addr The memory address.
5172 @return The 16-bit value from the memory address.
5177 IN VM_CONTEXT
*VmPtr
,
5182 // Convert the address if it's in the stack gap
5184 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5186 // Read direct if aligned
5188 if (IS_ALIGNED (Addr
, sizeof (UINT16
))) {
5189 return * (UINT16
*) Addr
;
5192 // Return unaligned data
5194 return (UINT16
) (*(UINT8
*) Addr
+ (*(UINT8
*) (Addr
+ 1) << 8));
5198 Reads 32-bit data form the memory address.
5200 @param VmPtr A pointer to VM context.
5201 @param Addr The memory address.
5203 @return The 32-bit value from the memory address.
5208 IN VM_CONTEXT
*VmPtr
,
5215 // Convert the address if it's in the stack gap
5217 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5219 // Read direct if aligned
5221 if (IS_ALIGNED (Addr
, sizeof (UINT32
))) {
5222 return * (UINT32
*) Addr
;
5225 // Return unaligned data
5227 Data
= (UINT32
) VmReadMem16 (VmPtr
, Addr
);
5228 Data
|= (VmReadMem16 (VmPtr
, Addr
+ 2) << 16);
5233 Reads 64-bit data form the memory address.
5235 @param VmPtr A pointer to VM context.
5236 @param Addr The memory address.
5238 @return The 64-bit value from the memory address.
5243 IN VM_CONTEXT
*VmPtr
,
5251 // Convert the address if it's in the stack gap
5253 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5256 // Read direct if aligned
5258 if (IS_ALIGNED (Addr
, sizeof (UINT64
))) {
5259 return * (UINT64
*) Addr
;
5262 // Return unaligned data. Assume little endian.
5264 Data
= (UINT64
) VmReadMem32 (VmPtr
, Addr
);
5265 Data32
= VmReadMem32 (VmPtr
, Addr
+ sizeof (UINT32
));
5266 *(UINT32
*) ((UINT32
*) &Data
+ 1) = Data32
;
5272 Given an address that EBC is going to read from or write to, return
5273 an appropriate address that accounts for a gap in the stack.
5274 The stack for this application looks like this (high addr on top)
5275 [EBC entry point arguments]
5278 The EBC assumes that its arguments are at the top of its stack, which
5279 is where the VM stack is really. Therefore if the EBC does memory
5280 accesses into the VM stack area, then we need to convert the address
5281 to point to the EBC entry point arguments area. Do this here.
5283 @param VmPtr A Pointer to VM context.
5284 @param Addr Address of interest
5286 @return The unchanged address if it's not in the VM stack region. Otherwise,
5287 adjust for the stack gap and return the modified address.
5292 IN VM_CONTEXT
*VmPtr
,
5296 ASSERT(((Addr
< VmPtr
->LowStackTop
) || (Addr
> VmPtr
->HighStackBottom
)));
5302 Read a natural value from memory. May or may not be aligned.
5304 @param VmPtr current VM context
5305 @param Addr the address to read from
5307 @return The natural value at address Addr.
5312 IN VM_CONTEXT
*VmPtr
,
5317 volatile UINT32 Size
;
5321 // Convert the address if it's in the stack gap
5323 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5325 // Read direct if aligned
5327 if (IS_ALIGNED (Addr
, sizeof (UINTN
))) {
5328 return * (UINTN
*) Addr
;
5331 // Return unaligned data
5334 FromPtr
= (UINT8
*) Addr
;
5335 ToPtr
= (UINT8
*) &Data
;
5337 for (Size
= 0; Size
< sizeof (Data
); Size
++) {
5347 Returns the version of the EBC virtual machine.
5349 @return The 64-bit version of EBC virtual machine.
5357 return (UINT64
) (((VM_MAJOR_VERSION
& 0xFFFF) << 16) | ((VM_MINOR_VERSION
& 0xFFFF)));