2 Contains code that implements the virtual machine.
4 Copyright (c) 2006 - 2008, Intel Corporation. <BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "EbcExecute.h"
20 // Define some useful data size constants to allow switch statements based on
21 // size of operands or data.
23 #define DATA_SIZE_INVALID 0
25 #define DATA_SIZE_16 2
26 #define DATA_SIZE_32 4
27 #define DATA_SIZE_64 8
28 #define DATA_SIZE_N 48 // 4 or 8
30 // Structure we'll use to dispatch opcodes to execute functions.
33 EFI_STATUS (*ExecuteFunction
) (IN VM_CONTEXT
* VmPtr
);
39 (*DATA_MANIP_EXEC_FUNCTION
) (
40 IN VM_CONTEXT
* VmPtr
,
46 Decode a 16-bit index to determine the offset. Given an index value:
49 b14:12 - number of bits in this index assigned to natural units (=a)
50 ba:11 - constant units = ConstUnits
51 b0:a - natural units = NaturalUnits
53 Given this info, the offset can be computed by:
54 offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
56 Max offset is achieved with index = 0x7FFF giving an offset of
57 0x27B (32-bit machine) or 0x477 (64-bit machine).
58 Min offset is achieved with index =
60 @param VmPtr A pointer to VM context.
61 @param CodeOffset Offset from IP of the location of the 16-bit index
64 @return The decoded offset.
74 Decode a 32-bit index to determine the offset.
76 @param VmPtr A pointer to VM context.
77 @param CodeOffset Offset from IP of the location of the 32-bit index
80 @return Converted index per EBC VM specification.
90 Decode a 64-bit index to determine the offset.
92 @param VmPtr A pointer to VM context.s
93 @param CodeOffset Offset from IP of the location of the 64-bit index
96 @return Converted index per EBC VM specification
101 IN VM_CONTEXT
*VmPtr
,
106 Reads 8-bit data form the memory address.
108 @param VmPtr A pointer to VM context.
109 @param Addr The memory address.
111 @return The 8-bit value from the memory address.
116 IN VM_CONTEXT
*VmPtr
,
121 Reads 16-bit data form the memory address.
123 @param VmPtr A pointer to VM context.
124 @param Addr The memory address.
126 @return The 16-bit value from the memory address.
131 IN VM_CONTEXT
*VmPtr
,
136 Reads 32-bit data form the memory address.
138 @param VmPtr A pointer to VM context.
139 @param Addr The memory address.
141 @return The 32-bit value from the memory address.
146 IN VM_CONTEXT
*VmPtr
,
151 Reads 64-bit data form the memory address.
153 @param VmPtr A pointer to VM context.
154 @param Addr The memory address.
156 @return The 64-bit value from the memory address.
161 IN VM_CONTEXT
*VmPtr
,
166 Read a natural value from memory. May or may not be aligned.
168 @param VmPtr current VM context
169 @param Addr the address to read from
171 @return The natural value at address Addr.
176 IN VM_CONTEXT
*VmPtr
,
181 Writes 8-bit data to memory address.
183 This routine is called by the EBC data
184 movement instructions that write to memory. Since these writes
185 may be to the stack, which looks like (high address on top) this,
187 [EBC entry point arguments]
191 we need to detect all attempts to write to the EBC entry point argument
192 stack area and adjust the address (which will initially point into the
193 VM stack) to point into the EBC entry point arguments.
195 @param VmPtr A pointer to a VM context.
196 @param Addr Address to write to.
197 @param Data Value to write to Addr.
199 @retval EFI_SUCCESS The instruction is executed successfully.
200 @retval Other Some error occurs when writing data to the address.
205 IN VM_CONTEXT
*VmPtr
,
211 Writes 16-bit data to memory address.
213 This routine is called by the EBC data
214 movement instructions that write to memory. Since these writes
215 may be to the stack, which looks like (high address on top) this,
217 [EBC entry point arguments]
221 we need to detect all attempts to write to the EBC entry point argument
222 stack area and adjust the address (which will initially point into the
223 VM stack) to point into the EBC entry point arguments.
225 @param VmPtr A pointer to a VM context.
226 @param Addr Address to write to.
227 @param Data Value to write to Addr.
229 @retval EFI_SUCCESS The instruction is executed successfully.
230 @retval Other Some error occurs when writing data to the address.
235 IN VM_CONTEXT
*VmPtr
,
241 Writes 32-bit data to memory address.
243 This routine is called by the EBC data
244 movement instructions that write to memory. Since these writes
245 may be to the stack, which looks like (high address on top) this,
247 [EBC entry point arguments]
251 we need to detect all attempts to write to the EBC entry point argument
252 stack area and adjust the address (which will initially point into the
253 VM stack) to point into the EBC entry point arguments.
255 @param VmPtr A pointer to a VM context.
256 @param Addr Address to write to.
257 @param Data Value to write to Addr.
259 @retval EFI_SUCCESS The instruction is executed successfully.
260 @retval Other Some error occurs when writing data to the address.
265 IN VM_CONTEXT
*VmPtr
,
271 Reads 16-bit unsigned data from the code stream.
273 This routine provides the ability to read raw unsigned data from the code
276 @param VmPtr A pointer to VM context
277 @param Offset Offset from current IP to the raw data to read.
279 @return The raw unsigned 16-bit value from the code stream.
284 IN VM_CONTEXT
*VmPtr
,
289 Reads 32-bit unsigned data from the code stream.
291 This routine provides the ability to read raw unsigned data from the code
294 @param VmPtr A pointer to VM context
295 @param Offset Offset from current IP to the raw data to read.
297 @return The raw unsigned 32-bit value from the code stream.
302 IN VM_CONTEXT
*VmPtr
,
307 Reads 64-bit unsigned data from the code stream.
309 This routine provides the ability to read raw unsigned data from the code
312 @param VmPtr A pointer to VM context
313 @param Offset Offset from current IP to the raw data to read.
315 @return The raw unsigned 64-bit value from the code stream.
320 IN VM_CONTEXT
*VmPtr
,
325 Reads 8-bit immediate value at the offset.
327 This routine is called by the EBC execute
328 functions to read EBC immediate values from the code stream.
329 Since we can't assume alignment, each tries to read in the biggest
330 chunks size available, but will revert to smaller reads if necessary.
332 @param VmPtr A pointer to a VM context.
333 @param Offset offset from IP of the code bytes to read.
335 @return Signed data of the requested size from the specified address.
340 IN VM_CONTEXT
*VmPtr
,
345 Reads 16-bit immediate value at the offset.
347 This routine is called by the EBC execute
348 functions to read EBC immediate values from the code stream.
349 Since we can't assume alignment, each tries to read in the biggest
350 chunks size available, but will revert to smaller reads if necessary.
352 @param VmPtr A pointer to a VM context.
353 @param Offset offset from IP of the code bytes to read.
355 @return Signed data of the requested size from the specified address.
360 IN VM_CONTEXT
*VmPtr
,
365 Reads 32-bit immediate value at the offset.
367 This routine is called by the EBC execute
368 functions to read EBC immediate values from the code stream.
369 Since we can't assume alignment, each tries to read in the biggest
370 chunks size available, but will revert to smaller reads if necessary.
372 @param VmPtr A pointer to a VM context.
373 @param Offset offset from IP of the code bytes to read.
375 @return Signed data of the requested size from the specified address.
380 IN VM_CONTEXT
*VmPtr
,
385 Reads 64-bit immediate value at the offset.
387 This routine is called by the EBC execute
388 functions to read EBC immediate values from the code stream.
389 Since we can't assume alignment, each tries to read in the biggest
390 chunks size available, but will revert to smaller reads if necessary.
392 @param VmPtr A pointer to a VM context.
393 @param Offset offset from IP of the code bytes to read.
395 @return Signed data of the requested size from the specified address.
400 IN VM_CONTEXT
*VmPtr
,
405 Given an address that EBC is going to read from or write to, return
406 an appropriate address that accounts for a gap in the stack.
407 The stack for this application looks like this (high addr on top)
408 [EBC entry point arguments]
411 The EBC assumes that its arguments are at the top of its stack, which
412 is where the VM stack is really. Therefore if the EBC does memory
413 accesses into the VM stack area, then we need to convert the address
414 to point to the EBC entry point arguments area. Do this here.
416 @param VmPtr A Pointer to VM context.
417 @param Addr Address of interest
419 @return The unchanged address if it's not in the VM stack region. Otherwise,
420 adjust for the stack gap and return the modified address.
425 IN VM_CONTEXT
*VmPtr
,
430 Execute all the EBC data manipulation instructions.
431 Since the EBC data manipulation instructions all have the same basic form,
432 they can share the code that does the fetch of operands and the write-back
433 of the result. This function performs the fetch of the operands (even if
434 both are not needed to be fetched, like NOT instruction), dispatches to the
435 appropriate subfunction, then writes back the returned result.
438 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
440 @param VmPtr A pointer to VM context.
441 @param IsSignedOp Indicates whether the operand is signed or not.
443 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
444 @retval EFI_SUCCESS The instruction is executed successfully.
449 IN VM_CONTEXT
*VmPtr
,
450 IN BOOLEAN IsSignedOp
454 // Functions that execute VM opcodes
457 Execute the EBC BREAK instruction.
459 @param VmPtr A pointer to a VM context.
461 @retval EFI_SUCCESS The instruction is executed successfully.
470 Execute the JMP instruction.
474 JMP32{cs|cc} {@}R1 {Immed32|Index32}
477 b0.7 - immediate data present
478 b0.6 - 1 = 64 bit immediate data
479 0 = 32 bit immediate data
480 b1.7 - 1 = conditional
481 b1.6 1 = CS (condition set)
482 0 = CC (condition clear)
483 b1.4 1 = relative address
485 b1.3 1 = operand1 indirect
488 @param VmPtr A pointer to a VM context.
490 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
491 @retval EFI_SUCCESS The instruction is executed successfully.
500 Execute the EBC JMP8 instruction.
505 @param VmPtr A pointer to a VM context.
507 @retval EFI_SUCCESS The instruction is executed successfully.
516 Implements the EBC CALL instruction.
520 CALL32 {@}R1 {Immed32|Index32}
522 CALLEX16 {@}R1 {Immed32}
524 If Rx == R0, then it's a PC relative call to PC = PC + imm32.
526 @param VmPtr A pointer to a VM context.
528 @retval EFI_SUCCESS The instruction is executed successfully.
537 Execute the EBC RET instruction.
542 @param VmPtr A pointer to a VM context.
544 @retval EFI_SUCCESS The instruction is executed successfully.
553 Execute the EBC CMP instruction.
556 CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
558 @param VmPtr A pointer to a VM context.
560 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
561 @retval EFI_SUCCESS The instruction is executed successfully.
570 Execute the EBC CMPI instruction
573 CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
575 @param VmPtr A pointer to a VM context.
577 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
578 @retval EFI_SUCCESS The instruction is executed successfully.
587 Execute the MOVxx instructions.
591 MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
592 MOVqq {@}R1 {Index64}, {@}R2 {Index64}
594 Copies contents of [R2] -> [R1], zero extending where required.
596 First character indicates the size of the move.
597 Second character indicates the size of the index(s).
599 Invalid to have R1 direct with index.
601 @param VmPtr A pointer to a VM context.
603 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
604 @retval EFI_SUCCESS The instruction is executed successfully.
613 Execute the EBC MOVI.
617 MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
619 First variable character specifies the move size
620 Second variable character specifies size of the immediate data
622 Sign-extend the immediate data to the size of the operation, and zero-extend
623 if storing to a register.
625 Operand1 direct with index/immed is invalid.
627 @param VmPtr A pointer to a VM context.
629 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
630 @retval EFI_SUCCESS The instruction is executed successfully.
639 Execute the EBC MOV immediate natural. This instruction moves an immediate
640 index value into a register or memory location.
644 MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
646 @param VmPtr A pointer to a VM context.
648 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
649 @retval EFI_SUCCESS The instruction is executed successfully.
658 Execute the EBC MOVREL instruction.
663 MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
665 @param VmPtr A pointer to a VM context.
667 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
668 @retval EFI_SUCCESS The instruction is executed successfully.
677 Execute the EBC PUSHn instruction
680 PUSHn {@}R1 {Index16|Immed16}
682 @param VmPtr A pointer to a VM context.
684 @retval EFI_SUCCESS The instruction is executed successfully.
693 Execute the EBC PUSH instruction.
696 PUSH[32|64] {@}R1 {Index16|Immed16}
698 @param VmPtr A pointer to a VM context.
700 @retval EFI_SUCCESS The instruction is executed successfully.
709 Execute the EBC POPn instruction.
712 POPn {@}R1 {Index16|Immed16}
714 @param VmPtr A pointer to a VM context.
716 @retval EFI_SUCCESS The instruction is executed successfully.
725 Execute the EBC POP instruction.
728 POPn {@}R1 {Index16|Immed16}
730 @param VmPtr A pointer to a VM context.
732 @retval EFI_SUCCESS The instruction is executed successfully.
741 Execute all the EBC signed data manipulation instructions.
742 Since the EBC data manipulation instructions all have the same basic form,
743 they can share the code that does the fetch of operands and the write-back
744 of the result. This function performs the fetch of the operands (even if
745 both are not needed to be fetched, like NOT instruction), dispatches to the
746 appropriate subfunction, then writes back the returned result.
749 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
751 @param VmPtr A pointer to VM context.
753 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
754 @retval EFI_SUCCESS The instruction is executed successfully.
758 ExecuteSignedDataManip (
763 Execute all the EBC unsigned data manipulation instructions.
764 Since the EBC data manipulation instructions all have the same basic form,
765 they can share the code that does the fetch of operands and the write-back
766 of the result. This function performs the fetch of the operands (even if
767 both are not needed to be fetched, like NOT instruction), dispatches to the
768 appropriate subfunction, then writes back the returned result.
771 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
773 @param VmPtr A pointer to VM context.
775 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
776 @retval EFI_SUCCESS The instruction is executed successfully.
780 ExecuteUnsignedDataManip (
785 Execute the EBC LOADSP instruction.
790 @param VmPtr A pointer to a VM context.
792 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
793 @retval EFI_SUCCESS The instruction is executed successfully.
802 Execute the EBC STORESP instruction.
807 @param VmPtr A pointer to a VM context.
809 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
810 @retval EFI_SUCCESS The instruction is executed successfully.
819 Execute the EBC MOVsnw instruction. This instruction loads a signed
820 natural value from memory or register to another memory or register. On
821 32-bit machines, the value gets sign-extended to 64 bits if the destination
826 MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
828 0:7 1=>operand1 index present
829 0:6 1=>operand2 index present
831 @param VmPtr A pointer to a VM context.
833 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
834 @retval EFI_SUCCESS The instruction is executed successfully.
843 Execute the EBC MOVsnw instruction. This instruction loads a signed
844 natural value from memory or register to another memory or register. On
845 32-bit machines, the value gets sign-extended to 64 bits if the destination
850 MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
852 0:7 1=>operand1 index present
853 0:6 1=>operand2 index present
855 @param VmPtr A pointer to a VM context.
857 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
858 @retval EFI_SUCCESS The instruction is executed successfully.
867 // Data manipulation subfunctions
870 Execute the EBC NOT instruction.s
873 NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
875 @param VmPtr A pointer to a VM context.
876 @param Op1 Operand 1 from the instruction
877 @param Op2 Operand 2 from the instruction
884 IN VM_CONTEXT
*VmPtr
,
890 Execute the EBC NEG instruction.
893 NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
895 @param VmPtr A pointer to a VM context.
896 @param Op1 Operand 1 from the instruction
897 @param Op2 Operand 2 from the instruction
904 IN VM_CONTEXT
*VmPtr
,
910 Execute the EBC ADD instruction.
913 ADD[32|64] {@}R1, {@}R2 {Index16}
915 @param VmPtr A pointer to a VM context.
916 @param Op1 Operand 1 from the instruction
917 @param Op2 Operand 2 from the instruction
924 IN VM_CONTEXT
*VmPtr
,
930 Execute the EBC SUB instruction.
933 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
935 @param VmPtr A pointer to a VM context.
936 @param Op1 Operand 1 from the instruction
937 @param Op2 Operand 2 from the instruction
944 IN VM_CONTEXT
*VmPtr
,
950 Execute the EBC MUL instruction.
953 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
955 @param VmPtr A pointer to a VM context.
956 @param Op1 Operand 1 from the instruction
957 @param Op2 Operand 2 from the instruction
964 IN VM_CONTEXT
*VmPtr
,
970 Execute the EBC MULU instruction
973 MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
975 @param VmPtr A pointer to a VM context.
976 @param Op1 Operand 1 from the instruction
977 @param Op2 Operand 2 from the instruction
979 @return (unsigned)Op1 * (unsigned)Op2
984 IN VM_CONTEXT
*VmPtr
,
990 Execute the EBC DIV instruction.
993 DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
995 @param VmPtr A pointer to a VM context.
996 @param Op1 Operand 1 from the instruction
997 @param Op2 Operand 2 from the instruction
1004 IN VM_CONTEXT
*VmPtr
,
1010 Execute the EBC DIVU instruction
1013 DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
1015 @param VmPtr A pointer to a VM context.
1016 @param Op1 Operand 1 from the instruction
1017 @param Op2 Operand 2 from the instruction
1019 @return (unsigned)Op1 / (unsigned)Op2
1024 IN VM_CONTEXT
*VmPtr
,
1030 Execute the EBC MOD instruction.
1033 MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
1035 @param VmPtr A pointer to a VM context.
1036 @param Op1 Operand 1 from the instruction
1037 @param Op2 Operand 2 from the instruction
1039 @return Op1 MODULUS Op2
1044 IN VM_CONTEXT
*VmPtr
,
1050 Execute the EBC MODU instruction.
1053 MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
1055 @param VmPtr A pointer to a VM context.
1056 @param Op1 Operand 1 from the instruction
1057 @param Op2 Operand 2 from the instruction
1059 @return Op1 UNSIGNED_MODULUS Op2
1064 IN VM_CONTEXT
*VmPtr
,
1070 Execute the EBC AND instruction.
1073 AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
1075 @param VmPtr A pointer to a VM context.
1076 @param Op1 Operand 1 from the instruction
1077 @param Op2 Operand 2 from the instruction
1084 IN VM_CONTEXT
*VmPtr
,
1090 Execute the EBC OR instruction.
1093 OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1095 @param VmPtr A pointer to a VM context.
1096 @param Op1 Operand 1 from the instruction
1097 @param Op2 Operand 2 from the instruction
1104 IN VM_CONTEXT
*VmPtr
,
1110 Execute the EBC XOR instruction.
1113 XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1115 @param VmPtr A pointer to a VM context.
1116 @param Op1 Operand 1 from the instruction
1117 @param Op2 Operand 2 from the instruction
1124 IN VM_CONTEXT
*VmPtr
,
1130 Execute the EBC SHL shift left instruction.
1133 SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
1135 @param VmPtr A pointer to a VM context.
1136 @param Op1 Operand 1 from the instruction
1137 @param Op2 Operand 2 from the instruction
1144 IN VM_CONTEXT
*VmPtr
,
1150 Execute the EBC SHR instruction.
1153 SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1155 @param VmPtr A pointer to a VM context.
1156 @param Op1 Operand 1 from the instruction
1157 @param Op2 Operand 2 from the instruction
1159 @return Op1 >> Op2 (unsigned operands)
1164 IN VM_CONTEXT
*VmPtr
,
1170 Execute the EBC ASHR instruction.
1173 ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
1175 @param VmPtr A pointer to a VM context.
1176 @param Op1 Operand 1 from the instruction
1177 @param Op2 Operand 2 from the instruction
1179 @return Op1 >> Op2 (signed)
1184 IN VM_CONTEXT
*VmPtr
,
1190 Execute the EBC EXTNDB instruction to sign-extend a byte value.
1193 EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
1195 @param VmPtr A pointer to a VM context.
1196 @param Op1 Operand 1 from the instruction
1197 @param Op2 Operand 2 from the instruction
1199 @return (INT64)(INT8)Op2
1204 IN VM_CONTEXT
*VmPtr
,
1210 Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
1213 EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
1215 @param VmPtr A pointer to a VM context.
1216 @param Op1 Operand 1 from the instruction
1217 @param Op2 Operand 2 from the instruction
1219 @return (INT64)(INT16)Op2
1224 IN VM_CONTEXT
*VmPtr
,
1230 Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
1233 EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
1235 @param VmPtr A pointer to a VM context.
1236 @param Op1 Operand 1 from the instruction
1237 @param Op2 Operand 2 from the instruction
1239 @return (INT64)(INT32)Op2
1244 IN VM_CONTEXT
*VmPtr
,
1250 // Once we retrieve the operands for the data manipulation instructions,
1251 // call these functions to perform the operation.
1253 CONST DATA_MANIP_EXEC_FUNCTION mDataManipDispatchTable
[] = {
1275 CONST VM_TABLE_ENTRY mVmOpcodeTable
[] = {
1276 { ExecuteBREAK
}, // opcode 0x00
1277 { ExecuteJMP
}, // opcode 0x01
1278 { ExecuteJMP8
}, // opcode 0x02
1279 { ExecuteCALL
}, // opcode 0x03
1280 { ExecuteRET
}, // opcode 0x04
1281 { ExecuteCMP
}, // opcode 0x05 CMPeq
1282 { ExecuteCMP
}, // opcode 0x06 CMPlte
1283 { ExecuteCMP
}, // opcode 0x07 CMPgte
1284 { ExecuteCMP
}, // opcode 0x08 CMPulte
1285 { ExecuteCMP
}, // opcode 0x09 CMPugte
1286 { ExecuteUnsignedDataManip
}, // opcode 0x0A NOT
1287 { ExecuteSignedDataManip
}, // opcode 0x0B NEG
1288 { ExecuteSignedDataManip
}, // opcode 0x0C ADD
1289 { ExecuteSignedDataManip
}, // opcode 0x0D SUB
1290 { ExecuteSignedDataManip
}, // opcode 0x0E MUL
1291 { ExecuteUnsignedDataManip
}, // opcode 0x0F MULU
1292 { ExecuteSignedDataManip
}, // opcode 0x10 DIV
1293 { ExecuteUnsignedDataManip
}, // opcode 0x11 DIVU
1294 { ExecuteSignedDataManip
}, // opcode 0x12 MOD
1295 { ExecuteUnsignedDataManip
}, // opcode 0x13 MODU
1296 { ExecuteUnsignedDataManip
}, // opcode 0x14 AND
1297 { ExecuteUnsignedDataManip
}, // opcode 0x15 OR
1298 { ExecuteUnsignedDataManip
}, // opcode 0x16 XOR
1299 { ExecuteUnsignedDataManip
}, // opcode 0x17 SHL
1300 { ExecuteUnsignedDataManip
}, // opcode 0x18 SHR
1301 { ExecuteSignedDataManip
}, // opcode 0x19 ASHR
1302 { ExecuteUnsignedDataManip
}, // opcode 0x1A EXTNDB
1303 { ExecuteUnsignedDataManip
}, // opcode 0x1B EXTNDW
1304 { ExecuteUnsignedDataManip
}, // opcode 0x1C EXTNDD
1305 { ExecuteMOVxx
}, // opcode 0x1D MOVBW
1306 { ExecuteMOVxx
}, // opcode 0x1E MOVWW
1307 { ExecuteMOVxx
}, // opcode 0x1F MOVDW
1308 { ExecuteMOVxx
}, // opcode 0x20 MOVQW
1309 { ExecuteMOVxx
}, // opcode 0x21 MOVBD
1310 { ExecuteMOVxx
}, // opcode 0x22 MOVWD
1311 { ExecuteMOVxx
}, // opcode 0x23 MOVDD
1312 { ExecuteMOVxx
}, // opcode 0x24 MOVQD
1313 { ExecuteMOVsnw
}, // opcode 0x25 MOVsnw
1314 { ExecuteMOVsnd
}, // opcode 0x26 MOVsnd
1315 { NULL
}, // opcode 0x27
1316 { ExecuteMOVxx
}, // opcode 0x28 MOVqq
1317 { ExecuteLOADSP
}, // opcode 0x29 LOADSP SP1, R2
1318 { ExecuteSTORESP
}, // opcode 0x2A STORESP R1, SP2
1319 { ExecutePUSH
}, // opcode 0x2B PUSH {@}R1 [imm16]
1320 { ExecutePOP
}, // opcode 0x2C POP {@}R1 [imm16]
1321 { ExecuteCMPI
}, // opcode 0x2D CMPIEQ
1322 { ExecuteCMPI
}, // opcode 0x2E CMPILTE
1323 { ExecuteCMPI
}, // opcode 0x2F CMPIGTE
1324 { ExecuteCMPI
}, // opcode 0x30 CMPIULTE
1325 { ExecuteCMPI
}, // opcode 0x31 CMPIUGTE
1326 { ExecuteMOVxx
}, // opcode 0x32 MOVN
1327 { ExecuteMOVxx
}, // opcode 0x33 MOVND
1328 { NULL
}, // opcode 0x34
1329 { ExecutePUSHn
}, // opcode 0x35
1330 { ExecutePOPn
}, // opcode 0x36
1331 { ExecuteMOVI
}, // opcode 0x37 - mov immediate data
1332 { ExecuteMOVIn
}, // opcode 0x38 - mov immediate natural
1333 { ExecuteMOVREL
} // opcode 0x39 - move data relative to PC
1337 // Length of JMP instructions, depending on upper two bits of opcode.
1339 CONST UINT8 mJMPLen
[] = { 2, 2, 6, 10 };
1342 // Simple Debugger Protocol GUID
1344 EFI_GUID mEbcSimpleDebuggerProtocolGuid
= EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL_GUID
;
1348 Given a pointer to a new VM context, execute one or more instructions. This
1349 function is only used for test purposes via the EBC VM test protocol.
1351 @param This A pointer to the EFI_EBC_VM_TEST_PROTOCOL structure.
1352 @param VmPtr A pointer to a VM context.
1353 @param InstructionCount A pointer to a UINTN value holding the number of
1354 instructions to execute. If it holds value of 0,
1355 then the instruction to be executed is 1.
1357 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
1358 @retval EFI_SUCCESS All of the instructions are executed successfully.
1362 EbcExecuteInstructions (
1363 IN EFI_EBC_VM_TEST_PROTOCOL
*This
,
1364 IN VM_CONTEXT
*VmPtr
,
1365 IN OUT UINTN
*InstructionCount
1370 UINTN InstructionsLeft
;
1371 UINTN SavedInstructionCount
;
1373 Status
= EFI_SUCCESS
;
1375 if (*InstructionCount
== 0) {
1376 InstructionsLeft
= 1;
1378 InstructionsLeft
= *InstructionCount
;
1381 SavedInstructionCount
= *InstructionCount
;
1382 *InstructionCount
= 0;
1385 // Index into the opcode table using the opcode byte for this instruction.
1386 // This gives you the execute function, which we first test for null, then
1387 // call it if it's not null.
1389 while (InstructionsLeft
!= 0) {
1390 ExecFunc
= (UINTN
) mVmOpcodeTable
[(*VmPtr
->Ip
& 0x3F)].ExecuteFunction
;
1391 if (ExecFunc
== (UINTN
) NULL
) {
1392 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1393 return EFI_UNSUPPORTED
;
1395 mVmOpcodeTable
[(*VmPtr
->Ip
& 0x3F)].ExecuteFunction (VmPtr
);
1396 *InstructionCount
= *InstructionCount
+ 1;
1400 // Decrement counter if applicable
1402 if (SavedInstructionCount
!= 0) {
1412 Execute an EBC image from an entry point or from a published protocol.
1414 @param VmPtr A pointer to a VM context.
1416 @retval EFI_UNSUPPORTED At least one of the opcodes is not supported.
1417 @retval EFI_SUCCESS All of the instructions are executed successfully.
1422 IN VM_CONTEXT
*VmPtr
1426 UINT8 StackCorrupted
;
1428 EFI_EBC_SIMPLE_DEBUGGER_PROTOCOL
*EbcSimpleDebugger
;
1431 EbcSimpleDebugger
= NULL
;
1432 Status
= EFI_SUCCESS
;
1436 // Make sure the magic value has been put on the stack before we got here.
1438 if (*VmPtr
->StackMagicPtr
!= (UINTN
) VM_STACK_KEY_VALUE
) {
1442 VmPtr
->FramePtr
= (VOID
*) ((UINT8
*) (UINTN
) VmPtr
->R
[0] + 8);
1445 // Try to get the debug support for EBC
1447 DEBUG_CODE_BEGIN ();
1448 Status
= gBS
->LocateProtocol (
1449 &mEbcSimpleDebuggerProtocolGuid
,
1451 (VOID
**) &EbcSimpleDebugger
1453 if (EFI_ERROR (Status
)) {
1454 EbcSimpleDebugger
= NULL
;
1459 // Save the start IP for debug. For example, if we take an exception we
1460 // can print out the location of the exception relative to the entry point,
1461 // which could then be used in a disassembly listing to find the problem.
1463 VmPtr
->EntryPoint
= (VOID
*) VmPtr
->Ip
;
1466 // We'll wait for this flag to know when we're done. The RET
1467 // instruction sets it if it runs out of stack.
1469 VmPtr
->StopFlags
= 0;
1470 while ((VmPtr
->StopFlags
& STOPFLAG_APP_DONE
) == 0) {
1472 // If we've found a simple debugger protocol, call it
1474 DEBUG_CODE_BEGIN ();
1475 if (EbcSimpleDebugger
!= NULL
) {
1476 EbcSimpleDebugger
->Debugger (EbcSimpleDebugger
, VmPtr
);
1481 // Verify the opcode is in range. Otherwise generate an exception.
1483 if ((*VmPtr
->Ip
& OPCODE_M_OPCODE
) >= (sizeof (mVmOpcodeTable
) / sizeof (mVmOpcodeTable
[0]))) {
1484 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1485 Status
= EFI_UNSUPPORTED
;
1489 // Use the opcode bits to index into the opcode dispatch table. If the
1490 // function pointer is null then generate an exception.
1492 ExecFunc
= (UINTN
) mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction
;
1493 if (ExecFunc
== (UINTN
) NULL
) {
1494 EbcDebugSignalException (EXCEPT_EBC_INVALID_OPCODE
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1495 Status
= EFI_UNSUPPORTED
;
1499 // The EBC VM is a strongly ordered processor, so perform a fence operation before
1500 // and after each instruction is executed.
1504 mVmOpcodeTable
[(*VmPtr
->Ip
& OPCODE_M_OPCODE
)].ExecuteFunction (VmPtr
);
1509 // If the step flag is set, signal an exception and continue. We don't
1510 // clear it here. Assuming the debugger is responsible for clearing it.
1512 if (VMFLAG_ISSET (VmPtr
, VMFLAGS_STEP
)) {
1513 EbcDebugSignalException (EXCEPT_EBC_STEP
, EXCEPTION_FLAG_NONE
, VmPtr
);
1516 // Make sure stack has not been corrupted. Only report it once though.
1518 if ((StackCorrupted
== 0) && (*VmPtr
->StackMagicPtr
!= (UINTN
) VM_STACK_KEY_VALUE
)) {
1519 EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1522 if ((StackCorrupted
== 0) && ((UINT64
)VmPtr
->R
[0] <= (UINT64
)(UINTN
) VmPtr
->StackTop
)) {
1523 EbcDebugSignalException (EXCEPT_EBC_STACK_FAULT
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1536 Execute the MOVxx instructions.
1540 MOV[b|w|d|q|n]{w|d} {@}R1 {Index16|32}, {@}R2 {Index16|32}
1541 MOVqq {@}R1 {Index64}, {@}R2 {Index64}
1543 Copies contents of [R2] -> [R1], zero extending where required.
1545 First character indicates the size of the move.
1546 Second character indicates the size of the index(s).
1548 Invalid to have R1 direct with index.
1550 @param VmPtr A pointer to a VM context.
1552 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
1553 @retval EFI_SUCCESS The instruction is executed successfully.
1558 IN VM_CONTEXT
*VmPtr
1574 Opcode
= GETOPCODE (VmPtr
);
1575 OpcMasked
= (UINT8
) (Opcode
& OPCODE_M_OPCODE
);
1578 // Get the operands byte so we can get R1 and R2
1580 Operands
= GETOPERANDS (VmPtr
);
1583 // Assume no indexes
1590 // Determine if we have an index/immediate data. Base instruction size
1591 // is 2 (opcode + operands). Add to this size each index specified.
1594 if ((Opcode
& (OPCODE_M_IMMED_OP1
| OPCODE_M_IMMED_OP2
)) != 0) {
1596 // Determine size of the index from the opcode. Then get it.
1598 if ((OpcMasked
<= OPCODE_MOVQW
) || (OpcMasked
== OPCODE_MOVNW
)) {
1600 // MOVBW, MOVWW, MOVDW, MOVQW, and MOVNW have 16-bit immediate index.
1601 // Get one or both index values.
1603 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1604 Index16
= VmReadIndex16 (VmPtr
, 2);
1605 Index64Op1
= (INT64
) Index16
;
1606 Size
+= sizeof (UINT16
);
1609 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1610 Index16
= VmReadIndex16 (VmPtr
, Size
);
1611 Index64Op2
= (INT64
) Index16
;
1612 Size
+= sizeof (UINT16
);
1614 } else if ((OpcMasked
<= OPCODE_MOVQD
) || (OpcMasked
== OPCODE_MOVND
)) {
1616 // MOVBD, MOVWD, MOVDD, MOVQD, and MOVND have 32-bit immediate index
1618 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1619 Index32
= VmReadIndex32 (VmPtr
, 2);
1620 Index64Op1
= (INT64
) Index32
;
1621 Size
+= sizeof (UINT32
);
1624 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1625 Index32
= VmReadIndex32 (VmPtr
, Size
);
1626 Index64Op2
= (INT64
) Index32
;
1627 Size
+= sizeof (UINT32
);
1629 } else if (OpcMasked
== OPCODE_MOVQQ
) {
1631 // MOVqq -- only form with a 64-bit index
1633 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1634 Index64Op1
= VmReadIndex64 (VmPtr
, 2);
1635 Size
+= sizeof (UINT64
);
1638 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1639 Index64Op2
= VmReadIndex64 (VmPtr
, Size
);
1640 Size
+= sizeof (UINT64
);
1644 // Obsolete MOVBQ, MOVWQ, MOVDQ, and MOVNQ have 64-bit immediate index
1646 EbcDebugSignalException (
1647 EXCEPT_EBC_INSTRUCTION_ENCODING
,
1648 EXCEPTION_FLAG_FATAL
,
1651 return EFI_UNSUPPORTED
;
1655 // Determine the size of the move, and create a mask for it so we can
1656 // clear unused bits.
1658 if ((OpcMasked
== OPCODE_MOVBW
) || (OpcMasked
== OPCODE_MOVBD
)) {
1659 MoveSize
= DATA_SIZE_8
;
1661 } else if ((OpcMasked
== OPCODE_MOVWW
) || (OpcMasked
== OPCODE_MOVWD
)) {
1662 MoveSize
= DATA_SIZE_16
;
1664 } else if ((OpcMasked
== OPCODE_MOVDW
) || (OpcMasked
== OPCODE_MOVDD
)) {
1665 MoveSize
= DATA_SIZE_32
;
1666 DataMask
= 0xFFFFFFFF;
1667 } else if ((OpcMasked
== OPCODE_MOVQW
) || (OpcMasked
== OPCODE_MOVQD
) || (OpcMasked
== OPCODE_MOVQQ
)) {
1668 MoveSize
= DATA_SIZE_64
;
1669 DataMask
= (UINT64
)~0;
1670 } else if ((OpcMasked
== OPCODE_MOVNW
) || (OpcMasked
== OPCODE_MOVND
)) {
1671 MoveSize
= DATA_SIZE_N
;
1672 DataMask
= (UINT64
)~0 >> (64 - 8 * sizeof (UINTN
));
1675 // We were dispatched to this function and we don't recognize the opcode
1677 EbcDebugSignalException (EXCEPT_EBC_UNDEFINED
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1678 return EFI_UNSUPPORTED
;
1681 // Now get the source address
1683 if (OPERAND2_INDIRECT (Operands
)) {
1685 // Indirect form @R2. Compute address of operand2
1687 Source
= (UINTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index64Op2
);
1689 // Now get the data from the source. Always 0-extend and let the compiler
1690 // sign-extend where required.
1694 Data64
= (UINT64
) (UINT8
) VmReadMem8 (VmPtr
, Source
);
1698 Data64
= (UINT64
) (UINT16
) VmReadMem16 (VmPtr
, Source
);
1702 Data64
= (UINT64
) (UINT32
) VmReadMem32 (VmPtr
, Source
);
1706 Data64
= (UINT64
) VmReadMem64 (VmPtr
, Source
);
1710 Data64
= (UINT64
) (UINTN
) VmReadMemN (VmPtr
, Source
);
1721 // Not indirect source: MOVxx {@}Rx, Ry [Index]
1723 Data64
= VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index64Op2
;
1725 // Did Operand2 have an index? If so, treat as two signed values since
1726 // indexes are signed values.
1728 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
1730 // NOTE: need to find a way to fix this, most likely by changing the VM
1731 // implementation to remove the stack gap. To do that, we'd need to
1732 // allocate stack space for the VM and actually set the system
1733 // stack pointer to the allocated buffer when the VM starts.
1735 // Special case -- if someone took the address of a function parameter
1736 // then we need to make sure it's not in the stack gap. We can identify
1737 // this situation if (Operand2 register == 0) && (Operand2 is direct)
1738 // && (Index applies to Operand2) && (Index > 0) && (Operand1 register != 0)
1739 // Situations that to be aware of:
1740 // * stack adjustments at beginning and end of functions R0 = R0 += stacksize
1742 if ((OPERAND2_REGNUM (Operands
) == 0) &&
1743 (!OPERAND2_INDIRECT (Operands
)) &&
1745 (OPERAND1_REGNUM (Operands
) == 0) &&
1746 (OPERAND1_INDIRECT (Operands
))
1748 Data64
= (UINT64
) ConvertStackAddr (VmPtr
, (UINTN
) (INT64
) Data64
);
1753 // Now write it back
1755 if (OPERAND1_INDIRECT (Operands
)) {
1757 // Reuse the Source variable to now be dest.
1759 Source
= (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index64Op1
);
1761 // Do the write based on the size
1765 VmWriteMem8 (VmPtr
, Source
, (UINT8
) Data64
);
1769 VmWriteMem16 (VmPtr
, Source
, (UINT16
) Data64
);
1773 VmWriteMem32 (VmPtr
, Source
, (UINT32
) Data64
);
1777 VmWriteMem64 (VmPtr
, Source
, Data64
);
1781 VmWriteMemN (VmPtr
, Source
, (UINTN
) Data64
);
1793 // Make sure we didn't have an index on operand1.
1795 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
1796 EbcDebugSignalException (
1797 EXCEPT_EBC_INSTRUCTION_ENCODING
,
1798 EXCEPTION_FLAG_FATAL
,
1801 return EFI_UNSUPPORTED
;
1804 // Direct storage in register. Clear unused bits and store back to
1807 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Data64
& DataMask
;
1810 // Advance the instruction pointer
1818 Execute the EBC BREAK instruction.
1820 @param VmPtr A pointer to a VM context.
1822 @retval EFI_SUCCESS The instruction is executed successfully.
1827 IN VM_CONTEXT
*VmPtr
1831 VOID
*EbcEntryPoint
;
1833 UINT64 U64EbcEntryPoint
;
1836 Operands
= GETOPERANDS (VmPtr
);
1839 // Runaway program break. Generate an exception and terminate
1842 EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1846 // Get VM version -- return VM revision number in R7
1852 // 16-8 = Major version
1853 // 7-0 = Minor version
1855 VmPtr
->R
[7] = GetVmVersion ();
1859 // Debugger breakpoint
1862 VmPtr
->StopFlags
|= STOPFLAG_BREAKPOINT
;
1864 // See if someone has registered a handler
1866 EbcDebugSignalException (
1867 EXCEPT_EBC_BREAKPOINT
,
1868 EXCEPTION_FLAG_NONE
,
1874 // System call, which there are none, so NOP it.
1880 // Create a thunk for EBC code. R7 points to a 32-bit (in a 64-bit slot)
1881 // "offset from self" pointer to the EBC entry point.
1882 // After we're done, *(UINT64 *)R7 will be the address of the new thunk.
1885 Offset
= (INT32
) VmReadMem32 (VmPtr
, (UINTN
) VmPtr
->R
[7]);
1886 U64EbcEntryPoint
= (UINT64
) (VmPtr
->R
[7] + Offset
+ 4);
1887 EbcEntryPoint
= (VOID
*) (UINTN
) U64EbcEntryPoint
;
1890 // Now create a new thunk
1892 EbcCreateThunks (VmPtr
->ImageHandle
, EbcEntryPoint
, &Thunk
, 0);
1895 // Finally replace the EBC entry point memory with the thunk address
1897 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->R
[7], (UINT64
) (UINTN
) Thunk
);
1901 // Compiler setting version per value in R7
1904 VmPtr
->CompilerVersion
= (UINT32
) VmPtr
->R
[7];
1906 // Check compiler version against VM version?
1911 // Unhandled break code. Signal exception.
1914 EbcDebugSignalException (EXCEPT_EBC_BAD_BREAK
, EXCEPTION_FLAG_FATAL
, VmPtr
);
1926 Execute the JMP instruction.
1929 JMP64{cs|cc} Immed64
1930 JMP32{cs|cc} {@}R1 {Immed32|Index32}
1933 b0.7 - immediate data present
1934 b0.6 - 1 = 64 bit immediate data
1935 0 = 32 bit immediate data
1936 b1.7 - 1 = conditional
1937 b1.6 1 = CS (condition set)
1938 0 = CC (condition clear)
1939 b1.4 1 = relative address
1940 0 = absolute address
1941 b1.3 1 = operand1 indirect
1944 @param VmPtr A pointer to a VM context.
1946 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
1947 @retval EFI_SUCCESS The instruction is executed successfully.
1952 IN VM_CONTEXT
*VmPtr
1957 UINT8 ConditionFlag
;
1964 Operand
= GETOPERANDS (VmPtr
);
1965 Opcode
= GETOPCODE (VmPtr
);
1968 // Get instruction length from the opcode. The upper two bits are used here
1969 // to index into the length array.
1971 Size
= mJMPLen
[(Opcode
>> 6) & 0x03];
1974 // Decode instruction conditions
1975 // If we haven't met the condition, then simply advance the IP and return.
1977 CompareSet
= (UINT8
) (((Operand
& JMP_M_CS
) != 0) ? 1 : 0);
1978 ConditionFlag
= (UINT8
) VMFLAG_ISSET (VmPtr
, VMFLAGS_CC
);
1979 if ((Operand
& CONDITION_M_CONDITIONAL
) != 0) {
1980 if (CompareSet
!= ConditionFlag
) {
1986 // Check for 64-bit form and do it right away since it's the most
1987 // straight-forward form.
1989 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
1991 // Double check for immediate-data, which is required. If not there,
1992 // then signal an exception
1994 if ((Opcode
& OPCODE_M_IMMDATA
) == 0) {
1995 EbcDebugSignalException (
1996 EXCEPT_EBC_INSTRUCTION_ENCODING
,
1997 EXCEPTION_FLAG_ERROR
,
2000 return EFI_UNSUPPORTED
;
2003 // 64-bit immediate data is full address. Read the immediate data,
2004 // check for alignment, and jump absolute.
2006 Data64
= VmReadImmed64 (VmPtr
, 2);
2007 if (!IS_ALIGNED ((UINTN
) Data64
, sizeof (UINT16
))) {
2008 EbcDebugSignalException (
2009 EXCEPT_EBC_ALIGNMENT_CHECK
,
2010 EXCEPTION_FLAG_FATAL
,
2014 return EFI_UNSUPPORTED
;
2018 // Take jump -- relative or absolute
2020 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2021 VmPtr
->Ip
+= (UINTN
) Data64
+ Size
;
2023 VmPtr
->Ip
= (VMIP
) (UINTN
) Data64
;
2030 // Get the index if there is one. May be either an index, or an immediate
2031 // offset depending on indirect operand.
2032 // JMP32 @R1 Index32 -- immediate data is an index
2033 // JMP32 R1 Immed32 -- immedate data is an offset
2035 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
2036 if (OPERAND1_INDIRECT (Operand
)) {
2037 Index32
= VmReadIndex32 (VmPtr
, 2);
2039 Index32
= VmReadImmed32 (VmPtr
, 2);
2045 // Get the register data. If R == 0, then special case where it's ignored.
2047 if (OPERAND1_REGNUM (Operand
) == 0) {
2050 Data64
= OPERAND1_REGDATA (VmPtr
, Operand
);
2055 if (OPERAND1_INDIRECT (Operand
)) {
2057 // Form: JMP32 @Rx {Index32}
2059 Addr
= VmReadMemN (VmPtr
, (UINTN
) Data64
+ Index32
);
2060 if (!IS_ALIGNED ((UINTN
) Addr
, sizeof (UINT16
))) {
2061 EbcDebugSignalException (
2062 EXCEPT_EBC_ALIGNMENT_CHECK
,
2063 EXCEPTION_FLAG_FATAL
,
2067 return EFI_UNSUPPORTED
;
2070 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2071 VmPtr
->Ip
+= (UINTN
) Addr
+ Size
;
2073 VmPtr
->Ip
= (VMIP
) Addr
;
2077 // Form: JMP32 Rx {Immed32}
2079 Addr
= (UINTN
) (Data64
+ Index32
);
2080 if (!IS_ALIGNED ((UINTN
) Addr
, sizeof (UINT16
))) {
2081 EbcDebugSignalException (
2082 EXCEPT_EBC_ALIGNMENT_CHECK
,
2083 EXCEPTION_FLAG_FATAL
,
2087 return EFI_UNSUPPORTED
;
2090 if ((Operand
& JMP_M_RELATIVE
) != 0) {
2091 VmPtr
->Ip
+= (UINTN
) Addr
+ Size
;
2093 VmPtr
->Ip
= (VMIP
) Addr
;
2102 Execute the EBC JMP8 instruction.
2105 JMP8{cs|cc} Offset/2
2107 @param VmPtr A pointer to a VM context.
2109 @retval EFI_SUCCESS The instruction is executed successfully.
2114 IN VM_CONTEXT
*VmPtr
2118 UINT8 ConditionFlag
;
2123 // Decode instruction.
2125 Opcode
= GETOPCODE (VmPtr
);
2126 CompareSet
= (UINT8
) (((Opcode
& JMP_M_CS
) != 0) ? 1 : 0);
2127 ConditionFlag
= (UINT8
) VMFLAG_ISSET (VmPtr
, VMFLAGS_CC
);
2130 // If we haven't met the condition, then simply advance the IP and return
2132 if ((Opcode
& CONDITION_M_CONDITIONAL
) != 0) {
2133 if (CompareSet
!= ConditionFlag
) {
2139 // Get the offset from the instruction stream. It's relative to the
2140 // following instruction, and divided by 2.
2142 Offset
= VmReadImmed8 (VmPtr
, 1);
2144 // Want to check for offset == -2 and then raise an exception?
2146 VmPtr
->Ip
+= (Offset
* 2) + 2;
2152 Execute the EBC MOVI.
2156 MOVI[b|w|d|q][w|d|q] {@}R1 {Index16}, ImmData16|32|64
2158 First variable character specifies the move size
2159 Second variable character specifies size of the immediate data
2161 Sign-extend the immediate data to the size of the operation, and zero-extend
2162 if storing to a register.
2164 Operand1 direct with index/immed is invalid.
2166 @param VmPtr A pointer to a VM context.
2168 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2169 @retval EFI_SUCCESS The instruction is executed successfully.
2174 IN VM_CONTEXT
*VmPtr
2186 // Get the opcode and operands byte so we can get R1 and R2
2188 Opcode
= GETOPCODE (VmPtr
);
2189 Operands
= GETOPERANDS (VmPtr
);
2192 // Get the index (16-bit) if present
2194 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2195 Index16
= VmReadIndex16 (VmPtr
, 2);
2202 // Extract the immediate data. Sign-extend always.
2204 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2205 ImmData64
= (INT64
) (INT16
) VmReadImmed16 (VmPtr
, Size
);
2207 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2208 ImmData64
= (INT64
) (INT32
) VmReadImmed32 (VmPtr
, Size
);
2210 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2211 ImmData64
= (INT64
) VmReadImmed64 (VmPtr
, Size
);
2217 EbcDebugSignalException (
2218 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2219 EXCEPTION_FLAG_FATAL
,
2222 return EFI_UNSUPPORTED
;
2225 // Now write back the result
2227 if (!OPERAND1_INDIRECT (Operands
)) {
2229 // Operand1 direct. Make sure it didn't have an index.
2231 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2232 EbcDebugSignalException (
2233 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2234 EXCEPTION_FLAG_FATAL
,
2237 return EFI_UNSUPPORTED
;
2240 // Writing directly to a register. Clear unused bits.
2242 if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH8
) {
2243 Mask64
= 0x000000FF;
2244 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH16
) {
2245 Mask64
= 0x0000FFFF;
2246 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH32
) {
2247 Mask64
= 0x00000000FFFFFFFF;
2249 Mask64
= (UINT64
)~0;
2252 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = ImmData64
& Mask64
;
2255 // Get the address then write back based on size of the move
2257 Op1
= (UINT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2258 if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH8
) {
2259 VmWriteMem8 (VmPtr
, (UINTN
) Op1
, (UINT8
) ImmData64
);
2260 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH16
) {
2261 VmWriteMem16 (VmPtr
, (UINTN
) Op1
, (UINT16
) ImmData64
);
2262 } else if ((Operands
& MOVI_M_MOVEWIDTH
) == MOVI_MOVEWIDTH32
) {
2263 VmWriteMem32 (VmPtr
, (UINTN
) Op1
, (UINT32
) ImmData64
);
2265 VmWriteMem64 (VmPtr
, (UINTN
) Op1
, ImmData64
);
2269 // Advance the instruction pointer
2277 Execute the EBC MOV immediate natural. This instruction moves an immediate
2278 index value into a register or memory location.
2282 MOVIn[w|d|q] {@}R1 {Index16}, Index16|32|64
2284 @param VmPtr A pointer to a VM context.
2286 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2287 @retval EFI_SUCCESS The instruction is executed successfully.
2292 IN VM_CONTEXT
*VmPtr
2305 // Get the opcode and operands byte so we can get R1 and R2
2307 Opcode
= GETOPCODE (VmPtr
);
2308 Operands
= GETOPERANDS (VmPtr
);
2311 // Get the operand1 index (16-bit) if present
2313 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2314 Index16
= VmReadIndex16 (VmPtr
, 2);
2321 // Extract the immediate data and convert to a 64-bit index.
2323 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2324 ImmedIndex16
= VmReadIndex16 (VmPtr
, Size
);
2325 ImmedIndex64
= (INT64
) ImmedIndex16
;
2327 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2328 ImmedIndex32
= VmReadIndex32 (VmPtr
, Size
);
2329 ImmedIndex64
= (INT64
) ImmedIndex32
;
2331 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2332 ImmedIndex64
= VmReadIndex64 (VmPtr
, Size
);
2338 EbcDebugSignalException (
2339 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2340 EXCEPTION_FLAG_FATAL
,
2343 return EFI_UNSUPPORTED
;
2346 // Now write back the result
2348 if (!OPERAND1_INDIRECT (Operands
)) {
2350 // Check for MOVIn R1 Index16, Immed (not indirect, with index), which
2353 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2354 EbcDebugSignalException (
2355 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2356 EXCEPTION_FLAG_FATAL
,
2359 return EFI_UNSUPPORTED
;
2362 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = ImmedIndex64
;
2367 Op1
= (UINT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2368 VmWriteMemN (VmPtr
, (UINTN
) Op1
, (INTN
) ImmedIndex64
);
2371 // Advance the instruction pointer
2379 Execute the EBC MOVREL instruction.
2380 Dest <- Ip + ImmData
2384 MOVREL[w|d|q] {@}R1 {Index16}, ImmData16|32|64
2386 @param VmPtr A pointer to a VM context.
2388 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2389 @retval EFI_SUCCESS The instruction is executed successfully.
2394 IN VM_CONTEXT
*VmPtr
2406 // Get the opcode and operands byte so we can get R1 and R2
2408 Opcode
= GETOPCODE (VmPtr
);
2409 Operands
= GETOPERANDS (VmPtr
);
2412 // Get the Operand 1 index (16-bit) if present
2414 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2415 Index16
= VmReadIndex16 (VmPtr
, 2);
2422 // Get the immediate data.
2424 if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH16
) {
2425 ImmData64
= (INT64
) VmReadImmed16 (VmPtr
, Size
);
2427 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH32
) {
2428 ImmData64
= (INT64
) VmReadImmed32 (VmPtr
, Size
);
2430 } else if ((Opcode
& MOVI_M_DATAWIDTH
) == MOVI_DATAWIDTH64
) {
2431 ImmData64
= VmReadImmed64 (VmPtr
, Size
);
2437 EbcDebugSignalException (
2438 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2439 EXCEPTION_FLAG_FATAL
,
2442 return EFI_UNSUPPORTED
;
2445 // Compute the value and write back the result
2447 Op2
= (UINT64
) ((INT64
) ((UINT64
) (UINTN
) VmPtr
->Ip
) + (INT64
) ImmData64
+ Size
);
2448 if (!OPERAND1_INDIRECT (Operands
)) {
2450 // Check for illegal combination of operand1 direct with immediate data
2452 if ((Operands
& MOVI_M_IMMDATA
) != 0) {
2453 EbcDebugSignalException (
2454 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2455 EXCEPTION_FLAG_FATAL
,
2458 return EFI_UNSUPPORTED
;
2461 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (VM_REGISTER
) Op2
;
2464 // Get the address = [Rx] + Index16
2465 // Write back the result. Always a natural size write, since
2466 // we're talking addresses here.
2468 Op1
= (UINT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2469 VmWriteMemN (VmPtr
, (UINTN
) Op1
, (UINTN
) Op2
);
2472 // Advance the instruction pointer
2480 Execute the EBC MOVsnw instruction. This instruction loads a signed
2481 natural value from memory or register to another memory or register. On
2482 32-bit machines, the value gets sign-extended to 64 bits if the destination
2487 MOVsnw {@}R1 {Index16}, {@}R2 {Index16|Immed16}
2489 0:7 1=>operand1 index present
2490 0:6 1=>operand2 index present
2492 @param VmPtr A pointer to a VM context.
2494 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2495 @retval EFI_SUCCESS The instruction is executed successfully.
2500 IN VM_CONTEXT
*VmPtr
2511 // Get the opcode and operand bytes
2513 Opcode
= GETOPCODE (VmPtr
);
2514 Operands
= GETOPERANDS (VmPtr
);
2516 Op1Index
= Op2Index
= 0;
2519 // Get the indexes if present.
2522 if ((Opcode
& OPCODE_M_IMMED_OP1
) !=0) {
2523 if (OPERAND1_INDIRECT (Operands
)) {
2524 Op1Index
= VmReadIndex16 (VmPtr
, 2);
2527 // Illegal form operand1 direct with index: MOVsnw R1 Index16, {@}R2
2529 EbcDebugSignalException (
2530 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2531 EXCEPTION_FLAG_FATAL
,
2534 return EFI_UNSUPPORTED
;
2537 Size
+= sizeof (UINT16
);
2540 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
2541 if (OPERAND2_INDIRECT (Operands
)) {
2542 Op2Index
= VmReadIndex16 (VmPtr
, Size
);
2544 Op2Index
= VmReadImmed16 (VmPtr
, Size
);
2547 Size
+= sizeof (UINT16
);
2550 // Get the data from the source.
2552 Op2
= (INT64
) ((INTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Op2Index
));
2553 if (OPERAND2_INDIRECT (Operands
)) {
2554 Op2
= (INT64
) (INTN
) VmReadMemN (VmPtr
, (UINTN
) Op2
);
2557 // Now write back the result.
2559 if (!OPERAND1_INDIRECT (Operands
)) {
2560 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Op2
;
2562 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Op1Index
), (UINTN
) Op2
);
2565 // Advance the instruction pointer
2573 Execute the EBC MOVsnw instruction. This instruction loads a signed
2574 natural value from memory or register to another memory or register. On
2575 32-bit machines, the value gets sign-extended to 64 bits if the destination
2580 MOVsnd {@}R1 {Indx32}, {@}R2 {Index32|Immed32}
2582 0:7 1=>operand1 index present
2583 0:6 1=>operand2 index present
2585 @param VmPtr A pointer to a VM context.
2587 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
2588 @retval EFI_SUCCESS The instruction is executed successfully.
2593 IN VM_CONTEXT
*VmPtr
2604 // Get the opcode and operand bytes
2606 Opcode
= GETOPCODE (VmPtr
);
2607 Operands
= GETOPERANDS (VmPtr
);
2609 Op1Index
= Op2Index
= 0;
2612 // Get the indexes if present.
2615 if ((Opcode
& OPCODE_M_IMMED_OP1
) != 0) {
2616 if (OPERAND1_INDIRECT (Operands
)) {
2617 Op1Index
= VmReadIndex32 (VmPtr
, 2);
2620 // Illegal form operand1 direct with index: MOVsnd R1 Index16,..
2622 EbcDebugSignalException (
2623 EXCEPT_EBC_INSTRUCTION_ENCODING
,
2624 EXCEPTION_FLAG_FATAL
,
2627 return EFI_UNSUPPORTED
;
2630 Size
+= sizeof (UINT32
);
2633 if ((Opcode
& OPCODE_M_IMMED_OP2
) != 0) {
2634 if (OPERAND2_INDIRECT (Operands
)) {
2635 Op2Index
= VmReadIndex32 (VmPtr
, Size
);
2637 Op2Index
= VmReadImmed32 (VmPtr
, Size
);
2640 Size
+= sizeof (UINT32
);
2643 // Get the data from the source.
2645 Op2
= (INT64
) ((INTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Op2Index
));
2646 if (OPERAND2_INDIRECT (Operands
)) {
2647 Op2
= (INT64
) (INTN
) VmReadMemN (VmPtr
, (UINTN
) Op2
);
2650 // Now write back the result.
2652 if (!OPERAND1_INDIRECT (Operands
)) {
2653 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Op2
;
2655 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Op1Index
), (UINTN
) Op2
);
2658 // Advance the instruction pointer
2666 Execute the EBC PUSHn instruction
2669 PUSHn {@}R1 {Index16|Immed16}
2671 @param VmPtr A pointer to a VM context.
2673 @retval EFI_SUCCESS The instruction is executed successfully.
2678 IN VM_CONTEXT
*VmPtr
2687 // Get opcode and operands
2689 Opcode
= GETOPCODE (VmPtr
);
2690 Operands
= GETOPERANDS (VmPtr
);
2693 // Get index if present
2695 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2696 if (OPERAND1_INDIRECT (Operands
)) {
2697 Index16
= VmReadIndex16 (VmPtr
, 2);
2699 Index16
= VmReadImmed16 (VmPtr
, 2);
2708 // Get the data to push
2710 if (OPERAND1_INDIRECT (Operands
)) {
2711 DataN
= VmReadMemN (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
));
2713 DataN
= (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
);
2716 // Adjust the stack down.
2718 VmPtr
->R
[0] -= sizeof (UINTN
);
2719 VmWriteMemN (VmPtr
, (UINTN
) VmPtr
->R
[0], DataN
);
2725 Execute the EBC PUSH instruction.
2728 PUSH[32|64] {@}R1 {Index16|Immed16}
2730 @param VmPtr A pointer to a VM context.
2732 @retval EFI_SUCCESS The instruction is executed successfully.
2737 IN VM_CONTEXT
*VmPtr
2747 // Get opcode and operands
2749 Opcode
= GETOPCODE (VmPtr
);
2750 Operands
= GETOPERANDS (VmPtr
);
2752 // Get immediate index if present, then advance the IP.
2754 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2755 if (OPERAND1_INDIRECT (Operands
)) {
2756 Index16
= VmReadIndex16 (VmPtr
, 2);
2758 Index16
= VmReadImmed16 (VmPtr
, 2);
2767 // Get the data to push
2769 if ((Opcode
& PUSHPOP_M_64
) != 0) {
2770 if (OPERAND1_INDIRECT (Operands
)) {
2771 Data64
= VmReadMem64 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
));
2773 Data64
= (UINT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2776 // Adjust the stack down, then write back the data
2778 VmPtr
->R
[0] -= sizeof (UINT64
);
2779 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->R
[0], Data64
);
2784 if (OPERAND1_INDIRECT (Operands
)) {
2785 Data32
= VmReadMem32 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
));
2787 Data32
= (UINT32
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
;
2790 // Adjust the stack down and write the data
2792 VmPtr
->R
[0] -= sizeof (UINT32
);
2793 VmWriteMem32 (VmPtr
, (UINTN
) VmPtr
->R
[0], Data32
);
2801 Execute the EBC POPn instruction.
2804 POPn {@}R1 {Index16|Immed16}
2806 @param VmPtr A pointer to a VM context.
2808 @retval EFI_SUCCESS The instruction is executed successfully.
2813 IN VM_CONTEXT
*VmPtr
2822 // Get opcode and operands
2824 Opcode
= GETOPCODE (VmPtr
);
2825 Operands
= GETOPERANDS (VmPtr
);
2827 // Get immediate data if present, and advance the IP
2829 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2830 if (OPERAND1_INDIRECT (Operands
)) {
2831 Index16
= VmReadIndex16 (VmPtr
, 2);
2833 Index16
= VmReadImmed16 (VmPtr
, 2);
2842 // Read the data off the stack, then adjust the stack pointer
2844 DataN
= VmReadMemN (VmPtr
, (UINTN
) VmPtr
->R
[0]);
2845 VmPtr
->R
[0] += sizeof (UINTN
);
2847 // Do the write-back
2849 if (OPERAND1_INDIRECT (Operands
)) {
2850 VmWriteMemN (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
), DataN
);
2852 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (INT64
) (UINT64
) ((UINTN
) DataN
+ Index16
);
2860 Execute the EBC POP instruction.
2863 POPn {@}R1 {Index16|Immed16}
2865 @param VmPtr A pointer to a VM context.
2867 @retval EFI_SUCCESS The instruction is executed successfully.
2872 IN VM_CONTEXT
*VmPtr
2882 // Get opcode and operands
2884 Opcode
= GETOPCODE (VmPtr
);
2885 Operands
= GETOPERANDS (VmPtr
);
2887 // Get immediate data if present, and advance the IP.
2889 if ((Opcode
& PUSHPOP_M_IMMDATA
) != 0) {
2890 if (OPERAND1_INDIRECT (Operands
)) {
2891 Index16
= VmReadIndex16 (VmPtr
, 2);
2893 Index16
= VmReadImmed16 (VmPtr
, 2);
2902 // Get the data off the stack, then write it to the appropriate location
2904 if ((Opcode
& PUSHPOP_M_64
) != 0) {
2906 // Read the data off the stack, then adjust the stack pointer
2908 Data64
= VmReadMem64 (VmPtr
, (UINTN
) VmPtr
->R
[0]);
2909 VmPtr
->R
[0] += sizeof (UINT64
);
2911 // Do the write-back
2913 if (OPERAND1_INDIRECT (Operands
)) {
2914 VmWriteMem64 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
), Data64
);
2916 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Data64
+ Index16
;
2920 // 32-bit pop. Read it off the stack and adjust the stack pointer
2922 Data32
= (INT32
) VmReadMem32 (VmPtr
, (UINTN
) VmPtr
->R
[0]);
2923 VmPtr
->R
[0] += sizeof (UINT32
);
2925 // Do the write-back
2927 if (OPERAND1_INDIRECT (Operands
)) {
2928 VmWriteMem32 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND1_REGNUM (Operands
)] + Index16
), Data32
);
2930 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (INT64
) Data32
+ Index16
;
2939 Implements the EBC CALL instruction.
2943 CALL32 {@}R1 {Immed32|Index32}
2945 CALLEX16 {@}R1 {Immed32}
2947 If Rx == R0, then it's a PC relative call to PC = PC + imm32.
2949 @param VmPtr A pointer to a VM context.
2951 @retval EFI_SUCCESS The instruction is executed successfully.
2956 IN VM_CONTEXT
*VmPtr
2967 // Get opcode and operands
2969 Opcode
= GETOPCODE (VmPtr
);
2970 Operands
= GETOPERANDS (VmPtr
);
2972 // Assign these as well to avoid compiler warnings
2977 FramePtr
= VmPtr
->FramePtr
;
2979 // Determine the instruction size, and get immediate data if present
2981 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
2982 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
2983 Immed64
= VmReadImmed64 (VmPtr
, 2);
2987 // If register operand is indirect, then the immediate data is an index
2989 if (OPERAND1_INDIRECT (Operands
)) {
2990 Immed32
= VmReadIndex32 (VmPtr
, 2);
2992 Immed32
= VmReadImmed32 (VmPtr
, 2);
3001 // If it's a call to EBC, adjust the stack pointer down 16 bytes and
3002 // put our return address and frame pointer on the VM stack.
3004 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3006 VmWriteMemN (VmPtr
, (UINTN
) VmPtr
->R
[0], (UINTN
) FramePtr
);
3007 VmPtr
->FramePtr
= (VOID
*) (UINTN
) VmPtr
->R
[0];
3009 VmWriteMem64 (VmPtr
, (UINTN
) VmPtr
->R
[0], (UINT64
) (UINTN
) (VmPtr
->Ip
+ Size
));
3012 // If 64-bit data, then absolute jump only
3014 if ((Opcode
& OPCODE_M_IMMDATA64
) != 0) {
3016 // Native or EBC call?
3018 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3019 VmPtr
->Ip
= (VMIP
) (UINTN
) Immed64
;
3022 // Call external function, get the return value, and advance the IP
3024 EbcLLCALLEX (VmPtr
, (UINTN
) Immed64
, (UINTN
) VmPtr
->R
[0], FramePtr
, Size
);
3028 // Get the register data. If operand1 == 0, then ignore register and
3029 // take immediate data as relative or absolute address.
3030 // Compiler should take care of upper bits if 32-bit machine.
3032 if (OPERAND1_REGNUM (Operands
) != 0) {
3033 Immed64
= (UINT64
) (UINTN
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
3036 // Get final address
3038 if (OPERAND1_INDIRECT (Operands
)) {
3039 Immed64
= (INT64
) (UINT64
) (UINTN
) VmReadMemN (VmPtr
, (UINTN
) (Immed64
+ Immed32
));
3044 // Now determine if external call, and then if relative or absolute
3046 if ((Operands
& OPERAND_M_NATIVE_CALL
) == 0) {
3048 // EBC call. Relative or absolute? If relative, then it's relative to the
3049 // start of the next instruction.
3051 if ((Operands
& OPERAND_M_RELATIVE_ADDR
) != 0) {
3052 VmPtr
->Ip
+= Immed64
+ Size
;
3054 VmPtr
->Ip
= (VMIP
) (UINTN
) Immed64
;
3058 // Native call. Relative or absolute?
3060 if ((Operands
& OPERAND_M_RELATIVE_ADDR
) != 0) {
3061 EbcLLCALLEX (VmPtr
, (UINTN
) (Immed64
+ VmPtr
->Ip
+ Size
), (UINTN
) VmPtr
->R
[0], FramePtr
, Size
);
3063 if ((VmPtr
->StopFlags
& STOPFLAG_BREAK_ON_CALLEX
) != 0) {
3067 EbcLLCALLEX (VmPtr
, (UINTN
) Immed64
, (UINTN
) VmPtr
->R
[0], FramePtr
, Size
);
3077 Execute the EBC RET instruction.
3082 @param VmPtr A pointer to a VM context.
3084 @retval EFI_SUCCESS The instruction is executed successfully.
3089 IN VM_CONTEXT
*VmPtr
3093 // If we're at the top of the stack, then simply set the done
3096 if (VmPtr
->StackRetAddr
== (UINT64
) VmPtr
->R
[0]) {
3097 VmPtr
->StopFlags
|= STOPFLAG_APP_DONE
;
3100 // Pull the return address off the VM app's stack and set the IP
3103 if (!IS_ALIGNED ((UINTN
) VmPtr
->R
[0], sizeof (UINT16
))) {
3104 EbcDebugSignalException (
3105 EXCEPT_EBC_ALIGNMENT_CHECK
,
3106 EXCEPTION_FLAG_FATAL
,
3111 // Restore the IP and frame pointer from the stack
3113 VmPtr
->Ip
= (VMIP
) (UINTN
) VmReadMem64 (VmPtr
, (UINTN
) VmPtr
->R
[0]);
3115 VmPtr
->FramePtr
= (VOID
*) VmReadMemN (VmPtr
, (UINTN
) VmPtr
->R
[0]);
3124 Execute the EBC CMP instruction.
3127 CMP[32|64][eq|lte|gte|ulte|ugte] R1, {@}R2 {Index16|Immed16}
3129 @param VmPtr A pointer to a VM context.
3131 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
3132 @retval EFI_SUCCESS The instruction is executed successfully.
3137 IN VM_CONTEXT
*VmPtr
3149 // Get opcode and operands
3151 Opcode
= GETOPCODE (VmPtr
);
3152 Operands
= GETOPERANDS (VmPtr
);
3154 // Get the register data we're going to compare to
3156 Op1
= VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
3158 // Get immediate data
3160 if ((Opcode
& OPCODE_M_IMMDATA
) != 0) {
3161 if (OPERAND2_INDIRECT (Operands
)) {
3162 Index16
= VmReadIndex16 (VmPtr
, 2);
3164 Index16
= VmReadImmed16 (VmPtr
, 2);
3175 if (OPERAND2_INDIRECT (Operands
)) {
3176 if ((Opcode
& OPCODE_M_64BIT
) != 0) {
3177 Op2
= (INT64
) VmReadMem64 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index16
));
3180 // 32-bit operations. 0-extend the values for all cases.
3182 Op2
= (INT64
) (UINT64
) ((UINT32
) VmReadMem32 (VmPtr
, (UINTN
) (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index16
)));
3185 Op2
= VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index16
;
3188 // Now do the compare
3191 if ((Opcode
& OPCODE_M_64BIT
) != 0) {
3195 switch (Opcode
& OPCODE_M_OPCODE
) {
3214 case OPCODE_CMPULTE
:
3215 if ((UINT64
) Op1
<= (UINT64
) Op2
) {
3220 case OPCODE_CMPUGTE
:
3221 if ((UINT64
) Op1
>= (UINT64
) Op2
) {
3233 switch (Opcode
& OPCODE_M_OPCODE
) {
3235 if ((INT32
) Op1
== (INT32
) Op2
) {
3241 if ((INT32
) Op1
<= (INT32
) Op2
) {
3247 if ((INT32
) Op1
>= (INT32
) Op2
) {
3252 case OPCODE_CMPULTE
:
3253 if ((UINT32
) Op1
<= (UINT32
) Op2
) {
3258 case OPCODE_CMPUGTE
:
3259 if ((UINT32
) Op1
>= (UINT32
) Op2
) {
3269 // Now set the flag accordingly for the comparison
3272 VMFLAG_SET (VmPtr
, VMFLAGS_CC
);
3274 VMFLAG_CLEAR (VmPtr
, VMFLAGS_CC
);
3285 Execute the EBC CMPI instruction
3288 CMPI[32|64]{w|d}[eq|lte|gte|ulte|ugte] {@}Rx {Index16}, Immed16|Immed32
3290 @param VmPtr A pointer to a VM context.
3292 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
3293 @retval EFI_SUCCESS The instruction is executed successfully.
3298 IN VM_CONTEXT
*VmPtr
3310 // Get opcode and operands
3312 Opcode
= GETOPCODE (VmPtr
);
3313 Operands
= GETOPERANDS (VmPtr
);
3316 // Get operand1 index if present
3319 if ((Operands
& OPERAND_M_CMPI_INDEX
) != 0) {
3320 Index16
= VmReadIndex16 (VmPtr
, 2);
3326 // Get operand1 data we're going to compare to
3328 Op1
= (INT64
) VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
3329 if (OPERAND1_INDIRECT (Operands
)) {
3331 // Indirect operand1. Fetch 32 or 64-bit value based on compare size.
3333 if ((Opcode
& OPCODE_M_CMPI64
) != 0) {
3334 Op1
= (INT64
) VmReadMem64 (VmPtr
, (UINTN
) Op1
+ Index16
);
3336 Op1
= (INT64
) VmReadMem32 (VmPtr
, (UINTN
) Op1
+ Index16
);
3340 // Better not have been an index with direct. That is, CMPI R1 Index,...
3343 if ((Operands
& OPERAND_M_CMPI_INDEX
) != 0) {
3344 EbcDebugSignalException (
3345 EXCEPT_EBC_INSTRUCTION_ENCODING
,
3346 EXCEPTION_FLAG_ERROR
,
3350 return EFI_UNSUPPORTED
;
3354 // Get immediate data -- 16- or 32-bit sign extended
3356 if ((Opcode
& OPCODE_M_CMPI32_DATA
) != 0) {
3357 Op2
= (INT64
) VmReadImmed32 (VmPtr
, Size
);
3361 // 16-bit immediate data. Sign extend always.
3363 Op2
= (INT64
) ((INT16
) VmReadImmed16 (VmPtr
, Size
));
3367 // Now do the compare
3370 if ((Opcode
& OPCODE_M_CMPI64
) != 0) {
3372 // 64 bit comparison
3374 switch (Opcode
& OPCODE_M_OPCODE
) {
3376 if (Op1
== (INT64
) Op2
) {
3381 case OPCODE_CMPILTE
:
3382 if (Op1
<= (INT64
) Op2
) {
3387 case OPCODE_CMPIGTE
:
3388 if (Op1
>= (INT64
) Op2
) {
3393 case OPCODE_CMPIULTE
:
3394 if ((UINT64
) Op1
<= (UINT64
) ((UINT32
) Op2
)) {
3399 case OPCODE_CMPIUGTE
:
3400 if ((UINT64
) Op1
>= (UINT64
) ((UINT32
) Op2
)) {
3410 // 32-bit comparisons
3412 switch (Opcode
& OPCODE_M_OPCODE
) {
3414 if ((INT32
) Op1
== Op2
) {
3419 case OPCODE_CMPILTE
:
3420 if ((INT32
) Op1
<= Op2
) {
3425 case OPCODE_CMPIGTE
:
3426 if ((INT32
) Op1
>= Op2
) {
3431 case OPCODE_CMPIULTE
:
3432 if ((UINT32
) Op1
<= (UINT32
) Op2
) {
3437 case OPCODE_CMPIUGTE
:
3438 if ((UINT32
) Op1
>= (UINT32
) Op2
) {
3448 // Now set the flag accordingly for the comparison
3451 VMFLAG_SET (VmPtr
, VMFLAGS_CC
);
3453 VMFLAG_CLEAR (VmPtr
, VMFLAGS_CC
);
3464 Execute the EBC NOT instruction.s
3467 NOT[32|64] {@}R1, {@}R2 {Index16|Immed16}
3469 @param VmPtr A pointer to a VM context.
3470 @param Op1 Operand 1 from the instruction
3471 @param Op2 Operand 2 from the instruction
3478 IN VM_CONTEXT
*VmPtr
,
3488 Execute the EBC NEG instruction.
3491 NEG[32|64] {@}R1, {@}R2 {Index16|Immed16}
3493 @param VmPtr A pointer to a VM context.
3494 @param Op1 Operand 1 from the instruction
3495 @param Op2 Operand 2 from the instruction
3502 IN VM_CONTEXT
*VmPtr
,
3512 Execute the EBC ADD instruction.
3515 ADD[32|64] {@}R1, {@}R2 {Index16}
3517 @param VmPtr A pointer to a VM context.
3518 @param Op1 Operand 1 from the instruction
3519 @param Op2 Operand 2 from the instruction
3526 IN VM_CONTEXT
*VmPtr
,
3536 Execute the EBC SUB instruction.
3539 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3541 @param VmPtr A pointer to a VM context.
3542 @param Op1 Operand 1 from the instruction
3543 @param Op2 Operand 2 from the instruction
3550 IN VM_CONTEXT
*VmPtr
,
3555 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3556 return (UINT64
) ((INT64
) ((INT64
) Op1
- (INT64
) Op2
));
3558 return (UINT64
) ((INT64
) ((INT32
) Op1
- (INT32
) Op2
));
3564 Execute the EBC MUL instruction.
3567 SUB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3569 @param VmPtr A pointer to a VM context.
3570 @param Op1 Operand 1 from the instruction
3571 @param Op2 Operand 2 from the instruction
3578 IN VM_CONTEXT
*VmPtr
,
3583 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3584 return MultS64x64 ((INT64
)Op1
, (INT64
)Op2
);
3586 return (UINT64
) ((INT64
) ((INT32
) Op1
* (INT32
) Op2
));
3592 Execute the EBC MULU instruction
3595 MULU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3597 @param VmPtr A pointer to a VM context.
3598 @param Op1 Operand 1 from the instruction
3599 @param Op2 Operand 2 from the instruction
3601 @return (unsigned)Op1 * (unsigned)Op2
3606 IN VM_CONTEXT
*VmPtr
,
3611 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3612 return MultU64x64 (Op1
, Op2
);
3614 return (UINT64
) ((UINT32
) Op1
* (UINT32
) Op2
);
3620 Execute the EBC DIV instruction.
3623 DIV[32|64] {@}R1, {@}R2 {Index16|Immed16}
3625 @param VmPtr A pointer to a VM context.
3626 @param Op1 Operand 1 from the instruction
3627 @param Op2 Operand 2 from the instruction
3634 IN VM_CONTEXT
*VmPtr
,
3642 // Check for divide-by-0
3645 EbcDebugSignalException (
3646 EXCEPT_EBC_DIVIDE_ERROR
,
3647 EXCEPTION_FLAG_FATAL
,
3653 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3654 return (UINT64
) (DivS64x64Remainder (Op1
, Op2
, &Remainder
));
3656 return (UINT64
) ((INT64
) ((INT32
) Op1
/ (INT32
) Op2
));
3663 Execute the EBC DIVU instruction
3666 DIVU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3668 @param VmPtr A pointer to a VM context.
3669 @param Op1 Operand 1 from the instruction
3670 @param Op2 Operand 2 from the instruction
3672 @return (unsigned)Op1 / (unsigned)Op2
3677 IN VM_CONTEXT
*VmPtr
,
3685 // Check for divide-by-0
3688 EbcDebugSignalException (
3689 EXCEPT_EBC_DIVIDE_ERROR
,
3690 EXCEPTION_FLAG_FATAL
,
3696 // Get the destination register
3698 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3699 return (UINT64
) (DivU64x64Remainder ((INT64
)Op1
, (INT64
)Op2
, &Remainder
));
3701 return (UINT64
) ((UINT32
) Op1
/ (UINT32
) Op2
);
3708 Execute the EBC MOD instruction.
3711 MOD[32|64] {@}R1, {@}R2 {Index16|Immed16}
3713 @param VmPtr A pointer to a VM context.
3714 @param Op1 Operand 1 from the instruction
3715 @param Op2 Operand 2 from the instruction
3717 @return Op1 MODULUS Op2
3722 IN VM_CONTEXT
*VmPtr
,
3730 // Check for divide-by-0
3733 EbcDebugSignalException (
3734 EXCEPT_EBC_DIVIDE_ERROR
,
3735 EXCEPTION_FLAG_FATAL
,
3740 DivS64x64Remainder ((INT64
)Op1
, (INT64
)Op2
, &Remainder
);
3747 Execute the EBC MODU instruction.
3750 MODU[32|64] {@}R1, {@}R2 {Index16|Immed16}
3752 @param VmPtr A pointer to a VM context.
3753 @param Op1 Operand 1 from the instruction
3754 @param Op2 Operand 2 from the instruction
3756 @return Op1 UNSIGNED_MODULUS Op2
3761 IN VM_CONTEXT
*VmPtr
,
3769 // Check for divide-by-0
3772 EbcDebugSignalException (
3773 EXCEPT_EBC_DIVIDE_ERROR
,
3774 EXCEPTION_FLAG_FATAL
,
3779 DivU64x64Remainder (Op1
, Op2
, &Remainder
);
3786 Execute the EBC AND instruction.
3789 AND[32|64] {@}R1, {@}R2 {Index16|Immed16}
3791 @param VmPtr A pointer to a VM context.
3792 @param Op1 Operand 1 from the instruction
3793 @param Op2 Operand 2 from the instruction
3800 IN VM_CONTEXT
*VmPtr
,
3810 Execute the EBC OR instruction.
3813 OR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3815 @param VmPtr A pointer to a VM context.
3816 @param Op1 Operand 1 from the instruction
3817 @param Op2 Operand 2 from the instruction
3824 IN VM_CONTEXT
*VmPtr
,
3834 Execute the EBC XOR instruction.
3837 XOR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3839 @param VmPtr A pointer to a VM context.
3840 @param Op1 Operand 1 from the instruction
3841 @param Op2 Operand 2 from the instruction
3848 IN VM_CONTEXT
*VmPtr
,
3858 Execute the EBC SHL shift left instruction.
3861 SHL[32|64] {@}R1, {@}R2 {Index16|Immed16}
3863 @param VmPtr A pointer to a VM context.
3864 @param Op1 Operand 1 from the instruction
3865 @param Op2 Operand 2 from the instruction
3872 IN VM_CONTEXT
*VmPtr
,
3877 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3878 return LShiftU64 (Op1
, (UINTN
)Op2
);
3880 return (UINT64
) ((UINT32
) ((UINT32
) Op1
<< (UINT32
) Op2
));
3886 Execute the EBC SHR instruction.
3889 SHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3891 @param VmPtr A pointer to a VM context.
3892 @param Op1 Operand 1 from the instruction
3893 @param Op2 Operand 2 from the instruction
3895 @return Op1 >> Op2 (unsigned operands)
3900 IN VM_CONTEXT
*VmPtr
,
3905 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3906 return RShiftU64 (Op1
, (UINTN
)Op2
);
3908 return (UINT64
) ((UINT32
) Op1
>> (UINT32
) Op2
);
3914 Execute the EBC ASHR instruction.
3917 ASHR[32|64] {@}R1, {@}R2 {Index16|Immed16}
3919 @param VmPtr A pointer to a VM context.
3920 @param Op1 Operand 1 from the instruction
3921 @param Op2 Operand 2 from the instruction
3923 @return Op1 >> Op2 (signed)
3928 IN VM_CONTEXT
*VmPtr
,
3933 if ((*VmPtr
->Ip
& DATAMANIP_M_64
) != 0) {
3934 return ARShiftU64 (Op1
, (UINTN
)Op2
);
3936 return (UINT64
) ((INT64
) ((INT32
) Op1
>> (UINT32
) Op2
));
3942 Execute the EBC EXTNDB instruction to sign-extend a byte value.
3945 EXTNDB[32|64] {@}R1, {@}R2 {Index16|Immed16}
3947 @param VmPtr A pointer to a VM context.
3948 @param Op1 Operand 1 from the instruction
3949 @param Op2 Operand 2 from the instruction
3951 @return (INT64)(INT8)Op2
3956 IN VM_CONTEXT
*VmPtr
,
3964 // Convert to byte, then return as 64-bit signed value to let compiler
3965 // sign-extend the value
3968 Data64
= (INT64
) Data8
;
3970 return (UINT64
) Data64
;
3975 Execute the EBC EXTNDW instruction to sign-extend a 16-bit value.
3978 EXTNDW[32|64] {@}R1, {@}R2 {Index16|Immed16}
3980 @param VmPtr A pointer to a VM context.
3981 @param Op1 Operand 1 from the instruction
3982 @param Op2 Operand 2 from the instruction
3984 @return (INT64)(INT16)Op2
3989 IN VM_CONTEXT
*VmPtr
,
3997 // Convert to word, then return as 64-bit signed value to let compiler
3998 // sign-extend the value
4000 Data16
= (INT16
) Op2
;
4001 Data64
= (INT64
) Data16
;
4003 return (UINT64
) Data64
;
4006 // Execute the EBC EXTNDD instruction.
4008 // Format: EXTNDD {@}Rx, {@}Ry [Index16|Immed16]
4009 // EXTNDD Dest, Source
4011 // Operation: Dest <- SignExtended((DWORD)Source))
4015 Execute the EBC EXTNDD instruction to sign-extend a 32-bit value.
4018 EXTNDD[32|64] {@}R1, {@}R2 {Index16|Immed16}
4020 @param VmPtr A pointer to a VM context.
4021 @param Op1 Operand 1 from the instruction
4022 @param Op2 Operand 2 from the instruction
4024 @return (INT64)(INT32)Op2
4029 IN VM_CONTEXT
*VmPtr
,
4037 // Convert to 32-bit value, then return as 64-bit signed value to let compiler
4038 // sign-extend the value
4040 Data32
= (INT32
) Op2
;
4041 Data64
= (INT64
) Data32
;
4043 return (UINT64
) Data64
;
4048 Execute all the EBC signed data manipulation instructions.
4049 Since the EBC data manipulation instructions all have the same basic form,
4050 they can share the code that does the fetch of operands and the write-back
4051 of the result. This function performs the fetch of the operands (even if
4052 both are not needed to be fetched, like NOT instruction), dispatches to the
4053 appropriate subfunction, then writes back the returned result.
4056 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4058 @param VmPtr A pointer to VM context.
4060 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4061 @retval EFI_SUCCESS The instruction is executed successfully.
4065 ExecuteSignedDataManip (
4066 IN VM_CONTEXT
*VmPtr
4070 // Just call the data manipulation function with a flag indicating this
4071 // is a signed operation.
4073 return ExecuteDataManip (VmPtr
, TRUE
);
4078 Execute all the EBC unsigned data manipulation instructions.
4079 Since the EBC data manipulation instructions all have the same basic form,
4080 they can share the code that does the fetch of operands and the write-back
4081 of the result. This function performs the fetch of the operands (even if
4082 both are not needed to be fetched, like NOT instruction), dispatches to the
4083 appropriate subfunction, then writes back the returned result.
4086 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4088 @param VmPtr A pointer to VM context.
4090 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4091 @retval EFI_SUCCESS The instruction is executed successfully.
4095 ExecuteUnsignedDataManip (
4096 IN VM_CONTEXT
*VmPtr
4100 // Just call the data manipulation function with a flag indicating this
4101 // is not a signed operation.
4103 return ExecuteDataManip (VmPtr
, FALSE
);
4108 Execute all the EBC data manipulation instructions.
4109 Since the EBC data manipulation instructions all have the same basic form,
4110 they can share the code that does the fetch of operands and the write-back
4111 of the result. This function performs the fetch of the operands (even if
4112 both are not needed to be fetched, like NOT instruction), dispatches to the
4113 appropriate subfunction, then writes back the returned result.
4116 INSTRUCITON[32|64] {@}R1, {@}R2 {Immed16|Index16}
4118 @param VmPtr A pointer to VM context.
4119 @param IsSignedOp Indicates whether the operand is signed or not.
4121 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4122 @retval EFI_SUCCESS The instruction is executed successfully.
4127 IN VM_CONTEXT
*VmPtr
,
4128 IN BOOLEAN IsSignedOp
4139 // Get opcode and operands
4141 Opcode
= GETOPCODE (VmPtr
);
4142 Operands
= GETOPERANDS (VmPtr
);
4145 // Determine if we have immediate data by the opcode
4147 if ((Opcode
& DATAMANIP_M_IMMDATA
) != 0) {
4149 // Index16 if Ry is indirect, or Immed16 if Ry direct.
4151 if (OPERAND2_INDIRECT (Operands
)) {
4152 Index16
= VmReadIndex16 (VmPtr
, 2);
4154 Index16
= VmReadImmed16 (VmPtr
, 2);
4163 // Now get operand2 (source). It's of format {@}R2 {Index16|Immed16}
4165 Op2
= (UINT64
) VmPtr
->R
[OPERAND2_REGNUM (Operands
)] + Index16
;
4166 if (OPERAND2_INDIRECT (Operands
)) {
4168 // Indirect form: @R2 Index16. Fetch as 32- or 64-bit data
4170 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4171 Op2
= VmReadMem64 (VmPtr
, (UINTN
) Op2
);
4174 // Read as signed value where appropriate.
4177 Op2
= (UINT64
) (INT64
) ((INT32
) VmReadMem32 (VmPtr
, (UINTN
) Op2
));
4179 Op2
= (UINT64
) VmReadMem32 (VmPtr
, (UINTN
) Op2
);
4183 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4185 Op2
= (UINT64
) (INT64
) ((INT32
) Op2
);
4187 Op2
= (UINT64
) ((UINT32
) Op2
);
4192 // Get operand1 (destination and sometimes also an actual operand)
4195 Op1
= VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
4196 if (OPERAND1_INDIRECT (Operands
)) {
4197 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4198 Op1
= VmReadMem64 (VmPtr
, (UINTN
) Op1
);
4201 Op1
= (UINT64
) (INT64
) ((INT32
) VmReadMem32 (VmPtr
, (UINTN
) Op1
));
4203 Op1
= (UINT64
) VmReadMem32 (VmPtr
, (UINTN
) Op1
);
4207 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4209 Op1
= (UINT64
) (INT64
) ((INT32
) Op1
);
4211 Op1
= (UINT64
) ((UINT32
) Op1
);
4216 // Dispatch to the computation function
4218 if (((Opcode
& OPCODE_M_OPCODE
) - OPCODE_NOT
) >=
4219 (sizeof (mDataManipDispatchTable
) / sizeof (mDataManipDispatchTable
[0]))
4221 EbcDebugSignalException (
4222 EXCEPT_EBC_INVALID_OPCODE
,
4223 EXCEPTION_FLAG_ERROR
,
4227 // Advance and return
4230 return EFI_UNSUPPORTED
;
4232 Op2
= mDataManipDispatchTable
[(Opcode
& OPCODE_M_OPCODE
) - OPCODE_NOT
](VmPtr
, Op1
, Op2
);
4235 // Write back the result.
4237 if (OPERAND1_INDIRECT (Operands
)) {
4238 Op1
= VmPtr
->R
[OPERAND1_REGNUM (Operands
)];
4239 if ((Opcode
& DATAMANIP_M_64
) != 0) {
4240 VmWriteMem64 (VmPtr
, (UINTN
) Op1
, Op2
);
4242 VmWriteMem32 (VmPtr
, (UINTN
) Op1
, (UINT32
) Op2
);
4246 // Storage back to a register. Write back, clearing upper bits (as per
4247 // the specification) if 32-bit operation.
4249 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = Op2
;
4250 if ((Opcode
& DATAMANIP_M_64
) == 0) {
4251 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] &= 0xFFFFFFFF;
4255 // Advance the instruction pointer
4263 Execute the EBC LOADSP instruction.
4268 @param VmPtr A pointer to a VM context.
4270 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4271 @retval EFI_SUCCESS The instruction is executed successfully.
4276 IN VM_CONTEXT
*VmPtr
4284 Operands
= GETOPERANDS (VmPtr
);
4289 switch (OPERAND1_REGNUM (Operands
)) {
4295 // Spec states that this instruction will not modify reserved bits in
4296 // the flags register.
4298 VmPtr
->Flags
= (VmPtr
->Flags
&~VMFLAGS_ALL_VALID
) | (VmPtr
->R
[OPERAND2_REGNUM (Operands
)] & VMFLAGS_ALL_VALID
);
4302 EbcDebugSignalException (
4303 EXCEPT_EBC_INSTRUCTION_ENCODING
,
4304 EXCEPTION_FLAG_WARNING
,
4308 return EFI_UNSUPPORTED
;
4317 Execute the EBC STORESP instruction.
4320 STORESP Rx, FLAGS|IP
4322 @param VmPtr A pointer to a VM context.
4324 @retval EFI_UNSUPPORTED The opcodes/operands is not supported.
4325 @retval EFI_SUCCESS The instruction is executed successfully.
4330 IN VM_CONTEXT
*VmPtr
4338 Operands
= GETOPERANDS (VmPtr
);
4343 switch (OPERAND2_REGNUM (Operands
)) {
4349 // Retrieve the value in the flags register, then clear reserved bits
4351 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (UINT64
) (VmPtr
->Flags
& VMFLAGS_ALL_VALID
);
4355 // Get IP -- address of following instruction
4358 VmPtr
->R
[OPERAND1_REGNUM (Operands
)] = (UINT64
) (UINTN
) VmPtr
->Ip
+ 2;
4362 EbcDebugSignalException (
4363 EXCEPT_EBC_INSTRUCTION_ENCODING
,
4364 EXCEPTION_FLAG_WARNING
,
4368 return EFI_UNSUPPORTED
;
4378 Decode a 16-bit index to determine the offset. Given an index value:
4381 b14:12 - number of bits in this index assigned to natural units (=a)
4382 ba:11 - constant units = ConstUnits
4383 b0:a - natural units = NaturalUnits
4385 Given this info, the offset can be computed by:
4386 offset = sign_bit * (ConstUnits + NaturalUnits * sizeof(UINTN))
4388 Max offset is achieved with index = 0x7FFF giving an offset of
4389 0x27B (32-bit machine) or 0x477 (64-bit machine).
4390 Min offset is achieved with index =
4392 @param VmPtr A pointer to VM context.
4393 @param CodeOffset Offset from IP of the location of the 16-bit index
4396 @return The decoded offset.
4401 IN VM_CONTEXT
*VmPtr
,
4402 IN UINT32 CodeOffset
4413 // First read the index from the code stream
4415 Index
= VmReadCode16 (VmPtr
, CodeOffset
);
4418 // Get the mask for NaturalUnits. First get the number of bits from the index.
4420 NBits
= (INT16
) ((Index
& 0x7000) >> 12);
4423 // Scale it for 16-bit indexes
4428 // Now using the number of bits, create a mask.
4430 Mask
= (INT16
) ((INT16
)~0 << NBits
);
4433 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4435 NaturalUnits
= (INT16
) (Index
&~Mask
);
4438 // Now compute ConstUnits
4440 ConstUnits
= (INT16
) (((Index
&~0xF000) & Mask
) >> NBits
);
4442 Offset
= (INT16
) (NaturalUnits
* sizeof (UINTN
) + ConstUnits
);
4447 if ((Index
& 0x8000) != 0) {
4449 // Do it the hard way to work around a bogus compiler warning
4451 // Offset = -1 * Offset;
4453 Offset
= (INT16
) ((INT32
) Offset
* -1);
4461 Decode a 32-bit index to determine the offset.
4463 @param VmPtr A pointer to VM context.
4464 @param CodeOffset Offset from IP of the location of the 32-bit index
4467 @return Converted index per EBC VM specification.
4472 IN VM_CONTEXT
*VmPtr
,
4473 IN UINT32 CodeOffset
4483 Index
= VmReadImmed32 (VmPtr
, CodeOffset
);
4486 // Get the mask for NaturalUnits. First get the number of bits from the index.
4488 NBits
= (Index
& 0x70000000) >> 28;
4491 // Scale it for 32-bit indexes
4496 // Now using the number of bits, create a mask.
4498 Mask
= (INT32
)~0 << NBits
;
4501 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4503 NaturalUnits
= Index
&~Mask
;
4506 // Now compute ConstUnits
4508 ConstUnits
= ((Index
&~0xF0000000) & Mask
) >> NBits
;
4510 Offset
= NaturalUnits
* sizeof (UINTN
) + ConstUnits
;
4515 if ((Index
& 0x80000000) != 0) {
4516 Offset
= Offset
* -1;
4524 Decode a 64-bit index to determine the offset.
4526 @param VmPtr A pointer to VM context.s
4527 @param CodeOffset Offset from IP of the location of the 64-bit index
4530 @return Converted index per EBC VM specification
4535 IN VM_CONTEXT
*VmPtr
,
4536 IN UINT32 CodeOffset
4546 Index
= VmReadCode64 (VmPtr
, CodeOffset
);
4549 // Get the mask for NaturalUnits. First get the number of bits from the index.
4551 NBits
= RShiftU64 ((Index
& 0x7000000000000000ULL
), 60);
4554 // Scale it for 64-bit indexes (multiply by 8 by shifting left 3)
4556 NBits
= LShiftU64 ((UINT64
)NBits
, 3);
4559 // Now using the number of bits, create a mask.
4561 Mask
= (LShiftU64 ((UINT64
)~0, (UINTN
)NBits
));
4564 // Now using the mask, extract NaturalUnits from the lower bits of the index.
4566 NaturalUnits
= Index
&~Mask
;
4569 // Now compute ConstUnits
4571 ConstUnits
= ARShiftU64 (((Index
&~0xF000000000000000ULL
) & Mask
), (UINTN
)NBits
);
4573 Offset
= MultU64x64 (NaturalUnits
, sizeof (UINTN
)) + ConstUnits
;
4578 if ((Index
& 0x8000000000000000ULL
) != 0) {
4579 Offset
= MultS64x64 (Offset
, -1);
4587 Writes 8-bit data to memory address.
4589 This routine is called by the EBC data
4590 movement instructions that write to memory. Since these writes
4591 may be to the stack, which looks like (high address on top) this,
4593 [EBC entry point arguments]
4597 we need to detect all attempts to write to the EBC entry point argument
4598 stack area and adjust the address (which will initially point into the
4599 VM stack) to point into the EBC entry point arguments.
4601 @param VmPtr A pointer to a VM context.
4602 @param Addr Address to write to.
4603 @param Data Value to write to Addr.
4605 @retval EFI_SUCCESS The instruction is executed successfully.
4606 @retval Other Some error occurs when writing data to the address.
4611 IN VM_CONTEXT
*VmPtr
,
4617 // Convert the address if it's in the stack gap
4619 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4620 *(UINT8
*) Addr
= Data
;
4625 Writes 16-bit data to memory address.
4627 This routine is called by the EBC data
4628 movement instructions that write to memory. Since these writes
4629 may be to the stack, which looks like (high address on top) this,
4631 [EBC entry point arguments]
4635 we need to detect all attempts to write to the EBC entry point argument
4636 stack area and adjust the address (which will initially point into the
4637 VM stack) to point into the EBC entry point arguments.
4639 @param VmPtr A pointer to a VM context.
4640 @param Addr Address to write to.
4641 @param Data Value to write to Addr.
4643 @retval EFI_SUCCESS The instruction is executed successfully.
4644 @retval Other Some error occurs when writing data to the address.
4649 IN VM_CONTEXT
*VmPtr
,
4657 // Convert the address if it's in the stack gap
4659 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4662 // Do a simple write if aligned
4664 if (IS_ALIGNED (Addr
, sizeof (UINT16
))) {
4665 *(UINT16
*) Addr
= Data
;
4668 // Write as two bytes
4671 if ((Status
= VmWriteMem8 (VmPtr
, Addr
, (UINT8
) Data
)) != EFI_SUCCESS
) {
4676 if ((Status
= VmWriteMem8 (VmPtr
, Addr
+ 1, (UINT8
) (Data
>> 8))) != EFI_SUCCESS
) {
4688 Writes 32-bit data to memory address.
4690 This routine is called by the EBC data
4691 movement instructions that write to memory. Since these writes
4692 may be to the stack, which looks like (high address on top) this,
4694 [EBC entry point arguments]
4698 we need to detect all attempts to write to the EBC entry point argument
4699 stack area and adjust the address (which will initially point into the
4700 VM stack) to point into the EBC entry point arguments.
4702 @param VmPtr A pointer to a VM context.
4703 @param Addr Address to write to.
4704 @param Data Value to write to Addr.
4706 @retval EFI_SUCCESS The instruction is executed successfully.
4707 @retval Other Some error occurs when writing data to the address.
4712 IN VM_CONTEXT
*VmPtr
,
4720 // Convert the address if it's in the stack gap
4722 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4725 // Do a simple write if aligned
4727 if (IS_ALIGNED (Addr
, sizeof (UINT32
))) {
4728 *(UINT32
*) Addr
= Data
;
4731 // Write as two words
4734 if ((Status
= VmWriteMem16 (VmPtr
, Addr
, (UINT16
) Data
)) != EFI_SUCCESS
) {
4739 if ((Status
= VmWriteMem16 (VmPtr
, Addr
+ sizeof (UINT16
), (UINT16
) (Data
>> 16))) != EFI_SUCCESS
) {
4751 Writes 64-bit data to memory address.
4753 This routine is called by the EBC data
4754 movement instructions that write to memory. Since these writes
4755 may be to the stack, which looks like (high address on top) this,
4757 [EBC entry point arguments]
4761 we need to detect all attempts to write to the EBC entry point argument
4762 stack area and adjust the address (which will initially point into the
4763 VM stack) to point into the EBC entry point arguments.
4765 @param VmPtr A pointer to a VM context.
4766 @param Addr Address to write to.
4767 @param Data Value to write to Addr.
4769 @retval EFI_SUCCESS The instruction is executed successfully.
4770 @retval Other Some error occurs when writing data to the address.
4775 IN VM_CONTEXT
*VmPtr
,
4784 // Convert the address if it's in the stack gap
4786 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4789 // Do a simple write if aligned
4791 if (IS_ALIGNED (Addr
, sizeof (UINT64
))) {
4792 *(UINT64
*) Addr
= Data
;
4795 // Write as two 32-bit words
4798 if ((Status
= VmWriteMem32 (VmPtr
, Addr
, (UINT32
) Data
)) != EFI_SUCCESS
) {
4803 Data32
= (UINT32
) (((UINT32
*) &Data
)[1]);
4804 if ((Status
= VmWriteMem32 (VmPtr
, Addr
+ sizeof (UINT32
), Data32
)) != EFI_SUCCESS
) {
4816 Writes UINTN data to memory address.
4818 This routine is called by the EBC data
4819 movement instructions that write to memory. Since these writes
4820 may be to the stack, which looks like (high address on top) this,
4822 [EBC entry point arguments]
4826 we need to detect all attempts to write to the EBC entry point argument
4827 stack area and adjust the address (which will initially point into the
4828 VM stack) to point into the EBC entry point arguments.
4830 @param VmPtr A pointer to a VM context.
4831 @param Addr Address to write to.
4832 @param Data Value to write to Addr.
4834 @retval EFI_SUCCESS The instruction is executed successfully.
4835 @retval Other Some error occurs when writing data to the address.
4840 IN VM_CONTEXT
*VmPtr
,
4848 Status
= EFI_SUCCESS
;
4851 // Convert the address if it's in the stack gap
4853 Addr
= ConvertStackAddr (VmPtr
, Addr
);
4856 // Do a simple write if aligned
4858 if (IS_ALIGNED (Addr
, sizeof (UINTN
))) {
4859 *(UINTN
*) Addr
= Data
;
4861 for (Index
= 0; Index
< sizeof (UINTN
) / sizeof (UINT32
); Index
++) {
4863 Status
= VmWriteMem32 (VmPtr
, Addr
+ Index
* sizeof (UINT32
), (UINT32
) Data
);
4865 Data
= (UINTN
) RShiftU64 ((UINT64
)Data
, 32);
4874 Reads 8-bit immediate value at the offset.
4876 This routine is called by the EBC execute
4877 functions to read EBC immediate values from the code stream.
4878 Since we can't assume alignment, each tries to read in the biggest
4879 chunks size available, but will revert to smaller reads if necessary.
4881 @param VmPtr A pointer to a VM context.
4882 @param Offset offset from IP of the code bytes to read.
4884 @return Signed data of the requested size from the specified address.
4889 IN VM_CONTEXT
*VmPtr
,
4894 // Simply return the data in flat memory space
4896 return * (INT8
*) (VmPtr
->Ip
+ Offset
);
4900 Reads 16-bit immediate value at the offset.
4902 This routine is called by the EBC execute
4903 functions to read EBC immediate values from the code stream.
4904 Since we can't assume alignment, each tries to read in the biggest
4905 chunks size available, but will revert to smaller reads if necessary.
4907 @param VmPtr A pointer to a VM context.
4908 @param Offset offset from IP of the code bytes to read.
4910 @return Signed data of the requested size from the specified address.
4915 IN VM_CONTEXT
*VmPtr
,
4920 // Read direct if aligned
4922 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (INT16
))) {
4923 return * (INT16
*) (VmPtr
->Ip
+ Offset
);
4926 // All code word reads should be aligned
4928 EbcDebugSignalException (
4929 EXCEPT_EBC_ALIGNMENT_CHECK
,
4930 EXCEPTION_FLAG_WARNING
,
4935 // Return unaligned data
4937 return (INT16
) (*(UINT8
*) (VmPtr
->Ip
+ Offset
) + (*(UINT8
*) (VmPtr
->Ip
+ Offset
+ 1) << 8));
4942 Reads 32-bit immediate value at the offset.
4944 This routine is called by the EBC execute
4945 functions to read EBC immediate values from the code stream.
4946 Since we can't assume alignment, each tries to read in the biggest
4947 chunks size available, but will revert to smaller reads if necessary.
4949 @param VmPtr A pointer to a VM context.
4950 @param Offset offset from IP of the code bytes to read.
4952 @return Signed data of the requested size from the specified address.
4957 IN VM_CONTEXT
*VmPtr
,
4964 // Read direct if aligned
4966 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT32
))) {
4967 return * (INT32
*) (VmPtr
->Ip
+ Offset
);
4970 // Return unaligned data
4972 Data
= (UINT32
) VmReadCode16 (VmPtr
, Offset
);
4973 Data
|= (UINT32
)(VmReadCode16 (VmPtr
, Offset
+ 2) << 16);
4979 Reads 64-bit immediate value at the offset.
4981 This routine is called by the EBC execute
4982 functions to read EBC immediate values from the code stream.
4983 Since we can't assume alignment, each tries to read in the biggest
4984 chunks size available, but will revert to smaller reads if necessary.
4986 @param VmPtr A pointer to a VM context.
4987 @param Offset offset from IP of the code bytes to read.
4989 @return Signed data of the requested size from the specified address.
4994 IN VM_CONTEXT
*VmPtr
,
5003 // Read direct if aligned
5005 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT64
))) {
5006 return * (UINT64
*) (VmPtr
->Ip
+ Offset
);
5009 // Return unaligned data.
5011 Ptr
= (UINT8
*) &Data64
;
5012 Data32
= VmReadCode32 (VmPtr
, Offset
);
5013 *(UINT32
*) Ptr
= Data32
;
5014 Ptr
+= sizeof (Data32
);
5015 Data32
= VmReadCode32 (VmPtr
, Offset
+ sizeof (UINT32
));
5016 *(UINT32
*) Ptr
= Data32
;
5022 Reads 16-bit unsigned data from the code stream.
5024 This routine provides the ability to read raw unsigned data from the code
5027 @param VmPtr A pointer to VM context
5028 @param Offset Offset from current IP to the raw data to read.
5030 @return The raw unsigned 16-bit value from the code stream.
5035 IN VM_CONTEXT
*VmPtr
,
5040 // Read direct if aligned
5042 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT16
))) {
5043 return * (UINT16
*) (VmPtr
->Ip
+ Offset
);
5046 // All code word reads should be aligned
5048 EbcDebugSignalException (
5049 EXCEPT_EBC_ALIGNMENT_CHECK
,
5050 EXCEPTION_FLAG_WARNING
,
5055 // Return unaligned data
5057 return (UINT16
) (*(UINT8
*) (VmPtr
->Ip
+ Offset
) + (*(UINT8
*) (VmPtr
->Ip
+ Offset
+ 1) << 8));
5062 Reads 32-bit unsigned data from the code stream.
5064 This routine provides the ability to read raw unsigned data from the code
5067 @param VmPtr A pointer to VM context
5068 @param Offset Offset from current IP to the raw data to read.
5070 @return The raw unsigned 32-bit value from the code stream.
5075 IN VM_CONTEXT
*VmPtr
,
5081 // Read direct if aligned
5083 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT32
))) {
5084 return * (UINT32
*) (VmPtr
->Ip
+ Offset
);
5087 // Return unaligned data
5089 Data
= (UINT32
) VmReadCode16 (VmPtr
, Offset
);
5090 Data
|= (VmReadCode16 (VmPtr
, Offset
+ 2) << 16);
5096 Reads 64-bit unsigned data from the code stream.
5098 This routine provides the ability to read raw unsigned data from the code
5101 @param VmPtr A pointer to VM context
5102 @param Offset Offset from current IP to the raw data to read.
5104 @return The raw unsigned 64-bit value from the code stream.
5109 IN VM_CONTEXT
*VmPtr
,
5118 // Read direct if aligned
5120 if (IS_ALIGNED ((UINTN
) VmPtr
->Ip
+ Offset
, sizeof (UINT64
))) {
5121 return * (UINT64
*) (VmPtr
->Ip
+ Offset
);
5124 // Return unaligned data.
5126 Ptr
= (UINT8
*) &Data64
;
5127 Data32
= VmReadCode32 (VmPtr
, Offset
);
5128 *(UINT32
*) Ptr
= Data32
;
5129 Ptr
+= sizeof (Data32
);
5130 Data32
= VmReadCode32 (VmPtr
, Offset
+ sizeof (UINT32
));
5131 *(UINT32
*) Ptr
= Data32
;
5137 Reads 8-bit data form the memory address.
5139 @param VmPtr A pointer to VM context.
5140 @param Addr The memory address.
5142 @return The 8-bit value from the memory address.
5147 IN VM_CONTEXT
*VmPtr
,
5152 // Convert the address if it's in the stack gap
5154 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5156 // Simply return the data in flat memory space
5158 return * (UINT8
*) Addr
;
5162 Reads 16-bit data form the memory address.
5164 @param VmPtr A pointer to VM context.
5165 @param Addr The memory address.
5167 @return The 16-bit value from the memory address.
5172 IN VM_CONTEXT
*VmPtr
,
5177 // Convert the address if it's in the stack gap
5179 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5181 // Read direct if aligned
5183 if (IS_ALIGNED (Addr
, sizeof (UINT16
))) {
5184 return * (UINT16
*) Addr
;
5187 // Return unaligned data
5189 return (UINT16
) (*(UINT8
*) Addr
+ (*(UINT8
*) (Addr
+ 1) << 8));
5193 Reads 32-bit data form the memory address.
5195 @param VmPtr A pointer to VM context.
5196 @param Addr The memory address.
5198 @return The 32-bit value from the memory address.
5203 IN VM_CONTEXT
*VmPtr
,
5210 // Convert the address if it's in the stack gap
5212 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5214 // Read direct if aligned
5216 if (IS_ALIGNED (Addr
, sizeof (UINT32
))) {
5217 return * (UINT32
*) Addr
;
5220 // Return unaligned data
5222 Data
= (UINT32
) VmReadMem16 (VmPtr
, Addr
);
5223 Data
|= (VmReadMem16 (VmPtr
, Addr
+ 2) << 16);
5228 Reads 64-bit data form the memory address.
5230 @param VmPtr A pointer to VM context.
5231 @param Addr The memory address.
5233 @return The 64-bit value from the memory address.
5238 IN VM_CONTEXT
*VmPtr
,
5246 // Convert the address if it's in the stack gap
5248 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5251 // Read direct if aligned
5253 if (IS_ALIGNED (Addr
, sizeof (UINT64
))) {
5254 return * (UINT64
*) Addr
;
5257 // Return unaligned data. Assume little endian.
5259 Data
= (UINT64
) VmReadMem32 (VmPtr
, Addr
);
5260 Data32
= VmReadMem32 (VmPtr
, Addr
+ sizeof (UINT32
));
5261 *(UINT32
*) ((UINT32
*) &Data
+ 1) = Data32
;
5267 Given an address that EBC is going to read from or write to, return
5268 an appropriate address that accounts for a gap in the stack.
5269 The stack for this application looks like this (high addr on top)
5270 [EBC entry point arguments]
5273 The EBC assumes that its arguments are at the top of its stack, which
5274 is where the VM stack is really. Therefore if the EBC does memory
5275 accesses into the VM stack area, then we need to convert the address
5276 to point to the EBC entry point arguments area. Do this here.
5278 @param VmPtr A Pointer to VM context.
5279 @param Addr Address of interest
5281 @return The unchanged address if it's not in the VM stack region. Otherwise,
5282 adjust for the stack gap and return the modified address.
5287 IN VM_CONTEXT
*VmPtr
,
5291 ASSERT(((Addr
< VmPtr
->LowStackTop
) || (Addr
> VmPtr
->HighStackBottom
)));
5297 Read a natural value from memory. May or may not be aligned.
5299 @param VmPtr current VM context
5300 @param Addr the address to read from
5302 @return The natural value at address Addr.
5307 IN VM_CONTEXT
*VmPtr
,
5312 volatile UINT32 Size
;
5316 // Convert the address if it's in the stack gap
5318 Addr
= ConvertStackAddr (VmPtr
, Addr
);
5320 // Read direct if aligned
5322 if (IS_ALIGNED (Addr
, sizeof (UINTN
))) {
5323 return * (UINTN
*) Addr
;
5326 // Return unaligned data
5329 FromPtr
= (UINT8
*) Addr
;
5330 ToPtr
= (UINT8
*) &Data
;
5332 for (Size
= 0; Size
< sizeof (Data
); Size
++) {
5342 Returns the version of the EBC virtual machine.
5344 @return The 64-bit version of EBC virtual machine.
5352 return (UINT64
) (((VM_MAJOR_VERSION
& 0xFFFF) << 16) | ((VM_MINOR_VERSION
& 0xFFFF)));