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
1334 { NULL
}, // opcode 0x3a
1335 { NULL
}, // opcode 0x3b
1336 { NULL
}, // opcode 0x3c
1337 { NULL
}, // opcode 0x3d
1338 { NULL
}, // opcode 0x3e
1339 { NULL
} // opcode 0x3f
1343 // Length of JMP instructions, depending on upper two bits of opcode.
1345 CONST UINT8 mJMPLen
[] = { 2, 2, 6, 10 };
1348 // Simple Debugger Protocol GUID
1350 EFI_GUID mEbcSimpleDebuggerProtocolGuid
= EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL_GUID
;
1354 Given a pointer to a new VM context, execute one or more instructions. This
1355 function is only used for test purposes via the EBC VM test protocol.
1357 @param This A pointer to the EFI_EBC_VM_TEST_PROTOCOL structure.
1358 @param VmPtr A pointer to a VM context.
1359 @param InstructionCount A pointer to a UINTN value holding the number of
1360 instructions to execute. If it holds value of 0,
1361 then the instruction to be executed is 1.
1363 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
1364 @retval EFI_SUCCESS All of the instructions are executed successfully.
1368 EbcExecuteInstructions (
1369 IN EFI_EBC_VM_TEST_PROTOCOL
*This
,
1370 IN VM_CONTEXT
*VmPtr
,
1371 IN OUT UINTN
*InstructionCount
1376 UINTN InstructionsLeft
;
1377 UINTN SavedInstructionCount
;
1379 Status
= EFI_SUCCESS
;
1381 if (*InstructionCount
== 0) {
1382 InstructionsLeft
= 1;
1384 InstructionsLeft
= *InstructionCount
;
1387 SavedInstructionCount
= *InstructionCount
;
1388 *InstructionCount
= 0;
1391 // Index into the opcode table using the opcode byte for this instruction.
1392 // This gives you the execute function, which we first test for null, then
1393 // call it if it's not null.
1395 while (InstructionsLeft
!= 0) {
1396 ExecFunc
= (UINTN
) mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction
;
1397 if (ExecFunc
== (UINTN
) NULL
) {
1398 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1399 return EFI_UNSUPPORTED
;
1401 mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction (VmPtr
);
1402 *InstructionCount
= *InstructionCount
+ 1;
1406 // Decrement counter if applicable
1408 if (SavedInstructionCount
!= 0) {
1418 Execute an EBC image from an entry point or from a published protocol.
1420 @param VmPtr A pointer to a VM context.
1422 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
1423 @retval EFI_SUCCESS All of the instructions are executed successfully.
1428 IN VM_CONTEXT
*VmPtr
1432 UINT8 StackCorrupted
;
1434 EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL
*EbcSimpleDebugger
;
1437 EbcSimpleDebugger
= NULL
;
1438 Status
= EFI_SUCCESS
;
1442 // Make sure the magic value has been put on the stack before we got here.
1444 if (*VmPtr
->StackMagicPtr
!= (UINTN
) VM_STACK_KEY_VALUE
) {
1448 VmPtr
->FramePtr
= (VOID
*) ((UINT8
*) (UINTN
) VmPtr
->R
[0] + 8);
1451 // Try to get the debug support for EBC
1453 DEBUG_CODE_BEGIN ();
1454 Status
= gBS
->LocateProtocol (
1455 &mEbcSimpleDebuggerProtocolGuid
,
1457 (VOID
**) &EbcSimpleDebugger
1459 if (EFI_ERROR (Status
)) {
1460 EbcSimpleDebugger
= NULL
;
1465 // Save the start IP for debug. For example, if we take an exception we
1466 // can print out the location of the exception relative to the entry point,
1467 // which could then be used in a disassembly listing to find the problem.
1469 VmPtr
->EntryPoint
= (VOID
*) VmPtr
->Ip
;
1472 // We'll wait for this flag to know when we're done. The RET
1473 // instruction sets it if it runs out of stack.
1475 VmPtr
->StopFlags
= 0;
1476 while ((VmPtr
->StopFlags
& STOPFLAG_APP_DONE
) == 0) {
1478 // If we've found a simple debugger protocol, call it
1480 DEBUG_CODE_BEGIN ();
1481 if (EbcSimpleDebugger
!= NULL
) {
1482 EbcSimpleDebugger
->Debugger (EbcSimpleDebugger
, VmPtr
);
1487 // Use the opcode bits to index into the opcode dispatch table. If the
1488 // function pointer is null then generate an exception.
1490 ExecFunc
= (UINTN
) mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction
;
1491 if (ExecFunc
== (UINTN
) NULL
) {
1492 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1493 Status
= EFI_UNSUPPORTED
;
1497 // The EBC VM is a strongly ordered processor, so perform a fence operation before
1498 // and after each instruction is executed.
1502 mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction (VmPtr
);
1507 // If the step flag is set, signal an exception and continue. We don't
1508 // clear it here. Assuming the debugger is responsible for clearing it.
1510 if (VMFLAG_ISSET (VmPtr
, VMFLAGS_STEP
)) {
1511 EbcDebugSignalException (EXCEPT_EBC_STEP
, EXCEPTION_FLAG_NONE
, VmPtr
);
1514 // Make sure stack has not been corrupted. Only report it once though.
1516 if ((StackCorrupted
== 0) && (*VmPtr
->StackMagicPtr
!= (UINTN
) VM_STACK_KEY_VALUE
)) {
1517 EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1520 if ((StackCorrupted
== 0) && ((UINT64
)VmPtr
->R
[0] <= (UINT64
)(UINTN
) VmPtr
->StackTop
)) {
1521 EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1534 Execute the MOVxx instructions.
1538 MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
1539 MOVqq {@}R1 {Index64}, {@}R2 {Index64}
1541 Copies contents of [R2] -> [R1], zero extending where required.
1543 First character indicates the size of the move.
1544 Second character indicates the size of the index(s).
1546 Invalid to have R1 direct with index.
1548 @param VmPtr A pointer to a VM context.
1550 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
1551 @retval EFI_SUCCESS The instruction is executed successfully.
1556 IN VM_CONTEXT
*VmPtr
1572 Opcode
= GETOPCODE (VmPtr
);
1573 OpcMasked
= (UINT8
) (Opcode
& OPCODE_M_OPCODE
);
1576 // Get the operands byte so we can get R1 and R2
1578 Operands
= GETOPERANDS (VmPtr
);
1581 // Assume no indexes
1588 // Determine if we have an index/immediate data. Base instruction size
1589 // is 2 (opcode + operands). Add to this size each index specified.
1592 if ((Opcode
& (OPCODE_M_IMMED_OP1
| OPCODE_M_IMMED_OP2
)) != 0) {
1594 // Determine size of the index from the opcode. Then get it.
1596 if ((OpcMasked
<= OPCODE_MOVQW
) || (OpcMasked
== OPCODE_MOVNW
)) {
1598 // MOVBW, MOVWW, MOVDW, MOVQW, and MOVNW have 16-bit immediate index.
1599 // Get one or both index values.
1601 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1602 Index16
= VmReadIndex16 (VmPtr
, 2);
1603 Index64Op1
= (INT64
) Index16
;
1604 Size
+= sizeof (UINT16
);
1607 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1608 Index16
= VmReadIndex16 (VmPtr
, Size
);
1609 Index64Op2
= (INT64
) Index16
;
1610 Size
+= sizeof (UINT16
);
1612 } else if ((OpcMasked
<= OPCODE_MOVQD
) || (OpcMasked
== OPCODE_MOVND
)) {
1614 // MOVBD, MOVWD, MOVDD, MOVQD, and MOVND have 32-bit immediate index
1616 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1617 Index32
= VmReadIndex32 (VmPtr
, 2);
1618 Index64Op1
= (INT64
) Index32
;
1619 Size
+= sizeof (UINT32
);
1622 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1623 Index32
= VmReadIndex32 (VmPtr
, Size
);
1624 Index64Op2
= (INT64
) Index32
;
1625 Size
+= sizeof (UINT32
);
1627 } else if (OpcMasked
== OPCODE_MOVQQ
) {
1629 // MOVqq -- only form with a 64-bit index
1631 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1632 Index64Op1
= VmReadIndex64 (VmPtr
, 2);
1633 Size
+= sizeof (UINT64
);
1636 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1637 Index64Op2
= VmReadIndex64 (VmPtr
, Size
);
1638 Size
+= sizeof (UINT64
);
1642 // Obsolete MOVBQ, MOVWQ, MOVDQ, and MOVNQ have 64-bit immediate index
1644 EbcDebugSignalException (
1645 EXCEPT_EBC_INSTRUCTION_ENCODING
,
1646 EXCEPTION_FLAG_FATAL
,
1649 return EFI_UNSUPPORTED
;
1653 // Determine the size of the move, and create a mask for it so we can
1654 // clear unused bits.
1656 if ((OpcMasked
== OPCODE_MOVBW
) || (OpcMasked
== OPCODE_MOVBD
)) {
1657 MoveSize
= DATA_SIZE_8
;
1659 } else if ((OpcMasked
== OPCODE_MOVWW
) || (OpcMasked
== OPCODE_MOVWD
)) {
1660 MoveSize
= DATA_SIZE_16
;
1662 } else if ((OpcMasked
== OPCODE_MOVDW
) || (OpcMasked
== OPCODE_MOVDD
)) {
1663 MoveSize
= DATA_SIZE_32
;
1664 DataMask
= 0xFFFFFFFF;
1665 } else if ((OpcMasked
== OPCODE_MOVQW
) || (OpcMasked
== OPCODE_MOVQD
) || (OpcMasked
== OPCODE_MOVQQ
)) {
1666 MoveSize
= DATA_SIZE_64
;
1667 DataMask
= (UINT64
)~0;
1668 } else if ((OpcMasked
== OPCODE_MOVNW
) || (OpcMasked
== OPCODE_MOVND
)) {
1669 MoveSize
= DATA_SIZE_N
;
1670 DataMask
= (UINT64
)~0 >> (64 - 8 * sizeof (UINTN
));
1673 // We were dispatched to this function and we don't recognize the opcode
1675 EbcDebugSignalException (EXCEPT_EBC_UNDEFINED
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1676 return EFI_UNSUPPORTED
;
1679 // Now get the source address
1681 if (OPERAND2_INDIRECT (Operands
)) {
1683 // Indirect form @R2. Compute address of operand2
1685 Source
= (UINTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index64Op2
);
1687 // Now get the data from the source. Always 0-extend and let the compiler
1688 // sign-extend where required.
1692 Data64
= (UINT64
) (UINT8
) VmReadMem8 (VmPtr
, Source
);
1696 Data64
= (UINT64
) (UINT16
) VmReadMem16 (VmPtr
, Source
);
1700 Data64
= (UINT64
) (UINT32
) VmReadMem32 (VmPtr
, Source
);
1704 Data64
= (UINT64
) VmReadMem64 (VmPtr
, Source
);
1708 Data64
= (UINT64
) (UINTN
) VmReadMemN (VmPtr
, Source
);
1719 // Not indirect source: MOVxx {@}Rx, Ry [Index]
1721 Data64
= VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index64Op2
;
1723 // Did Operand2 have an index? If so, treat as two signed values since
1724 // indexes are signed values.
1726 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1728 // NOTE: need to find a way to fix this, most likely by changing the VM
1729 // implementation to remove the stack gap. To do that, we'd need to
1730 // allocate stack space for the VM and actually set the system
1731 // stack pointer to the allocated buffer when the VM starts.
1733 // Special case -- if someone took the address of a function parameter
1734 // then we need to make sure it's not in the stack gap. We can identify
1735 // this situation if (Operand2 register == 0) && (Operand2 is direct)
1736 // && (Index applies to Operand2) && (Index > 0) && (Operand1 register != 0)
1737 // Situations that to be aware of:
1738 // * stack adjustments at beginning and end of functions R0 = R0 += stacksize
1740 if ((OPERAND2_REGNUM (Operands
) == 0) &&
1741 (!OPERAND2_INDIRECT (Operands
)) &&
1743 (OPERAND1_REGNUM (Operands
) == 0) &&
1744 (OPERAND1_INDIRECT (Operands
))
1746 Data64
= (UINT64
) ConvertStackAddr (VmPtr
, (UINTN
) (INT64
) Data64
);
1751 // Now write it back
1753 if (OPERAND1_INDIRECT (Operands
)) {
1755 // Reuse the Source variable to now be dest.
1757 Source
= (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index64Op1
);
1759 // Do the write based on the size
1763 VmWriteMem8 (VmPtr
, Source
, (UINT8
) Data64
);
1767 VmWriteMem16 (VmPtr
, Source
, (UINT16
) Data64
);
1771 VmWriteMem32 (VmPtr
, Source
, (UINT32
) Data64
);
1775 VmWriteMem64 (VmPtr
, Source
, Data64
);
1779 VmWriteMemN (VmPtr
, Source
, (UINTN
) Data64
);
1791 // Make sure we didn't have an index on operand1.
1793 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1794 EbcDebugSignalException (
1795 EXCEPT_EBC_INSTRUCTION_ENCODING
,
1796 EXCEPTION_FLAG_FATAL
,
1799 return EFI_UNSUPPORTED
;
1802 // Direct storage in register. Clear unused bits and store back to
1805 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Data64
& DataMask
;
1808 // Advance the instruction pointer
1816 Execute the EBC BREAK instruction.
1818 @param VmPtr A pointer to a VM context.
1820 @retval EFI_SUCCESS The instruction is executed successfully.
1825 IN VM_CONTEXT
*VmPtr
1830 VOID
*EbcEntryPoint
;
1832 UINT64 U64EbcEntryPoint
;
1835 Operands
= GETOPERANDS (VmPtr
);
1838 // Runaway program break. Generate an exception and terminate
1841 EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1845 // Get VM version -- return VM revision number in R7
1851 // 16-8 = Major version
1852 // 7-0 = Minor version
1854 VmPtr
->R
[7] = GetVmVersion ();
1858 // Debugger breakpoint
1861 VmPtr
->StopFlags
|= STOPFLAG_BREAKPOINT
;
1863 // See if someone has registered a handler
1865 EbcDebugSignalException (
1866 EXCEPT_EBC_BREAKPOINT
,
1867 EXCEPTION_FLAG_NONE
,
1873 // System call, which there are none, so NOP it.
1879 // Create a thunk for EBC code. R7 points to a 32-bit (in a 64-bit slot)
1880 // "offset from self" pointer to the EBC entry point.
1881 // After we're done, *(UINT64 *)R7 will be the address of the new thunk.
1884 Offset
= (INT32
) VmReadMem32 (VmPtr
, (UINTN
) VmPtr
->R
[7]);
1885 U64EbcEntryPoint
= (UINT64
) (VmPtr
->R
[7] + Offset
+ 4);
1886 EbcEntryPoint
= (VOID
*) (UINTN
) U64EbcEntryPoint
;
1889 // Now create a new thunk
1891 Status
= EbcCreateThunks (VmPtr
->ImageHandle
, EbcEntryPoint
, &Thunk
, 0);
1892 if (EFI_ERROR (Status
)) {
1897 // Finally replace the EBC entry point memory with the thunk address
1899 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->R
[7], (UINT64
) (UINTN
) Thunk
);
1903 // Compiler setting version per value in R7
1906 VmPtr
->CompilerVersion
= (UINT32
) VmPtr
->R
[7];
1908 // Check compiler version against VM version?
1913 // Unhandled break code. Signal exception.
1916 EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1928 Execute the JMP instruction.
1931 JMP64{cs|cc} Immed64
1932 JMP32{cs|cc} {@}R1 {Immed32|Index32}
1935 b0.7 - immediate data present
1936 b0.6 - 1 = 64 bit immediate data
1937 0 = 32 bit immediate data
1938 b1.7 - 1 = conditional
1939 b1.6 1 = CS (condition set)
1940 0 = CC (condition clear)
1941 b1.4 1 = relative address
1942 0 = absolute address
1943 b1.3 1 = operand1 indirect
1946 @param VmPtr A pointer to a VM context.
1948 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
1949 @retval EFI_SUCCESS The instruction is executed successfully.
1954 IN VM_CONTEXT
*VmPtr
1959 UINT8 ConditionFlag
;
1966 Operand
= GETOPERANDS (VmPtr
);
1967 Opcode
= GETOPCODE (VmPtr
);
1970 // Get instruction length from the opcode. The upper two bits are used here
1971 // to index into the length array.
1973 Size
= mJMPLen
[(Opcode
>> 6) & 0x03];
1976 // Decode instruction conditions
1977 // If we haven't met the condition, then simply advance the IP and return.
1979 CompareSet
= (UINT8
) (((Operand
& JMP_M_CS
) != 0) ? 1 : 0);
1980 ConditionFlag
= (UINT8
) VMFLAG_ISSET (VmPtr
, VMFLAGS_CC
);
1981 if ((Operand
& CONDITION_M_CONDITIONAL
) != 0) {
1982 if (CompareSet
!= ConditionFlag
) {
1988 // Check for 64-bit form and do it right away since it's the most
1989 // straight-forward form.
1991 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
1993 // Double check for immediate-data, which is required. If not there,
1994 // then signal an exception
1996 if ((Opcode
& OPCODE_M_IMMDATA
) == 0) {
1997 EbcDebugSignalException (
1998 EXCEPT_EBC_INSTRUCTION_ENCODING
,
1999 EXCEPTION_FLAG_ERROR
,
2002 return EFI_UNSUPPORTED
;
2005 // 64-bit immediate data is full address. Read the immediate data,
2006 // check for alignment, and jump absolute.
2008 Data64
= VmReadImmed64 (VmPtr
, 2);
2009 if (!IS_ALIGNED ((UINTN
) Data64
, sizeof (UINT16
))) {
2010 EbcDebugSignalException (
2011 EXCEPT_EBC_ALIGNMENT_CHECK
,
2012 EXCEPTION_FLAG_FATAL
,
2016 return EFI_UNSUPPORTED
;
2020 // Take jump -- relative or absolute
2022 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2023 VmPtr
->Ip
+= (UINTN
) Data64
+ Size
;
2025 VmPtr
->Ip
= (VMIP
) (UINTN
) Data64
;
2032 // Get the index if there is one. May be either an index, or an immediate
2033 // offset depending on indirect operand.
2034 // JMP32 @R1 Index32 -- immediate data is an index
2035 // JMP32 R1 Immed32 -- immedate data is an offset
2037 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
2038 if (OPERAND1_INDIRECT (Operand
)) {
2039 Index32
= VmReadIndex32 (VmPtr
, 2);
2041 Index32
= VmReadImmed32 (VmPtr
, 2);
2047 // Get the register data. If R == 0, then special case where it's ignored.
2049 if (OPERAND1_REGNUM (Operand
) == 0) {
2052 Data64
= OPERAND1_REGDATA (VmPtr
, Operand
);
2057 if (OPERAND1_INDIRECT (Operand
)) {
2059 // Form: JMP32 @Rx {Index32}
2061 Addr
= VmReadMemN (VmPtr
, (UINTN
) Data64
+ Index32
);
2062 if (!IS_ALIGNED ((UINTN
) Addr
, sizeof (UINT16
))) {
2063 EbcDebugSignalException (
2064 EXCEPT_EBC_ALIGNMENT_CHECK
,
2065 EXCEPTION_FLAG_FATAL
,
2069 return EFI_UNSUPPORTED
;
2072 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2073 VmPtr
->Ip
+= (UINTN
) Addr
+ Size
;
2075 VmPtr
->Ip
= (VMIP
) Addr
;
2079 // Form: JMP32 Rx {Immed32}
2081 Addr
= (UINTN
) (Data64
+ Index32
);
2082 if (!IS_ALIGNED ((UINTN
) Addr
, sizeof (UINT16
))) {
2083 EbcDebugSignalException (
2084 EXCEPT_EBC_ALIGNMENT_CHECK
,
2085 EXCEPTION_FLAG_FATAL
,
2089 return EFI_UNSUPPORTED
;
2092 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2093 VmPtr
->Ip
+= (UINTN
) Addr
+ Size
;
2095 VmPtr
->Ip
= (VMIP
) Addr
;
2104 Execute the EBC JMP8 instruction.
2107 JMP8{cs|cc} Offset/2
2109 @param VmPtr A pointer to a VM context.
2111 @retval EFI_SUCCESS The instruction is executed successfully.
2116 IN VM_CONTEXT
*VmPtr
2120 UINT8 ConditionFlag
;
2125 // Decode instruction.
2127 Opcode
= GETOPCODE (VmPtr
);
2128 CompareSet
= (UINT8
) (((Opcode
& JMP_M_CS
) != 0) ? 1 : 0);
2129 ConditionFlag
= (UINT8
) VMFLAG_ISSET (VmPtr
, VMFLAGS_CC
);
2132 // If we haven't met the condition, then simply advance the IP and return
2134 if ((Opcode
& CONDITION_M_CONDITIONAL
) != 0) {
2135 if (CompareSet
!= ConditionFlag
) {
2141 // Get the offset from the instruction stream. It's relative to the
2142 // following instruction, and divided by 2.
2144 Offset
= VmReadImmed8 (VmPtr
, 1);
2146 // Want to check for offset == -2 and then raise an exception?
2148 VmPtr
->Ip
+= (Offset
* 2) + 2;
2154 Execute the EBC MOVI.
2158 MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
2160 First variable character specifies the move size
2161 Second variable character specifies size of the immediate data
2163 Sign-extend the immediate data to the size of the operation, and zero-extend
2164 if storing to a register.
2166 Operand1 direct with index/immed is invalid.
2168 @param VmPtr A pointer to a VM context.
2170 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2171 @retval EFI_SUCCESS The instruction is executed successfully.
2176 IN VM_CONTEXT
*VmPtr
2188 // Get the opcode and operands byte so we can get R1 and R2
2190 Opcode
= GETOPCODE (VmPtr
);
2191 Operands
= GETOPERANDS (VmPtr
);
2194 // Get the index (16-bit) if present
2196 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2197 Index16
= VmReadIndex16 (VmPtr
, 2);
2204 // Extract the immediate data. Sign-extend always.
2206 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2207 ImmData64
= (INT64
) (INT16
) VmReadImmed16 (VmPtr
, Size
);
2209 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2210 ImmData64
= (INT64
) (INT32
) VmReadImmed32 (VmPtr
, Size
);
2212 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2213 ImmData64
= (INT64
) VmReadImmed64 (VmPtr
, Size
);
2219 EbcDebugSignalException (
2220 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2221 EXCEPTION_FLAG_FATAL
,
2224 return EFI_UNSUPPORTED
;
2227 // Now write back the result
2229 if (!OPERAND1_INDIRECT (Operands
)) {
2231 // Operand1 direct. Make sure it didn't have an index.
2233 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2234 EbcDebugSignalException (
2235 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2236 EXCEPTION_FLAG_FATAL
,
2239 return EFI_UNSUPPORTED
;
2242 // Writing directly to a register. Clear unused bits.
2244 if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH8
) {
2245 Mask64
= 0x000000FF;
2246 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH16
) {
2247 Mask64
= 0x0000FFFF;
2248 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH32
) {
2249 Mask64
= 0x00000000FFFFFFFF;
2251 Mask64
= (UINT64
)~0;
2254 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = ImmData64
& Mask64
;
2257 // Get the address then write back based on size of the move
2259 Op1
= (UINT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2260 if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH8
) {
2261 VmWriteMem8 (VmPtr
, (UINTN
) Op1
, (UINT8
) ImmData64
);
2262 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH16
) {
2263 VmWriteMem16 (VmPtr
, (UINTN
) Op1
, (UINT16
) ImmData64
);
2264 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH32
) {
2265 VmWriteMem32 (VmPtr
, (UINTN
) Op1
, (UINT32
) ImmData64
);
2267 VmWriteMem64 (VmPtr
, (UINTN
) Op1
, ImmData64
);
2271 // Advance the instruction pointer
2279 Execute the EBC MOV immediate natural. This instruction moves an immediate
2280 index value into a register or memory location.
2284 MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
2286 @param VmPtr A pointer to a VM context.
2288 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2289 @retval EFI_SUCCESS The instruction is executed successfully.
2294 IN VM_CONTEXT
*VmPtr
2307 // Get the opcode and operands byte so we can get R1 and R2
2309 Opcode
= GETOPCODE (VmPtr
);
2310 Operands
= GETOPERANDS (VmPtr
);
2313 // Get the operand1 index (16-bit) if present
2315 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2316 Index16
= VmReadIndex16 (VmPtr
, 2);
2323 // Extract the immediate data and convert to a 64-bit index.
2325 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2326 ImmedIndex16
= VmReadIndex16 (VmPtr
, Size
);
2327 ImmedIndex64
= (INT64
) ImmedIndex16
;
2329 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2330 ImmedIndex32
= VmReadIndex32 (VmPtr
, Size
);
2331 ImmedIndex64
= (INT64
) ImmedIndex32
;
2333 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2334 ImmedIndex64
= VmReadIndex64 (VmPtr
, Size
);
2340 EbcDebugSignalException (
2341 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2342 EXCEPTION_FLAG_FATAL
,
2345 return EFI_UNSUPPORTED
;
2348 // Now write back the result
2350 if (!OPERAND1_INDIRECT (Operands
)) {
2352 // Check for MOVIn R1 Index16, Immed (not indirect, with index), which
2355 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2356 EbcDebugSignalException (
2357 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2358 EXCEPTION_FLAG_FATAL
,
2361 return EFI_UNSUPPORTED
;
2364 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = ImmedIndex64
;
2369 Op1
= (UINT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2370 VmWriteMemN (VmPtr
, (UINTN
) Op1
, (INTN
) ImmedIndex64
);
2373 // Advance the instruction pointer
2381 Execute the EBC MOVREL instruction.
2382 Dest <- Ip + ImmData
2386 MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
2388 @param VmPtr A pointer to a VM context.
2390 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2391 @retval EFI_SUCCESS The instruction is executed successfully.
2396 IN VM_CONTEXT
*VmPtr
2408 // Get the opcode and operands byte so we can get R1 and R2
2410 Opcode
= GETOPCODE (VmPtr
);
2411 Operands
= GETOPERANDS (VmPtr
);
2414 // Get the Operand 1 index (16-bit) if present
2416 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2417 Index16
= VmReadIndex16 (VmPtr
, 2);
2424 // Get the immediate data.
2426 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2427 ImmData64
= (INT64
) VmReadImmed16 (VmPtr
, Size
);
2429 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2430 ImmData64
= (INT64
) VmReadImmed32 (VmPtr
, Size
);
2432 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2433 ImmData64
= VmReadImmed64 (VmPtr
, Size
);
2439 EbcDebugSignalException (
2440 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2441 EXCEPTION_FLAG_FATAL
,
2444 return EFI_UNSUPPORTED
;
2447 // Compute the value and write back the result
2449 Op2
= (UINT64
) ((INT64
) ((UINT64
) (UINTN
) VmPtr
->Ip
) + (INT64
) ImmData64
+ Size
);
2450 if (!OPERAND1_INDIRECT (Operands
)) {
2452 // Check for illegal combination of operand1 direct with immediate data
2454 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2455 EbcDebugSignalException (
2456 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2457 EXCEPTION_FLAG_FATAL
,
2460 return EFI_UNSUPPORTED
;
2463 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (VM_REGISTER
) Op2
;
2466 // Get the address = [Rx] + Index16
2467 // Write back the result. Always a natural size write, since
2468 // we're talking addresses here.
2470 Op1
= (UINT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2471 VmWriteMemN (VmPtr
, (UINTN
) Op1
, (UINTN
) Op2
);
2474 // Advance the instruction pointer
2482 Execute the EBC MOVsnw instruction. This instruction loads a signed
2483 natural value from memory or register to another memory or register. On
2484 32-bit machines, the value gets sign-extended to 64 bits if the destination
2489 MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
2491 0:7 1=>operand1 index present
2492 0:6 1=>operand2 index present
2494 @param VmPtr A pointer to a VM context.
2496 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2497 @retval EFI_SUCCESS The instruction is executed successfully.
2502 IN VM_CONTEXT
*VmPtr
2513 // Get the opcode and operand bytes
2515 Opcode
= GETOPCODE (VmPtr
);
2516 Operands
= GETOPERANDS (VmPtr
);
2518 Op1Index
= Op2Index
= 0;
2521 // Get the indexes if present.
2524 if ((Opcode
& OPCODE_M_IMMED_OP1
) !=0) {
2525 if (OPERAND1_INDIRECT (Operands
)) {
2526 Op1Index
= VmReadIndex16 (VmPtr
, 2);
2529 // Illegal form operand1 direct with index: MOVsnw R1 Index16, {@}R2
2531 EbcDebugSignalException (
2532 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2533 EXCEPTION_FLAG_FATAL
,
2536 return EFI_UNSUPPORTED
;
2539 Size
+= sizeof (UINT16
);
2542 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
2543 if (OPERAND2_INDIRECT (Operands
)) {
2544 Op2Index
= VmReadIndex16 (VmPtr
, Size
);
2546 Op2Index
= VmReadImmed16 (VmPtr
, Size
);
2549 Size
+= sizeof (UINT16
);
2552 // Get the data from the source.
2554 Op2
= (INT64
) ((INTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Op2Index
));
2555 if (OPERAND2_INDIRECT (Operands
)) {
2556 Op2
= (INT64
) (INTN
) VmReadMemN (VmPtr
, (UINTN
) Op2
);
2559 // Now write back the result.
2561 if (!OPERAND1_INDIRECT (Operands
)) {
2562 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Op2
;
2564 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Op1Index
), (UINTN
) Op2
);
2567 // Advance the instruction pointer
2575 Execute the EBC MOVsnw instruction. This instruction loads a signed
2576 natural value from memory or register to another memory or register. On
2577 32-bit machines, the value gets sign-extended to 64 bits if the destination
2582 MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
2584 0:7 1=>operand1 index present
2585 0:6 1=>operand2 index present
2587 @param VmPtr A pointer to a VM context.
2589 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2590 @retval EFI_SUCCESS The instruction is executed successfully.
2595 IN VM_CONTEXT
*VmPtr
2606 // Get the opcode and operand bytes
2608 Opcode
= GETOPCODE (VmPtr
);
2609 Operands
= GETOPERANDS (VmPtr
);
2611 Op1Index
= Op2Index
= 0;
2614 // Get the indexes if present.
2617 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
2618 if (OPERAND1_INDIRECT (Operands
)) {
2619 Op1Index
= VmReadIndex32 (VmPtr
, 2);
2622 // Illegal form operand1 direct with index: MOVsnd R1 Index16,..
2624 EbcDebugSignalException (
2625 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2626 EXCEPTION_FLAG_FATAL
,
2629 return EFI_UNSUPPORTED
;
2632 Size
+= sizeof (UINT32
);
2635 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
2636 if (OPERAND2_INDIRECT (Operands
)) {
2637 Op2Index
= VmReadIndex32 (VmPtr
, Size
);
2639 Op2Index
= VmReadImmed32 (VmPtr
, Size
);
2642 Size
+= sizeof (UINT32
);
2645 // Get the data from the source.
2647 Op2
= (INT64
) ((INTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Op2Index
));
2648 if (OPERAND2_INDIRECT (Operands
)) {
2649 Op2
= (INT64
) (INTN
) VmReadMemN (VmPtr
, (UINTN
) Op2
);
2652 // Now write back the result.
2654 if (!OPERAND1_INDIRECT (Operands
)) {
2655 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Op2
;
2657 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Op1Index
), (UINTN
) Op2
);
2660 // Advance the instruction pointer
2668 Execute the EBC PUSHn instruction
2671 PUSHn {@}R1 {Index16|Immed16}
2673 @param VmPtr A pointer to a VM context.
2675 @retval EFI_SUCCESS The instruction is executed successfully.
2680 IN VM_CONTEXT
*VmPtr
2689 // Get opcode and operands
2691 Opcode
= GETOPCODE (VmPtr
);
2692 Operands
= GETOPERANDS (VmPtr
);
2695 // Get index if present
2697 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2698 if (OPERAND1_INDIRECT (Operands
)) {
2699 Index16
= VmReadIndex16 (VmPtr
, 2);
2701 Index16
= VmReadImmed16 (VmPtr
, 2);
2710 // Get the data to push
2712 if (OPERAND1_INDIRECT (Operands
)) {
2713 DataN
= VmReadMemN (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
));
2715 DataN
= (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
);
2718 // Adjust the stack down.
2720 VmPtr
->R
[0] -= sizeof (UINTN
);
2721 VmWriteMemN (VmPtr
, (UINTN
) VmPtr
->R
[0], DataN
);
2727 Execute the EBC PUSH instruction.
2730 PUSH[32|64] {@}R1 {Index16|Immed16}
2732 @param VmPtr A pointer to a VM context.
2734 @retval EFI_SUCCESS The instruction is executed successfully.
2739 IN VM_CONTEXT
*VmPtr
2749 // Get opcode and operands
2751 Opcode
= GETOPCODE (VmPtr
);
2752 Operands
= GETOPERANDS (VmPtr
);
2754 // Get immediate index if present, then advance the IP.
2756 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2757 if (OPERAND1_INDIRECT (Operands
)) {
2758 Index16
= VmReadIndex16 (VmPtr
, 2);
2760 Index16
= VmReadImmed16 (VmPtr
, 2);
2769 // Get the data to push
2771 if ((Opcode
& PUSHPOP_M_64
) != 0) {
2772 if (OPERAND1_INDIRECT (Operands
)) {
2773 Data64
= VmReadMem64 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
));
2775 Data64
= (UINT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2778 // Adjust the stack down, then write back the data
2780 VmPtr
->R
[0] -= sizeof (UINT64
);
2781 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->R
[0], Data64
);
2786 if (OPERAND1_INDIRECT (Operands
)) {
2787 Data32
= VmReadMem32 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
));
2789 Data32
= (UINT32
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2792 // Adjust the stack down and write the data
2794 VmPtr
->R
[0] -= sizeof (UINT32
);
2795 VmWriteMem32 (VmPtr
, (UINTN
) VmPtr
->R
[0], Data32
);
2803 Execute the EBC POPn instruction.
2806 POPn {@}R1 {Index16|Immed16}
2808 @param VmPtr A pointer to a VM context.
2810 @retval EFI_SUCCESS The instruction is executed successfully.
2815 IN VM_CONTEXT
*VmPtr
2824 // Get opcode and operands
2826 Opcode
= GETOPCODE (VmPtr
);
2827 Operands
= GETOPERANDS (VmPtr
);
2829 // Get immediate data if present, and advance the IP
2831 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2832 if (OPERAND1_INDIRECT (Operands
)) {
2833 Index16
= VmReadIndex16 (VmPtr
, 2);
2835 Index16
= VmReadImmed16 (VmPtr
, 2);
2844 // Read the data off the stack, then adjust the stack pointer
2846 DataN
= VmReadMemN (VmPtr
, (UINTN
) VmPtr
->R
[0]);
2847 VmPtr
->R
[0] += sizeof (UINTN
);
2849 // Do the write-back
2851 if (OPERAND1_INDIRECT (Operands
)) {
2852 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
), DataN
);
2854 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (INT64
) (UINT64
) ((UINTN
) DataN
+ Index16
);
2862 Execute the EBC POP instruction.
2865 POPn {@}R1 {Index16|Immed16}
2867 @param VmPtr A pointer to a VM context.
2869 @retval EFI_SUCCESS The instruction is executed successfully.
2874 IN VM_CONTEXT
*VmPtr
2884 // Get opcode and operands
2886 Opcode
= GETOPCODE (VmPtr
);
2887 Operands
= GETOPERANDS (VmPtr
);
2889 // Get immediate data if present, and advance the IP.
2891 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2892 if (OPERAND1_INDIRECT (Operands
)) {
2893 Index16
= VmReadIndex16 (VmPtr
, 2);
2895 Index16
= VmReadImmed16 (VmPtr
, 2);
2904 // Get the data off the stack, then write it to the appropriate location
2906 if ((Opcode
& PUSHPOP_M_64
) != 0) {
2908 // Read the data off the stack, then adjust the stack pointer
2910 Data64
= VmReadMem64 (VmPtr
, (UINTN
) VmPtr
->R
[0]);
2911 VmPtr
->R
[0] += sizeof (UINT64
);
2913 // Do the write-back
2915 if (OPERAND1_INDIRECT (Operands
)) {
2916 VmWriteMem64 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
), Data64
);
2918 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Data64
+ Index16
;
2922 // 32-bit pop. Read it off the stack and adjust the stack pointer
2924 Data32
= (INT32
) VmReadMem32 (VmPtr
, (UINTN
) VmPtr
->R
[0]);
2925 VmPtr
->R
[0] += sizeof (UINT32
);
2927 // Do the write-back
2929 if (OPERAND1_INDIRECT (Operands
)) {
2930 VmWriteMem32 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
), Data32
);
2932 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (INT64
) Data32
+ Index16
;
2941 Implements the EBC CALL instruction.
2945 CALL32 {@}R1 {Immed32|Index32}
2947 CALLEX16 {@}R1 {Immed32}
2949 If Rx == R0, then it's a PC relative call to PC = PC + imm32.
2951 @param VmPtr A pointer to a VM context.
2953 @retval EFI_SUCCESS The instruction is executed successfully.
2958 IN VM_CONTEXT
*VmPtr
2969 // Get opcode and operands
2971 Opcode
= GETOPCODE (VmPtr
);
2972 Operands
= GETOPERANDS (VmPtr
);
2974 // Assign these as well to avoid compiler warnings
2979 FramePtr
= VmPtr
->FramePtr
;
2981 // Determine the instruction size, and get immediate data if present
2983 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
2984 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
2985 Immed64
= VmReadImmed64 (VmPtr
, 2);
2989 // If register operand is indirect, then the immediate data is an index
2991 if (OPERAND1_INDIRECT (Operands
)) {
2992 Immed32
= VmReadIndex32 (VmPtr
, 2);
2994 Immed32
= VmReadImmed32 (VmPtr
, 2);
3003 // If it's a call to EBC, adjust the stack pointer down 16 bytes and
3004 // put our return address and frame pointer on the VM stack.
3006 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3008 VmWriteMemN (VmPtr
, (UINTN
) VmPtr
->R
[0], (UINTN
) FramePtr
);
3009 VmPtr
->FramePtr
= (VOID
*) (UINTN
) VmPtr
->R
[0];
3011 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->R
[0], (UINT64
) (UINTN
) (VmPtr
->Ip
+ Size
));
3014 // If 64-bit data, then absolute jump only
3016 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
3018 // Native or EBC call?
3020 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3021 VmPtr
->Ip
= (VMIP
) (UINTN
) Immed64
;
3024 // Call external function, get the return value, and advance the IP
3026 EbcLLCALLEX (VmPtr
, (UINTN
) Immed64
, (UINTN
) VmPtr
->R
[0], FramePtr
, Size
);
3030 // Get the register data. If operand1 == 0, then ignore register and
3031 // take immediate data as relative or absolute address.
3032 // Compiler should take care of upper bits if 32-bit machine.
3034 if (OPERAND1_REGNUM (Operands
) != 0) {
3035 Immed64
= (UINT64
) (UINTN
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
3038 // Get final address
3040 if (OPERAND1_INDIRECT (Operands
)) {
3041 Immed64
= (INT64
) (UINT64
) (UINTN
) VmReadMemN (VmPtr
, (UINTN
) (Immed64
+ Immed32
));
3046 // Now determine if external call, and then if relative or absolute
3048 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3050 // EBC call. Relative or absolute? If relative, then it's relative to the
3051 // start of the next instruction.
3053 if ((Operands
& OPERAND_M_RELATIVE_ADDR
) != 0) {
3054 VmPtr
->Ip
+= Immed64
+ Size
;
3056 VmPtr
->Ip
= (VMIP
) (UINTN
) Immed64
;
3060 // Native call. Relative or absolute?
3062 if ((Operands
& OPERAND_M_RELATIVE_ADDR
) != 0) {
3063 EbcLLCALLEX (VmPtr
, (UINTN
) (Immed64
+ VmPtr
->Ip
+ Size
), (UINTN
) VmPtr
->R
[0], FramePtr
, Size
);
3065 if ((VmPtr
->StopFlags
& STOPFLAG_BREAK_ON_CALLEX
) != 0) {
3069 EbcLLCALLEX (VmPtr
, (UINTN
) Immed64
, (UINTN
) VmPtr
->R
[0], FramePtr
, Size
);
3079 Execute the EBC RET instruction.
3084 @param VmPtr A pointer to a VM context.
3086 @retval EFI_SUCCESS The instruction is executed successfully.
3091 IN VM_CONTEXT
*VmPtr
3095 // If we're at the top of the stack, then simply set the done
3098 if (VmPtr
->StackRetAddr
== (UINT64
) VmPtr
->R
[0]) {
3099 VmPtr
->StopFlags
|= STOPFLAG_APP_DONE
;
3102 // Pull the return address off the VM app's stack and set the IP
3105 if (!IS_ALIGNED ((UINTN
) VmPtr
->R
[0], sizeof (UINT16
))) {
3106 EbcDebugSignalException (
3107 EXCEPT_EBC_ALIGNMENT_CHECK
,
3108 EXCEPTION_FLAG_FATAL
,
3113 // Restore the IP and frame pointer from the stack
3115 VmPtr
->Ip
= (VMIP
) (UINTN
) VmReadMem64 (VmPtr
, (UINTN
) VmPtr
->R
[0]);
3117 VmPtr
->FramePtr
= (VOID
*) VmReadMemN (VmPtr
, (UINTN
) VmPtr
->R
[0]);
3126 Execute the EBC CMP instruction.
3129 CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
3131 @param VmPtr A pointer to a VM context.
3133 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
3134 @retval EFI_SUCCESS The instruction is executed successfully.
3139 IN VM_CONTEXT
*VmPtr
3151 // Get opcode and operands
3153 Opcode
= GETOPCODE (VmPtr
);
3154 Operands
= GETOPERANDS (VmPtr
);
3156 // Get the register data we're going to compare to
3158 Op1
= VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
3160 // Get immediate data
3162 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
3163 if (OPERAND2_INDIRECT (Operands
)) {
3164 Index16
= VmReadIndex16 (VmPtr
, 2);
3166 Index16
= VmReadImmed16 (VmPtr
, 2);
3177 if (OPERAND2_INDIRECT (Operands
)) {
3178 if ((Opcode
& OPCODE_M_64BIT
) != 0) {
3179 Op2
= (INT64
) VmReadMem64 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index16
));
3182 // 32-bit operations. 0-extend the values for all cases.
3184 Op2
= (INT64
) (UINT64
) ((UINT32
) VmReadMem32 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index16
)));
3187 Op2
= VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index16
;
3190 // Now do the compare
3193 if ((Opcode
& OPCODE_M_64BIT
) != 0) {
3197 switch (Opcode
& OPCODE_M_OPCODE
) {
3216 case OPCODE_CMPULTE
:
3217 if ((UINT64
) Op1
<= (UINT64
) Op2
) {
3222 case OPCODE_CMPUGTE
:
3223 if ((UINT64
) Op1
>= (UINT64
) Op2
) {
3235 switch (Opcode
& OPCODE_M_OPCODE
) {
3237 if ((INT32
) Op1
== (INT32
) Op2
) {
3243 if ((INT32
) Op1
<= (INT32
) Op2
) {
3249 if ((INT32
) Op1
>= (INT32
) Op2
) {
3254 case OPCODE_CMPULTE
:
3255 if ((UINT32
) Op1
<= (UINT32
) Op2
) {
3260 case OPCODE_CMPUGTE
:
3261 if ((UINT32
) Op1
>= (UINT32
) Op2
) {
3271 // Now set the flag accordingly for the comparison
3274 VMFLAG_SET (VmPtr
, VMFLAGS_CC
);
3276 VMFLAG_CLEAR (VmPtr
, VMFLAGS_CC
);
3287 Execute the EBC CMPI instruction
3290 CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
3292 @param VmPtr A pointer to a VM context.
3294 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
3295 @retval EFI_SUCCESS The instruction is executed successfully.
3300 IN VM_CONTEXT
*VmPtr
3312 // Get opcode and operands
3314 Opcode
= GETOPCODE (VmPtr
);
3315 Operands
= GETOPERANDS (VmPtr
);
3318 // Get operand1 index if present
3321 if ((Operands
& OPERAND_M_CMPI_INDEX
) != 0) {
3322 Index16
= VmReadIndex16 (VmPtr
, 2);
3328 // Get operand1 data we're going to compare to
3330 Op1
= (INT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
3331 if (OPERAND1_INDIRECT (Operands
)) {
3333 // Indirect operand1. Fetch 32 or 64-bit value based on compare size.
3335 if ((Opcode
& OPCODE_M_CMPI64
) != 0) {
3336 Op1
= (INT64
) VmReadMem64 (VmPtr
, (UINTN
) Op1
+ Index16
);
3338 Op1
= (INT64
) VmReadMem32 (VmPtr
, (UINTN
) Op1
+ Index16
);
3342 // Better not have been an index with direct. That is, CMPI R1 Index,...
3345 if ((Operands
& OPERAND_M_CMPI_INDEX
) != 0) {
3346 EbcDebugSignalException (
3347 EXCEPT_EBC_INSTRUCTION_ENCODING
,
3348 EXCEPTION_FLAG_ERROR
,
3352 return EFI_UNSUPPORTED
;
3356 // Get immediate data -- 16- or 32-bit sign extended
3358 if ((Opcode
& OPCODE_M_CMPI32_DATA
) != 0) {
3359 Op2
= (INT64
) VmReadImmed32 (VmPtr
, Size
);
3363 // 16-bit immediate data. Sign extend always.
3365 Op2
= (INT64
) ((INT16
) VmReadImmed16 (VmPtr
, Size
));
3369 // Now do the compare
3372 if ((Opcode
& OPCODE_M_CMPI64
) != 0) {
3374 // 64 bit comparison
3376 switch (Opcode
& OPCODE_M_OPCODE
) {
3378 if (Op1
== (INT64
) Op2
) {
3383 case OPCODE_CMPILTE
:
3384 if (Op1
<= (INT64
) Op2
) {
3389 case OPCODE_CMPIGTE
:
3390 if (Op1
>= (INT64
) Op2
) {
3395 case OPCODE_CMPIULTE
:
3396 if ((UINT64
) Op1
<= (UINT64
) ((UINT32
) Op2
)) {
3401 case OPCODE_CMPIUGTE
:
3402 if ((UINT64
) Op1
>= (UINT64
) ((UINT32
) Op2
)) {
3412 // 32-bit comparisons
3414 switch (Opcode
& OPCODE_M_OPCODE
) {
3416 if ((INT32
) Op1
== Op2
) {
3421 case OPCODE_CMPILTE
:
3422 if ((INT32
) Op1
<= Op2
) {
3427 case OPCODE_CMPIGTE
:
3428 if ((INT32
) Op1
>= Op2
) {
3433 case OPCODE_CMPIULTE
:
3434 if ((UINT32
) Op1
<= (UINT32
) Op2
) {
3439 case OPCODE_CMPIUGTE
:
3440 if ((UINT32
) Op1
>= (UINT32
) Op2
) {
3450 // Now set the flag accordingly for the comparison
3453 VMFLAG_SET (VmPtr
, VMFLAGS_CC
);
3455 VMFLAG_CLEAR (VmPtr
, VMFLAGS_CC
);
3466 Execute the EBC NOT instruction.s
3469 NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
3471 @param VmPtr A pointer to a VM context.
3472 @param Op1 Operand 1 from the instruction
3473 @param Op2 Operand 2 from the instruction
3480 IN VM_CONTEXT
*VmPtr
,
3490 Execute the EBC NEG instruction.
3493 NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
3495 @param VmPtr A pointer to a VM context.
3496 @param Op1 Operand 1 from the instruction
3497 @param Op2 Operand 2 from the instruction
3504 IN VM_CONTEXT
*VmPtr
,
3514 Execute the EBC ADD instruction.
3517 ADD[32|64] {@}R1, {@}R2 {Index16}
3519 @param VmPtr A pointer to a VM context.
3520 @param Op1 Operand 1 from the instruction
3521 @param Op2 Operand 2 from the instruction
3528 IN VM_CONTEXT
*VmPtr
,
3538 Execute the EBC SUB instruction.
3541 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3543 @param VmPtr A pointer to a VM context.
3544 @param Op1 Operand 1 from the instruction
3545 @param Op2 Operand 2 from the instruction
3552 IN VM_CONTEXT
*VmPtr
,
3557 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3558 return (UINT64
) ((INT64
) ((INT64
) Op1
- (INT64
) Op2
));
3560 return (UINT64
) ((INT64
) ((INT32
) Op1
- (INT32
) Op2
));
3566 Execute the EBC MUL instruction.
3569 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3571 @param VmPtr A pointer to a VM context.
3572 @param Op1 Operand 1 from the instruction
3573 @param Op2 Operand 2 from the instruction
3580 IN VM_CONTEXT
*VmPtr
,
3585 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3586 return MultS64x64 ((INT64
)Op1
, (INT64
)Op2
);
3588 return (UINT64
) ((INT64
) ((INT32
) Op1
* (INT32
) Op2
));
3594 Execute the EBC MULU instruction
3597 MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3599 @param VmPtr A pointer to a VM context.
3600 @param Op1 Operand 1 from the instruction
3601 @param Op2 Operand 2 from the instruction
3603 @return (unsigned)Op1 * (unsigned)Op2
3608 IN VM_CONTEXT
*VmPtr
,
3613 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3614 return MultU64x64 (Op1
, Op2
);
3616 return (UINT64
) ((UINT32
) Op1
* (UINT32
) Op2
);
3622 Execute the EBC DIV instruction.
3625 DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
3627 @param VmPtr A pointer to a VM context.
3628 @param Op1 Operand 1 from the instruction
3629 @param Op2 Operand 2 from the instruction
3636 IN VM_CONTEXT
*VmPtr
,
3644 // Check for divide-by-0
3647 EbcDebugSignalException (
3648 EXCEPT_EBC_DIVIDE_ERROR
,
3649 EXCEPTION_FLAG_FATAL
,
3655 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3656 return (UINT64
) (DivS64x64Remainder (Op1
, Op2
, &Remainder
));
3658 return (UINT64
) ((INT64
) ((INT32
) Op1
/ (INT32
) Op2
));
3665 Execute the EBC DIVU instruction
3668 DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3670 @param VmPtr A pointer to a VM context.
3671 @param Op1 Operand 1 from the instruction
3672 @param Op2 Operand 2 from the instruction
3674 @return (unsigned)Op1 / (unsigned)Op2
3679 IN VM_CONTEXT
*VmPtr
,
3687 // Check for divide-by-0
3690 EbcDebugSignalException (
3691 EXCEPT_EBC_DIVIDE_ERROR
,
3692 EXCEPTION_FLAG_FATAL
,
3698 // Get the destination register
3700 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3701 return (UINT64
) (DivU64x64Remainder ((INT64
)Op1
, (INT64
)Op2
, &Remainder
));
3703 return (UINT64
) ((UINT32
) Op1
/ (UINT32
) Op2
);
3710 Execute the EBC MOD instruction.
3713 MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
3715 @param VmPtr A pointer to a VM context.
3716 @param Op1 Operand 1 from the instruction
3717 @param Op2 Operand 2 from the instruction
3719 @return Op1 MODULUS Op2
3724 IN VM_CONTEXT
*VmPtr
,
3732 // Check for divide-by-0
3735 EbcDebugSignalException (
3736 EXCEPT_EBC_DIVIDE_ERROR
,
3737 EXCEPTION_FLAG_FATAL
,
3742 DivS64x64Remainder ((INT64
)Op1
, (INT64
)Op2
, &Remainder
);
3749 Execute the EBC MODU instruction.
3752 MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3754 @param VmPtr A pointer to a VM context.
3755 @param Op1 Operand 1 from the instruction
3756 @param Op2 Operand 2 from the instruction
3758 @return Op1 UNSIGNED_MODULUS Op2
3763 IN VM_CONTEXT
*VmPtr
,
3771 // Check for divide-by-0
3774 EbcDebugSignalException (
3775 EXCEPT_EBC_DIVIDE_ERROR
,
3776 EXCEPTION_FLAG_FATAL
,
3781 DivU64x64Remainder (Op1
, Op2
, &Remainder
);
3788 Execute the EBC AND instruction.
3791 AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
3793 @param VmPtr A pointer to a VM context.
3794 @param Op1 Operand 1 from the instruction
3795 @param Op2 Operand 2 from the instruction
3802 IN VM_CONTEXT
*VmPtr
,
3812 Execute the EBC OR instruction.
3815 OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3817 @param VmPtr A pointer to a VM context.
3818 @param Op1 Operand 1 from the instruction
3819 @param Op2 Operand 2 from the instruction
3826 IN VM_CONTEXT
*VmPtr
,
3836 Execute the EBC XOR instruction.
3839 XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3841 @param VmPtr A pointer to a VM context.
3842 @param Op1 Operand 1 from the instruction
3843 @param Op2 Operand 2 from the instruction
3850 IN VM_CONTEXT
*VmPtr
,
3860 Execute the EBC SHL shift left instruction.
3863 SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
3865 @param VmPtr A pointer to a VM context.
3866 @param Op1 Operand 1 from the instruction
3867 @param Op2 Operand 2 from the instruction
3874 IN VM_CONTEXT
*VmPtr
,
3879 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3880 return LShiftU64 (Op1
, (UINTN
)Op2
);
3882 return (UINT64
) ((UINT32
) ((UINT32
) Op1
<< (UINT32
) Op2
));
3888 Execute the EBC SHR instruction.
3891 SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3893 @param VmPtr A pointer to a VM context.
3894 @param Op1 Operand 1 from the instruction
3895 @param Op2 Operand 2 from the instruction
3897 @return Op1 >> Op2 (unsigned operands)
3902 IN VM_CONTEXT
*VmPtr
,
3907 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3908 return RShiftU64 (Op1
, (UINTN
)Op2
);
3910 return (UINT64
) ((UINT32
) Op1
>> (UINT32
) Op2
);
3916 Execute the EBC ASHR instruction.
3919 ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3921 @param VmPtr A pointer to a VM context.
3922 @param Op1 Operand 1 from the instruction
3923 @param Op2 Operand 2 from the instruction
3925 @return Op1 >> Op2 (signed)
3930 IN VM_CONTEXT
*VmPtr
,
3935 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3936 return ARShiftU64 (Op1
, (UINTN
)Op2
);
3938 return (UINT64
) ((INT64
) ((INT32
) Op1
>> (UINT32
) Op2
));
3944 Execute the EBC EXTNDB instruction to sign-extend a byte value.
3947 EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3949 @param VmPtr A pointer to a VM context.
3950 @param Op1 Operand 1 from the instruction
3951 @param Op2 Operand 2 from the instruction
3953 @return (INT64)(INT8)Op2
3958 IN VM_CONTEXT
*VmPtr
,
3966 // Convert to byte, then return as 64-bit signed value to let compiler
3967 // sign-extend the value
3970 Data64
= (INT64
) Data8
;
3972 return (UINT64
) Data64
;
3977 Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
3980 EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
3982 @param VmPtr A pointer to a VM context.
3983 @param Op1 Operand 1 from the instruction
3984 @param Op2 Operand 2 from the instruction
3986 @return (INT64)(INT16)Op2
3991 IN VM_CONTEXT
*VmPtr
,
3999 // Convert to word, then return as 64-bit signed value to let compiler
4000 // sign-extend the value
4002 Data16
= (INT16
) Op2
;
4003 Data64
= (INT64
) Data16
;
4005 return (UINT64
) Data64
;
4008 // Execute the EBC EXTNDD instruction.
4010 // Format: EXTNDD {@}Rx, {@}Ry [Index16|Immed16]
4011 // EXTNDD Dest, Source
4013 // Operation: Dest <- SignExtended((DWORD)Source))
4017 Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
4020 EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
4022 @param VmPtr A pointer to a VM context.
4023 @param Op1 Operand 1 from the instruction
4024 @param Op2 Operand 2 from the instruction
4026 @return (INT64)(INT32)Op2
4031 IN VM_CONTEXT
*VmPtr
,
4039 // Convert to 32-bit value, then return as 64-bit signed value to let compiler
4040 // sign-extend the value
4042 Data32
= (INT32
) Op2
;
4043 Data64
= (INT64
) Data32
;
4045 return (UINT64
) Data64
;
4050 Execute all the EBC signed data manipulation instructions.
4051 Since the EBC data manipulation instructions all have the same basic form,
4052 they can share the code that does the fetch of operands and the write-back
4053 of the result. This function performs the fetch of the operands (even if
4054 both are not needed to be fetched, like NOT instruction), dispatches to the
4055 appropriate subfunction, then writes back the returned result.
4058 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4060 @param VmPtr A pointer to VM context.
4062 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4063 @retval EFI_SUCCESS The instruction is executed successfully.
4067 ExecuteSignedDataManip (
4068 IN VM_CONTEXT
*VmPtr
4072 // Just call the data manipulation function with a flag indicating this
4073 // is a signed operation.
4075 return ExecuteDataManip (VmPtr
, TRUE
);
4080 Execute all the EBC unsigned data manipulation instructions.
4081 Since the EBC data manipulation instructions all have the same basic form,
4082 they can share the code that does the fetch of operands and the write-back
4083 of the result. This function performs the fetch of the operands (even if
4084 both are not needed to be fetched, like NOT instruction), dispatches to the
4085 appropriate subfunction, then writes back the returned result.
4088 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4090 @param VmPtr A pointer to VM context.
4092 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4093 @retval EFI_SUCCESS The instruction is executed successfully.
4097 ExecuteUnsignedDataManip (
4098 IN VM_CONTEXT
*VmPtr
4102 // Just call the data manipulation function with a flag indicating this
4103 // is not a signed operation.
4105 return ExecuteDataManip (VmPtr
, FALSE
);
4110 Execute all the EBC data manipulation instructions.
4111 Since the EBC data manipulation instructions all have the same basic form,
4112 they can share the code that does the fetch of operands and the write-back
4113 of the result. This function performs the fetch of the operands (even if
4114 both are not needed to be fetched, like NOT instruction), dispatches to the
4115 appropriate subfunction, then writes back the returned result.
4118 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4120 @param VmPtr A pointer to VM context.
4121 @param IsSignedOp Indicates whether the operand is signed or not.
4123 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4124 @retval EFI_SUCCESS The instruction is executed successfully.
4129 IN VM_CONTEXT
*VmPtr
,
4130 IN BOOLEAN IsSignedOp
4139 INTN DataManipDispatchTableIndex
;
4142 // Get opcode and operands
4144 Opcode
= GETOPCODE (VmPtr
);
4145 Operands
= GETOPERANDS (VmPtr
);
4148 // Determine if we have immediate data by the opcode
4150 if ((Opcode
& DATAMANIP_M_IMMDATA
) != 0) {
4152 // Index16 if Ry is indirect, or Immed16 if Ry direct.
4154 if (OPERAND2_INDIRECT (Operands
)) {
4155 Index16
= VmReadIndex16 (VmPtr
, 2);
4157 Index16
= VmReadImmed16 (VmPtr
, 2);
4166 // Now get operand2 (source). It's of format {@}R2 {Index16|Immed16}
4168 Op2
= (UINT64
) VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index16
;
4169 if (OPERAND2_INDIRECT (Operands
)) {
4171 // Indirect form: @R2 Index16. Fetch as 32- or 64-bit data
4173 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4174 Op2
= VmReadMem64 (VmPtr
, (UINTN
) Op2
);
4177 // Read as signed value where appropriate.
4180 Op2
= (UINT64
) (INT64
) ((INT32
) VmReadMem32 (VmPtr
, (UINTN
) Op2
));
4182 Op2
= (UINT64
) VmReadMem32 (VmPtr
, (UINTN
) Op2
);
4186 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4188 Op2
= (UINT64
) (INT64
) ((INT32
) Op2
);
4190 Op2
= (UINT64
) ((UINT32
) Op2
);
4195 // Get operand1 (destination and sometimes also an actual operand)
4198 Op1
= VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
4199 if (OPERAND1_INDIRECT (Operands
)) {
4200 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4201 Op1
= VmReadMem64 (VmPtr
, (UINTN
) Op1
);
4204 Op1
= (UINT64
) (INT64
) ((INT32
) VmReadMem32 (VmPtr
, (UINTN
) Op1
));
4206 Op1
= (UINT64
) VmReadMem32 (VmPtr
, (UINTN
) Op1
);
4210 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4212 Op1
= (UINT64
) (INT64
) ((INT32
) Op1
);
4214 Op1
= (UINT64
) ((UINT32
) Op1
);
4219 // Dispatch to the computation function
4221 DataManipDispatchTableIndex
= (Opcode
& OPCODE_M_OPCODE
) - OPCODE_NOT
;
4222 if ((DataManipDispatchTableIndex
< 0) ||
4223 (DataManipDispatchTableIndex
>= sizeof (mDataManipDispatchTable
) / sizeof (mDataManipDispatchTable
[0]))) {
4224 EbcDebugSignalException (
4225 EXCEPT_EBC_INVALID_OPCODE
,
4226 EXCEPTION_FLAG_ERROR
,
4230 // Advance and return
4233 return EFI_UNSUPPORTED
;
4235 Op2
= mDataManipDispatchTable
[DataManipDispatchTableIndex
](VmPtr
, Op1
, Op2
);
4238 // Write back the result.
4240 if (OPERAND1_INDIRECT (Operands
)) {
4241 Op1
= VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
4242 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4243 VmWriteMem64 (VmPtr
, (UINTN
) Op1
, Op2
);
4245 VmWriteMem32 (VmPtr
, (UINTN
) Op1
, (UINT32
) Op2
);
4249 // Storage back to a register. Write back, clearing upper bits (as per
4250 // the specification) if 32-bit operation.
4252 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Op2
;
4253 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4254 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] &= 0xFFFFFFFF;
4258 // Advance the instruction pointer
4266 Execute the EBC LOADSP instruction.
4271 @param VmPtr A pointer to a VM context.
4273 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4274 @retval EFI_SUCCESS The instruction is executed successfully.
4279 IN VM_CONTEXT
*VmPtr
4287 Operands
= GETOPERANDS (VmPtr
);
4292 switch (OPERAND1_REGNUM (Operands
)) {
4298 // Spec states that this instruction will not modify reserved bits in
4299 // the flags register.
4301 VmPtr
->Flags
= (VmPtr
->Flags
&~VMFLAGS_ALL_VALID
) | (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] & VMFLAGS_ALL_VALID
);
4305 EbcDebugSignalException (
4306 EXCEPT_EBC_INSTRUCTION_ENCODING
,
4307 EXCEPTION_FLAG_WARNING
,
4311 return EFI_UNSUPPORTED
;
4320 Execute the EBC STORESP instruction.
4323 STORESP Rx, FLAGS|IP
4325 @param VmPtr A pointer to a VM context.
4327 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4328 @retval EFI_SUCCESS The instruction is executed successfully.
4333 IN VM_CONTEXT
*VmPtr
4341 Operands
= GETOPERANDS (VmPtr
);
4346 switch (OPERAND2_REGNUM (Operands
)) {
4352 // Retrieve the value in the flags register, then clear reserved bits
4354 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (UINT64
) (VmPtr
->Flags
& VMFLAGS_ALL_VALID
);
4358 // Get IP -- address of following instruction
4361 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (UINT64
) (UINTN
) VmPtr
->Ip
+ 2;
4365 EbcDebugSignalException (
4366 EXCEPT_EBC_INSTRUCTION_ENCODING
,
4367 EXCEPTION_FLAG_WARNING
,
4371 return EFI_UNSUPPORTED
;
4381 Decode a 16-bit index to determine the offset. Given an index value:
4384 b14:12 - number of bits in this index assigned to natural units (=a)
4385 ba:11 - constant units = ConstUnits
4386 b0:a - natural units = NaturalUnits
4388 Given this info, the offset can be computed by:
4389 offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
4391 Max offset is achieved with index = 0x7FFF giving an offset of
4392 0x27B (32-bit machine) or 0x477 (64-bit machine).
4393 Min offset is achieved with index =
4395 @param VmPtr A pointer to VM context.
4396 @param CodeOffset Offset from IP of the location of the 16-bit index
4399 @return The decoded offset.
4404 IN VM_CONTEXT
*VmPtr
,
4405 IN UINT32 CodeOffset
4416 // First read the index from the code stream
4418 Index
= VmReadCode16 (VmPtr
, CodeOffset
);
4421 // Get the mask for NaturalUnits. First get the number of bits from the index.
4423 NBits
= (INT16
) ((Index
& 0x7000) >> 12);
4426 // Scale it for 16-bit indexes
4431 // Now using the number of bits, create a mask.
4433 Mask
= (INT16
) ((INT16
)~0 << NBits
);
4436 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4438 NaturalUnits
= (INT16
) (Index
&~Mask
);
4441 // Now compute ConstUnits
4443 ConstUnits
= (INT16
) (((Index
&~0xF000) & Mask
) >> NBits
);
4445 Offset
= (INT16
) (NaturalUnits
* sizeof (UINTN
) + ConstUnits
);
4450 if ((Index
& 0x8000) != 0) {
4452 // Do it the hard way to work around a bogus compiler warning
4454 // Offset = -1 * Offset;
4456 Offset
= (INT16
) ((INT32
) Offset
* -1);
4464 Decode a 32-bit index to determine the offset.
4466 @param VmPtr A pointer to VM context.
4467 @param CodeOffset Offset from IP of the location of the 32-bit index
4470 @return Converted index per EBC VM specification.
4475 IN VM_CONTEXT
*VmPtr
,
4476 IN UINT32 CodeOffset
4486 Index
= VmReadImmed32 (VmPtr
, CodeOffset
);
4489 // Get the mask for NaturalUnits. First get the number of bits from the index.
4491 NBits
= (Index
& 0x70000000) >> 28;
4494 // Scale it for 32-bit indexes
4499 // Now using the number of bits, create a mask.
4501 Mask
= (INT32
)~0 << NBits
;
4504 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4506 NaturalUnits
= Index
&~Mask
;
4509 // Now compute ConstUnits
4511 ConstUnits
= ((Index
&~0xF0000000) & Mask
) >> NBits
;
4513 Offset
= NaturalUnits
* sizeof (UINTN
) + ConstUnits
;
4518 if ((Index
& 0x80000000) != 0) {
4519 Offset
= Offset
* -1;
4527 Decode a 64-bit index to determine the offset.
4529 @param VmPtr A pointer to VM context.s
4530 @param CodeOffset Offset from IP of the location of the 64-bit index
4533 @return Converted index per EBC VM specification
4538 IN VM_CONTEXT
*VmPtr
,
4539 IN UINT32 CodeOffset
4549 Index
= VmReadCode64 (VmPtr
, CodeOffset
);
4552 // Get the mask for NaturalUnits. First get the number of bits from the index.
4554 NBits
= RShiftU64 ((Index
& 0x7000000000000000ULL
), 60);
4557 // Scale it for 64-bit indexes (multiply by 8 by shifting left 3)
4559 NBits
= LShiftU64 ((UINT64
)NBits
, 3);
4562 // Now using the number of bits, create a mask.
4564 Mask
= (LShiftU64 ((UINT64
)~0, (UINTN
)NBits
));
4567 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4569 NaturalUnits
= Index
&~Mask
;
4572 // Now compute ConstUnits
4574 ConstUnits
= ARShiftU64 (((Index
&~0xF000000000000000ULL
) & Mask
), (UINTN
)NBits
);
4576 Offset
= MultU64x64 (NaturalUnits
, sizeof (UINTN
)) + ConstUnits
;
4581 if ((Index
& 0x8000000000000000ULL
) != 0) {
4582 Offset
= MultS64x64 (Offset
, -1);
4590 Writes 8-bit data to memory address.
4592 This routine is called by the EBC data
4593 movement instructions that write to memory. Since these writes
4594 may be to the stack, which looks like (high address on top) this,
4596 [EBC entry point arguments]
4600 we need to detect all attempts to write to the EBC entry point argument
4601 stack area and adjust the address (which will initially point into the
4602 VM stack) to point into the EBC entry point arguments.
4604 @param VmPtr A pointer to a VM context.
4605 @param Addr Address to write to.
4606 @param Data Value to write to Addr.
4608 @retval EFI_SUCCESS The instruction is executed successfully.
4609 @retval Other Some error occurs when writing data to the address.
4614 IN VM_CONTEXT
*VmPtr
,
4620 // Convert the address if it's in the stack gap
4622 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4623 *(UINT8
*) Addr
= Data
;
4628 Writes 16-bit data to memory address.
4630 This routine is called by the EBC data
4631 movement instructions that write to memory. Since these writes
4632 may be to the stack, which looks like (high address on top) this,
4634 [EBC entry point arguments]
4638 we need to detect all attempts to write to the EBC entry point argument
4639 stack area and adjust the address (which will initially point into the
4640 VM stack) to point into the EBC entry point arguments.
4642 @param VmPtr A pointer to a VM context.
4643 @param Addr Address to write to.
4644 @param Data Value to write to Addr.
4646 @retval EFI_SUCCESS The instruction is executed successfully.
4647 @retval Other Some error occurs when writing data to the address.
4652 IN VM_CONTEXT
*VmPtr
,
4660 // Convert the address if it's in the stack gap
4662 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4665 // Do a simple write if aligned
4667 if (IS_ALIGNED (Addr
, sizeof (UINT16
))) {
4668 *(UINT16
*) Addr
= Data
;
4671 // Write as two bytes
4674 if ((Status
= VmWriteMem8 (VmPtr
, Addr
, (UINT8
) Data
)) != EFI_SUCCESS
) {
4679 if ((Status
= VmWriteMem8 (VmPtr
, Addr
+ 1, (UINT8
) (Data
>> 8))) != EFI_SUCCESS
) {
4691 Writes 32-bit data to memory address.
4693 This routine is called by the EBC data
4694 movement instructions that write to memory. Since these writes
4695 may be to the stack, which looks like (high address on top) this,
4697 [EBC entry point arguments]
4701 we need to detect all attempts to write to the EBC entry point argument
4702 stack area and adjust the address (which will initially point into the
4703 VM stack) to point into the EBC entry point arguments.
4705 @param VmPtr A pointer to a VM context.
4706 @param Addr Address to write to.
4707 @param Data Value to write to Addr.
4709 @retval EFI_SUCCESS The instruction is executed successfully.
4710 @retval Other Some error occurs when writing data to the address.
4715 IN VM_CONTEXT
*VmPtr
,
4723 // Convert the address if it's in the stack gap
4725 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4728 // Do a simple write if aligned
4730 if (IS_ALIGNED (Addr
, sizeof (UINT32
))) {
4731 *(UINT32
*) Addr
= Data
;
4734 // Write as two words
4737 if ((Status
= VmWriteMem16 (VmPtr
, Addr
, (UINT16
) Data
)) != EFI_SUCCESS
) {
4742 if ((Status
= VmWriteMem16 (VmPtr
, Addr
+ sizeof (UINT16
), (UINT16
) (Data
>> 16))) != EFI_SUCCESS
) {
4754 Writes 64-bit data to memory address.
4756 This routine is called by the EBC data
4757 movement instructions that write to memory. Since these writes
4758 may be to the stack, which looks like (high address on top) this,
4760 [EBC entry point arguments]
4764 we need to detect all attempts to write to the EBC entry point argument
4765 stack area and adjust the address (which will initially point into the
4766 VM stack) to point into the EBC entry point arguments.
4768 @param VmPtr A pointer to a VM context.
4769 @param Addr Address to write to.
4770 @param Data Value to write to Addr.
4772 @retval EFI_SUCCESS The instruction is executed successfully.
4773 @retval Other Some error occurs when writing data to the address.
4778 IN VM_CONTEXT
*VmPtr
,
4787 // Convert the address if it's in the stack gap
4789 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4792 // Do a simple write if aligned
4794 if (IS_ALIGNED (Addr
, sizeof (UINT64
))) {
4795 *(UINT64
*) Addr
= Data
;
4798 // Write as two 32-bit words
4801 if ((Status
= VmWriteMem32 (VmPtr
, Addr
, (UINT32
) Data
)) != EFI_SUCCESS
) {
4806 Data32
= (UINT32
) (((UINT32
*) &Data
)[1]);
4807 if ((Status
= VmWriteMem32 (VmPtr
, Addr
+ sizeof (UINT32
), Data32
)) != EFI_SUCCESS
) {
4819 Writes UINTN data to memory address.
4821 This routine is called by the EBC data
4822 movement instructions that write to memory. Since these writes
4823 may be to the stack, which looks like (high address on top) this,
4825 [EBC entry point arguments]
4829 we need to detect all attempts to write to the EBC entry point argument
4830 stack area and adjust the address (which will initially point into the
4831 VM stack) to point into the EBC entry point arguments.
4833 @param VmPtr A pointer to a VM context.
4834 @param Addr Address to write to.
4835 @param Data Value to write to Addr.
4837 @retval EFI_SUCCESS The instruction is executed successfully.
4838 @retval Other Some error occurs when writing data to the address.
4843 IN VM_CONTEXT
*VmPtr
,
4851 Status
= EFI_SUCCESS
;
4854 // Convert the address if it's in the stack gap
4856 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4859 // Do a simple write if aligned
4861 if (IS_ALIGNED (Addr
, sizeof (UINTN
))) {
4862 *(UINTN
*) Addr
= Data
;
4864 for (Index
= 0; Index
< sizeof (UINTN
) / sizeof (UINT32
); Index
++) {
4866 Status
= VmWriteMem32 (VmPtr
, Addr
+ Index
* sizeof (UINT32
), (UINT32
) Data
);
4868 Data
= (UINTN
) RShiftU64 ((UINT64
)Data
, 32);
4877 Reads 8-bit immediate value at the offset.
4879 This routine is called by the EBC execute
4880 functions to read EBC immediate values from the code stream.
4881 Since we can't assume alignment, each tries to read in the biggest
4882 chunks size available, but will revert to smaller reads if necessary.
4884 @param VmPtr A pointer to a VM context.
4885 @param Offset offset from IP of the code bytes to read.
4887 @return Signed data of the requested size from the specified address.
4892 IN VM_CONTEXT
*VmPtr
,
4897 // Simply return the data in flat memory space
4899 return * (INT8
*) (VmPtr
->Ip
+ Offset
);
4903 Reads 16-bit immediate value at the offset.
4905 This routine is called by the EBC execute
4906 functions to read EBC immediate values from the code stream.
4907 Since we can't assume alignment, each tries to read in the biggest
4908 chunks size available, but will revert to smaller reads if necessary.
4910 @param VmPtr A pointer to a VM context.
4911 @param Offset offset from IP of the code bytes to read.
4913 @return Signed data of the requested size from the specified address.
4918 IN VM_CONTEXT
*VmPtr
,
4923 // Read direct if aligned
4925 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (INT16
))) {
4926 return * (INT16
*) (VmPtr
->Ip
+ Offset
);
4929 // All code word reads should be aligned
4931 EbcDebugSignalException (
4932 EXCEPT_EBC_ALIGNMENT_CHECK
,
4933 EXCEPTION_FLAG_WARNING
,
4938 // Return unaligned data
4940 return (INT16
) (*(UINT8
*) (VmPtr
->Ip
+ Offset
) + (*(UINT8
*) (VmPtr
->Ip
+ Offset
+ 1) << 8));
4945 Reads 32-bit immediate value at the offset.
4947 This routine is called by the EBC execute
4948 functions to read EBC immediate values from the code stream.
4949 Since we can't assume alignment, each tries to read in the biggest
4950 chunks size available, but will revert to smaller reads if necessary.
4952 @param VmPtr A pointer to a VM context.
4953 @param Offset offset from IP of the code bytes to read.
4955 @return Signed data of the requested size from the specified address.
4960 IN VM_CONTEXT
*VmPtr
,
4967 // Read direct if aligned
4969 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT32
))) {
4970 return * (INT32
*) (VmPtr
->Ip
+ Offset
);
4973 // Return unaligned data
4975 Data
= (UINT32
) VmReadCode16 (VmPtr
, Offset
);
4976 Data
|= (UINT32
)(VmReadCode16 (VmPtr
, Offset
+ 2) << 16);
4982 Reads 64-bit immediate value at the offset.
4984 This routine is called by the EBC execute
4985 functions to read EBC immediate values from the code stream.
4986 Since we can't assume alignment, each tries to read in the biggest
4987 chunks size available, but will revert to smaller reads if necessary.
4989 @param VmPtr A pointer to a VM context.
4990 @param Offset offset from IP of the code bytes to read.
4992 @return Signed data of the requested size from the specified address.
4997 IN VM_CONTEXT
*VmPtr
,
5006 // Read direct if aligned
5008 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT64
))) {
5009 return * (UINT64
*) (VmPtr
->Ip
+ Offset
);
5012 // Return unaligned data.
5014 Ptr
= (UINT8
*) &Data64
;
5015 Data32
= VmReadCode32 (VmPtr
, Offset
);
5016 *(UINT32
*) Ptr
= Data32
;
5017 Ptr
+= sizeof (Data32
);
5018 Data32
= VmReadCode32 (VmPtr
, Offset
+ sizeof (UINT32
));
5019 *(UINT32
*) Ptr
= Data32
;
5025 Reads 16-bit unsigned data from the code stream.
5027 This routine provides the ability to read raw unsigned data from the code
5030 @param VmPtr A pointer to VM context
5031 @param Offset Offset from current IP to the raw data to read.
5033 @return The raw unsigned 16-bit value from the code stream.
5038 IN VM_CONTEXT
*VmPtr
,
5043 // Read direct if aligned
5045 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT16
))) {
5046 return * (UINT16
*) (VmPtr
->Ip
+ Offset
);
5049 // All code word reads should be aligned
5051 EbcDebugSignalException (
5052 EXCEPT_EBC_ALIGNMENT_CHECK
,
5053 EXCEPTION_FLAG_WARNING
,
5058 // Return unaligned data
5060 return (UINT16
) (*(UINT8
*) (VmPtr
->Ip
+ Offset
) + (*(UINT8
*) (VmPtr
->Ip
+ Offset
+ 1) << 8));
5065 Reads 32-bit unsigned data from the code stream.
5067 This routine provides the ability to read raw unsigned data from the code
5070 @param VmPtr A pointer to VM context
5071 @param Offset Offset from current IP to the raw data to read.
5073 @return The raw unsigned 32-bit value from the code stream.
5078 IN VM_CONTEXT
*VmPtr
,
5084 // Read direct if aligned
5086 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT32
))) {
5087 return * (UINT32
*) (VmPtr
->Ip
+ Offset
);
5090 // Return unaligned data
5092 Data
= (UINT32
) VmReadCode16 (VmPtr
, Offset
);
5093 Data
|= (VmReadCode16 (VmPtr
, Offset
+ 2) << 16);
5099 Reads 64-bit unsigned data from the code stream.
5101 This routine provides the ability to read raw unsigned data from the code
5104 @param VmPtr A pointer to VM context
5105 @param Offset Offset from current IP to the raw data to read.
5107 @return The raw unsigned 64-bit value from the code stream.
5112 IN VM_CONTEXT
*VmPtr
,
5121 // Read direct if aligned
5123 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT64
))) {
5124 return * (UINT64
*) (VmPtr
->Ip
+ Offset
);
5127 // Return unaligned data.
5129 Ptr
= (UINT8
*) &Data64
;
5130 Data32
= VmReadCode32 (VmPtr
, Offset
);
5131 *(UINT32
*) Ptr
= Data32
;
5132 Ptr
+= sizeof (Data32
);
5133 Data32
= VmReadCode32 (VmPtr
, Offset
+ sizeof (UINT32
));
5134 *(UINT32
*) Ptr
= Data32
;
5140 Reads 8-bit data form the memory address.
5142 @param VmPtr A pointer to VM context.
5143 @param Addr The memory address.
5145 @return The 8-bit value from the memory address.
5150 IN VM_CONTEXT
*VmPtr
,
5155 // Convert the address if it's in the stack gap
5157 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5159 // Simply return the data in flat memory space
5161 return * (UINT8
*) Addr
;
5165 Reads 16-bit data form the memory address.
5167 @param VmPtr A pointer to VM context.
5168 @param Addr The memory address.
5170 @return The 16-bit value from the memory address.
5175 IN VM_CONTEXT
*VmPtr
,
5180 // Convert the address if it's in the stack gap
5182 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5184 // Read direct if aligned
5186 if (IS_ALIGNED (Addr
, sizeof (UINT16
))) {
5187 return * (UINT16
*) Addr
;
5190 // Return unaligned data
5192 return (UINT16
) (*(UINT8
*) Addr
+ (*(UINT8
*) (Addr
+ 1) << 8));
5196 Reads 32-bit data form the memory address.
5198 @param VmPtr A pointer to VM context.
5199 @param Addr The memory address.
5201 @return The 32-bit value from the memory address.
5206 IN VM_CONTEXT
*VmPtr
,
5213 // Convert the address if it's in the stack gap
5215 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5217 // Read direct if aligned
5219 if (IS_ALIGNED (Addr
, sizeof (UINT32
))) {
5220 return * (UINT32
*) Addr
;
5223 // Return unaligned data
5225 Data
= (UINT32
) VmReadMem16 (VmPtr
, Addr
);
5226 Data
|= (VmReadMem16 (VmPtr
, Addr
+ 2) << 16);
5231 Reads 64-bit data form the memory address.
5233 @param VmPtr A pointer to VM context.
5234 @param Addr The memory address.
5236 @return The 64-bit value from the memory address.
5241 IN VM_CONTEXT
*VmPtr
,
5249 // Convert the address if it's in the stack gap
5251 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5254 // Read direct if aligned
5256 if (IS_ALIGNED (Addr
, sizeof (UINT64
))) {
5257 return * (UINT64
*) Addr
;
5260 // Return unaligned data. Assume little endian.
5262 Data
= (UINT64
) VmReadMem32 (VmPtr
, Addr
);
5263 Data32
= VmReadMem32 (VmPtr
, Addr
+ sizeof (UINT32
));
5264 *(UINT32
*) ((UINT32
*) &Data
+ 1) = Data32
;
5270 Given an address that EBC is going to read from or write to, return
5271 an appropriate address that accounts for a gap in the stack.
5272 The stack for this application looks like this (high addr on top)
5273 [EBC entry point arguments]
5276 The EBC assumes that its arguments are at the top of its stack, which
5277 is where the VM stack is really. Therefore if the EBC does memory
5278 accesses into the VM stack area, then we need to convert the address
5279 to point to the EBC entry point arguments area. Do this here.
5281 @param VmPtr A Pointer to VM context.
5282 @param Addr Address of interest
5284 @return The unchanged address if it's not in the VM stack region. Otherwise,
5285 adjust for the stack gap and return the modified address.
5290 IN VM_CONTEXT
*VmPtr
,
5294 ASSERT(((Addr
< VmPtr
->LowStackTop
) || (Addr
> VmPtr
->HighStackBottom
)));
5300 Read a natural value from memory. May or may not be aligned.
5302 @param VmPtr current VM context
5303 @param Addr the address to read from
5305 @return The natural value at address Addr.
5310 IN VM_CONTEXT
*VmPtr
,
5315 volatile UINT32 Size
;
5319 // Convert the address if it's in the stack gap
5321 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5323 // Read direct if aligned
5325 if (IS_ALIGNED (Addr
, sizeof (UINTN
))) {
5326 return * (UINTN
*) Addr
;
5329 // Return unaligned data
5332 FromPtr
= (UINT8
*) Addr
;
5333 ToPtr
= (UINT8
*) &Data
;
5335 for (Size
= 0; Size
< sizeof (Data
); Size
++) {
5345 Returns the version of the EBC virtual machine.
5347 @return The 64-bit version of EBC virtual machine.
5355 return (UINT64
) (((VM_MAJOR_VERSION
& 0xFFFF) << 16) | ((VM_MINOR_VERSION
& 0xFFFF)));